Utilities
CustomJSONEncoder
¶
Bases: JSONEncoder
Custom JSON encoder that: 1. Converts numpy arrays/matrices to lists 2. Cleans numerical values (removes near-zero noise, rounds to precision) 3. Converts sets to lists
Source code in onshape_robotics_toolkit\utilities\helpers.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |
__init__(*args, clean_numerics=True, threshold=1e-10, decimals=8, **kwargs)
¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clean_numerics
|
bool
|
If True, clean numeric values (default True) |
True
|
threshold
|
float
|
Values below this are set to 0 (default 1e-10) |
1e-10
|
decimals
|
int
|
Number of decimal places to round to (default 8) |
8
|
Source code in onshape_robotics_toolkit\utilities\helpers.py
111 112 113 114 115 116 117 118 119 120 121 122 123 | |
default(obj)
¶
Handle non-serializable objects.
Source code in onshape_robotics_toolkit\utilities\helpers.py
149 150 151 152 153 154 155 156 | |
encode(obj)
¶
Override encode to clean numerics in the entire structure.
Source code in onshape_robotics_toolkit\utilities\helpers.py
125 126 127 128 129 | |
clean_json_numerics(data, threshold=1e-10, decimals=8)
¶
Recursively clean numeric values in a JSON-like data structure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Any
|
JSON data (dict, list, or scalar) |
required |
threshold
|
float
|
Values below this are set to 0 |
1e-10
|
decimals
|
int
|
Number of decimal places to round to |
8
|
Returns:
| Type | Description |
|---|---|
Any
|
Cleaned data structure |
Source code in onshape_robotics_toolkit\utilities\helpers.py
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
clean_name_for_urdf(name)
¶
Clean a name to be URDF-safe by replacing problematic characters.
This is similar to get_sanitized_name but specifically for URDF compatibility, following the reference implementation's approach.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name to clean for URDF compatibility. |
required |
Returns:
| Type | Description |
|---|---|
str
|
URDF-safe name. |
Examples:
>>> clean_name_for_urdf("wheel <1>")
"wheel_(1)"
>>> clean_name_for_urdf("joint/arm\link")
"joint_arm_link"
Source code in onshape_robotics_toolkit\utilities\helpers.py
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | |
clean_numeric_list(data, threshold=1e-10, decimals=8)
¶
Recursively clean numeric values in nested lists/arrays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Any
|
Data structure (can be list, nested list, or scalar) |
required |
threshold
|
float
|
Values with absolute value below this are set to 0 |
1e-10
|
decimals
|
int
|
Number of decimal places to round to |
8
|
Returns:
| Type | Description |
|---|---|
Any
|
Cleaned data structure |
Source code in onshape_robotics_toolkit\utilities\helpers.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
clean_numeric_value(value, threshold=1e-10, decimals=8)
¶
Clean a numeric value by: 1. Setting values below threshold to exactly 0 2. Rounding to specified decimal places
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float
|
The numeric value to clean |
required |
threshold
|
float
|
Values with absolute value below this are set to 0 (default 1e-10) |
1e-10
|
decimals
|
int
|
Number of decimal places to round to (default 8) |
8
|
Returns:
| Type | Description |
|---|---|
float
|
Cleaned numeric value |
Examples:
>>> clean_numeric_value(5.62050406e-16)
0.0
>>> clean_numeric_value(0.123456789012345, decimals=5)
0.12346
>>> clean_numeric_value(-1e-11)
0.0
Source code in onshape_robotics_toolkit\utilities\helpers.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | |
format_number(value)
¶
Format a number to 8 significant figures
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float
|
Number to format |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Formatted number |
Examples:
>>> format_number(0.123456789)
"0.12345679"
>>> format_number(123456789)
"123456789"
Source code in onshape_robotics_toolkit\utilities\helpers.py
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | |
generate_uid(values)
¶
Generate a 16-character unique identifier from a list of strings
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
list[str]
|
List of strings to concatenate |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Unique identifier |
Examples:
>>> generate_uid(["hello", "world"])
"c4ca4238a0b92382"
Source code in onshape_robotics_toolkit\utilities\helpers.py
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | |
get_random_files(directory, file_extension, count)
¶
Get random files from a directory with a specific file extension and count
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
str
|
Directory path |
required |
file_extension
|
str
|
File extension |
required |
count
|
int
|
Number of files to select |
required |
Returns:
| Type | Description |
|---|---|
tuple[list[str], list[str]]
|
list[str]: List of file paths |
Raises:
| Type | Description |
|---|---|
ValueError
|
Not enough files in directory if count exceeds number of files |
Examples:
>>> get_random_files("json", ".json", 1)
["json/file.json"]
>>> get_random_files("json", ".json", 2)
["json/file1.json", "json/file2.json"]
Source code in onshape_robotics_toolkit\utilities\helpers.py
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | |
get_random_names(directory, count, filename='words.txt')
¶
Generate random names from a list of words in a file
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
directory
|
str
|
Path to directory containing words file |
required |
count
|
int
|
Number of random names to generate |
required |
filename
|
str
|
File containing list of words. Default is "words.txt" |
'words.txt'
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of random names |
Raises:
| Type | Description |
|---|---|
ValueError
|
If count exceeds the number of available words |
Examples:
>>> get_random_names(directory="../", count=1)
["charizard"]
>>> get_random_names(directory="../", count=2)
["charizard", "pikachu"]
Source code in onshape_robotics_toolkit\utilities\helpers.py
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | |
get_sanitized_name(name, replace_with='_', remove_onshape_tags=False)
¶
Sanitize a name by removing special characters, preserving only the specified
replacement character, and replacing spaces with it. Ensures no consecutive
replacement characters in the result.
Optionally preserves a trailing "
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name to sanitize. |
required |
replace_with
|
str
|
Character to replace spaces and other special characters with (default is '_'). |
'_'
|
remove_onshape_tags
|
bool
|
If True, removes a trailing " |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Sanitized name. |
Examples:
>>> get_sanitized_name("wheel1 <3>")
"wheel1_3"
>>> get_sanitized_name("wheel1 <3>", remove_onshape_tags=True)
"wheel1"
>>> get_sanitized_name("wheel1 <3>", replace_with='-', remove_onshape_tags=False)
"wheel1-3"
Source code in onshape_robotics_toolkit\utilities\helpers.py
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | |
load_model_from_json(model_class, file_path, clean_numerics=True, threshold=1e-10, decimals=8)
¶
Load a Pydantic model from a JSON file with optional numeric cleaning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_class
|
type[BaseModel]
|
The Pydantic model class to instantiate |
required |
file_path
|
str
|
Path to JSON file |
required |
clean_numerics
|
bool
|
If True, clean numeric values before validation (default True) |
True
|
threshold
|
float
|
Values below this are set to 0 (default 1e-10) |
1e-10
|
decimals
|
int
|
Number of decimal places to round to (default 8) |
8
|
Returns:
| Name | Type | Description |
|---|---|---|
BaseModel |
BaseModel
|
Instance of the model class populated from JSON |
Examples:
>>> class TestModel(BaseModel):
... a: int
... b: str
...
>>> model = load_model_from_json(TestModel, "test.json")
>>> print(model.a, model.b)
1 hello
>>> from onshape_robotics_toolkit.models import Assembly
>>> assembly = load_model_from_json(Assembly, "assembly.json")
>>> assembly = load_model_from_json(Assembly, "assembly.json", decimals=5)
Source code in onshape_robotics_toolkit\utilities\helpers.py
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | |
make_unique_keys(keys)
¶
Make a list of keys unique by appending a number to duplicate keys and return a mapping of unique keys to their original indices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
keys
|
list[str]
|
List of keys. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
A dictionary mapping unique keys to their original indices. |
Examples:
>>> make_unique_keys(["a", "b", "a", "a"])
{"a": 0, "b": 1, "a-1": 2, "a-2": 3}
Source code in onshape_robotics_toolkit\utilities\helpers.py
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | |
make_unique_name(name, existing_names)
¶
Make a name unique by appending a number to the name if it already exists in a set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name to make unique. |
required |
existing_names
|
set[str]
|
Set of existing names. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A unique name. |
Examples:
>>> make_unique_name("name", {"name"})
"name-1"
>>> make_unique_name("name", {"name", "name-1"})
"name-2"
Source code in onshape_robotics_toolkit\utilities\helpers.py
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | |
parse_onshape_expression(expr)
¶
Parse an Onshape expression string to a float value.
Handles common units for angles and lengths. Returns None if the expression is None, empty, or cannot be parsed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
str | None
|
Onshape expression string (e.g., "90 deg", "0.5 m", "100 mm") |
required |
Returns:
| Type | Description |
|---|---|
float | None
|
Parsed float value with appropriate unit conversion, or None if invalid |
Unit Conversions
- Angles: "deg" or "°" → radians, "rad" → as-is
- Length: "m" → as-is, "mm" → /1000, "cm" → /100, "in" → *0.0254
- No unit: return float as-is
Examples:
>>> parse_onshape_expression("90 deg")
1.5707963267948966
>>> parse_onshape_expression("0.5 m")
0.5
>>> parse_onshape_expression("100 mm")
0.1
>>> parse_onshape_expression("3.14159")
3.14159
>>> parse_onshape_expression(None)
None
>>> parse_onshape_expression("")
None
Source code in onshape_robotics_toolkit\utilities\helpers.py
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | |
print_dict(d, indent=0)
¶
Print a dictionary with indentation for nested dictionaries
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
Dictionary to print |
required |
indent
|
int
|
Number of tabs to indent |
0
|
Returns:
| Type | Description |
|---|---|
None
|
None |
Examples:
>>> print_dict({"a": 1, "b": {"c": 2}})
a
1
b
c
2
Source code in onshape_robotics_toolkit\utilities\helpers.py
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | |
print_tf(tf)
¶
Print a 4x4 transformation matrix in a readable format
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tf
|
ndarray
|
4x4 transformation matrix |
required |
Returns:
| Type | Description |
|---|---|
None
|
None |
Examples:
>>> import numpy as np
>>> tf = np.array([[1, 0, 0, 1],
... [0, 1, 0, 2],
... [0, 0, 1, 3],
... [0, 0, 0, 1]])
>>> print_tf(tf)
[[1. 0. 0. 1. ]
[0. 1. 0. 2. ]
[0. 0. 1. 3. ]
[0. 0. 0. 1. ]]
Source code in onshape_robotics_toolkit\utilities\helpers.py
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | |
save_model_as_json(model, file_path, indent=4, clean_numerics=True, threshold=1e-10, decimals=8)
¶
Save a Pydantic model as a JSON file with optional numeric cleaning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
BaseModel
|
Pydantic model to save |
required |
file_path
|
str
|
File path to save JSON file |
required |
indent
|
int
|
JSON indentation level |
4
|
clean_numerics
|
bool
|
If True, clean numeric values (default True) |
True
|
threshold
|
float
|
Values below this are set to 0 (default 1e-10) |
1e-10
|
decimals
|
int
|
Number of decimal places to round to (default 8) |
8
|
Returns:
| Type | Description |
|---|---|
None
|
None |
Examples:
>>> class TestModel(BaseModel):
... a: int
... b: str
...
>>> save_model_as_json(TestModel(a=1, b="hello"), "test.json")
>>> save_model_as_json(model, "test.json", decimals=5, threshold=1e-8)
Source code in onshape_robotics_toolkit\utilities\helpers.py
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | |
setup_console_logging(level='INFO', format_string=None, colorize=True)
¶
Add a console (stderr) logging handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
str
|
Minimum log level to display (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
'INFO'
|
format_string
|
str | None
|
Custom format string. If None, uses DEFAULT_CONSOLE_FORMAT |
None
|
colorize
|
bool
|
Whether to colorize the output |
True
|
Returns:
| Type | Description |
|---|---|
int
|
Handler ID that can be used with logger.remove() if needed |
Example
from onshape_robotics_toolkit.utilities import setup_console_logging setup_console_logging(level="DEBUG")
Source code in onshape_robotics_toolkit\utilities\helpers.py
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | |
setup_default_logging(console_level='INFO', file_level='DEBUG', file_path='onshape_toolkit.log', clear_existing_handlers=True, delay_file_creation=False)
¶
Configure logging with sensible defaults: console at INFO + file at DEBUG.
This is the recommended way to set up logging for most users. It provides: - Colored console output at INFO level or higher - Detailed file logging at DEBUG level or higher - Automatic log rotation (10 MB) and retention (7 days) - Compressed archives of rotated logs
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
console_level
|
str
|
Minimum level for console output (default: "INFO") |
'INFO'
|
file_level
|
str
|
Minimum level for file output (default: "DEBUG") |
'DEBUG'
|
file_path
|
str
|
Path to the log file (default: "onshape_toolkit.log") |
'onshape_toolkit.log'
|
clear_existing_handlers
|
bool
|
Whether to remove existing handlers first (default: True) |
True
|
Returns:
| Type | Description |
|---|---|
tuple[int, int]
|
Tuple of (console_handler_id, file_handler_id) |
Example
from onshape_robotics_toolkit.utilities import setup_default_logging setup_default_logging() # Use all defaults
Or customize:¶
setup_default_logging(console_level="DEBUG", file_path="my_robot.log")
Source code in onshape_robotics_toolkit\utilities\helpers.py
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 | |
setup_file_logging(file_path='onshape_toolkit.log', level='DEBUG', format_string=None, rotation='10 MB', retention='7 days', compression='zip', enqueue=True, delay=False)
¶
Add a file logging handler with rotation and compression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str
|
Path to the log file |
'onshape_toolkit.log'
|
level
|
str
|
Minimum log level to write (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
'DEBUG'
|
format_string
|
str | None
|
Custom format string. If None, uses DEFAULT_FILE_FORMAT |
None
|
rotation
|
str
|
When to rotate the log file (e.g., "10 MB", "1 day", "12:00") |
'10 MB'
|
retention
|
str
|
How long to keep old log files (e.g., "7 days", "10 files") |
'7 days'
|
compression
|
str
|
Compression format for rotated files ("zip", "gz", "bz2", or None) |
'zip'
|
enqueue
|
bool
|
Whether to use thread-safe logging (recommended) |
True
|
Returns:
| Type | Description |
|---|---|
int
|
Handler ID that can be used with logger.remove() if needed |
Example
from onshape_robotics_toolkit.utilities import setup_file_logging setup_file_logging("my_robot.log", level="DEBUG", rotation="50 MB")
Source code in onshape_robotics_toolkit\utilities\helpers.py
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | |
setup_minimal_logging(level='INFO')
¶
Configure minimal console-only logging without file output.
Useful for quick scripts or when you don't want log files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
str
|
Minimum log level to display (default: "INFO") |
'INFO'
|
Returns:
| Type | Description |
|---|---|
int
|
Handler ID that can be used with logger.remove() if needed |
Example
from onshape_robotics_toolkit.utilities import setup_minimal_logging setup_minimal_logging(level="WARNING")
Source code in onshape_robotics_toolkit\utilities\helpers.py
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 | |
setup_quiet_logging(file_path='onshape_toolkit.log', level='DEBUG')
¶
Configure file-only logging with no console output.
Useful for background tasks or automated scripts where console output would be distracting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str
|
Path to the log file (default: "onshape_toolkit.log") |
'onshape_toolkit.log'
|
level
|
str
|
Minimum log level to write (default: "DEBUG") |
'DEBUG'
|
Returns:
| Type | Description |
|---|---|
int
|
Handler ID that can be used with logger.remove() if needed |
Example
from onshape_robotics_toolkit.utilities import setup_quiet_logging setup_quiet_logging("background_task.log")
Source code in onshape_robotics_toolkit\utilities\helpers.py
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | |
xml_escape(unescaped)
¶
Escape XML characters in a string
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unescaped
|
str
|
Unescaped string |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Escaped string |
Examples:
>>> xml_escape("hello 'world' "world"")
"hello 'world' "world""
>>> xml_escape("hello <world>")
"hello <world>"
Source code in onshape_robotics_toolkit\utilities\helpers.py
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | |