draftwright 0.4.11__tar.gz → 0.4.12__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.
Files changed (276) hide show
  1. {draftwright-0.4.11 → draftwright-0.4.12}/PKG-INFO +1 -1
  2. {draftwright-0.4.11 → draftwright-0.4.12}/pyproject.toml +1 -1
  3. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/_pmi_part21.py +234 -2
  4. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/_common.py +12 -2
  5. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/from_model.py +363 -60
  6. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/holes.py +2 -0
  7. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/builder.py +129 -19
  8. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/drawing.py +2 -1
  9. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/pmi_coverage.py +128 -31
  10. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/quality.py +4 -0
  11. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/__init__.py +8 -0
  12. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/callout.py +8 -1
  13. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/compiled.py +10 -3
  14. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/declare.py +69 -5
  15. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/detect.py +7 -2
  16. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/ir.py +328 -3
  17. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/model/planner.py +9 -2
  18. draftwright-0.4.12/src/draftwright/model/pmi_lowering.py +839 -0
  19. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/pmi.py +482 -35
  20. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/sheet.py +86 -3
  21. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/sheet_emit.py +212 -33
  22. draftwright-0.4.12/tests/fixtures/ap242_single_cylinder_diameter.step +163 -0
  23. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1177_angular_dimensions.py +3 -3
  24. draftwright-0.4.12/tests/test_issue_1209_linear_pmi_witnesses.py +181 -0
  25. draftwright-0.4.12/tests/test_issue_1296_cylindrical_diameter_pmi.py +839 -0
  26. draftwright-0.4.12/tests/test_issue_1298_manufacturing_requirements.py +1178 -0
  27. draftwright-0.4.12/tests/test_issue_1299_page_escalation.py +465 -0
  28. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_740_leader_assignment.py +2 -1
  29. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pmi.py +92 -1
  30. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pmi_part21.py +161 -0
  31. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_private_test_imports.py +6 -0
  32. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_emit.py +41 -0
  33. draftwright-0.4.11/src/draftwright/model/pmi_lowering.py +0 -276
  34. {draftwright-0.4.11 → draftwright-0.4.12}/.gitignore +0 -0
  35. {draftwright-0.4.11 → draftwright-0.4.12}/CHANGELOG.md +0 -0
  36. {draftwright-0.4.11 → draftwright-0.4.12}/LICENSE +0 -0
  37. {draftwright-0.4.11 → draftwright-0.4.12}/README.md +0 -0
  38. {draftwright-0.4.11 → draftwright-0.4.12}/docs/adr/README.md +0 -0
  39. {draftwright-0.4.11 → draftwright-0.4.12}/docs/reference/recogniser-capabilities.md +0 -0
  40. {draftwright-0.4.11 → draftwright-0.4.12}/docs/reference/sheet.md +0 -0
  41. {draftwright-0.4.11 → draftwright-0.4.12}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
  42. {draftwright-0.4.11 → draftwright-0.4.12}/skills/SKILL.md +0 -0
  43. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/__init__.py +0 -0
  44. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/_core.py +0 -0
  45. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/_geometry.py +0 -0
  46. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/_warnings.py +0 -0
  47. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/analysis.py +0 -0
  48. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotate.py +0 -0
  49. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/__init__.py +0 -0
  50. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/balloons.py +0 -0
  51. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/gears.py +0 -0
  52. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/leaders.py +0 -0
  53. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/orchestrator.py +0 -0
  54. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/annotations/sections.py +0 -0
  55. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/audit.py +0 -0
  56. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/cli.py +0 -0
  57. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/compose.py +0 -0
  58. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/evaluation/__init__.py +0 -0
  59. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/evaluation/step_analysis.py +0 -0
  60. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/export.py +0 -0
  61. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fits.py +0 -0
  62. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
  63. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
  64. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
  65. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
  66. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/fonts/__init__.py +0 -0
  67. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/intents.py +0 -0
  68. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/layout.py +0 -0
  69. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/__init__.py +0 -0
  70. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/channel_coverage.py +0 -0
  71. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/coverage.py +0 -0
  72. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/evidence.py +0 -0
  73. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/flat_coverage.py +0 -0
  74. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/gear_coverage.py +0 -0
  75. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/hole_coverage.py +0 -0
  76. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/issues.py +0 -0
  77. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/polygonal_stock_coverage.py +0 -0
  78. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/profiled_bore_coverage.py +0 -0
  79. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/slot_coverage.py +0 -0
  80. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/structural.py +0 -0
  81. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/linting/suggest.py +0 -0
  82. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/make_drawing.py +0 -0
  83. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/projection.py +0 -0
  84. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/py.typed +0 -0
  85. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/recogniser_contract.py +0 -0
  86. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/recognition/__init__.py +0 -0
  87. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/recognition_cache.py +0 -0
  88. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/registry.py +0 -0
  89. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/repair.py +0 -0
  90. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/score.py +0 -0
  91. {draftwright-0.4.11 → draftwright-0.4.12}/src/draftwright/view_plan.py +0 -0
  92. {draftwright-0.4.11 → draftwright-0.4.12}/tests/_kernel.py +0 -0
  93. {draftwright-0.4.11 → draftwright-0.4.12}/tests/_layout_sig.py +0 -0
  94. {draftwright-0.4.11 → draftwright-0.4.12}/tests/conftest.py +0 -0
  95. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/README.md +0 -0
  96. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
  97. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/blind-hole.step +0 -0
  98. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/corpus-v1.json +0 -0
  99. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/plain-block.step +0 -0
  100. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/topology-a.step +0 -0
  101. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/evaluation/topology-b.step +0 -0
  102. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
  103. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/grm04_drive_plate.step +0 -0
  104. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
  105. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
  106. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
  107. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/issue_915_case_study_2.step +0 -0
  108. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
  109. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
  110. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
  111. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
  112. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
  113. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
  114. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
  115. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
  116. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
  117. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
  118. {draftwright-0.4.11 → draftwright-0.4.12}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
  119. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/bracket_section.json +0 -0
  120. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/centered_rebate.json +0 -0
  121. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/chamfered.json +0 -0
  122. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/filleted.json +0 -0
  123. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/flange_dense.json +0 -0
  124. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/grid_plate.json +0 -0
  125. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/grooved_shaft.json +0 -0
  126. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/hex_bar.json +0 -0
  127. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/holed_slot.json +0 -0
  128. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/pocketed.json +0 -0
  129. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/prismatic_ladder.json +0 -0
  130. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/scattered_plate.json +0 -0
  131. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/side_drilled.json +0 -0
  132. {draftwright-0.4.11 → draftwright-0.4.12}/tests/refactor_golden/turned_stepped.json +0 -0
  133. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_add_dimension.py +0 -0
  134. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_adr0018_arrangement_gate.py +0 -0
  135. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_adr0018_view_routing.py +0 -0
  136. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_adr0018_view_selection.py +0 -0
  137. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_agents_guide.py +0 -0
  138. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_api_docs.py +0 -0
  139. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_architecture_docs.py +0 -0
  140. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_audit_differential.py +0 -0
  141. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_balloon_ring_standoff.py +0 -0
  142. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_carve_free_position_callers.py +0 -0
  143. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_compiled_plan_boundary.py +0 -0
  144. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_counting_calls.py +0 -0
  145. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_declare.py +0 -0
  146. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_declared_recognition_gate.py +0 -0
  147. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_dense_sheet_canary.py +0 -0
  148. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_deprecation_dates.py +0 -0
  149. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_detect_once.py +0 -0
  150. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_detect_registry.py +0 -0
  151. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_dimension_role_vocabulary.py +0 -0
  152. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_drawing_encapsulation.py +0 -0
  153. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_e2e_slice.py +0 -0
  154. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_e2e_standards.py +0 -0
  155. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_export_dxf_curves.py +0 -0
  156. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_export_dxf_zoom.py +0 -0
  157. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_external_recognition_boundary.py +0 -0
  158. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_fillets_adjacency.py +0 -0
  159. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_fits.py +0 -0
  160. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_flat_completeness.py +0 -0
  161. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_flat_stock_identity.py +0 -0
  162. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_flat_stock_opposition.py +0 -0
  163. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_gdt_placement.py +0 -0
  164. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_grid_lattice_convention.py +0 -0
  165. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_import_boundaries.py +0 -0
  166. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_iso_nts_caption_placement.py +0 -0
  167. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1000_envelope_reuse.py +0 -0
  168. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1058_wheel_profile.py +0 -0
  169. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1073_cross_body_patterns.py +0 -0
  170. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1082_polygonal_stock.py +0 -0
  171. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1086_declared_gears.py +0 -0
  172. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +0 -0
  173. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1130_view_planning_evidence.py +0 -0
  174. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1142_hole_leader_labels.py +0 -0
  175. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1143_hole_completeness.py +0 -0
  176. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1144_transactional_hole_table.py +0 -0
  177. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1146_scale_completeness.py +0 -0
  178. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1147_legibility_pair_aggregation.py +0 -0
  179. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1153_contradictory_dimensions.py +0 -0
  180. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1154_one_owner_per_measurement.py +0 -0
  181. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1155_grm04_sheet_use.py +0 -0
  182. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1166_cross_pass_feature_leaders.py +0 -0
  183. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1176_quality_fidelity.py +0 -0
  184. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1187_unroutable_leaders.py +0 -0
  185. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1188_per_view_assignment.py +0 -0
  186. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1190_section_decision.py +0 -0
  187. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1196_deterministic_view_names.py +0 -0
  188. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1202_observed_drawing_consumer.py +0 -0
  189. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1204_multiscale_view_issues.py +0 -0
  190. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1215_envelope_tolerance.py +0 -0
  191. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +0 -0
  192. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1216_callout_reservation_measures_ink.py +0 -0
  193. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1216_pairwise_across_scale_groups.py +0 -0
  194. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1217_claimed_representations.py +0 -0
  195. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1217_the_facility_is_shared.py +0 -0
  196. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1219_location_claims_its_own_axis.py +0 -0
  197. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1229_ledger_member_keying.py +0 -0
  198. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1240_iso_above_strip_visibility.py +0 -0
  199. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1254_turned_chamfers.py +0 -0
  200. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1260_view_constraints.py +0 -0
  201. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1276_turned_leader_targets.py +0 -0
  202. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_1281_turned_fillets.py +0 -0
  203. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_367_leader_ink.py +0 -0
  204. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_443_grm03_axial_coverage.py +0 -0
  205. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_676_polygonal_boss.py +0 -0
  206. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
  207. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_798_floor_cardinality.py +0 -0
  208. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_798_material_field.py +0 -0
  209. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_798_silhouette_lint.py +0 -0
  210. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_885_prismatic_coverage.py +0 -0
  211. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_909_sloped_profile.py +0 -0
  212. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_915_dense_case.py +0 -0
  213. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_916_pocket_leader.py +0 -0
  214. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_917_open_channel.py +0 -0
  215. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_924_zero_length_shoulders.py +0 -0
  216. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_955_height_contingency.py +0 -0
  217. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_issue_958_cross_solid_recognition.py +0 -0
  218. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_label_provenance.py +0 -0
  219. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_layout.py +0 -0
  220. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_layout_cleanliness.py +0 -0
  221. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_layout_hypothesis.py +0 -0
  222. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_layout_property.py +0 -0
  223. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_leader_footprint.py +0 -0
  224. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_lint_box_cache.py +0 -0
  225. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_lint_reconciliation.py +0 -0
  226. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_lint_structural.py +0 -0
  227. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_linting.py +0 -0
  228. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_location_vocabulary.py +0 -0
  229. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_make_drawing.py +0 -0
  230. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_note_verb.py +0 -0
  231. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_object_aspects.py +0 -0
  232. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_occupancy_boxes.py +0 -0
  233. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_parameter_id.py +0 -0
  234. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_part_model.py +0 -0
  235. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pitch_dim_footprint.py +0 -0
  236. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pmi_datum_lowering.py +0 -0
  237. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pmi_gtol_lowering.py +0 -0
  238. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pocket_pattern.py +0 -0
  239. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_pocket_pattern_recognition.py +0 -0
  240. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_principal_profile_classifier.py +0 -0
  241. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_private_test_attr_reads.py +0 -0
  242. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_quality_components.py +0 -0
  243. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recogniser_adoption.py +0 -0
  244. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recogniser_capabilities.py +0 -0
  245. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recogniser_contract.py +0 -0
  246. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recognition.py +0 -0
  247. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recognition_manifest.py +0 -0
  248. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_recognition_result.py +0 -0
  249. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_refactor_golden.py +0 -0
  250. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_registry.py +0 -0
  251. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_render_seam.py +0 -0
  252. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_repack_geometry_seam.py +0 -0
  253. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_score.py +0 -0
  254. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_script_detail_parity.py +0 -0
  255. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_shared_box_memo.py +0 -0
  256. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_gdt.py +0 -0
  257. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_identity_invariant.py +0 -0
  258. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_notes.py +0 -0
  259. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_of.py +0 -0
  260. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_section.py +0 -0
  261. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_sheet_tables.py +0 -0
  262. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_slanted_blind_step.py +0 -0
  263. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_slot_completeness.py +0 -0
  264. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_slot_pattern.py +0 -0
  265. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_slot_pattern_recognition.py +0 -0
  266. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_soft_deprecation.py +0 -0
  267. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_solve_trace.py +0 -0
  268. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_step_analysis_evaluation.py +0 -0
  269. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_strip_layout.py +0 -0
  270. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_suppression_ledger.py +0 -0
  271. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_suppression_marks.py +0 -0
  272. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_tolerances.py +0 -0
  273. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_turned_steps.py +0 -0
  274. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_view_plan.py +0 -0
  275. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_witness_label_reconciliation.py +0 -0
  276. {draftwright-0.4.11 → draftwright-0.4.12}/tests/test_workflows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: draftwright
3
- Version: 0.4.11
3
+ Version: 0.4.12
4
4
  Summary: Automated technical-drawing generation for build123d
5
5
  Project-URL: Homepage, https://github.com/pzfreo/draftwright
6
6
  Project-URL: Repository, https://github.com/pzfreo/draftwright
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "draftwright"
7
- version = "0.4.11"
7
+ version = "0.4.12"
8
8
  description = "Automated technical-drawing generation for build123d"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -1,13 +1,15 @@
1
1
  """Structured Part21 facts that OCCT's XCAF PMI transfer currently drops.
2
2
 
3
3
  This is deliberately a leaf adapter: it understands ISO 10303-21 entities and units, but
4
- knows nothing about XCAF labels, drafting IR, or placement. ``pmi.py`` owns the overlay and
5
- may use a fact only after :func:`match_geometric_tolerance` proves exact correspondence.
4
+ knows nothing about XCAF labels, drafting IR, or placement. ``pmi.py`` owns the overlay.
5
+ Geometric-tolerance facts require exact XCAF correspondence; manufacturing-requirement facts
6
+ retain their own complete property -> representation -> shape-aspect source chain.
6
7
  """
7
8
 
8
9
  from __future__ import annotations
9
10
 
10
11
  import math
12
+ import re
11
13
  from dataclasses import dataclass
12
14
  from pathlib import Path
13
15
 
@@ -53,6 +55,13 @@ _SI_METRE_TO_MM: dict[str, float] = {
53
55
  ".ATTO.": 1e-15,
54
56
  }
55
57
 
58
+ # Entity names are invariant ASCII Part21 syntax; string parameters are not. Keying this
59
+ # guard on the literal category text silently missed valid ``\X2\...\X0\`` encodings before
60
+ # steputils had a chance to decode them. A file with no property definitions cannot carry
61
+ # the requirement chain, while any file that does is parsed conservatively (#1297). Match
62
+ # only the invariant token: Part 21 comments may legally separate it from the opening ``(``.
63
+ _PROPERTY_DEFINITION_MARKER = re.compile(rb"\bPROPERTY_DEFINITION\b", re.IGNORECASE)
64
+
56
65
 
57
66
  @dataclass(frozen=True)
58
67
  class GeometricToleranceFact:
@@ -84,7 +93,31 @@ class DatumOccurrenceFact:
84
93
  reason: str = ""
85
94
 
86
95
 
96
+ @dataclass(frozen=True)
97
+ class ManufacturingRequirementFact:
98
+ """One authoritative semantic manufacturing requirement from Part 21.
99
+
100
+ ``entity_id`` is the ``PROPERTY_DEFINITION`` identity, while ``text`` comes from the
101
+ linked ``DESCRIPTIVE_REPRESENTATION_ITEM`` rather than presentation glyphs. The
102
+ remaining IDs preserve the semantic-callout -> shape-aspect -> representation-item
103
+ association for concept lowering; this leaf adapter deliberately does not interpret
104
+ those items as drafting features.
105
+ """
106
+
107
+ entity_id: str
108
+ semantic_name: str
109
+ text: str
110
+ representation_id: str = ""
111
+ descriptive_item_id: str = ""
112
+ callout_ids: tuple[str, ...] = ()
113
+ shape_aspect_ids: tuple[str, ...] = ()
114
+ reference_item_ids: tuple[str, ...] = ()
115
+ reason: str = ""
116
+
117
+
87
118
  def _entities(instance) -> tuple:
119
+ if instance is None:
120
+ return ()
88
121
  entity = getattr(instance, "entity", None)
89
122
  if entity is not None:
90
123
  return (entity,)
@@ -158,6 +191,205 @@ def _datum_feature_items(step) -> dict[str, tuple[str, ...]]:
158
191
  return {key: tuple(dict.fromkeys(values)) for key, values in result.items()}
159
192
 
160
193
 
194
+ def _text(value) -> str:
195
+ return str(value).strip() if isinstance(value, str) else ""
196
+
197
+
198
+ def _name_tokens(value: str) -> frozenset[str]:
199
+ """Normalise semantic names for callout correspondence, not requirement inference."""
200
+ words = []
201
+ for raw in value.lower().replace("_", " ").replace("-", " ").split():
202
+ word = "".join(character for character in raw if character.isalnum())
203
+ if len(word) > 3 and word.endswith("s") and not word.endswith("ss"):
204
+ word = word[:-1]
205
+ if word and word != "requirement":
206
+ words.append(word)
207
+ return frozenset(words)
208
+
209
+
210
+ def _manufacturing_graph(step):
211
+ """Collect the Part21 indexes shared by manufacturing-requirement facts."""
212
+ definitions: list[tuple[str, object]] = []
213
+ representations: dict[str, list[str]] = {}
214
+ callout_names: dict[str, str] = {}
215
+ callout_aspects: dict[str, list[str]] = {}
216
+ aspect_items: dict[str, list[str]] = {}
217
+
218
+ for section in step.data:
219
+ for entity_id, instance in section.instances.items():
220
+ definition = _entity_named(instance, "PROPERTY_DEFINITION")
221
+ if (
222
+ definition is not None
223
+ and len(definition.params) >= 2
224
+ and _text(definition.params[0]).lower() == "manufacturing requirement"
225
+ ):
226
+ definitions.append((entity_id, definition))
227
+
228
+ relationship = _entity_named(instance, "PROPERTY_DEFINITION_REPRESENTATION")
229
+ if relationship is not None and len(relationship.params) >= 2:
230
+ definition_ref, representation_ref = relationship.params[:2]
231
+ if isinstance(definition_ref, p21.Reference) and isinstance(
232
+ representation_ref, p21.Reference
233
+ ):
234
+ representations.setdefault(str(definition_ref), []).append(
235
+ str(representation_ref)
236
+ )
237
+
238
+ callout = _entity_named(instance, "DRAUGHTING_CALLOUT")
239
+ if callout is not None and callout.params:
240
+ callout_names[entity_id] = _text(callout.params[0])
241
+
242
+ association = _entity_named(instance, "DRAUGHTING_MODEL_ITEM_ASSOCIATION")
243
+ if association is not None and len(association.params) >= 5:
244
+ aspect_ref = association.params[2]
245
+ if isinstance(aspect_ref, p21.Reference) and _instance_is(
246
+ step, str(aspect_ref), "SHAPE_ASPECT"
247
+ ):
248
+ for callout_ref in _references(association.params[4]):
249
+ if _instance_is(step, callout_ref, "DRAUGHTING_CALLOUT"):
250
+ callout_aspects.setdefault(callout_ref, []).append(str(aspect_ref))
251
+
252
+ usage = _entity_named(instance, "GEOMETRIC_ITEM_SPECIFIC_USAGE")
253
+ if usage is not None and len(usage.params) >= 5:
254
+ aspect_ref = usage.params[2]
255
+ if isinstance(aspect_ref, p21.Reference) and _instance_is(
256
+ step, str(aspect_ref), "SHAPE_ASPECT"
257
+ ):
258
+ aspect_items.setdefault(str(aspect_ref), []).extend(
259
+ _references(usage.params[4])
260
+ )
261
+
262
+ return definitions, representations, callout_names, callout_aspects, aspect_items
263
+
264
+
265
+ def read_manufacturing_requirements(
266
+ step_file: str | Path,
267
+ ) -> tuple[ManufacturingRequirementFact, ...]:
268
+ """Read authoritative semantic requirements and retain their geometry associations.
269
+
270
+ The property-definition chain owns the full requirement text. A draughting callout
271
+ with the same representation name (or, where the presentation adds a qualifier such as
272
+ ``Straight``, the same semantic-name tokens) supplies the shape-aspect association.
273
+ This is correspondence between two source semantic identities; no nominal value or
274
+ B-rep measurement is guessed here.
275
+ """
276
+ # A file with no property-definition entity cannot carry this semantic chain, so avoid a
277
+ # third full Part21 parse there. Once any property definition exists, parse
278
+ # conservatively: its string category may use a valid escape encoding that a byte-level
279
+ # literal check cannot interpret.
280
+ if _PROPERTY_DEFINITION_MARKER.search(Path(step_file).read_bytes()) is None:
281
+ return ()
282
+ step = p21.readfile(step_file)
283
+ (
284
+ definitions,
285
+ representations,
286
+ callout_names,
287
+ callout_aspects,
288
+ aspect_items,
289
+ ) = _manufacturing_graph(step)
290
+ facts: list[ManufacturingRequirementFact] = []
291
+
292
+ for entity_id, definition in definitions:
293
+ semantic_name = _text(definition.params[1])
294
+ reasons: list[str] = []
295
+ if not semantic_name:
296
+ reasons.append("manufacturing requirement has no semantic name")
297
+
298
+ representation_ids = tuple(dict.fromkeys(representations.get(entity_id, ())))
299
+ representation_id = representation_ids[0] if len(representation_ids) == 1 else ""
300
+ if len(representation_ids) != 1:
301
+ reasons.append(
302
+ f"manufacturing requirement has {len(representation_ids)} linked representations"
303
+ )
304
+
305
+ representation_name = ""
306
+ descriptive_ids: tuple[str, ...] = ()
307
+ if representation_id:
308
+ representation = _entity_named(step.get(representation_id), "REPRESENTATION")
309
+ if representation is None or len(representation.params) < 2:
310
+ reasons.append(
311
+ f"linked representation {representation_id} is unavailable or malformed"
312
+ )
313
+ else:
314
+ representation_name = _text(representation.params[0])
315
+ descriptive_ids = tuple(
316
+ dict.fromkeys(
317
+ ref
318
+ for ref in _references(representation.params[1])
319
+ if _instance_is(step, ref, "DESCRIPTIVE_REPRESENTATION_ITEM")
320
+ )
321
+ )
322
+
323
+ descriptive_item_id = descriptive_ids[0] if len(descriptive_ids) == 1 else ""
324
+ text = ""
325
+ if representation_id and len(descriptive_ids) != 1:
326
+ reasons.append(f"linked representation has {len(descriptive_ids)} descriptive items")
327
+ if descriptive_item_id:
328
+ item = _entity_named(step.get(descriptive_item_id), "DESCRIPTIVE_REPRESENTATION_ITEM")
329
+ if item is None or len(item.params) < 2:
330
+ reasons.append(f"descriptive item {descriptive_item_id} is malformed")
331
+ else:
332
+ text = _text(item.params[1])
333
+ if not text:
334
+ reasons.append("manufacturing requirement has no authoritative text")
335
+
336
+ exact_callouts = tuple(
337
+ callout_id
338
+ for callout_id, name in callout_names.items()
339
+ if representation_name and name.casefold() == representation_name.casefold()
340
+ )
341
+ semantic_tokens = _name_tokens(semantic_name)
342
+ callout_ids = exact_callouts or tuple(
343
+ callout_id
344
+ for callout_id, name in callout_names.items()
345
+ if semantic_tokens and semantic_tokens <= _name_tokens(name)
346
+ )
347
+ missing_callout_associations = tuple(
348
+ callout_id for callout_id in callout_ids if not callout_aspects.get(callout_id)
349
+ )
350
+ if missing_callout_associations:
351
+ reasons.append(
352
+ "matched semantic callout(s) have no shape-aspect association: "
353
+ + ", ".join(missing_callout_associations)
354
+ )
355
+ shape_aspect_ids = tuple(
356
+ dict.fromkeys(
357
+ aspect_id
358
+ for callout_id in callout_ids
359
+ for aspect_id in callout_aspects.get(callout_id, ())
360
+ )
361
+ )
362
+ missing_aspect_items = tuple(
363
+ aspect_id for aspect_id in shape_aspect_ids if not aspect_items.get(aspect_id)
364
+ )
365
+ if missing_aspect_items:
366
+ reasons.append(
367
+ "associated shape aspect(s) have no representation items: "
368
+ + ", ".join(missing_aspect_items)
369
+ )
370
+ reference_item_ids = tuple(
371
+ dict.fromkeys(
372
+ item_id
373
+ for aspect_id in shape_aspect_ids
374
+ for item_id in aspect_items.get(aspect_id, ())
375
+ )
376
+ )
377
+ facts.append(
378
+ ManufacturingRequirementFact(
379
+ entity_id=entity_id,
380
+ semantic_name=semantic_name,
381
+ text=text,
382
+ representation_id=representation_id,
383
+ descriptive_item_id=descriptive_item_id,
384
+ callout_ids=tuple(dict.fromkeys(callout_ids)),
385
+ shape_aspect_ids=shape_aspect_ids,
386
+ reference_item_ids=reference_item_ids,
387
+ reason="; ".join(dict.fromkeys(reasons)),
388
+ )
389
+ )
390
+ return tuple(facts)
391
+
392
+
161
393
  def _unit_factor_mm(step, unit_ref: str) -> tuple[float | None, str]:
162
394
  unit = step.get(unit_ref)
163
395
  if unit is None:
@@ -1761,14 +1761,24 @@ class PlacementContext:
1761
1761
  """Place an annotation onto the drawing through this context (#817) — the render passes'
1762
1762
  door to the placement primitive, so a pass never reaches into the ``Drawing`` (ADR 0005
1763
1763
  §2). Registers *obj* under *name* (owning *view* + source *feature*) and appends it to the
1764
- render list. Returns *obj*."""
1764
+ render list. Opaque compiler provenance is resolved here, at the placement boundary,
1765
+ so public ``annotations_of(IR feature)`` / ``drop(IR feature)`` keep their value-based
1766
+ contract for immediate passes as well as corridor-drained candidates. Returns *obj*."""
1765
1767
  if self.items is None:
1766
1768
  raise ValueError(
1767
1769
  "PlacementContext.place() needs the drawing's render list — construct the context "
1768
1770
  "with items=dwg.items (the orchestrator and Drawing verbs already do; a unit test "
1769
1771
  "calling a render helper must pass it too)."
1770
1772
  )
1771
- return place_annotation(self.registry, self.items, obj, name, view, feature, measurement)
1773
+ return place_annotation(
1774
+ self.registry,
1775
+ self.items,
1776
+ obj,
1777
+ name,
1778
+ view,
1779
+ resolve_feature(feature),
1780
+ measurement,
1781
+ )
1772
1782
 
1773
1783
  def feature_of_hole_at(self, location):
1774
1784
  """The IR hole/pattern feature whose member sits at model-space *location*, or ``None``