draftwright 0.4.12__tar.gz → 0.4.14__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 (288) hide show
  1. {draftwright-0.4.12 → draftwright-0.4.14}/CHANGELOG.md +19 -0
  2. {draftwright-0.4.12 → draftwright-0.4.14}/PKG-INFO +2 -2
  3. {draftwright-0.4.12 → draftwright-0.4.14}/docs/reference/recogniser-capabilities.md +31 -0
  4. {draftwright-0.4.12 → draftwright-0.4.14}/pyproject.toml +2 -2
  5. draftwright-0.4.14/src/draftwright/_build_profile.py +186 -0
  6. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/_core.py +4 -1
  7. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/_geometry.py +9 -0
  8. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/_common.py +417 -33
  9. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/from_model.py +149 -470
  10. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/holes.py +3 -3
  11. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/leaders.py +74 -16
  12. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/builder.py +67 -26
  13. draftwright-0.4.14/src/draftwright/linting/ink_overlap.py +745 -0
  14. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/quality.py +1 -0
  15. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/structural.py +161 -13
  16. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/suggest.py +7 -0
  17. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/repair.py +26 -0
  18. {draftwright-0.4.12 → draftwright-0.4.14}/tests/conftest.py +2 -0
  19. draftwright-0.4.14/tests/fixtures/grm03_thumbwheel_drive_screw_ap242_pmi.step +32991 -0
  20. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_adr0018_view_selection.py +20 -4
  21. draftwright-0.4.14/tests/test_build_profile_harness.py +194 -0
  22. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_e2e_standards.py +8 -3
  23. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_import_boundaries.py +3 -0
  24. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1058_wheel_profile.py +4 -1
  25. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1143_hole_completeness.py +61 -33
  26. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1144_transactional_hole_table.py +15 -8
  27. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1166_cross_pass_feature_leaders.py +90 -12
  28. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1176_quality_fidelity.py +5 -1
  29. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1187_unroutable_leaders.py +0 -1
  30. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1204_multiscale_view_issues.py +4 -3
  31. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +65 -54
  32. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1216_callout_reservation_measures_ink.py +15 -5
  33. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1276_turned_leader_targets.py +11 -4
  34. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1296_cylindrical_diameter_pmi.py +1 -2
  35. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1298_manufacturing_requirements.py +1 -3
  36. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1299_page_escalation.py +37 -13
  37. draftwright-0.4.14/tests/test_issue_1308_machined_leader_analytics.py +261 -0
  38. draftwright-0.4.14/tests/test_issue_1312_engine_costs.py +25 -0
  39. draftwright-0.4.14/tests/test_issue_1332_overlap_remedy.py +89 -0
  40. draftwright-0.4.14/tests/test_issue_1332_overlap_remedy_fast.py +106 -0
  41. draftwright-0.4.14/tests/test_issue_1332_zone_labels.py +49 -0
  42. draftwright-0.4.14/tests/test_issue_1334_prevent_ink.py +158 -0
  43. draftwright-0.4.14/tests/test_issue_1336_grm03_ap242_pmi_fixture.py +77 -0
  44. draftwright-0.4.14/tests/test_issue_1338_scale_before_page_escalation.py +103 -0
  45. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_443_grm03_axial_coverage.py +7 -4
  46. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_740_leader_assignment.py +45 -36
  47. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_798_silhouette_lint.py +1 -1
  48. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_885_prismatic_coverage.py +4 -1
  49. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_915_dense_case.py +62 -2
  50. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_916_pocket_leader.py +29 -1
  51. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_917_open_channel.py +5 -2
  52. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_layout_property.py +4 -4
  53. draftwright-0.4.14/tests/test_lint_ink_overlap.py +727 -0
  54. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_lint_structural.py +56 -0
  55. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_make_drawing.py +86 -24
  56. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recogniser_capabilities.py +40 -0
  57. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_emit.py +65 -33
  58. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_slanted_blind_step.py +12 -5
  59. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_strip_layout.py +10 -2
  60. {draftwright-0.4.12 → draftwright-0.4.14}/.gitignore +0 -0
  61. {draftwright-0.4.12 → draftwright-0.4.14}/LICENSE +0 -0
  62. {draftwright-0.4.12 → draftwright-0.4.14}/README.md +0 -0
  63. {draftwright-0.4.12 → draftwright-0.4.14}/docs/adr/README.md +0 -0
  64. {draftwright-0.4.12 → draftwright-0.4.14}/docs/reference/sheet.md +0 -0
  65. {draftwright-0.4.12 → draftwright-0.4.14}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
  66. {draftwright-0.4.12 → draftwright-0.4.14}/skills/SKILL.md +0 -0
  67. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/__init__.py +0 -0
  68. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/_pmi_part21.py +0 -0
  69. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/_warnings.py +0 -0
  70. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/analysis.py +0 -0
  71. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotate.py +0 -0
  72. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/__init__.py +0 -0
  73. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/balloons.py +0 -0
  74. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/gears.py +0 -0
  75. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/orchestrator.py +0 -0
  76. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/annotations/sections.py +0 -0
  77. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/audit.py +0 -0
  78. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/cli.py +0 -0
  79. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/compose.py +0 -0
  80. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/drawing.py +0 -0
  81. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/evaluation/__init__.py +0 -0
  82. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/evaluation/step_analysis.py +0 -0
  83. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/export.py +0 -0
  84. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fits.py +0 -0
  85. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
  86. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
  87. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
  88. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
  89. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/fonts/__init__.py +0 -0
  90. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/intents.py +0 -0
  91. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/layout.py +0 -0
  92. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/__init__.py +0 -0
  93. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/channel_coverage.py +0 -0
  94. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/coverage.py +0 -0
  95. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/evidence.py +0 -0
  96. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/flat_coverage.py +0 -0
  97. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/gear_coverage.py +0 -0
  98. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/hole_coverage.py +0 -0
  99. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/issues.py +0 -0
  100. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/pmi_coverage.py +0 -0
  101. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/polygonal_stock_coverage.py +0 -0
  102. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/profiled_bore_coverage.py +0 -0
  103. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/linting/slot_coverage.py +0 -0
  104. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/make_drawing.py +0 -0
  105. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/__init__.py +0 -0
  106. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/callout.py +0 -0
  107. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/compiled.py +0 -0
  108. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/declare.py +0 -0
  109. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/detect.py +0 -0
  110. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/ir.py +0 -0
  111. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/planner.py +0 -0
  112. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/model/pmi_lowering.py +0 -0
  113. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/pmi.py +0 -0
  114. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/projection.py +0 -0
  115. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/py.typed +0 -0
  116. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/recogniser_contract.py +0 -0
  117. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/recognition/__init__.py +0 -0
  118. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/recognition_cache.py +0 -0
  119. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/registry.py +0 -0
  120. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/score.py +0 -0
  121. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/sheet.py +0 -0
  122. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/sheet_emit.py +0 -0
  123. {draftwright-0.4.12 → draftwright-0.4.14}/src/draftwright/view_plan.py +0 -0
  124. {draftwright-0.4.12 → draftwright-0.4.14}/tests/_kernel.py +0 -0
  125. {draftwright-0.4.12 → draftwright-0.4.14}/tests/_layout_sig.py +0 -0
  126. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/ap242_single_cylinder_diameter.step +0 -0
  127. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/README.md +0 -0
  128. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
  129. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/blind-hole.step +0 -0
  130. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/corpus-v1.json +0 -0
  131. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/plain-block.step +0 -0
  132. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/topology-a.step +0 -0
  133. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/evaluation/topology-b.step +0 -0
  134. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
  135. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/grm04_drive_plate.step +0 -0
  136. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
  137. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
  138. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
  139. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/issue_915_case_study_2.step +0 -0
  140. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
  141. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
  142. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
  143. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
  144. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
  145. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
  146. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
  147. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
  148. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
  149. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
  150. {draftwright-0.4.12 → draftwright-0.4.14}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
  151. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/bracket_section.json +0 -0
  152. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/centered_rebate.json +0 -0
  153. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/chamfered.json +0 -0
  154. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/filleted.json +0 -0
  155. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/flange_dense.json +0 -0
  156. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/grid_plate.json +0 -0
  157. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/grooved_shaft.json +0 -0
  158. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/hex_bar.json +0 -0
  159. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/holed_slot.json +0 -0
  160. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/pocketed.json +0 -0
  161. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/prismatic_ladder.json +0 -0
  162. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/scattered_plate.json +0 -0
  163. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/side_drilled.json +0 -0
  164. {draftwright-0.4.12 → draftwright-0.4.14}/tests/refactor_golden/turned_stepped.json +0 -0
  165. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_add_dimension.py +0 -0
  166. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_adr0018_arrangement_gate.py +0 -0
  167. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_adr0018_view_routing.py +0 -0
  168. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_agents_guide.py +0 -0
  169. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_api_docs.py +0 -0
  170. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_architecture_docs.py +0 -0
  171. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_audit_differential.py +0 -0
  172. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_balloon_ring_standoff.py +0 -0
  173. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_carve_free_position_callers.py +0 -0
  174. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_compiled_plan_boundary.py +0 -0
  175. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_counting_calls.py +0 -0
  176. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_declare.py +0 -0
  177. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_declared_recognition_gate.py +0 -0
  178. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_dense_sheet_canary.py +0 -0
  179. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_deprecation_dates.py +0 -0
  180. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_detect_once.py +0 -0
  181. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_detect_registry.py +0 -0
  182. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_dimension_role_vocabulary.py +0 -0
  183. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_drawing_encapsulation.py +0 -0
  184. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_e2e_slice.py +0 -0
  185. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_export_dxf_curves.py +0 -0
  186. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_export_dxf_zoom.py +0 -0
  187. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_external_recognition_boundary.py +0 -0
  188. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_fillets_adjacency.py +0 -0
  189. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_fits.py +0 -0
  190. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_flat_completeness.py +0 -0
  191. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_flat_stock_identity.py +0 -0
  192. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_flat_stock_opposition.py +0 -0
  193. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_gdt_placement.py +0 -0
  194. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_grid_lattice_convention.py +0 -0
  195. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_iso_nts_caption_placement.py +0 -0
  196. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1000_envelope_reuse.py +0 -0
  197. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1073_cross_body_patterns.py +0 -0
  198. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1082_polygonal_stock.py +0 -0
  199. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1086_declared_gears.py +0 -0
  200. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +0 -0
  201. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1130_view_planning_evidence.py +0 -0
  202. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1142_hole_leader_labels.py +0 -0
  203. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1146_scale_completeness.py +0 -0
  204. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1147_legibility_pair_aggregation.py +0 -0
  205. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1153_contradictory_dimensions.py +0 -0
  206. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1154_one_owner_per_measurement.py +0 -0
  207. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1155_grm04_sheet_use.py +0 -0
  208. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1177_angular_dimensions.py +0 -0
  209. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1188_per_view_assignment.py +0 -0
  210. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1190_section_decision.py +0 -0
  211. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1196_deterministic_view_names.py +0 -0
  212. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1202_observed_drawing_consumer.py +0 -0
  213. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1209_linear_pmi_witnesses.py +0 -0
  214. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1215_envelope_tolerance.py +0 -0
  215. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1216_pairwise_across_scale_groups.py +0 -0
  216. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1217_claimed_representations.py +0 -0
  217. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1217_the_facility_is_shared.py +0 -0
  218. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1219_location_claims_its_own_axis.py +0 -0
  219. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1229_ledger_member_keying.py +0 -0
  220. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1240_iso_above_strip_visibility.py +0 -0
  221. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1254_turned_chamfers.py +0 -0
  222. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1260_view_constraints.py +0 -0
  223. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_1281_turned_fillets.py +0 -0
  224. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_367_leader_ink.py +0 -0
  225. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_676_polygonal_boss.py +0 -0
  226. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
  227. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_798_floor_cardinality.py +0 -0
  228. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_798_material_field.py +0 -0
  229. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_909_sloped_profile.py +0 -0
  230. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_924_zero_length_shoulders.py +0 -0
  231. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_955_height_contingency.py +0 -0
  232. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_issue_958_cross_solid_recognition.py +0 -0
  233. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_label_provenance.py +0 -0
  234. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_layout.py +0 -0
  235. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_layout_cleanliness.py +0 -0
  236. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_layout_hypothesis.py +0 -0
  237. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_leader_footprint.py +0 -0
  238. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_lint_box_cache.py +0 -0
  239. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_lint_reconciliation.py +0 -0
  240. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_linting.py +0 -0
  241. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_location_vocabulary.py +0 -0
  242. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_note_verb.py +0 -0
  243. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_object_aspects.py +0 -0
  244. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_occupancy_boxes.py +0 -0
  245. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_parameter_id.py +0 -0
  246. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_part_model.py +0 -0
  247. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pitch_dim_footprint.py +0 -0
  248. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pmi.py +0 -0
  249. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pmi_datum_lowering.py +0 -0
  250. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pmi_gtol_lowering.py +0 -0
  251. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pmi_part21.py +0 -0
  252. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pocket_pattern.py +0 -0
  253. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_pocket_pattern_recognition.py +0 -0
  254. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_principal_profile_classifier.py +0 -0
  255. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_private_test_attr_reads.py +0 -0
  256. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_private_test_imports.py +0 -0
  257. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_quality_components.py +0 -0
  258. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recogniser_adoption.py +0 -0
  259. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recogniser_contract.py +0 -0
  260. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recognition.py +0 -0
  261. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recognition_manifest.py +0 -0
  262. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_recognition_result.py +0 -0
  263. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_refactor_golden.py +0 -0
  264. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_registry.py +0 -0
  265. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_render_seam.py +0 -0
  266. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_repack_geometry_seam.py +0 -0
  267. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_score.py +0 -0
  268. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_script_detail_parity.py +0 -0
  269. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_shared_box_memo.py +0 -0
  270. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_gdt.py +0 -0
  271. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_identity_invariant.py +0 -0
  272. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_notes.py +0 -0
  273. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_of.py +0 -0
  274. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_section.py +0 -0
  275. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_sheet_tables.py +0 -0
  276. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_slot_completeness.py +0 -0
  277. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_slot_pattern.py +0 -0
  278. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_slot_pattern_recognition.py +0 -0
  279. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_soft_deprecation.py +0 -0
  280. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_solve_trace.py +0 -0
  281. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_step_analysis_evaluation.py +0 -0
  282. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_suppression_ledger.py +0 -0
  283. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_suppression_marks.py +0 -0
  284. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_tolerances.py +0 -0
  285. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_turned_steps.py +0 -0
  286. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_view_plan.py +0 -0
  287. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_witness_label_reconciliation.py +0 -0
  288. {draftwright-0.4.12 → draftwright-0.4.14}/tests/test_workflows.py +0 -0
@@ -2,8 +2,27 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Added
6
+
7
+ - New lint code `annotation_ink_overlap`: reports another annotation's line-work —
8
+ a dimension line, an extension line or a leader shaft — drawn through a label's
9
+ text, which `annotation_overlap` cannot see because it compares label boxes to
10
+ each other and to nothing else. Measured as the longest connected stroke path
11
+ crossing the label's exact polygon (or its axis-aligned box), in millimetres,
12
+ with a 0.5 mm floor. It scores on legibility, so
13
+ dense sheets that previously scored clean now score lower — 17 findings on
14
+ NIST CTC-02 AP203 alone, every sampled one confirmed a real defect by rendering.
15
+ Repair does not yet act on it (#1333) and the corridor solve does not yet avoid
16
+ it (#1334) (#1321, #1332).
17
+
5
18
  ### Changed
6
19
 
20
+ - `annotation_overlap` now reports the whole defect when the same pair also draws
21
+ line-work through one of the two labels: the message names the crosser, the label
22
+ crossed and the millimetres, and replaces the "use `label_offset_x`" remedy, which
23
+ is the advice that case contradicts. `LintIssue.suggestion` is `None` for those
24
+ issues rather than a snippet that re-places the text (#1321, #1332).
25
+
7
26
  - Recogniser integration now uses only the exact `b123d-recognisers` dependency in
8
27
  `pyproject.toml` and `uv.lock`. The separate release-evidence record, dependency-bump workflow,
9
28
  candidate-checkout harness, and release-time capability-version rewrites have been removed;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: draftwright
3
- Version: 0.4.12
3
+ Version: 0.4.14
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
@@ -685,7 +685,7 @@ Classifier: Topic :: Scientific/Engineering
685
685
  Requires-Python: <3.15,>=3.10
686
686
  Requires-Dist: antlr4-python3-runtime<4.10
687
687
  Requires-Dist: b123d-recognisers==0.3.1
688
- Requires-Dist: build123d-drafting-helpers>=0.14.1
688
+ Requires-Dist: build123d-drafting-helpers>=0.14.2
689
689
  Requires-Dist: build123d<0.11,>=0.9.0; python_full_version < '3.13'
690
690
  Requires-Dist: build123d<0.12,>=0.11; python_full_version >= '3.13'
691
691
  Requires-Dist: numpy>=1.24
@@ -64,3 +64,34 @@ pass.
64
64
  `bosses` is the fully consumed reference family. `repeating-radial-profiles` is the opposite
65
65
  reference: it remains geometry-only critique evidence for a separately authored gear declaration,
66
66
  with no inferred gear feature added to fill the table.
67
+
68
+ ## Passage compatibility boundary
69
+
70
+ The installed `b123d-recognisers==0.3.1` release already contains the `passages` family introduced
71
+ in 0.2.6. Draftwright declares its schema-v1 `Passage` output exhaustively but deliberately keeps
72
+ the family `unsupported`, with the drafting decision tracked by issue #1245. This is a truthful
73
+ consumer disposition: the geometry remains visible in the aggregate inventory, while Draftwright
74
+ does not invent an IR feature, DSL declaration, generated code, drawing annotation, or completeness
75
+ requirement for it.
76
+
77
+ Draftwright's exact dependency pin must remain on a reviewed released version in the interval
78
+ `>=0.2.6,<0.4.0` until the separately reviewed F4b transition is ready. The lower boundary ensures
79
+ the installed manifest really contains `passages`; the upper boundary prevents accidental adoption
80
+ of the planned 0.4 compatibility change.
81
+
82
+ The reviewed future 0.4 model is a distinct migration, not latent behavior in this declaration:
83
+
84
+ - `SectionPassage` will be the authoritative physical output and aggregate census source;
85
+ - legacy `Passage` values will be an accepted-only compatibility projection;
86
+ - `recognise_passages(..., ledger=...)` will be a fail-loud unavailable compatibility operation;
87
+ - the writer-free `recognise_passages` name will remain public but non-authoritative; and
88
+ - rich split-junction passages can supersede a currently rendered Slot claim, moving ownership to
89
+ the Passage family through `SLOT_SUPERSEDED_BY_PASSAGE`; and
90
+ - the capability contract must represent those API and per-output roles exhaustively before the
91
+ dependency pin can cross 0.4.
92
+
93
+ That migration must update the package release, Draftwright adapter and declaration model,
94
+ validator, tests, exact pin, and lockfile together. The current validator remains unchanged and
95
+ fail closed; there is no forward declaration or stale-manifest exception. Crossing 0.4 also
96
+ requires #1245 to decide what those newly Passage-owned occurrences draw, or an explicit reviewed
97
+ decision to accept the resulting loss of the existing Slot callout.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "draftwright"
7
- version = "0.4.12"
7
+ version = "0.4.14"
8
8
  description = "Automated technical-drawing generation for build123d"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -17,7 +17,7 @@ dependencies = [
17
17
  # 3.13+. Mirrors pzfreo/build123d-mcp's dependency handling.
18
18
  "build123d>=0.9.0,<0.11 ; python_full_version < '3.13'",
19
19
  "build123d>=0.11,<0.12 ; python_full_version >= '3.13'",
20
- "build123d-drafting-helpers>=0.14.1",
20
+ "build123d-drafting-helpers>=0.14.2",
21
21
  "b123d-recognisers==0.3.1",
22
22
  "numpy>=1.24",
23
23
  # PNG raster export (SVG→PDF→PNG). Both permissively licensed (Pillow HPND; pypdfium2
@@ -0,0 +1,186 @@
1
+ """Pytest plugin and runner support for reproducible build-cost profiles (#1307)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ import sys
8
+ from collections import defaultdict
9
+ from collections.abc import Callable
10
+ from dataclasses import dataclass, field
11
+ from functools import wraps
12
+ from pathlib import Path
13
+ from time import perf_counter
14
+ from typing import Any
15
+
16
+ _MIN_REPORT_SECONDS = 0.005
17
+ _STATE: _ProfileState | None = None
18
+ _CURRENT_NODEID = "<collection>"
19
+
20
+
21
+ @dataclass
22
+ class _ProfileState:
23
+ output_dir: Path
24
+ worker_id: str
25
+ collected: int | None = None
26
+ calls: dict[tuple[str, str], list[float]] = field(
27
+ default_factory=lambda: defaultdict(lambda: [0, 0.0])
28
+ )
29
+ phases: list[dict[str, Any]] = field(default_factory=list)
30
+
31
+ def record_call(self, seam: str, seconds: float) -> None:
32
+ aggregate = self.calls[(_CURRENT_NODEID, seam)]
33
+ aggregate[0] += 1
34
+ aggregate[1] += seconds
35
+
36
+ def write(self, exitstatus: int) -> Path:
37
+ self.output_dir.mkdir(parents=True, exist_ok=True)
38
+ safe_worker = re.sub(r"[^A-Za-z0-9_.-]", "_", self.worker_id)
39
+ path = self.output_dir / f"profile-{safe_worker}.json"
40
+ payload = {
41
+ "worker_id": self.worker_id,
42
+ "collected": self.collected,
43
+ "exitstatus": exitstatus,
44
+ "calls": [
45
+ {
46
+ "nodeid": nodeid,
47
+ "seam": seam,
48
+ "count": int(values[0]),
49
+ "seconds": values[1],
50
+ }
51
+ for (nodeid, seam), values in sorted(self.calls.items())
52
+ ],
53
+ "phases": self.phases,
54
+ }
55
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
56
+ return path
57
+
58
+
59
+ def _timed(seam: str, function: Callable[..., Any]) -> Callable[..., Any]:
60
+ @wraps(function)
61
+ def wrapper(*args, **kwargs):
62
+ started = perf_counter()
63
+ try:
64
+ return function(*args, **kwargs)
65
+ finally:
66
+ assert _STATE is not None
67
+ _STATE.record_call(seam, perf_counter() - started)
68
+
69
+ return wrapper
70
+
71
+
72
+ def pytest_addoption(parser) -> None:
73
+ group = parser.getgroup("draftwright-build-profile")
74
+ group.addoption(
75
+ "--build-profile-dir",
76
+ help="write one Draftwright build profile JSON file per pytest-xdist worker",
77
+ )
78
+
79
+
80
+ def pytest_configure(config) -> None:
81
+ global _STATE
82
+ output = config.getoption("--build-profile-dir")
83
+ if not output:
84
+ return
85
+
86
+ worker_input = getattr(config, "workerinput", None)
87
+ # Under xdist the controller executes no tests; worker processes write the useful files.
88
+ if worker_input is None and getattr(config.option, "numprocesses", None):
89
+ return
90
+
91
+ worker_id = worker_input.get("workerid", "worker") if worker_input else "main"
92
+ _STATE = _ProfileState(Path(output).resolve(), worker_id)
93
+
94
+ import draftwright.builder as builder
95
+ import draftwright.sheet as sheet
96
+
97
+ draftwright = sys.modules["draftwright"]
98
+ builder_public = _timed("builder.build_drawing", builder.build_drawing)
99
+ builder.build_drawing = builder_public
100
+ # The public lazy package attribute and Sheet's import-time binding otherwise bypass a
101
+ # patch installed only on builder.py. That omission made the first #1307 census a lower
102
+ # bound, so all three bindings are explicit here.
103
+ setattr(draftwright, "build_drawing", builder_public)
104
+ sheet.build_drawing = _timed("sheet.build_drawing", sheet.build_drawing)
105
+ builder._build_drawing_once = _timed(
106
+ "builder._build_drawing_once", builder._build_drawing_once
107
+ )
108
+
109
+
110
+ def pytest_collection_finish(session) -> None:
111
+ if _STATE is not None:
112
+ _STATE.collected = len(session.items)
113
+
114
+
115
+ def pytest_runtest_logstart(nodeid, location) -> None:
116
+ del location
117
+ global _CURRENT_NODEID
118
+ _CURRENT_NODEID = nodeid
119
+
120
+
121
+ def pytest_runtest_logfinish(nodeid, location) -> None:
122
+ del nodeid, location
123
+ global _CURRENT_NODEID
124
+ _CURRENT_NODEID = "<between-tests>"
125
+
126
+
127
+ def pytest_runtest_logreport(report) -> None:
128
+ if _STATE is not None and report.duration >= _MIN_REPORT_SECONDS:
129
+ _STATE.phases.append(
130
+ {
131
+ "nodeid": report.nodeid,
132
+ "phase": report.when,
133
+ "seconds": report.duration,
134
+ "outcome": report.outcome,
135
+ }
136
+ )
137
+
138
+
139
+ def pytest_sessionfinish(session, exitstatus) -> None:
140
+ del session
141
+ if _STATE is not None:
142
+ _STATE.write(int(exitstatus))
143
+
144
+
145
+ def build_pytest_command(output_dir: Path, pytest_args: list[str]) -> list[str]:
146
+ """Return argv without joining *pytest_args* into a shell-expanded module string."""
147
+ return [
148
+ "uv",
149
+ "run",
150
+ "pytest",
151
+ "-p",
152
+ "draftwright._build_profile",
153
+ f"--build-profile-dir={output_dir}",
154
+ *pytest_args,
155
+ ]
156
+
157
+
158
+ def summarise_profiles(output_dir: Path, expected_collected: int) -> dict[str, Any]:
159
+ paths = sorted(output_dir.glob("profile-*.json"))
160
+ if not paths:
161
+ raise ValueError(f"no worker profiles were written to {output_dir}")
162
+
163
+ by_seam: dict[str, list[float]] = defaultdict(lambda: [0, 0.0])
164
+ workers = []
165
+ for path in paths:
166
+ payload = json.loads(path.read_text(encoding="utf-8"))
167
+ collected = payload.get("collected")
168
+ if collected != expected_collected:
169
+ raise ValueError(
170
+ f"{path.name} collected {collected!r}, expected {expected_collected}; "
171
+ "refusing to report a successful empty or partial profile"
172
+ )
173
+ workers.append(payload["worker_id"])
174
+ for call in payload["calls"]:
175
+ aggregate = by_seam[call["seam"]]
176
+ aggregate[0] += call["count"]
177
+ aggregate[1] += call["seconds"]
178
+
179
+ return {
180
+ "expected_collected": expected_collected,
181
+ "workers": workers,
182
+ "seams": {
183
+ seam: {"count": int(values[0]), "seconds": values[1]}
184
+ for seam, values in sorted(by_seam.items())
185
+ },
186
+ }
@@ -358,7 +358,10 @@ _QUOTED_RE = re.compile(r"'([^']*)'")
358
358
 
359
359
  @functools.lru_cache(maxsize=512)
360
360
  def _text_size(
361
- text: str, font_size: float, font_path: str | None = PLEX_MONO, font: str = "Arial"
361
+ text: str,
362
+ font_size: float,
363
+ font_path: str | None = PLEX_MONO,
364
+ font: str = "Arial",
362
365
  ) -> tuple[float, float]:
363
366
  """Measured rendered (width, height) (page-mm) of *text* at *font_size*.
364
367
 
@@ -456,6 +456,15 @@ def _convex_polygons_overlap(left, right) -> bool:
456
456
 
457
457
  if len(left) < 3 or len(right) < 3:
458
458
  return False
459
+ left_x, left_y = zip(*left, strict=True)
460
+ right_x, right_y = zip(*right, strict=True)
461
+ if (
462
+ max(left_x) <= min(right_x)
463
+ or max(right_x) <= min(left_x)
464
+ or max(left_y) <= min(right_y)
465
+ or max(right_y) <= min(left_y)
466
+ ):
467
+ return False
459
468
  axes: list[tuple[float, float]] = []
460
469
  for points in (left, right):
461
470
  axes.extend(