symdef 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- symdef-0.4.0/.gitattributes +1 -0
- symdef-0.4.0/.github/workflows/docs.yml +33 -0
- symdef-0.4.0/.github/workflows/publish.yml +37 -0
- symdef-0.4.0/.gitignore +8 -0
- symdef-0.4.0/.python-version +1 -0
- symdef-0.4.0/AGENTS.md +12 -0
- symdef-0.4.0/CLAUDE.md +62 -0
- symdef-0.4.0/LICENSE +21 -0
- symdef-0.4.0/PKG-INFO +114 -0
- symdef-0.4.0/README.md +102 -0
- symdef-0.4.0/docs/DECISIONS.md +814 -0
- symdef-0.4.0/docs/GUIDE.md +215 -0
- symdef-0.4.0/justfile +39 -0
- symdef-0.4.0/pyproject.toml +115 -0
- symdef-0.4.0/schema/symbol.schema.json +247 -0
- symdef-0.4.0/scripts/build.py +41 -0
- symdef-0.4.0/scripts/build_site.py +69 -0
- symdef-0.4.0/scripts/fp_purity_gate.py +66 -0
- symdef-0.4.0/src/symdef/__init__.py +97 -0
- symdef-0.4.0/src/symdef/_version.py +3 -0
- symdef-0.4.0/src/symdef/boxes.py +112 -0
- symdef-0.4.0/src/symdef/build.py +207 -0
- symdef-0.4.0/src/symdef/docs/SYMBOL_INTERFACE.html +573 -0
- symdef-0.4.0/src/symdef/errors.py +23 -0
- symdef-0.4.0/src/symdef/gallery.py +85 -0
- symdef-0.4.0/src/symdef/geometry.py +209 -0
- symdef-0.4.0/src/symdef/lint/__init__.py +141 -0
- symdef-0.4.0/src/symdef/lint/anchors.py +40 -0
- symdef-0.4.0/src/symdef/lint/connectivity.py +186 -0
- symdef-0.4.0/src/symdef/lint/exemptions.py +56 -0
- symdef-0.4.0/src/symdef/lint/file.py +124 -0
- symdef-0.4.0/src/symdef/lint/geometry.py +269 -0
- symdef-0.4.0/src/symdef/lint/overlap.py +274 -0
- symdef-0.4.0/src/symdef/lint/ports.py +253 -0
- symdef-0.4.0/src/symdef/lint/registry.py +172 -0
- symdef-0.4.0/src/symdef/lint/slots.py +136 -0
- symdef-0.4.0/src/symdef/load.py +621 -0
- symdef-0.4.0/src/symdef/model.py +248 -0
- symdef-0.4.0/src/symdef/orient.py +151 -0
- symdef-0.4.0/src/symdef/py.typed +0 -0
- symdef-0.4.0/src/symdef/repeat.py +99 -0
- symdef-0.4.0/src/symdef/resolve.py +586 -0
- symdef-0.4.0/src/symdef/serialize.py +239 -0
- symdef-0.4.0/src/symdef/svg.py +505 -0
- symdef-0.4.0/src/symdef/units.py +18 -0
- symdef-0.4.0/tests/build_symbol.py +19 -0
- symdef-0.4.0/tests/damage.py +63 -0
- symdef-0.4.0/tests/fixture_pipeline.py +62 -0
- symdef-0.4.0/tests/fixtures/broken/allow-unknown/symbols/S00001.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/allow-unknown/symbols/S00002.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/allow-unused/symbols/S00001.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/anchor-duplicate-id/symbols/S00001.toml +14 -0
- symdef-0.4.0/tests/fixtures/broken/anchor-off-geometry/symbols/S00001.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/degenerate/symbols/S00001.toml +14 -0
- symdef-0.4.0/tests/fixtures/broken/degenerate/symbols/S00002.toml +12 -0
- symdef-0.4.0/tests/fixtures/broken/export-unknown/symbols/S00001.toml +11 -0
- symdef-0.4.0/tests/fixtures/broken/export-unknown/symbols/S00010.toml +17 -0
- symdef-0.4.0/tests/fixtures/broken/id-format/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/id-format/symbols/S00002.toml +18 -0
- symdef-0.4.0/tests/fixtures/broken/id-format/symbols/S00010.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/lead-off-port/symbols/S00001.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/lead-off-port/symbols/S00002.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/lead-off-port/symbols/S00003.toml +20 -0
- symdef-0.4.0/tests/fixtures/broken/library.toml +3 -0
- symdef-0.4.0/tests/fixtures/broken/metadata/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/node-invalid/symbols/S00001.toml +21 -0
- symdef-0.4.0/tests/fixtures/broken/off-drawing-grid/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/off-drawing-grid/symbols/S00002.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/off-drawing-grid/symbols/S00003.toml +12 -0
- symdef-0.4.0/tests/fixtures/broken/off-drawing-grid/symbols/S00004.toml +12 -0
- symdef-0.4.0/tests/fixtures/broken/part-anchor/symbols/S00001.toml +10 -0
- symdef-0.4.0/tests/fixtures/broken/part-anchor/symbols/S00010.toml +13 -0
- symdef-0.4.0/tests/fixtures/broken/part-cycle/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/part-cycle/symbols/S00010.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/part-port-unexported/symbols/S00001.toml +11 -0
- symdef-0.4.0/tests/fixtures/broken/part-port-unexported/symbols/S00010.toml +18 -0
- symdef-0.4.0/tests/fixtures/broken/part-unknown/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/path-invalid/symbols/S00001.toml +20 -0
- symdef-0.4.0/tests/fixtures/broken/path-invalid/symbols/S00002.toml +23 -0
- symdef-0.4.0/tests/fixtures/broken/path-invalid/symbols/S00003.toml +20 -0
- symdef-0.4.0/tests/fixtures/broken/pitch-overflow/symbols/S00001.toml +27 -0
- symdef-0.4.0/tests/fixtures/broken/pitch-overflow/symbols/S00002.toml +26 -0
- symdef-0.4.0/tests/fixtures/broken/pitch-overflow/symbols/S00003.toml +26 -0
- symdef-0.4.0/tests/fixtures/broken/port-duplicate-id/symbols/S00001.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/port-isolated/symbols/S00001.toml +20 -0
- symdef-0.4.0/tests/fixtures/broken/port-lane-clear/symbols/S00001.toml +25 -0
- symdef-0.4.0/tests/fixtures/broken/port-lane-clear/symbols/S00002.toml +25 -0
- symdef-0.4.0/tests/fixtures/broken/port-off-geometry/symbols/S00001.toml +17 -0
- symdef-0.4.0/tests/fixtures/broken/port-off-wiring-grid/symbols/S00001.toml +17 -0
- symdef-0.4.0/tests/fixtures/broken/port-on-body-edge/symbols/S00001.toml +20 -0
- symdef-0.4.0/tests/fixtures/broken/port-on-body-edge/symbols/S00002.toml +21 -0
- symdef-0.4.0/tests/fixtures/broken/port-position-shared/symbols/S00001.toml +18 -0
- symdef-0.4.0/tests/fixtures/broken/port-spacing/symbols/S00001.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/schema/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/slot-missing/symbols/S00001.toml +24 -0
- symdef-0.4.0/tests/fixtures/broken/slot-missing/symbols/S00002.toml +24 -0
- symdef-0.4.0/tests/fixtures/broken/slot-overlap-body/symbols/S00001.toml +25 -0
- symdef-0.4.0/tests/fixtures/broken/slot-overlap-body/symbols/S00002.toml +26 -0
- symdef-0.4.0/tests/fixtures/broken/slot-overlap-slot/symbols/S00001.toml +23 -0
- symdef-0.4.0/tests/fixtures/broken/slot-overlap-slot/symbols/S00002.toml +26 -0
- symdef-0.4.0/tests/fixtures/broken/slot-unknown-port/symbols/S00001.toml +23 -0
- symdef-0.4.0/tests/fixtures/broken/text-too-large/symbols/S00001.toml +9 -0
- symdef-0.4.0/tests/fixtures/broken/through-axis/symbols/S00001.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/through-axis/symbols/S00002.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/through-axis/symbols/S00003.toml +19 -0
- symdef-0.4.0/tests/fixtures/broken/through-count/symbols/S00001.toml +29 -0
- symdef-0.4.0/tests/fixtures/broken/through-missing/symbols/S00001.toml +25 -0
- symdef-0.4.0/tests/fixtures/expected/S00227.json +159 -0
- symdef-0.4.0/tests/fixtures/expected/bundle.json +271 -0
- symdef-0.4.0/tests/fixtures/guide/library.toml +3 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00016.toml +28 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00171.toml +16 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00227.toml +29 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00230.toml +35 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00254.toml +17 -0
- symdef-0.4.0/tests/fixtures/guide/symbols/S00305.toml +29 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/anchor_at_missing.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/anchor_dir_unknown.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/arc_angle_above_limit.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/arc_end_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/arc_start_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/body_box_wrong_shape.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/circle_centre_wrong_length.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/circle_radius_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/circle_radius_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/composite_ports_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/composite_symbol_without_slots.toml +14 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_closed_on_circle.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_closed_on_line.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_empty.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_fill_on_arc.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_fill_on_line.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_line_port_not_string.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_no_shape.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_not_table.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_radius_on_line.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_style_on_circle.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_style_on_text.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_style_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_two_shapes.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/element_weight_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/elements_not_array.toml +15 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/integer_400_digits_as_number.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/keepout_box_bad_point.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/kind_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/kind_wrong_case.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/line_not_array.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/line_one_point.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/line_three_points.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/lint_allow_not_array.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/lint_allow_reason_missing.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/lint_allow_rule_not_string.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/name_is_a_date.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/name_missing.toml +16 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/name_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/negative_integer_400_digits_as_number.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/neither_elements_nor_parts.toml +14 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/node_port_not_string.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/node_ports_missing.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/node_ports_not_array.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/node_potential_unknown.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_1e7.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_above_limit.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_below_negative_limit.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_inf.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_nan.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_negative_inf.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/number_negative_nan.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_as_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_at_400_digits.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_at_wrong_length.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_length_above_limit.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_length_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_orient_lowercase.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_orient_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_repeat_above_limit.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_repeat_fraction.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_unknown_key.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_use_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/part_via_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/parts_not_array.toml +14 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/path_from_not_string.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/path_kind_unknown.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/path_through_not_boolean.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/path_to_missing.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/point_boolean_coordinate.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/point_coordinate_inf.toml +10 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/point_one_coordinate.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/point_string_coordinate.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/point_three_coordinates.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/pole_pitch_400_digits.toml +11 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/pole_pitch_above_limit.toml +11 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/pole_pitch_boolean.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/pole_pitch_fraction.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/pole_pitch_string.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/polyline_closed_not_boolean.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/polyline_fill_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/polyline_point_malformed.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_at_boolean.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_at_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_description_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_dir_lowercase.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_dir_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_dir_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_id_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/port_unknown_key.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/ports_array_of_strings.toml +14 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/ports_map_value_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/ports_string.toml +14 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/reference_not_table.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/reference_number_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/reference_number_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/reference_unknown_key.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/schema_boolean.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/schema_missing.toml +16 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/schema_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/schema_wrong_number.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_at_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_box_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_box_nan.toml +13 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_box_not_numbers.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_box_three_numbers.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_side_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_unknown_key.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slot_value_integer.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/slots_not_table.toml +15 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/status_unknown.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/symbol_without_slots.toml +16 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/text_content_not_string.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/text_height_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/text_position_missing.toml +17 -0
- symdef-0.4.0/tests/fixtures/schema/invalid/top_level_unknown_key.toml +18 -0
- symdef-0.4.0/tests/fixtures/schema/valid/atomic_all_keys.toml +59 -0
- symdef-0.4.0/tests/fixtures/schema/valid/atomic_minimal.toml +16 -0
- symdef-0.4.0/tests/fixtures/schema/valid/composite_empty_rename_map.toml +9 -0
- symdef-0.4.0/tests/fixtures/schema/valid/composite_parts.toml +19 -0
- symdef-0.4.0/tests/fixtures/schema/valid/composite_with_elements.toml +19 -0
- symdef-0.4.0/tests/fixtures/schema/valid/element_kind.toml +9 -0
- symdef-0.4.0/tests/fixtures/schema/valid/element_line_with_port.toml +9 -0
- symdef-0.4.0/tests/fixtures/schema/valid/empty_polyline.toml +9 -0
- symdef-0.4.0/tests/fixtures/schema/valid/empty_tables.toml +15 -0
- symdef-0.4.0/tests/fixtures/schema/valid/integral_floats.toml +12 -0
- symdef-0.4.0/tests/fixtures/schema/valid/lint_matters_are_not_schema_matters.toml +22 -0
- symdef-0.4.0/tests/fixtures/schema/valid/numbers_at_the_limit.toml +13 -0
- symdef-0.4.0/tests/fixtures/schema/valid/qualifier_without_slots.toml +9 -0
- symdef-0.4.0/tests/fixtures/schema/valid/resolved_form.toml +33 -0
- symdef-0.4.0/tests/fixtures/schema/valid/symbol_with_empty_slots.toml +16 -0
- symdef-0.4.0/tests/fixtures/schema/valid/symbol_with_slots_but_no_tag.toml +17 -0
- symdef-0.4.0/tests/orientations.py +10 -0
- symdef-0.4.0/tests/roundtrip.py +25 -0
- symdef-0.4.0/tests/test_boxes.py +190 -0
- symdef-0.4.0/tests/test_broken_fixtures.py +160 -0
- symdef-0.4.0/tests/test_build.py +375 -0
- symdef-0.4.0/tests/test_build_load.py +167 -0
- symdef-0.4.0/tests/test_bundle.py +269 -0
- symdef-0.4.0/tests/test_gallery.py +114 -0
- symdef-0.4.0/tests/test_geometry.py +132 -0
- symdef-0.4.0/tests/test_guide_fixtures.py +149 -0
- symdef-0.4.0/tests/test_guide_lint.py +115 -0
- symdef-0.4.0/tests/test_guide_package_data.py +22 -0
- symdef-0.4.0/tests/test_lint_anchors.py +115 -0
- symdef-0.4.0/tests/test_lint_connectivity.py +493 -0
- symdef-0.4.0/tests/test_lint_driver.py +459 -0
- symdef-0.4.0/tests/test_lint_exemptions.py +116 -0
- symdef-0.4.0/tests/test_lint_file.py +216 -0
- symdef-0.4.0/tests/test_lint_geometry.py +372 -0
- symdef-0.4.0/tests/test_lint_ports.py +858 -0
- symdef-0.4.0/tests/test_lint_registry.py +123 -0
- symdef-0.4.0/tests/test_lint_slots.py +595 -0
- symdef-0.4.0/tests/test_load.py +840 -0
- symdef-0.4.0/tests/test_model.py +163 -0
- symdef-0.4.0/tests/test_orient.py +361 -0
- symdef-0.4.0/tests/test_overlap.py +536 -0
- symdef-0.4.0/tests/test_public_api.py +151 -0
- symdef-0.4.0/tests/test_purity_gate.py +92 -0
- symdef-0.4.0/tests/test_readme.py +54 -0
- symdef-0.4.0/tests/test_repeat.py +357 -0
- symdef-0.4.0/tests/test_resolve.py +1256 -0
- symdef-0.4.0/tests/test_rules_complete.py +113 -0
- symdef-0.4.0/tests/test_schema_agreement.py +127 -0
- symdef-0.4.0/tests/test_serialize.py +440 -0
- symdef-0.4.0/tests/test_site.py +24 -0
- symdef-0.4.0/tests/test_svg.py +476 -0
- symdef-0.4.0/tests/test_svg_annotated.py +526 -0
- symdef-0.4.0/tests/test_svg_total.py +156 -0
- symdef-0.4.0/tests/test_units.py +20 -0
- symdef-0.4.0/tests/test_version.py +45 -0
- symdef-0.4.0/uv.lock +441 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* text=auto eol=lf
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
16
|
+
- run: uv run --only-group dev python scripts/build_site.py site
|
|
17
|
+
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
18
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
19
|
+
with:
|
|
20
|
+
path: site/
|
|
21
|
+
|
|
22
|
+
deploy:
|
|
23
|
+
needs: build
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
environment:
|
|
26
|
+
name: github-pages
|
|
27
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
28
|
+
permissions:
|
|
29
|
+
pages: write
|
|
30
|
+
id-token: write
|
|
31
|
+
steps:
|
|
32
|
+
- id: deployment
|
|
33
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
15
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
16
|
+
- name: The tag matches the package version
|
|
17
|
+
run: test "v$(uv version --short)" = "$GITHUB_REF_NAME"
|
|
18
|
+
- run: uv build
|
|
19
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
20
|
+
with:
|
|
21
|
+
name: dist
|
|
22
|
+
path: dist/
|
|
23
|
+
|
|
24
|
+
pypi:
|
|
25
|
+
needs: build
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
environment: pypi
|
|
28
|
+
permissions:
|
|
29
|
+
id-token: write # trusted publishing: no token secret
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
32
|
+
with:
|
|
33
|
+
name: dist
|
|
34
|
+
path: dist/
|
|
35
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
36
|
+
with:
|
|
37
|
+
attestations: true
|
symdef-0.4.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.15
|
symdef-0.4.0/AGENTS.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
`CLAUDE.md` holds this repo's rules for any agent, not only Claude. This file restates none of
|
|
4
|
+
them.
|
|
5
|
+
|
|
6
|
+
- To work on the toolkit: read `CLAUDE.md`, then the spec,
|
|
7
|
+
`src/symdef/docs/SYMBOL_INTERFACE.html`. `just --list` names the recipes, and
|
|
8
|
+
`just ci` is the gate.
|
|
9
|
+
- To use the toolkit from another project: read `README.md` (install and a short tour), then
|
|
10
|
+
`docs/GUIDE.md` (the concepts and the calls). The docstrings of the names in
|
|
11
|
+
`symdef.__all__` are the API reference. The spec ships inside the package:
|
|
12
|
+
`importlib.resources.files("symdef").joinpath("docs/SYMBOL_INTERFACE.html")`.
|
symdef-0.4.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# symdef: agent guide
|
|
2
|
+
|
|
3
|
+
Standard-agnostic Python toolkit for graphical-symbol data. It reads TOML symbol files, resolves
|
|
4
|
+
composition, lints the wiring contract, renders SVG, and builds a resolved JSON bundle plus an SVG
|
|
5
|
+
gallery. Data packages hold only data and reuse this toolkit: `electrical-symbols` (a package
|
|
6
|
+
of the Fransys repo, `../fransys-dev`) now, ISO 14617 and ISA 5.1 later. Alpha,
|
|
7
|
+
single owner.
|
|
8
|
+
|
|
9
|
+
Fransys is
|
|
10
|
+
one user. It pins an exact PyPI version, and its `electrical-symbols` package is an IEC 60617
|
|
11
|
+
data package. A change Fransys needs lands here first, released as `vX.Y.Z` on PyPI, then
|
|
12
|
+
Fransys bumps its pin. No code, test or script here imports or names a Fransys package.
|
|
13
|
+
|
|
14
|
+
## The spec decides
|
|
15
|
+
|
|
16
|
+
`src/graphical_symbols/docs/SYMBOL_INTERFACE.html` (the spec; older entries in
|
|
17
|
+
`docs/DECISIONS.md` call it the guide) is the only design document. It ships as package data,
|
|
18
|
+
readable at runtime through `importlib.resources`; `electrical-symbols`' verbatim gate reads it
|
|
19
|
+
from the installed distribution (D38). It is final and binding. Read all of it before doing
|
|
20
|
+
anything. Never edit it. Definitions in it
|
|
21
|
+
(extents, overlap, orientations, the wire lane, placement, `repeat`, the 33 lint rules, the JSON
|
|
22
|
+
output format) are exact: implement them as written. The toolkit has one rule beyond the spec's
|
|
23
|
+
33, `lead-off-port` (D40).
|
|
24
|
+
|
|
25
|
+
Where the spec is silent, decide yourself and record the decision in `docs/DECISIONS.md`, one entry
|
|
26
|
+
each: what you decided, why, what it costs if wrong. If you believe the spec is wrong or
|
|
27
|
+
self-contradictory, do not edit it: implement it as written, record the concern in
|
|
28
|
+
`docs/DECISIONS.md` and report it to the owner at the end.
|
|
29
|
+
|
|
30
|
+
## The work
|
|
31
|
+
|
|
32
|
+
The toolkit the spec describes is built (spec sections 4 to 12). Work now arrives as a work
|
|
33
|
+
order from the Fransys workflow's orchestrator: a change a Fransys package needs, a
|
|
34
|
+
bug, or a new public function, each recorded in `docs/DECISIONS.md`. Keep the public names of
|
|
35
|
+
spec section 11 exactly as written; a new name gets a decision entry.
|
|
36
|
+
|
|
37
|
+
## Rules
|
|
38
|
+
|
|
39
|
+
- Python 3.15 (`.python-version`); `requires-python` is `>=3.14`, and `just
|
|
40
|
+
ci` runs the tests on 3.14 too, `uv` only (never bare `python` or `pip`), ruff, ty, pytest, hypothesis,
|
|
41
|
+
vulture, deal. Every dependency pinned to the exact latest stable version. Runtime dependency:
|
|
42
|
+
`deal` only (`jsonschema` may be a dev dependency for the agreement test). TOML is read with the
|
|
43
|
+
standard library's `tomllib`.
|
|
44
|
+
- Pure core: every module-level function in a pure module is `@deal.pure` and does not raise. Only
|
|
45
|
+
the modules that read or write files are impure. `scripts/fp_purity_gate.py` enforces it.
|
|
46
|
+
- `docs/` holds `DECISIONS.md` and `GUIDE.md` only; plans stay out of the repo.
|
|
47
|
+
- Frozen slotted dataclasses; transforms are free functions; no positional port aliases.
|
|
48
|
+
- Every gate and lint rule is proven able to fail with a deliberately broken fixture.
|
|
49
|
+
- `just ci` passes before every commit; quote its output. Look at rendered output: convert SVGs to
|
|
50
|
+
PNG and view them (`uv run --with cairosvg` or playwright, from a scratch directory outside
|
|
51
|
+
the repo).
|
|
52
|
+
- Git: stage named paths only; Conventional Commits ending with
|
|
53
|
+
the attribution line your session gives; work on a feature branch from `main`, never commit to
|
|
54
|
+
`main` directly. The orchestrator reviews, merges, pushes and tags the release (`vX.Y.Z`,
|
|
55
|
+
matching `version` in `pyproject.toml`); an implementer does not.
|
|
56
|
+
- Never edit another repo. A change Fransys needs because of yours goes in your hand-back.
|
|
57
|
+
|
|
58
|
+
## Done means
|
|
59
|
+
|
|
60
|
+
The work order's acceptance is met, every new rule or gate has a failing fixture, `just ci` is
|
|
61
|
+
green (quote it), and the hand-back lists every decision recorded and anything the owner must
|
|
62
|
+
decide.
|
symdef-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OleJBondahl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
symdef-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: symdef
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Standard-agnostic core for graphical symbols as strict, typed, immutable Python values
|
|
5
|
+
Project-URL: Repository, https://github.com/OleJBondahl/symdef
|
|
6
|
+
Author: Ole Johan Bondahl
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.14
|
|
10
|
+
Requires-Dist: deal==4.24.6
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# symdef
|
|
14
|
+
|
|
15
|
+
Standard-agnostic toolkit for graphical-symbol data. Symbols are TOML files; the toolkit loads
|
|
16
|
+
them, resolves composition, lints the wiring contract, renders SVG, and builds a resolved JSON
|
|
17
|
+
bundle plus a gallery. Data packages hold only data and reuse the toolkit and its gates:
|
|
18
|
+
`electrical-symbols` (IEC 60617-style symbols, Fransys' `packages/electrical-symbols`) now, ISO 14617 and
|
|
19
|
+
ISA 5.1 later.
|
|
20
|
+
|
|
21
|
+
Status: alpha. The toolkit the spec below describes is built: reading, resolving, linting, SVG and
|
|
22
|
+
the build, with every lint rule and gate proven by a failing fixture. Released by exact git tags
|
|
23
|
+
(`v0.1.0` to `v0.3.0` as `graphical-symbols`; `v0.4.0` on as `symdef`); Fransys pins one of them.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
uv add "symdef==0.4.0"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Python 3.14 or later. The one runtime dependency is `deal`. More depth:
|
|
32
|
+
[docs/GUIDE.md](docs/GUIDE.md).
|
|
33
|
+
|
|
34
|
+
## The design
|
|
35
|
+
|
|
36
|
+
[src/symdef/docs/SYMBOL_INTERFACE.html](src/symdef/docs/SYMBOL_INTERFACE.html)
|
|
37
|
+
is the binding, final spec. Open it in a browser; it ships as package data, readable at runtime
|
|
38
|
+
through `importlib.resources.files("symdef").joinpath("docs/SYMBOL_INTERFACE.html")`.
|
|
39
|
+
The key ideas:
|
|
40
|
+
|
|
41
|
+
- A symbol is a definition: no tag, terminal numbers, position or orientation. Those belong to
|
|
42
|
+
the placement in a drawing library.
|
|
43
|
+
- Port ids are roles (`in`, `out`, `anode`, ...), never terminal markings (`13`, `A1`).
|
|
44
|
+
- Electrical function is data: nodes and typed paths, so a consumer can netlist without
|
|
45
|
+
per-symbol knowledge.
|
|
46
|
+
- Text lives in slots: the symbol reserves boxes for tags and terminal markings.
|
|
47
|
+
- Module units (M = 2.5 mm), a 0.125 M drawing grid and a 1 M wiring grid. A strict wiring
|
|
48
|
+
contract is linted in all 8 orientations.
|
|
49
|
+
- Composition mirrors the standard: composites reference parts by anchor, no copied coordinates.
|
|
50
|
+
|
|
51
|
+
## What is here
|
|
52
|
+
|
|
53
|
+
The data model and `orient`, the boxes and `repeat`, the TOML reader with its JSON Schema
|
|
54
|
+
(`schema/symbol.schema.json`), the composition resolver, 34 lint rules, plain and annotated SVG,
|
|
55
|
+
and the build (resolved JSON per symbol, the bundle, SVGs, a gallery README). Decisions the spec
|
|
56
|
+
leaves open, and concerns about the spec, are in [docs/DECISIONS.md](docs/DECISIONS.md).
|
|
57
|
+
|
|
58
|
+
## Use
|
|
59
|
+
|
|
60
|
+
A data repo has `library.toml` and `symbols/<number>.toml`; `root` below is its directory.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from symdef import lint, load_library
|
|
64
|
+
from symdef.lint import RULES
|
|
65
|
+
|
|
66
|
+
library = load_library(root) # raises LibraryError, listing every problem in the files
|
|
67
|
+
contact = library.get("S00227") # by number; iterating a library is sorted by number
|
|
68
|
+
assert len(RULES) == 34 # the spec's 33 rules plus lead-off-port (D40)
|
|
69
|
+
findings = lint(contact) # all 34 rules, geometric ones in all 8 orientations
|
|
70
|
+
assert findings == () # the spec's make contact lints clean
|
|
71
|
+
for finding in findings: # each has .rule, .severity, .message, .location, .orientation
|
|
72
|
+
print(finding.rule, finding.location, finding.message)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Symbols are immutable; `orient`, `translate` and `repeat` return new ones. A repeated symbol is
|
|
76
|
+
an ordinary symbol with ports such as `1.in` and `3.out`.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from symdef import Orientation, keepout_box, orient, repeat, to_svg
|
|
80
|
+
|
|
81
|
+
breaker = orient(repeat(contact, 3), Orientation.R0)
|
|
82
|
+
print(keepout_box(breaker))
|
|
83
|
+
svg = to_svg(breaker, annotate=True, texts={"tag": "-Q1"})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`write_build` writes `build/` and `src/<package>/bundle.json` under the repo; `stale_build` lists
|
|
87
|
+
the files that differ from what it would write, so a test can fail when a committed build is out
|
|
88
|
+
of date. `load_bundle` reads a bundle back without the sources. `<package>` is the standard's
|
|
89
|
+
normalised name (lowercase letters and digits, D8): the example's standard is `IEC 60617`, so its
|
|
90
|
+
package is `iec60617`.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from symdef import load_bundle, stale_build, write_build
|
|
94
|
+
|
|
95
|
+
write_build(library, root)
|
|
96
|
+
assert stale_build(library, root) == ()
|
|
97
|
+
assert len(load_bundle(root / "src" / "iec60617" / "bundle.json")) == len(library)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
uv sync
|
|
104
|
+
just ci # format check, ruff, ty, vulture, purity gate, pytest with coverage
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Coverage must stay at 100% (`--cov-fail-under=100`), so a partial run such as
|
|
108
|
+
`uv run pytest tests/test_units.py` fails on coverage alone: add `--no-cov` for one.
|
|
109
|
+
`tests/test_readme.py` runs the examples above and those in [docs/GUIDE.md](docs/GUIDE.md), so
|
|
110
|
+
they stay true. Agents: start at [AGENTS.md](AGENTS.md).
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT, see [LICENSE](LICENSE).
|
symdef-0.4.0/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# symdef
|
|
2
|
+
|
|
3
|
+
Standard-agnostic toolkit for graphical-symbol data. Symbols are TOML files; the toolkit loads
|
|
4
|
+
them, resolves composition, lints the wiring contract, renders SVG, and builds a resolved JSON
|
|
5
|
+
bundle plus a gallery. Data packages hold only data and reuse the toolkit and its gates:
|
|
6
|
+
`electrical-symbols` (IEC 60617-style symbols, Fransys' `packages/electrical-symbols`) now, ISO 14617 and
|
|
7
|
+
ISA 5.1 later.
|
|
8
|
+
|
|
9
|
+
Status: alpha. The toolkit the spec below describes is built: reading, resolving, linting, SVG and
|
|
10
|
+
the build, with every lint rule and gate proven by a failing fixture. Released by exact git tags
|
|
11
|
+
(`v0.1.0` to `v0.3.0` as `graphical-symbols`; `v0.4.0` on as `symdef`); Fransys pins one of them.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
uv add "symdef==0.4.0"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Python 3.14 or later. The one runtime dependency is `deal`. More depth:
|
|
20
|
+
[docs/GUIDE.md](docs/GUIDE.md).
|
|
21
|
+
|
|
22
|
+
## The design
|
|
23
|
+
|
|
24
|
+
[src/symdef/docs/SYMBOL_INTERFACE.html](src/symdef/docs/SYMBOL_INTERFACE.html)
|
|
25
|
+
is the binding, final spec. Open it in a browser; it ships as package data, readable at runtime
|
|
26
|
+
through `importlib.resources.files("symdef").joinpath("docs/SYMBOL_INTERFACE.html")`.
|
|
27
|
+
The key ideas:
|
|
28
|
+
|
|
29
|
+
- A symbol is a definition: no tag, terminal numbers, position or orientation. Those belong to
|
|
30
|
+
the placement in a drawing library.
|
|
31
|
+
- Port ids are roles (`in`, `out`, `anode`, ...), never terminal markings (`13`, `A1`).
|
|
32
|
+
- Electrical function is data: nodes and typed paths, so a consumer can netlist without
|
|
33
|
+
per-symbol knowledge.
|
|
34
|
+
- Text lives in slots: the symbol reserves boxes for tags and terminal markings.
|
|
35
|
+
- Module units (M = 2.5 mm), a 0.125 M drawing grid and a 1 M wiring grid. A strict wiring
|
|
36
|
+
contract is linted in all 8 orientations.
|
|
37
|
+
- Composition mirrors the standard: composites reference parts by anchor, no copied coordinates.
|
|
38
|
+
|
|
39
|
+
## What is here
|
|
40
|
+
|
|
41
|
+
The data model and `orient`, the boxes and `repeat`, the TOML reader with its JSON Schema
|
|
42
|
+
(`schema/symbol.schema.json`), the composition resolver, 34 lint rules, plain and annotated SVG,
|
|
43
|
+
and the build (resolved JSON per symbol, the bundle, SVGs, a gallery README). Decisions the spec
|
|
44
|
+
leaves open, and concerns about the spec, are in [docs/DECISIONS.md](docs/DECISIONS.md).
|
|
45
|
+
|
|
46
|
+
## Use
|
|
47
|
+
|
|
48
|
+
A data repo has `library.toml` and `symbols/<number>.toml`; `root` below is its directory.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from symdef import lint, load_library
|
|
52
|
+
from symdef.lint import RULES
|
|
53
|
+
|
|
54
|
+
library = load_library(root) # raises LibraryError, listing every problem in the files
|
|
55
|
+
contact = library.get("S00227") # by number; iterating a library is sorted by number
|
|
56
|
+
assert len(RULES) == 34 # the spec's 33 rules plus lead-off-port (D40)
|
|
57
|
+
findings = lint(contact) # all 34 rules, geometric ones in all 8 orientations
|
|
58
|
+
assert findings == () # the spec's make contact lints clean
|
|
59
|
+
for finding in findings: # each has .rule, .severity, .message, .location, .orientation
|
|
60
|
+
print(finding.rule, finding.location, finding.message)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Symbols are immutable; `orient`, `translate` and `repeat` return new ones. A repeated symbol is
|
|
64
|
+
an ordinary symbol with ports such as `1.in` and `3.out`.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from symdef import Orientation, keepout_box, orient, repeat, to_svg
|
|
68
|
+
|
|
69
|
+
breaker = orient(repeat(contact, 3), Orientation.R0)
|
|
70
|
+
print(keepout_box(breaker))
|
|
71
|
+
svg = to_svg(breaker, annotate=True, texts={"tag": "-Q1"})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`write_build` writes `build/` and `src/<package>/bundle.json` under the repo; `stale_build` lists
|
|
75
|
+
the files that differ from what it would write, so a test can fail when a committed build is out
|
|
76
|
+
of date. `load_bundle` reads a bundle back without the sources. `<package>` is the standard's
|
|
77
|
+
normalised name (lowercase letters and digits, D8): the example's standard is `IEC 60617`, so its
|
|
78
|
+
package is `iec60617`.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from symdef import load_bundle, stale_build, write_build
|
|
82
|
+
|
|
83
|
+
write_build(library, root)
|
|
84
|
+
assert stale_build(library, root) == ()
|
|
85
|
+
assert len(load_bundle(root / "src" / "iec60617" / "bundle.json")) == len(library)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Development
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
uv sync
|
|
92
|
+
just ci # format check, ruff, ty, vulture, purity gate, pytest with coverage
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Coverage must stay at 100% (`--cov-fail-under=100`), so a partial run such as
|
|
96
|
+
`uv run pytest tests/test_units.py` fails on coverage alone: add `--no-cov` for one.
|
|
97
|
+
`tests/test_readme.py` runs the examples above and those in [docs/GUIDE.md](docs/GUIDE.md), so
|
|
98
|
+
they stay true. Agents: start at [AGENTS.md](AGENTS.md).
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT, see [LICENSE](LICENSE).
|