draftwright 0.4.0__tar.gz → 0.4.2__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 (208) hide show
  1. {draftwright-0.4.0 → draftwright-0.4.2}/.gitignore +1 -0
  2. {draftwright-0.4.0 → draftwright-0.4.2}/CHANGELOG.md +151 -0
  3. {draftwright-0.4.0 → draftwright-0.4.2}/PKG-INFO +18 -3
  4. {draftwright-0.4.0 → draftwright-0.4.2}/README.md +14 -2
  5. {draftwright-0.4.0 → draftwright-0.4.2}/docs/adr/README.md +2 -0
  6. {draftwright-0.4.0 → draftwright-0.4.2}/pyproject.toml +28 -3
  7. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/__init__.py +20 -1
  8. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/_core.py +191 -43
  9. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/_geometry.py +97 -0
  10. draftwright-0.4.2/src/draftwright/_pmi_part21.py +421 -0
  11. draftwright-0.4.2/src/draftwright/_warnings.py +39 -0
  12. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/analysis.py +137 -36
  13. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/_common.py +42 -5
  14. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/from_model.py +659 -156
  15. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/holes.py +202 -39
  16. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/orchestrator.py +71 -7
  17. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/sections.py +108 -71
  18. draftwright-0.4.2/src/draftwright/audit.py +256 -0
  19. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/builder.py +46 -7
  20. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/cli.py +11 -10
  21. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/compose.py +38 -7
  22. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/drawing.py +331 -26
  23. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/export.py +57 -1
  24. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/linting/__init__.py +22 -0
  25. draftwright-0.4.2/src/draftwright/linting/channel_coverage.py +190 -0
  26. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/linting/coverage.py +522 -12
  27. draftwright-0.4.2/src/draftwright/linting/flat_coverage.py +207 -0
  28. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/linting/issues.py +8 -0
  29. draftwright-0.4.2/src/draftwright/linting/pmi_coverage.py +210 -0
  30. draftwright-0.4.2/src/draftwright/linting/profiled_bore_coverage.py +122 -0
  31. draftwright-0.4.2/src/draftwright/linting/slot_coverage.py +315 -0
  32. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/__init__.py +16 -0
  33. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/callout.py +33 -2
  34. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/compiled.py +283 -73
  35. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/declare.py +305 -21
  36. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/detect.py +200 -29
  37. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/ir.py +402 -9
  38. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/model/planner.py +158 -40
  39. draftwright-0.4.2/src/draftwright/pmi.py +1187 -0
  40. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/projection.py +9 -1
  41. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/__init__.py +32 -5
  42. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/flats.py +103 -3
  43. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/levels.py +170 -44
  44. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/pads.py +22 -11
  45. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/plates.py +5 -0
  46. draftwright-0.4.2/src/draftwright/recognition/polygonal_bosses.py +272 -0
  47. draftwright-0.4.2/src/draftwright/recognition/profiled_bores.py +368 -0
  48. draftwright-0.4.2/src/draftwright/recognition/result.py +281 -0
  49. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/slots.py +188 -36
  50. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/registry.py +109 -1
  51. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/repair.py +11 -3
  52. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/score.py +2 -0
  53. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/sheet.py +146 -26
  54. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/sheet_emit.py +452 -42
  55. draftwright-0.4.2/tests/conftest.py +84 -0
  56. draftwright-0.4.2/tests/fixtures/if_step_flat_across_cylinder.step +189 -0
  57. draftwright-0.4.2/tests/fixtures/issue_1058_wheel_rh.step +64624 -0
  58. draftwright-0.4.2/tests/fixtures/issue_909_basic_part_design_017_body.step +465 -0
  59. draftwright-0.4.2/tests/fixtures/issue_915_case_study_2.step +3527 -0
  60. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/grooved_shaft.json +19 -1
  61. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/pocketed.json +2 -2
  62. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_add_dimension.py +69 -11
  63. draftwright-0.4.2/tests/test_api_docs.py +31 -0
  64. draftwright-0.4.2/tests/test_audit_differential.py +793 -0
  65. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_compiled_plan_boundary.py +25 -0
  66. draftwright-0.4.2/tests/test_counting_calls.py +117 -0
  67. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_declare.py +70 -2
  68. draftwright-0.4.2/tests/test_declared_recognition_gate.py +542 -0
  69. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_detect_once.py +38 -36
  70. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_detect_registry.py +12 -3
  71. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_drawing_encapsulation.py +28 -4
  72. draftwright-0.4.2/tests/test_export_dxf_curves.py +135 -0
  73. draftwright-0.4.2/tests/test_flat_completeness.py +330 -0
  74. draftwright-0.4.2/tests/test_flat_stock_identity.py +240 -0
  75. draftwright-0.4.2/tests/test_flat_stock_opposition.py +63 -0
  76. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_gdt_placement.py +96 -0
  77. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_import_boundaries.py +11 -0
  78. draftwright-0.4.2/tests/test_issue_1000_envelope_reuse.py +90 -0
  79. draftwright-0.4.2/tests/test_issue_1058_wheel_profile.py +956 -0
  80. draftwright-0.4.2/tests/test_issue_676_polygonal_boss.py +285 -0
  81. draftwright-0.4.2/tests/test_issue_676_polygonal_boss_declare.py +328 -0
  82. draftwright-0.4.2/tests/test_issue_909_sloped_profile.py +150 -0
  83. draftwright-0.4.2/tests/test_issue_915_dense_case.py +108 -0
  84. draftwright-0.4.2/tests/test_issue_916_pocket_leader.py +102 -0
  85. draftwright-0.4.2/tests/test_issue_917_open_channel.py +189 -0
  86. draftwright-0.4.2/tests/test_issue_955_height_contingency.py +195 -0
  87. draftwright-0.4.2/tests/test_issue_958_cross_solid_recognition.py +150 -0
  88. draftwright-0.4.2/tests/test_location_vocabulary.py +400 -0
  89. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_make_drawing.py +333 -35
  90. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_parameter_id.py +54 -0
  91. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_part_model.py +2 -2
  92. draftwright-0.4.2/tests/test_pmi.py +1451 -0
  93. draftwright-0.4.2/tests/test_pmi_datum_lowering.py +463 -0
  94. draftwright-0.4.2/tests/test_pmi_gtol_lowering.py +244 -0
  95. draftwright-0.4.2/tests/test_pmi_part21.py +473 -0
  96. draftwright-0.4.2/tests/test_principal_profile_classifier.py +122 -0
  97. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_recogniser_contract.py +46 -4
  98. draftwright-0.4.2/tests/test_recognition_manifest.py +574 -0
  99. draftwright-0.4.2/tests/test_recognition_result.py +344 -0
  100. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_registry.py +93 -0
  101. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_render_seam.py +21 -3
  102. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_script_detail_parity.py +42 -4
  103. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_emit.py +637 -36
  104. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_identity_invariant.py +3 -0
  105. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_slanted_blind_step.py +15 -7
  106. draftwright-0.4.2/tests/test_slot_completeness.py +595 -0
  107. draftwright-0.4.2/tests/test_soft_deprecation.py +221 -0
  108. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_strip_layout.py +5 -5
  109. draftwright-0.4.2/tests/test_suppression_ledger.py +380 -0
  110. draftwright-0.4.2/tests/test_workflows.py +70 -0
  111. draftwright-0.4.0/src/draftwright/pmi.py +0 -363
  112. draftwright-0.4.0/tests/test_pmi.py +0 -248
  113. {draftwright-0.4.0 → draftwright-0.4.2}/LICENSE +0 -0
  114. {draftwright-0.4.0 → draftwright-0.4.2}/skills/SKILL.md +0 -0
  115. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotate.py +0 -0
  116. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/__init__.py +0 -0
  117. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/annotations/balloons.py +0 -0
  118. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fits.py +0 -0
  119. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
  120. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
  121. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
  122. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
  123. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/fonts/__init__.py +0 -0
  124. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/intents.py +0 -0
  125. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/layout.py +0 -0
  126. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/linting/structural.py +0 -0
  127. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/linting/suggest.py +0 -0
  128. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/make_drawing.py +0 -0
  129. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/py.typed +0 -0
  130. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/_features.py +0 -0
  131. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/_record.py +0 -0
  132. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/chamfers.py +0 -0
  133. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/countersinks.py +0 -0
  134. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/fillets.py +0 -0
  135. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/grooves.py +0 -0
  136. {draftwright-0.4.0 → draftwright-0.4.2}/src/draftwright/recognition/turned.py +0 -0
  137. {draftwright-0.4.0 → draftwright-0.4.2}/tests/_kernel.py +0 -0
  138. {draftwright-0.4.0 → draftwright-0.4.2}/tests/_layout_sig.py +0 -0
  139. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
  140. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
  141. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
  142. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
  143. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
  144. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
  145. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
  146. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
  147. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
  148. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
  149. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
  150. {draftwright-0.4.0 → draftwright-0.4.2}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
  151. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/bracket_section.json +0 -0
  152. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/centered_rebate.json +0 -0
  153. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/chamfered.json +0 -0
  154. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/filleted.json +0 -0
  155. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/flange_dense.json +0 -0
  156. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/grid_plate.json +0 -0
  157. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/hex_bar.json +0 -0
  158. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/holed_slot.json +0 -0
  159. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/prismatic_ladder.json +0 -0
  160. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/scattered_plate.json +0 -0
  161. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/side_drilled.json +0 -0
  162. {draftwright-0.4.0 → draftwright-0.4.2}/tests/refactor_golden/turned_stepped.json +0 -0
  163. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_agents_guide.py +0 -0
  164. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_architecture_docs.py +0 -0
  165. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_balloon_ring_standoff.py +0 -0
  166. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_carve_free_position_callers.py +0 -0
  167. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_dense_sheet_canary.py +0 -0
  168. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_deprecation_dates.py +0 -0
  169. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_dimension_role_vocabulary.py +0 -0
  170. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_e2e_slice.py +0 -0
  171. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_e2e_standards.py +0 -0
  172. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_export_dxf_zoom.py +0 -0
  173. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_fillets_adjacency.py +0 -0
  174. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_fits.py +0 -0
  175. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_grid_lattice_convention.py +0 -0
  176. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_issue_885_prismatic_coverage.py +0 -0
  177. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_label_provenance.py +0 -0
  178. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_layout.py +0 -0
  179. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_layout_cleanliness.py +0 -0
  180. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_layout_hypothesis.py +0 -0
  181. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_layout_property.py +0 -0
  182. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_lint_box_cache.py +0 -0
  183. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_lint_reconciliation.py +0 -0
  184. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_lint_structural.py +0 -0
  185. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_linting.py +0 -0
  186. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_note_verb.py +0 -0
  187. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_object_aspects.py +0 -0
  188. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_occupancy_boxes.py +0 -0
  189. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_pitch_dim_footprint.py +0 -0
  190. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_pocket_pattern.py +0 -0
  191. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_pocket_pattern_recognition.py +0 -0
  192. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_private_test_attr_reads.py +0 -0
  193. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_private_test_imports.py +0 -0
  194. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_recognition.py +0 -0
  195. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_refactor_golden.py +0 -0
  196. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_score.py +0 -0
  197. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_gdt.py +0 -0
  198. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_notes.py +0 -0
  199. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_of.py +0 -0
  200. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_section.py +0 -0
  201. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_sheet_tables.py +0 -0
  202. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_slot_pattern.py +0 -0
  203. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_slot_pattern_recognition.py +0 -0
  204. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_solve_trace.py +0 -0
  205. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_suppression_marks.py +0 -0
  206. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_tolerances.py +0 -0
  207. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_turned_steps.py +0 -0
  208. {draftwright-0.4.0 → draftwright-0.4.2}/tests/test_witness_label_reconciliation.py +0 -0
@@ -12,4 +12,5 @@ testenv/
12
12
  coverage.xml
13
13
  coverage*.json
14
14
  htmlcov/
15
+ site/
15
16
  .DS_Store
@@ -2,6 +2,157 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.4.2 — 2026-08-09
6
+
7
+ **The trustworthy manufacturing drawings release.** AP242 PMI is now accounted for from its
8
+ source records through lowering and rendering, imported datum faces retain an auditable topology
9
+ identity, and several drawing paths that previously omitted, invented, or stalled on defining
10
+ geometry now fail closed or produce the required annotation.
11
+
12
+ ### Added
13
+
14
+ - **AP242 geometric tolerances and datum features survive as source-backed manufacturing
15
+ requirements** (#62/#675/#1094/#1095/#1099/#1100). The importer recovers range-encoded
16
+ dimensional tolerances, tolerance characteristics, magnitudes, datum chains, and supported
17
+ all-around/all-over modifiers. Datum representation-item faces are resolved to imported
18
+ topology through OCCT's exact transfer relationship rather than geometric resemblance, so the
19
+ NIST CTC-01 datum definitions `A`, `B`, and `C` lower and render without guessing.
20
+
21
+ - **PMI completeness lint reconciles every AP242 source record through extraction, projection,
22
+ lowering, and rendering** (#623). Unsupported or incomplete requirements remain explicit with
23
+ source-specific outcomes instead of allowing a partial PMI transcription to report clean.
24
+
25
+ - **Hexagonal and other regular polygonal bosses are recognised and dimensioned by their
26
+ across-flats size** (#676). Automatic and declared paths share the same feature model, and
27
+ mutation tests reject incomplete, unequal, non-planar, and ambiguous face sets.
28
+
29
+ - **Generated `Sheet` scripts preserve references to named source objects where correspondence
30
+ is proven** (#1041). The `--script` path emits declarations such as
31
+ `sheet.hole(features.tap)` instead of copying detected numbers; ambiguous, stale, non-shape, or
32
+ unused mappings fail closed.
33
+
34
+ - **A curated API reference is published at
35
+ <https://pzfreo.github.io/draftwright/>** (#846), covering the supported entry points,
36
+ `Sheet` declaration surface and fluent handles, `Drawing` results, and feature constructors.
37
+
38
+ ### Fixed
39
+
40
+ - **Recognition no longer combines faces from different solids into phantom slots or pads**
41
+ (#958). Each physical solid is recognised independently before the results are combined.
42
+
43
+ - **`Sheet.from_part(...).envelope()` reuses the detected whole-part envelope** (#1000) instead
44
+ of appending a duplicate feature whose dimensions were then silently deduplicated on the page.
45
+
46
+ - **Crowded Z-turned step chains recover the independently approved overall height when the
47
+ chain cannot be placed** (#955), and placed step lengths retain measurement identity for
48
+ differential audit (#1004).
49
+
50
+ - **All-over GD&T leaders and complex STEP B-spline paths have bounded, export-safe DXF
51
+ conversion** (#1097/#1070). All-over scope now reaches the existing export-safe leader
52
+ representation, while spline conversion reads OCCT knots, poles, and weights through its
53
+ indexed API instead of expensive sequence wrappers; visible curve geometry is preserved.
54
+
55
+ ### Changed
56
+
57
+ - **Hosted CI retains every supported Python version and both dependency/kernel generations on
58
+ macOS and Windows with a smaller compatibility matrix** (#1103). PRs still require lint,
59
+ coverage, Codecov, and the compatibility gates; the slow standards tier runs once after merge.
60
+
61
+ - **The pinned wheel fixture now records mutation-gated evidence for a repeating 13-fold radial
62
+ profile without claiming gear semantics** (#1085). Runtime recognition remains fail-closed
63
+ until a separate feature contract has independently sufficient evidence.
64
+
65
+ ## v0.4.1 — 2026-08-07
66
+
67
+ **The recognition trust release.** Automatic drawings now fail closed on unsupported inner
68
+ profiles, prove semantic coverage for flats, slots and patterns, and retain the measurement
69
+ identity needed to explain placed, suppressed, dropped and missing definitions. Several real
70
+ STEP case studies also move from clean-looking but incomplete output to complete drawings or
71
+ actionable lint.
72
+
73
+ ### Discouraged (supported)
74
+
75
+ - **`Sheet.auto_dimensions()` and `Sheet.add_dimension()` now emit
76
+ `SoftDeprecationWarning`** (#1043). They remain supported with no removal planned; the
77
+ warning steers declared scripts toward `authored_dimensions()` plus explicit
78
+ `dimension(feature, parameter_id)` lines, where omission can mean suppression. Automatic
79
+ `build_drawing(part)` and the `Sheet.from_part(part)` on-ramp remain silent. See
80
+ `docs/deprecations.md` for filtering and migration guidance.
81
+
82
+ ### Added
83
+
84
+ - **Finished drawings expose why measurements were omitted and, on covered placement paths,
85
+ what an annotation measures** (#996/#1002). `Drawing.suppressions()` returns the compiler's
86
+ omission ledger, `Drawing.measurement_keys(name)` exposes recorded measurement provenance, and
87
+ `draftwright.audit.diff_builds(before, after)` reports losses, substitutions and candidate
88
+ suppression explanations. The differential is deliberately a triage aid, not a proof where
89
+ renderer identity remains incomplete.
90
+
91
+ - **Physical-completeness lint now follows semantic correspondence for flats, lone slots and
92
+ slot patterns** (#1018). Coverage is joined through recognition, IR and compiler identities
93
+ rather than inferred from label text or page geometry, and distinguishes authored
94
+ suppression, placement drops, missing definitions and unverifiable provenance.
95
+
96
+ - **Full-span floored open channels are recognised and dimensioned as first-class features**
97
+ (#917). Automatic and declared drawings state the independent overall extent, one wall and
98
+ channel width, suppress the derived opposite wall, and report any missing member of that
99
+ defining chain.
100
+
101
+ ### Fixed
102
+
103
+ - **Square and near-square parts retain both independent planar extents** (#997). A plain
104
+ square plate could previously lose both plan dimensions, while parts up to five percent off
105
+ square could lose one and be silently represented as square. The unsafe suppression rule is
106
+ removed; explicit square notation remains tracked separately in #918.
107
+
108
+ - **Machined flats retain their physical stock identity from recognition through placement
109
+ and completeness lint** (#1013/#1015/#1034/#1036). Flats on separate parallel, coaxial or
110
+ slanted stock no longer collapse into one definition or borrow an opposite face from another
111
+ stock region. Independent callouts receive clear-margin candidates, while double-D faces on
112
+ one stock still form one A/F requirement.
113
+
114
+ - **Dense callout and step-detail cases keep their complete defining set** (#915). Hole
115
+ callout batches are reconciled as a queue, detail views fit their actual aspect, step levels
116
+ retain the supporting-face correspondence needed for truthful crops, and a detail redraws
117
+ only rungs omitted from its parent view.
118
+
119
+ - **Pocket leaders start on the physical opening rim** (#916), removing the spurious inner
120
+ silhouette crossing while preserving the solved label corridor and approved dimensions on
121
+ X-, Y- and Z-depth pockets.
122
+
123
+ - **Wedge-mounted raised pads survive recognition** (#909). Lower ledges that touch only in
124
+ plan no longer make the recogniser discard a valid upper pad; true staircase tiers remain
125
+ excluded.
126
+
127
+ - **Annotation-dense detail placement no longer stalls the build** (#1065). Detail views
128
+ avoid every decomposed annotation shaft, witness, label and item footprint; CTC-02
129
+ supplies 571 such boxes. The free-rectangle search previously treated that set as tiny
130
+ and admitted roughly 34 billion candidate rectangles, exhausting the slow tier's
131
+ ten-minute test budget before export. A compressed-coordinate sweep preserves the same
132
+ deterministic winning rectangle while completing the real search in seconds.
133
+
134
+ - **Through double-D bores are recognised and called out as first-class hole profiles**
135
+ (#1061). Automatic and declared builds preserve the parent-circle diameter, A/F size,
136
+ orientation and depth, and render one compound `DOUBLE-D ... A/F` bore callout. Physical
137
+ critique now accepts that supported inner profile while retaining a separate warning for
138
+ 13 evenly spaced common-circle arcs on the unresolved outer boundary; it does not infer a
139
+ repeating full profile or a gear standard.
140
+
141
+ - **Unsupported internal profiles no longer pass physical-completeness lint silently**
142
+ (#1058). Inner loops on principal boundary faces are checked against the current
143
+ circular-hole, rectangular-opening, true-obround, and proven through-double-D vocabulary.
144
+ Profiles outside it now produce
145
+ `unrecognised_defining_geometry` and reduce the lint score instead of allowing an
146
+ envelope-only drawing to score 1.0.
147
+
148
+ ### Changed
149
+
150
+ - **Crowded prismatic step dimensions recover into an enlarged detail view by default**
151
+ (#909). The automatic `build_drawing` / `make_drawing` / CLI paths and generated
152
+ `Sheet` scripts now preserve the omitted dimensions instead of returning
153
+ `step_dim_dropped` unless the caller remembered `detail_view=True`. Pass
154
+ `detail_view=False` to retain the parent-view-only behavior and its lint warning.
155
+
5
156
  ## v0.4.0 — 2026-08-02
6
157
 
7
158
  **The compat-exit release.** Every surface whose documented removal target was 0.4.0 is gone,
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: draftwright
3
- Version: 0.4.0
3
+ Version: 0.4.2
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
7
7
  Project-URL: Issues, https://github.com/pzfreo/draftwright/issues
8
8
  Project-URL: Changelog, https://github.com/pzfreo/draftwright/blob/main/CHANGELOG.md
9
+ Project-URL: Documentation, https://pzfreo.github.io/draftwright/
9
10
  Author-email: Paul Fremantle <pzfreo@gmail.com>
10
11
  License: GNU AFFERO GENERAL PUBLIC LICENSE
11
12
  Version 3, 19 November 2007
@@ -682,6 +683,7 @@ Classifier: Programming Language :: Python :: 3.13
682
683
  Classifier: Programming Language :: Python :: 3.14
683
684
  Classifier: Topic :: Scientific/Engineering
684
685
  Requires-Python: <3.15,>=3.10
686
+ Requires-Dist: antlr4-python3-runtime<4.10
685
687
  Requires-Dist: build123d-drafting-helpers>=0.14.1
686
688
  Requires-Dist: build123d<0.11,>=0.9.0; python_full_version < '3.13'
687
689
  Requires-Dist: build123d<0.12,>=0.11; python_full_version >= '3.13'
@@ -689,6 +691,7 @@ Requires-Dist: numpy>=1.24
689
691
  Requires-Dist: pillow>=10
690
692
  Requires-Dist: pypdfium2>=4
691
693
  Requires-Dist: reportlab>=4.0
694
+ Requires-Dist: steputils==0.1
692
695
  Requires-Dist: svglib>=1.5
693
696
  Requires-Dist: typer>=0.12
694
697
  Requires-Dist: typing-extensions>=4.5; python_full_version < '3.13'
@@ -705,6 +708,9 @@ Description-Content-Type: text/markdown
705
708
  [![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](LICENSE)
706
709
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
707
710
 
711
+ **[API reference](https://pzfreo.github.io/draftwright/)** ·
712
+ **[Examples and source](https://github.com/pzfreo/draftwright#readme)**
713
+
708
714
  Automated technical-drawing generation for [build123d](https://github.com/gumyr/build123d).
709
715
  Point it at a solid (or a STEP file) and get a fully-annotated multi-view engineering
710
716
  drawing — orthographic views, dimensions, section A–A, ISO hatching, title block — ready
@@ -771,9 +777,12 @@ from draftwright import build_drawing
771
777
 
772
778
  dwg = build_drawing(part, title="Mounting Plate")
773
779
  issues = dwg.lint() # list[LintIssue] — coverage, page bounds, ISO
774
- svg_path, dxf_path = dwg.export("my_part")
780
+ paths = dwg.export("my_part", formats=("svg", "dxf")) # {"svg": ..., "dxf": ...}
775
781
  ```
776
782
 
783
+ `export()` with no `formats=` returns the old `(svg, dxf)` tuple; that shape is deprecated
784
+ and removed in 0.5.0 (see [docs/deprecations.md](docs/deprecations.md)).
785
+
777
786
  ### Declarative drawings — reference features, declare intent
778
787
 
779
788
  Instead of relying on detection, **reference the build123d objects you built** and declare
@@ -789,10 +798,16 @@ plate = Box(120, 80, 20)
789
798
  bore = Pos(0, 0, 0) * Cylinder(4, 20)
790
799
 
791
800
  sheet = Sheet(plate - bore, title="Plate", number="DWG-002")
792
- sheet.envelope()
801
+ env = sheet.envelope()
793
802
  sheet.datum("A", plate.faces().sort_by()[-1]) # datum A on the top face
794
803
  hole = sheet.hole(bore).finish("1.6").note("M3x0.5 TAP") # ⌀8 bore, Ra 1.6, tapped
795
804
  sheet.control(hole).position(0.1, to="A", diameter=True) # ⌀0.1 position wrt A
805
+
806
+ sheet.authored_dimensions() # THIS is the complete set
807
+ sheet.dimension(env, "width.length") # (ADR 0016: a build says where
808
+ sheet.dimension(env, "height.length") # its dimensions come from, and
809
+ sheet.dimension(hole, "bore.diameter") # omitting one means suppress it)
810
+
796
811
  sheet.export("plate") # writes plate.pdf
797
812
  ```
798
813
 
@@ -9,6 +9,9 @@
9
9
  [![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](LICENSE)
10
10
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
11
11
 
12
+ **[API reference](https://pzfreo.github.io/draftwright/)** ·
13
+ **[Examples and source](https://github.com/pzfreo/draftwright#readme)**
14
+
12
15
  Automated technical-drawing generation for [build123d](https://github.com/gumyr/build123d).
13
16
  Point it at a solid (or a STEP file) and get a fully-annotated multi-view engineering
14
17
  drawing — orthographic views, dimensions, section A–A, ISO hatching, title block — ready
@@ -75,9 +78,12 @@ from draftwright import build_drawing
75
78
 
76
79
  dwg = build_drawing(part, title="Mounting Plate")
77
80
  issues = dwg.lint() # list[LintIssue] — coverage, page bounds, ISO
78
- svg_path, dxf_path = dwg.export("my_part")
81
+ paths = dwg.export("my_part", formats=("svg", "dxf")) # {"svg": ..., "dxf": ...}
79
82
  ```
80
83
 
84
+ `export()` with no `formats=` returns the old `(svg, dxf)` tuple; that shape is deprecated
85
+ and removed in 0.5.0 (see [docs/deprecations.md](docs/deprecations.md)).
86
+
81
87
  ### Declarative drawings — reference features, declare intent
82
88
 
83
89
  Instead of relying on detection, **reference the build123d objects you built** and declare
@@ -93,10 +99,16 @@ plate = Box(120, 80, 20)
93
99
  bore = Pos(0, 0, 0) * Cylinder(4, 20)
94
100
 
95
101
  sheet = Sheet(plate - bore, title="Plate", number="DWG-002")
96
- sheet.envelope()
102
+ env = sheet.envelope()
97
103
  sheet.datum("A", plate.faces().sort_by()[-1]) # datum A on the top face
98
104
  hole = sheet.hole(bore).finish("1.6").note("M3x0.5 TAP") # ⌀8 bore, Ra 1.6, tapped
99
105
  sheet.control(hole).position(0.1, to="A", diameter=True) # ⌀0.1 position wrt A
106
+
107
+ sheet.authored_dimensions() # THIS is the complete set
108
+ sheet.dimension(env, "width.length") # (ADR 0016: a build says where
109
+ sheet.dimension(env, "height.length") # its dimensions come from, and
110
+ sheet.dimension(hole, "bore.diameter") # omitting one means suppress it)
111
+
100
112
  sheet.export("plate") # writes plate.pdf
101
113
  ```
102
114
 
@@ -33,6 +33,7 @@ architecture** table; open retired or superseded records only for design history
33
33
  | [0014](0014-collect-then-solve-annotation-placement.md) | Collect-then-solve annotation placement (as built) | Collect, select, assign, and deterministically solve annotations per corridor before rendering. | Accepted; supersedes 0009 | `test_carve_free_position_callers.py`, `test_strip_layout.py`, `test_layout_property.py`, `test_import_boundaries.py` |
34
34
  | [0015](0015-part-drawing-compiler-as-built.md) | The part-drawing compiler, as built | Use one detected-or-declared feature IR and planner-fed dimension groups as the compiler waist. | Accepted; supersedes 0008 | `test_part_model.py`, `test_detect_once.py`, `test_import_boundaries.py` |
35
35
  | [0016](0016-declared-dimensioning-intent.md) | Declared dimensioning intent: capture what to measure, let the engine place it | Declare which measurements matter as scale-independent intent routed through the planner and corridor solve; never hardcode dimension geometry. | Accepted; epic #867 complete; phase 6 landed (#940) | `test_compiled_plan_boundary.py`, `test_label_provenance.py`, `test_sheet_emit.py`, `test_add_dimension.py` |
36
+ | [0017](0017-recognition-inventory-correspondence-and-measurement-provenance.md) | One recognition result per run; correspondence is evidence-gated | Produce one explicit recognition result owned by `BuildState`; require vertical-slice evidence before generalising correspondence, identity, requirements, outcomes, or reconciliation. | Accepted; ownership phase landed, extensions gated by #1018 | `test_recognition_manifest.py`, `test_recognition_result.py`, `test_declared_recognition_gate.py` |
36
37
 
37
38
  ## Historical records
38
39
 
@@ -49,5 +50,6 @@ architecture** table; open retired or superseded records only for design history
49
50
  - Layout and placement: 0004 → 0014 → 0012.
50
51
  - Declared intent and the editable surface: 0001 → 0011 → 0012 → 0016.
51
52
  - Quality and correction: 0002, with provenance from 0010.
53
+ - Recognition correspondence and completeness: 0007 → 0013 → 0015 → 0017.
52
54
 
53
55
  Tracking issue: #745.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "draftwright"
7
- version = "0.4.0"
7
+ version = "0.4.2"
8
8
  description = "Automated technical-drawing generation for build123d"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -25,6 +25,11 @@ dependencies = [
25
25
  "pillow>=10",
26
26
  "pypdfium2>=4",
27
27
  "reportlab>=4.0",
28
+ # Structured ISO 10303-21 access for AP242 facts that OCCT's XCAF transfer drops (#62).
29
+ # STEPutils 0.1 is the only release; isolate it behind _pmi_part21 and pin its README's
30
+ # ANTLR compatibility constraint explicitly because the package metadata omits the cap.
31
+ "steputils==0.1",
32
+ "antlr4-python3-runtime<4.10",
28
33
  "svglib>=1.5",
29
34
  "typer>=0.12",
30
35
  # PEP 702 @deprecated: stdlib `warnings.deprecated` lands in 3.13; backport for 3.10–3.12.
@@ -53,6 +58,7 @@ Homepage = "https://github.com/pzfreo/draftwright"
53
58
  Repository = "https://github.com/pzfreo/draftwright"
54
59
  Issues = "https://github.com/pzfreo/draftwright/issues"
55
60
  Changelog = "https://github.com/pzfreo/draftwright/blob/main/CHANGELOG.md"
61
+ Documentation = "https://pzfreo.github.io/draftwright/"
56
62
 
57
63
  [tool.hatch.build.targets.wheel]
58
64
  packages = ["src/draftwright"]
@@ -80,6 +86,18 @@ markers = [
80
86
  "slow: heavy end-to-end CTC fixture builds (deselected by default)",
81
87
  "smoke: curated build-light subset for a fast local check (~30 s)",
82
88
  ]
89
+ # `SoftDeprecationWarning` marks a surface that is discouraged but SUPPORTED and not going
90
+ # away (#1043). The suite exercises `Sheet.auto_dimensions()` in ~170 places, deliberately —
91
+ # it is still a supported path and its behaviour must keep being tested. Migrating those to
92
+ # authored dimensions would be churn that tests less, so the category is silenced here rather
93
+ # than at ~170 call sites.
94
+ #
95
+ # This does NOT weaken the guard: `tests/test_soft_deprecation.py` asserts the warning with
96
+ # `pytest.warns`, which fires regardless of this filter. Real `DeprecationWarning`s are
97
+ # untouched and still carry removal dates (`tests/test_deprecation_dates.py`).
98
+ filterwarnings = [
99
+ "ignore::draftwright.SoftDeprecationWarning",
100
+ ]
83
101
  # Coverage is a CI concern (it adds ~13% locally and instruments every line); the
84
102
  # CI workflow passes the --cov flags explicitly. Keep the local default lean.
85
103
  addopts = "--tb=short -m 'not slow'"
@@ -87,6 +105,9 @@ addopts = "--tb=short -m 'not slow'"
87
105
  [tool.coverage.run]
88
106
  source = ["src/draftwright"]
89
107
  omit = ["src/draftwright/__init__.py"]
108
+ # Keep XML paths anchored at the repository root so local diff coverage and Codecov
109
+ # measure the same changed source lines rather than relying on runner-specific paths.
110
+ relative_files = true
90
111
  # Branch coverage makes the regression gate sensitive to untested decision paths,
91
112
  # which matter more than raw statement execution in the recognition/layout code.
92
113
  branch = true
@@ -94,8 +115,8 @@ branch = true
94
115
  [tool.coverage.report]
95
116
  # Baseline measured on the full fast tier on Linux/Python 3.13 (#825):
96
117
  # 92.05% combined line+branch coverage (93.90% statements, 86.89% branches).
97
- # Keep two points of cross-platform/kernel headroom; ratchet upward only after the
98
- # lowest CI matrix result has stayed above the proposed floor.
118
+ # Keep two points of headroom; ratchet upward only after the canonical coverage job
119
+ # has stayed above the proposed floor.
99
120
  fail_under = 90
100
121
  precision = 1
101
122
  exclude_lines = [
@@ -129,6 +150,10 @@ select = ["E", "F", "I", "UP"]
129
150
  ignore = ["E501"]
130
151
 
131
152
  [dependency-groups]
153
+ docs = [
154
+ "mkdocs>=1.6,<2",
155
+ "mkdocstrings[python]>=0.30,<1",
156
+ ]
132
157
  dev = [
133
158
  "codespell>=2.3.0",
134
159
  "hypothesis>=6",
@@ -29,9 +29,17 @@ _LAZY = {
29
29
  "FeatureInfo": "draftwright.drawing",
30
30
  "Sheet": "draftwright.sheet",
31
31
  "lint_feature_coverage": "draftwright.linting",
32
+ "PmiExtractionReport": "draftwright.pmi",
32
33
  "PmiRecord": "draftwright.pmi",
34
+ "PmiSourceEntity": "draftwright.pmi",
33
35
  "extract_pmi": "draftwright.pmi",
36
+ "extract_pmi_report": "draftwright.pmi",
34
37
  "choose_scale": "draftwright.compose",
38
+ # A warning category users are told to filter must be importable without reaching into a
39
+ # private module (#1043 review) — and without paying for the CAD kernel. It lives in the
40
+ # dependency-free `_warnings` leaf for that second reason: defined in `_core` it cost ~6 s
41
+ # to reach, and the pytest filterwarnings entry naming it paid that on every invocation.
42
+ "SoftDeprecationWarning": "draftwright._warnings",
35
43
  }
36
44
 
37
45
 
@@ -68,11 +76,18 @@ _sys.modules[__name__].__class__ = _DraftwrightModule
68
76
 
69
77
 
70
78
  if TYPE_CHECKING: # static analysers / IDEs — no runtime import, no kernel cost
79
+ from draftwright._warnings import SoftDeprecationWarning
71
80
  from draftwright.builder import build_drawing, make_drawing
72
81
  from draftwright.compose import choose_scale
73
82
  from draftwright.drawing import Drawing, FeatureInfo
74
83
  from draftwright.linting import lint_feature_coverage
75
- from draftwright.pmi import PmiRecord, extract_pmi
84
+ from draftwright.pmi import (
85
+ PmiExtractionReport,
86
+ PmiRecord,
87
+ PmiSourceEntity,
88
+ extract_pmi,
89
+ extract_pmi_report,
90
+ )
76
91
  from draftwright.sheet import Sheet
77
92
 
78
93
 
@@ -85,12 +100,16 @@ def __dir__():
85
100
 
86
101
  __all__ = [
87
102
  "Drawing",
103
+ "SoftDeprecationWarning",
88
104
  "FeatureInfo",
105
+ "PmiExtractionReport",
89
106
  "PmiRecord",
107
+ "PmiSourceEntity",
90
108
  "Sheet",
91
109
  "build_drawing",
92
110
  "choose_scale",
93
111
  "extract_pmi",
112
+ "extract_pmi_report",
94
113
  "lint_feature_coverage",
95
114
  "make_drawing",
96
115
  ]