python-cad-tools 0.1.18__tar.gz → 0.1.19__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 (272) hide show
  1. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.github/workflows/ci.yml +19 -28
  2. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/CHANGELOG.md +18 -0
  3. {python_cad_tools-0.1.18/src/python_cad_tools.egg-info → python_cad_tools-0.1.19}/PKG-INFO +1 -1
  4. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/toolchain.md +3 -1
  5. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/artifacts.py +7 -0
  6. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/build.py +7 -0
  7. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/context.py +2 -0
  8. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/__init__.py +22 -0
  9. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/elements.py +12 -0
  10. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/geometry.py +9 -0
  11. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/units.py +13 -0
  12. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/validation.py +1 -0
  13. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19/src/python_cad_tools.egg-info}/PKG-INFO +1 -1
  14. python_cad_tools-0.1.19/src/python_cad_tools.egg-info/scm_version.json +8 -0
  15. python_cad_tools-0.1.18/src/python_cad_tools.egg-info/scm_version.json +0 -8
  16. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.gitattributes +0 -0
  17. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.githooks/pre-push +0 -0
  18. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.github/workflows/downstream-compatibility.yml +0 -0
  19. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.github/workflows/release-candidate.yml +0 -0
  20. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.github/workflows/release.yml +0 -0
  21. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.gitignore +0 -0
  22. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.opencode/commands/autocommit.md +0 -0
  23. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.opencode/tools/specrepo-autocommit.js +0 -0
  24. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/.opencode/tools/specrepo-autocommit.py +0 -0
  25. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/AGENTS.md +0 -0
  26. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/CLAUDE.md +0 -0
  27. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/LICENSE +0 -0
  28. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/MANIFEST.in +0 -0
  29. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/README.md +0 -0
  30. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/build-semantics.md +0 -0
  31. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/drawing-extensions.md +0 -0
  32. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/manifests.md +0 -0
  33. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/neutral-model.md +0 -0
  34. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/project-configuration.md +0 -0
  35. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/public-api.md +0 -0
  36. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/spikes/curved-geometry-ifc-bounds.md +0 -0
  37. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/spikes/format-feasibility.md +0 -0
  38. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/two-tier-contract.md +0 -0
  39. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/docs/viewer-delivery.md +0 -0
  40. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/pyproject.toml +0 -0
  41. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/setup.cfg +0 -0
  42. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/__init__.py +0 -0
  43. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/__main__.py +0 -0
  44. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_locking.py +0 -0
  45. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_project_loader.py +0 -0
  46. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_project_state.py +0 -0
  47. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_scaffold.py +0 -0
  48. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_transaction.py +0 -0
  49. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/app.webmanifest +0 -0
  50. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/asset-manifest.json +0 -0
  51. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/animationGroup-CMgMiFPo.js +0 -0
  52. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bakedVertexAnimation-BlpwZEna.js +0 -0
  53. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/basisTextureLoader-pxgVvwE7.js +0 -0
  54. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/brdfTextureTools-CL1Nnrm1.js +0 -0
  55. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpFragment-BNBjNOnF.js +0 -0
  56. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpVertex-BTawYPw8.js +0 -0
  57. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpVertexDeclaration-B_fffQFY.js +0 -0
  58. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/clipPlaneFragment-D1ZAafqO.js +0 -0
  59. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/clipPlaneVertex-BC_wnvpq.js +0 -0
  60. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/cubemapToSphericalPolynomial-DeA9LJ87.js +0 -0
  61. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dds-C5zm4fz8.js +0 -0
  62. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dds.pure-B_7lJeYI.js +0 -0
  63. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/ddsTextureLoader-DsS5rL5j.js +0 -0
  64. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/default.fragment-BUHDudIn.js +0 -0
  65. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/default.vertex-B80Wq2Ab.js +0 -0
  66. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/defaultUboDeclaration-DuGcl3VN.js +0 -0
  67. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dumpTools-1F1Rx0a0.js +0 -0
  68. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/envTextureLoader-DqI1ceC5.js +0 -0
  69. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/exrTextureLoader-DmNwF2B5.js +0 -0
  70. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyForceBlock-DmvfeucL.js +0 -0
  71. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyImpulseBlock-ChgIpPqh.js +0 -0
  72. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphArrayIndexBlock-_JwXSrlj.js +0 -0
  73. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBezierCurveEasingBlock-B-T0qVRw.js +0 -0
  74. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBinaryOperationBlock-TpZm5BfV.js +0 -0
  75. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBranchBlock-CNwAs8cP.js +0 -0
  76. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCachedOperationBlock-DaEYpjja.js +0 -0
  77. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCancelDelayBlock-Dc4RKYSf.js +0 -0
  78. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCodeExecutionBlock-DCxeE8wr.js +0 -0
  79. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConditionalDataBlock-TckZ2SGl.js +0 -0
  80. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConsoleLogBlock-B5e69wX5.js +0 -0
  81. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConstantBlock-3ktOI1lC.js +0 -0
  82. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphContextBlock-XTBtETD_.js +0 -0
  83. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCounterBlock-Pb64y9OD.js +0 -0
  84. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDataSwitchBlock-DsG4QDCF.js +0 -0
  85. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDebounceBlock-B_XjPDoZ.js +0 -0
  86. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDebugBlock-CD6lTvpS.js +0 -0
  87. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDoNBlock-0NvER8W0.js +0 -0
  88. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphEasingBlock-B6hapywt.js +0 -0
  89. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphFlipFlopBlock-D1uyBOpq.js +0 -0
  90. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphForLoopBlock-BYD81Gof.js +0 -0
  91. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphFunctionReferenceBlock-zABkEq-X.js +0 -0
  92. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGLTFDataProvider-B0ofoVrD.js +0 -0
  93. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAngularVelocityBlock-DPTUNnTb.js +0 -0
  94. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAssetBlock-B8_99mSz.js +0 -0
  95. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetLinearVelocityBlock-DFYXgPrA.js +0 -0
  96. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPhysicsMassPropertiesBlock-DA6AqPR7.js +0 -0
  97. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPropertyBlock-Bp4o9QmW.js +0 -0
  98. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetSoundVolumeBlock-BAmdegmU.js +0 -0
  99. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetVariableBlock-Cd8Y6leR.js +0 -0
  100. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIndexOfBlock-CGYxKZZY.js +0 -0
  101. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphInterpolationBlock-CwjeWPr7.js +0 -0
  102. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIsKeyPressedBlock-rNAEqrST.js +0 -0
  103. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIsSoundPlayingBlock-BTztAQ_0.js +0 -0
  104. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphJsonPointerParserBlock-DoLWKXUb.js +0 -0
  105. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyDownEventBlock-DPIi37WK.js +0 -0
  106. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyUpEventBlock-ZV1Tim4d.js +0 -0
  107. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyboardEventBlock-ClUSFYDa.js +0 -0
  108. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMathBlocks-BEiYY5fC.js +0 -0
  109. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMathCombineExtractBlocks-CVfFjT4m.js +0 -0
  110. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMatrixMathBlocks-B6l0dCDc.js +0 -0
  111. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMeshPickEventBlock-kdpuo1mU.js +0 -0
  112. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMultiGateBlock-n99NMOON.js +0 -0
  113. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseAnimationBlock-DXKPP4nK.js +0 -0
  114. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseSoundBlock-e2k4W8Bc.js +0 -0
  115. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPhysicsCollisionEventBlock-ClgKwXfJ.js +0 -0
  116. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPlayAnimationBlock-BZj6MNgX.js +0 -0
  117. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPlaySoundBlock-BnzlrpjK.js +0 -0
  118. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerDownEventBlock-CQiX1RZi.js +0 -0
  119. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerMoveEventBlock-B_JzBfd9.js +0 -0
  120. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOutEventBlock-B-xKCRP6.js +0 -0
  121. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOverEventBlock-DPC5GKft.js +0 -0
  122. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerUpEventBlock-hCR14WZY.js +0 -0
  123. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphReceiveCustomEventBlock-EOc5SmbK.js +0 -0
  124. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneReadyEventBlock-BAOJ-S5R.js +0 -0
  125. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneTickEventBlock-BJla1nDw.js +0 -0
  126. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSendCustomEventBlock-CbJzCBSw.js +0 -0
  127. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSequenceBlock-C0E5Vhwk.js +0 -0
  128. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetAngularVelocityBlock-Crx1sltA.js +0 -0
  129. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetDelayBlock-t-D4JM8I.js +0 -0
  130. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetLinearVelocityBlock-DKNa-lhN.js +0 -0
  131. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPhysicsMotionTypeBlock-BIeMWJwi.js +0 -0
  132. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPropertyBlock-CFERwfo5.js +0 -0
  133. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetSoundVolumeBlock-B8fGBso9.js +0 -0
  134. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetVariableBlock-D3NUXLsU.js +0 -0
  135. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSoundEndedEventBlock-BsojQIIQ.js +0 -0
  136. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphStopAnimationBlock-Bhvi4mzM.js +0 -0
  137. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphStopSoundBlock-BL-vDlPP.js +0 -0
  138. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSwitchBlock-q5uox2Ll.js +0 -0
  139. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphThrottleBlock-ZvIobaF-.js +0 -0
  140. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphTransformCoordinatesSystemBlock-DC7IZTrj.js +0 -0
  141. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphTypeToTypeBlocks-DsmLuQmd.js +0 -0
  142. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphUnaryOperationBlock-CeFOvM8N.js +0 -0
  143. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphVectorMathBlocks-O_o0PB3R.js +0 -0
  144. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphWaitAllBlock-CS8S_sto.js +0 -0
  145. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphWhileLoopBlock-BogzY-TI.js +0 -0
  146. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/fogFragment-5iY5mDF9.js +0 -0
  147. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-CzELCfrg.js +0 -0
  148. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-Dm4qQcCl.js +0 -0
  149. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-Dl5Knagi.js +0 -0
  150. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-gV6NfBr2.js +0 -0
  151. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-BU7N8GWm.js +0 -0
  152. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-BYh0LKwp.js +0 -0
  153. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-DGCqlu5B.js +0 -0
  154. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-DPRpU6I6.js +0 -0
  155. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-D6831_Db.js +0 -0
  156. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-DVVqYQkj.js +0 -0
  157. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-CJ5P29rW.js +0 -0
  158. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-eMPAGW-C.js +0 -0
  159. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-Cfmd-eH1.js +0 -0
  160. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-D8aj2PHd.js +0 -0
  161. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowBlurPostProcess.fragment-BNUj6Ok4.js +0 -0
  162. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.fragment-BMfCbDSO.js +0 -0
  163. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.vertex-HFoIGtvW.js +0 -0
  164. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.fragment-DcbXX8O5.js +0 -0
  165. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.vertex-C6kfp5Df.js +0 -0
  166. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/harmonicsFunctions-B_Rux4W4.js +0 -0
  167. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/hdrTextureLoader-BGQvgh0h.js +0 -0
  168. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/helperFunctions-DfEEUVrK.js +0 -0
  169. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/iesTextureLoader-DRIv8q-c.js +0 -0
  170. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/index-Bi_hQlRi.css +0 -0
  171. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/index-QUv88KPb.js +0 -0
  172. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-AIxPvzg7.js +0 -0
  173. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-B-fzpNXl.js +0 -0
  174. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-BeCpz_iB.js +0 -0
  175. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-LF_ZsFNn.js +0 -0
  176. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-0MaBFn29.js +0 -0
  177. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-CKf1P4fb.js +0 -0
  178. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/ktxTextureLoader-tKPsUacI.js +0 -0
  179. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/lightFragment-k2nRX45x.js +0 -0
  180. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/logDepthDeclaration-BGXXcOUJ.js +0 -0
  181. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/logDepthVertex-BC72KyzN.js +0 -0
  182. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/mainUVVaryingDeclaration-BCMZuxRE.js +0 -0
  183. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/mesh.vertexData.functions-ayNlGC5K.js +0 -0
  184. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/meshUboDeclaration-Cxk75_zo.js +0 -0
  185. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/oitFragment-BtwWIihL.js +0 -0
  186. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-8rnUKL54.js +0 -0
  187. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-C6yWZfQI.js +0 -0
  188. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DGh-kC4B.js +0 -0
  189. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DbnVIs8Y.js +0 -0
  190. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrMaterial.pure-CFHhabYh.js +0 -0
  191. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrMaterialLoadingAdapter-BQGAj-f6.js +0 -0
  192. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-BMK7l2Ba.js +0 -0
  193. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-DNsGu5u0.js +0 -0
  194. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-Cd1JAAAL.js +0 -0
  195. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-rBzbf9n3.js +0 -0
  196. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/packingFunctions-Dji1Rr-b.js +0 -0
  197. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/packingFunctions-_goA4OEm.js +0 -0
  198. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pass.fragment-CgGToehX.js +0 -0
  199. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-CqqQ20XF.js +0 -0
  200. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-D93dlgjG.js +0 -0
  201. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbr.fragment-YSvcDJjz.js +0 -0
  202. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbr.vertex-BOhSAeHX.js +0 -0
  203. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrBRDFFunctions-DTEwurLZ.js +0 -0
  204. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrDebug-B4IzJZHZ.js +0 -0
  205. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrIBLFunctions-gJ0KErMb.js +0 -0
  206. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrMaterial.pure-BRIxFz02.js +0 -0
  207. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrMaterialLoadingAdapter--NRrZRBU.js +0 -0
  208. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrUboDeclaration-6dxbcrtA.js +0 -0
  209. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/postprocess.vertex-ZxthID8t.js +0 -0
  210. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-BSVnGss-.js +0 -0
  211. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-DzIg_d-k.js +0 -0
  212. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/reflectionFunction-CgKY-0t6.js +0 -0
  213. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdDecode.fragment-CAfeJDpQ.js +0 -0
  214. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-D7xEO0B-.js +0 -0
  215. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-DIzz0LC4.js +0 -0
  216. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/sceneUboDeclaration-kGrRDglr.js +0 -0
  217. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-CgQTw0M7.js +0 -0
  218. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-DnEEx4Gs.js +0 -0
  219. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/tgaTextureLoader-CwaQqeYn.js +0 -0
  220. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/vertexColorMixing-C2cK_vck.js +0 -0
  221. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/favicon.svg +0 -0
  222. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/index.html +0 -0
  223. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/sw.js +0 -0
  224. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/build-info.json +0 -0
  225. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/cli.py +0 -0
  226. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/determinism.py +0 -0
  227. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/_catalog.py +0 -0
  228. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/_validation.py +0 -0
  229. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exceptions.py +0 -0
  230. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/__init__.py +0 -0
  231. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/base.py +0 -0
  232. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/__init__.py +0 -0
  233. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/annotations.py +0 -0
  234. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/dxf.py +0 -0
  235. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/model.py +0 -0
  236. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/pdf.py +0 -0
  237. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/primitives.py +0 -0
  238. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/projection.py +0 -0
  239. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/svg.py +0 -0
  240. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/glb.py +0 -0
  241. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/ifc.py +0 -0
  242. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/quantities.py +0 -0
  243. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/step.py +0 -0
  244. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/manifests.py +0 -0
  245. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/project_config.py +0 -0
  246. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/py.typed +0 -0
  247. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/recipes.py +0 -0
  248. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/runtime_sync.py +0 -0
  249. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/build-manifest-1.json +0 -0
  250. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/design-manifest-1.json +0 -0
  251. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/download-manifest-2.json +0 -0
  252. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/drawing-annotations-1.json +0 -0
  253. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/glb-manifest-1.json +0 -0
  254. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/ifc-validation-1.json +0 -0
  255. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/quantities-1.json +0 -0
  256. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/run-metadata-1.json +0 -0
  257. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/site-metadata-1.json +0 -0
  258. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/step-validation-1.json +0 -0
  259. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/site.py +0 -0
  260. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/.gitignore +0 -0
  261. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/README.md +0 -0
  262. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/config.py +0 -0
  263. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/drawing_annotations.py +0 -0
  264. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/generated/.gitkeep +0 -0
  265. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/model.py +0 -0
  266. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/pyproject.toml +0 -0
  267. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/SOURCES.txt +0 -0
  268. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/dependency_links.txt +0 -0
  269. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/entry_points.txt +0 -0
  270. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/requires.txt +0 -0
  271. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/scm_file_list.json +0 -0
  272. {python_cad_tools-0.1.18 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/top_level.txt +0 -0
@@ -17,6 +17,12 @@
17
17
  # creates the tag and triggers this run. Keeping publish logic in one
18
18
  # gated place (instead of duplicating it in release.yml) avoids two
19
19
  # workflows racing to publish the same version.
20
+ #
21
+ # Test tiers (workspace test-cost-reduction, 2026-10-12): pushes and pull
22
+ # requests run the checks a code change can break on Linux, plus one macOS
23
+ # platform job. Version tags and manual dispatch (the release path, before
24
+ # PyPI) also run Windows, the per-extra toolchain matrix on macOS and Linux,
25
+ # and the platform locks. macOS minutes bill 10x on this private repository.
20
26
  name: CI
21
27
 
22
28
  on:
@@ -227,15 +233,15 @@ jobs:
227
233
  done
228
234
  echo "All tree shape checks passed."
229
235
 
230
- # Confirms init/build works on Linux, macOS, and Windows. Windows
231
- # skips ruff/mypy since static checks aren't part of the
232
- # cross-platform contract, just the CLI behavior.
236
+ # Confirms init/build works on Linux, macOS, and Windows (Windows only
237
+ # on the release tier). Windows skips ruff/mypy since static checks
238
+ # aren't part of the cross-platform contract, just the CLI behavior.
233
239
  supported-platforms:
234
240
  name: Supported platforms (${{ matrix.os }})
235
241
  strategy:
236
242
  fail-fast: false
237
243
  matrix:
238
- os: [ubuntu-latest, macos-latest, windows-latest]
244
+ os: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["ubuntu-latest","macos-latest","windows-latest"]' || '["ubuntu-latest","macos-latest"]') }}
239
245
  runs-on: ${{ matrix.os }}
240
246
  steps:
241
247
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -263,9 +269,10 @@ jobs:
263
269
 
264
270
  # Generates a per-OS `pip freeze` lockfile as a downloadable
265
271
  # artifact for reference. Informational only — not enforced or
266
- # committed anywhere automatically.
272
+ # committed anywhere automatically. Release tier only.
267
273
  platform-locks:
268
274
  name: Platform lock generation (${{ matrix.os }})
275
+ if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
269
276
  strategy:
270
277
  fail-fast: false
271
278
  matrix:
@@ -297,40 +304,27 @@ jobs:
297
304
  path: ${{ matrix.lock }}
298
305
 
299
306
  # Confirms every optional dependency group (cad, bim, mesh, ...)
300
- # installs cleanly and imports across OS/Python combinations. PRs
301
- # only run a fast subset (core+all on ubuntu/py3.13) via the gate
302
- # step below; main and tag pushes run the full matrix.
307
+ # installs cleanly and imports across OS/Python combinations. Pushes
308
+ # and PRs run core and all on Linux for both Pythons; the release tier
309
+ # runs every group on Linux and macOS. The matrix itself is narrowed,
310
+ # so no runner starts for a cell that would be skipped.
303
311
  toolchain-matrix:
304
312
  name: Toolchain matrix (${{ matrix.os }}, py${{ matrix.python }}, ${{ matrix.group }})
305
313
  strategy:
306
314
  fail-fast: false
307
315
  matrix:
308
- os: [ubuntu-latest, macos-latest]
316
+ os: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["ubuntu-latest","macos-latest"]' || '["ubuntu-latest"]') }}
309
317
  python: ["3.12", "3.13"]
310
- group: [core, cad, bim, mesh, drawings, engineering, visualization, all]
318
+ group: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["core","cad","bim","mesh","drawings","engineering","visualization","all"]' || '["core","all"]') }}
311
319
  runs-on: ${{ matrix.os }}
312
320
  steps:
313
321
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
314
- # Full matrix on main/tags/release-candidates; a fast core+all subset on pull requests.
315
- - name: Determine whether this matrix cell runs
316
- id: gate
317
- run: |
318
- if [ "${{ github.event_name }}" = "pull_request" ] && \
319
- ! { [ "${{ matrix.os }}" = "ubuntu-latest" ] && [ "${{ matrix.python }}" = "3.13" ] && \
320
- { [ "${{ matrix.group }}" = "core" ] || [ "${{ matrix.group }}" = "all" ]; }; }; then
321
- echo "run=false" >> "$GITHUB_OUTPUT"
322
- else
323
- echo "run=true" >> "$GITHUB_OUTPUT"
324
- fi
325
322
  - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
326
- if: steps.gate.outputs.run == 'true'
327
323
  with:
328
324
  python-version: ${{ matrix.python }}
329
325
  cache: pip
330
326
  - run: python -m pip install --upgrade pip
331
- if: steps.gate.outputs.run == 'true'
332
327
  - name: Install capability group
333
- if: steps.gate.outputs.run == 'true'
334
328
  run: |
335
329
  if [ "${{ matrix.group }}" = "core" ]; then
336
330
  pip install -e .
@@ -338,9 +332,7 @@ jobs:
338
332
  pip install -e ".[${{ matrix.group }}]"
339
333
  fi
340
334
  - run: pip check
341
- if: steps.gate.outputs.run == 'true'
342
335
  - name: Import declared libraries for this group
343
- if: steps.gate.outputs.run == 'true'
344
336
  run: |
345
337
  python - <<'PY'
346
338
  import importlib
@@ -384,7 +376,7 @@ jobs:
384
376
  print(json.dumps(report, indent=2, sort_keys=True))
385
377
  PY
386
378
  - name: Tier-2 interop smoke and no-GUI assertion
387
- if: steps.gate.outputs.run == 'true' && matrix.group == 'all'
379
+ if: matrix.group == 'all'
388
380
  run: |
389
381
  python - <<'PY'
390
382
  import sys
@@ -413,7 +405,6 @@ jobs:
413
405
  print("Tier-2 interop smoke and no-GUI assertion passed.")
414
406
  PY
415
407
  - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
416
- if: steps.gate.outputs.run == 'true'
417
408
  with:
418
409
  name: toolchain-compatibility-${{ matrix.os }}-py${{ matrix.python }}-${{ matrix.group }}
419
410
  path: toolchain-compatibility.json
@@ -7,6 +7,24 @@ stable release is published.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.19] - 2026-10-19
11
+
12
+ ### Changed
13
+
14
+ - Every public function and class in the authoring modules (`artifacts`,
15
+ `build`, `context`, `drawings`, `elements`, `geometry`, `units`,
16
+ `validation`) has a one-line docstring stating its units and, for
17
+ geometry, its placement:
18
+ - `box` puts its minimum corner at the origin;
19
+ - `prism_between` starts at a bottom corner, with its width to the left
20
+ of the run;
21
+ - `Placement` is recorded only and never moves geometry.
22
+
23
+ Tools that list the public API with signatures and first docstring
24
+ lines now describe each helper. Behavior is unchanged.
25
+ - Routine CI runs a smaller platform and extras matrix. Version tags and
26
+ manual dispatch still run the full release matrix.
27
+
10
28
  ## [0.1.18] - 2026-10-08
11
29
 
12
30
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cad-tools
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: Typed, headless Python tooling for CAD/BIM models and artifacts
5
5
  Author: Brandon Benge
6
6
  License: AGPL-3.0-only
@@ -90,7 +90,9 @@ See `docs/two-tier-contract.md` for what "Tier 1" and "Tier 2" mean.
90
90
  ## Compatibility verification
91
91
 
92
92
  The `toolchain-matrix` CI job (`.github/workflows/ci.yml`) installs every
93
- capability group across `{ubuntu-latest, macos-latest} × {3.12, 3.13}`, runs
93
+ capability group across `{ubuntu-latest, macos-latest} × {3.12, 3.13}` on
94
+ version tags and manual runs (the release path; pushes and pull requests
95
+ run `core` and `all` on Linux for both Pythons), runs
94
96
  `pip check`, imports every library the group declares, and — for `all` — runs
95
97
  a Tier-2 interop smoke (a shape crosses build123d → `geometry.tessellate` →
96
98
  trimesh → ifcopenshell read-back → ezdxf) plus the no-GUI assertion. It
@@ -25,6 +25,7 @@ _EXPECTED_REPRESENTATION_TYPE = {None: "Tessellation", "extruded_profile": "Swep
25
25
 
26
26
  @dataclass(frozen=True, slots=True)
27
27
  class ArtifactRecord:
28
+ """One generated file: its path, size, SHA-256, media type and producer."""
28
29
  path: str
29
30
  size: int
30
31
  sha256: str
@@ -37,6 +38,7 @@ class ArtifactRecord:
37
38
 
38
39
  @dataclass(frozen=True, slots=True)
39
40
  class VerificationResult:
41
+ """The outcome of ``verify_build_output``: whether the output matches its manifest, and any issues."""
40
42
  ok: bool
41
43
  output_root: Path
42
44
  issues: tuple[ValidationIssue, ...]
@@ -48,6 +50,7 @@ class VerificationResult:
48
50
 
49
51
  @dataclass(frozen=True, slots=True)
50
52
  class PackageBuildInfo:
53
+ """The installed python-cad-tools distribution's version and build provenance."""
51
54
  schema_id: Literal["urn:python-cad-tools:schema:package-build-info:1"]
52
55
  schema_version: Literal[1]
53
56
  distribution: Literal["python-cad-tools"]
@@ -58,6 +61,7 @@ class PackageBuildInfo:
58
61
 
59
62
 
60
63
  def load_build_manifest(path: Path) -> dict[str, Any]:
64
+ """Read and schema-check a build manifest JSON file."""
61
65
  value = validate_json_document(path)
62
66
  if value["schema_id"] != "urn:python-cad-tools:schema:build-manifest:1":
63
67
  raise ArtifactIntegrityError(f"Not a build manifest: {path}")
@@ -65,6 +69,7 @@ def load_build_manifest(path: Path) -> dict[str, Any]:
65
69
 
66
70
 
67
71
  def load_design_manifest(path: Path) -> dict[str, Any]:
72
+ """Read and schema-check a design manifest JSON file."""
68
73
  value = validate_json_document(path)
69
74
  if value["schema_id"] != "urn:python-cad-tools:schema:design-manifest:1":
70
75
  raise ArtifactIntegrityError(f"Not a design manifest: {path}")
@@ -171,6 +176,7 @@ def verify_output_root(output_root: Path, project_root: Path | None = None) -> V
171
176
 
172
177
 
173
178
  def verify_build_output(project_root: Path) -> VerificationResult:
179
+ """Check that a project's generated output still matches its build manifest."""
174
180
  from ._locking import project_lock
175
181
  from ._transaction import recover_promotion
176
182
  from .project_config import load_project_config, output_path, resolve_project_root
@@ -184,6 +190,7 @@ def verify_build_output(project_root: Path) -> VerificationResult:
184
190
 
185
191
 
186
192
  def get_package_build_info() -> PackageBuildInfo:
193
+ """Return the installed distribution's build information."""
187
194
  try:
188
195
  document = json.loads(resources.files("python_cad_tools").joinpath("build-info.json").read_text(encoding="utf-8"))
189
196
  except (FileNotFoundError, json.JSONDecodeError) as error:
@@ -32,18 +32,21 @@ type FormatName = Literal["step", "ifc", "glb", "drawings", "quantities"]
32
32
 
33
33
  @dataclass(frozen=True, slots=True)
34
34
  class BuildOptions:
35
+ """Options for ``build_project``: the project root and the formats to build (default: the project's own)."""
35
36
  project_root: Path
36
37
  formats: tuple[FormatName, ...] | None = None
37
38
 
38
39
 
39
40
  @dataclass(frozen=True, slots=True)
40
41
  class ValidationOptions:
42
+ """Options for ``validate_project``: the project root and the formats to check (default: the project's own)."""
41
43
  project_root: Path
42
44
  formats: tuple[FormatName, ...] | None = None
43
45
 
44
46
 
45
47
  @dataclass(frozen=True, slots=True)
46
48
  class BuildResult:
49
+ """What ``build_project`` produced: its output folder, artifacts, build manifest and hashes."""
47
50
  project_root: Path
48
51
  output_root: Path
49
52
  formats: tuple[FormatName, ...]
@@ -57,6 +60,7 @@ class BuildResult:
57
60
 
58
61
  @dataclass(frozen=True, slots=True)
59
62
  class ValidationReport:
63
+ """The issues ``validate_project`` found; ``ok`` is true when none is fatal."""
60
64
  project_root: Path
61
65
  formats: tuple[FormatName, ...]
62
66
  issues: tuple[ValidationIssue, ...]
@@ -79,6 +83,7 @@ EXPORTERS: dict[str, type[Any]] = {
79
83
 
80
84
 
81
85
  def build_project(options: BuildOptions) -> BuildResult:
86
+ """Build the project's requested formats into its output folder and return the result."""
82
87
  if not isinstance(options, BuildOptions):
83
88
  raise TypeError("build_project expects BuildOptions")
84
89
  requested = _validate_requested_formats(options.formats)
@@ -159,6 +164,7 @@ def build_project(options: BuildOptions) -> BuildResult:
159
164
 
160
165
 
161
166
  def validate_project(options: ValidationOptions) -> ValidationReport:
167
+ """Load the project's model and check it without writing any artifacts."""
162
168
  if not isinstance(options, ValidationOptions):
163
169
  raise TypeError("validate_project expects ValidationOptions")
164
170
  requested = _validate_requested_formats(options.formats)
@@ -182,6 +188,7 @@ def validate_project(options: ValidationOptions) -> ValidationReport:
182
188
 
183
189
 
184
190
  def clean_project(project_root: Path) -> None:
191
+ """Remove the project's generated output folder."""
185
192
  reject_nested_project_execution()
186
193
  root = resolve_project_root(project_root)
187
194
  config = load_project_config(root)
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
15
15
 
16
16
  @dataclass(frozen=True, slots=True)
17
17
  class BuildContext:
18
+ """What ``build_model`` receives: the project root, its loaded ``config`` and source revision, with recorded read-only access to declared sources."""
18
19
  project_root: Path
19
20
  config: Any
20
21
  source_revision: str | None
@@ -57,6 +58,7 @@ class BuildContext:
57
58
 
58
59
  @dataclass(frozen=True, slots=True)
59
60
  class DrawingContext:
61
+ """What a drawing annotation provider receives: the built model and its sheets, in millimetres."""
60
62
  project_root: Path
61
63
  config: Any
62
64
  model: DesignModel
@@ -19,6 +19,8 @@ type DrawingStyleToken = Literal[
19
19
 
20
20
  @dataclass(frozen=True, slots=True)
21
21
  class DrawingSheet:
22
+ """One drawing view: its id, view kind, projection origin and axes, and projected bounds in millimetres."""
23
+
22
24
  sheet_id: str
23
25
  view_id: Literal["plan", "front", "side", "section"]
24
26
  origin_mm: tuple[float, float, float]
@@ -29,6 +31,8 @@ class DrawingSheet:
29
31
 
30
32
  @dataclass(frozen=True, slots=True)
31
33
  class Line:
34
+ """A straight annotation line on a sheet, in projected millimetres."""
35
+
32
36
  id: str
33
37
  sheet_id: str
34
38
  start: Point2
@@ -38,6 +42,8 @@ class Line:
38
42
 
39
43
  @dataclass(frozen=True, slots=True)
40
44
  class Polyline:
45
+ """An open or closed annotation polyline on a sheet, in projected millimetres."""
46
+
41
47
  id: str
42
48
  sheet_id: str
43
49
  points: tuple[Point2, ...]
@@ -47,6 +53,8 @@ class Polyline:
47
53
 
48
54
  @dataclass(frozen=True, slots=True)
49
55
  class Text:
56
+ """Annotation text placed on a sheet, with its height in millimetres and rotation in degrees."""
57
+
50
58
  id: str
51
59
  sheet_id: str
52
60
  position: Point2
@@ -58,6 +66,8 @@ class Text:
58
66
 
59
67
  @dataclass(frozen=True, slots=True)
60
68
  class Dimension:
69
+ """A labelled dimension between two sheet points, offset in millimetres."""
70
+
61
71
  id: str
62
72
  sheet_id: str
63
73
  start: Point2
@@ -69,6 +79,8 @@ class Dimension:
69
79
 
70
80
  @dataclass(frozen=True, slots=True)
71
81
  class SectionCallout:
82
+ """A section cut line on a sheet that refers to the sheet showing that section."""
83
+
72
84
  id: str
73
85
  sheet_id: str
74
86
  start: Point2
@@ -80,6 +92,8 @@ class SectionCallout:
80
92
 
81
93
  @dataclass(frozen=True, slots=True)
82
94
  class ElevationMarker:
95
+ """A marker on a sheet that refers to the sheet showing that elevation."""
96
+
83
97
  id: str
84
98
  sheet_id: str
85
99
  position: Point2
@@ -90,12 +104,16 @@ class ElevationMarker:
90
104
 
91
105
  @dataclass(frozen=True, slots=True)
92
106
  class TableRow:
107
+ """One row of an annotation ``Table``."""
108
+
93
109
  id: str
94
110
  cells: tuple[str, ...]
95
111
 
96
112
 
97
113
  @dataclass(frozen=True, slots=True)
98
114
  class Table:
115
+ """A titled annotation table placed on a sheet."""
116
+
99
117
  id: str
100
118
  sheet_id: str
101
119
  position: Point2
@@ -109,12 +127,16 @@ type AnnotationPrimitive = Line | Polyline | Text | Dimension | SectionCallout |
109
127
 
110
128
  @dataclass(frozen=True, slots=True)
111
129
  class SheetAnnotations:
130
+ """All annotations for one sheet."""
131
+
112
132
  sheet_id: str
113
133
  annotations: tuple[AnnotationPrimitive, ...]
114
134
 
115
135
 
116
136
  @dataclass(frozen=True, slots=True)
117
137
  class DrawingAnnotationSet:
138
+ """What a drawing annotation provider returns: annotations per sheet."""
139
+
118
140
  provider_id: str
119
141
  sheets: tuple[SheetAnnotations, ...]
120
142
 
@@ -15,6 +15,8 @@ GeometryKind = Literal["solid", "shell", "wire", "edge", "reference"]
15
15
 
16
16
  @dataclass(frozen=True, slots=True)
17
17
  class MaterialSpec:
18
+ """A material: id, display name, category, RGB colour in 0-1 and optional density in kg/m3."""
19
+
18
20
  id: str
19
21
  name: str
20
22
  category: str
@@ -25,12 +27,16 @@ class MaterialSpec:
25
27
 
26
28
  @dataclass(frozen=True, slots=True)
27
29
  class Placement:
30
+ """An element's recorded position (millimetres) and XYZ rotation (degrees); it does not move the geometry, which must already be in place."""
31
+
28
32
  translation_mm: tuple[float, float, float] = (0.0, 0.0, 0.0)
29
33
  rotation_deg_xyz: tuple[float, float, float] = (0.0, 0.0, 0.0)
30
34
 
31
35
 
32
36
  @dataclass(frozen=True, slots=True)
33
37
  class Dimensions:
38
+ """An element's declared size in millimetres; every value given must be finite and positive."""
39
+
34
40
  length_mm: float | None = None
35
41
  width_mm: float | None = None
36
42
  height_mm: float | None = None
@@ -46,6 +52,8 @@ class Dimensions:
46
52
 
47
53
  @dataclass(frozen=True, slots=True)
48
54
  class IfcMapping:
55
+ """The IFC class and predefined type an element exports as, or why it is excluded from IFC."""
56
+
49
57
  ifc_class: str | None
50
58
  predefined_type: str | None = None
51
59
  exclude_reason: str | None = None
@@ -68,6 +76,8 @@ class Opening:
68
76
 
69
77
  @dataclass(slots=True)
70
78
  class DesignElement:
79
+ """One model element with a stable id; physical elements need solid geometry and a material, and colours use RGB in 0-1."""
80
+
71
81
  id: str
72
82
  name: str
73
83
  category: str
@@ -98,6 +108,8 @@ class DesignElement:
98
108
 
99
109
  @dataclass(slots=True)
100
110
  class DesignModel:
111
+ """The whole model a project's ``build_model`` returns: its elements in millimetres, X right, Y away, Z up."""
112
+
101
113
  id: str
102
114
  name: str
103
115
  artifact_stem: str
@@ -21,6 +21,7 @@ def box(
21
21
  *,
22
22
  origin: tuple[Length, Length, Length] | None = None,
23
23
  ) -> Solid:
24
+ """Return a solid box length (X) by width (Y) by height (Z) with its minimum corner at ``origin`` (default the world origin), not its centre."""
24
25
  _positive_lengths((length, width, height), "Box dimensions")
25
26
  if origin is not None:
26
27
  _point(origin, "Box origin")
@@ -42,6 +43,7 @@ def reference_line(
42
43
  start: tuple[Length, Length, Length],
43
44
  end: tuple[Length, Length, Length],
44
45
  ) -> Edge:
46
+ """Return a straight edge from ``start`` to ``end`` for non-physical reference geometry."""
45
47
  start_mm = _point(start, "Reference-line start")
46
48
  end_mm = _point(end, "Reference-line end")
47
49
  if start_mm == end_mm:
@@ -79,6 +81,7 @@ def prism_between(
79
81
  width: Length,
80
82
  height: Length,
81
83
  ) -> Solid:
84
+ """Return a solid of ``width`` by ``height`` running from ``start`` to ``end``, with ``start`` as a bottom corner, width to the left of the run and height upward."""
82
85
  _positive_lengths((width, height), "Prism dimensions")
83
86
  start_mm = _point(start, "Prism start")
84
87
  end_mm = _point(end, "Prism end")
@@ -103,6 +106,7 @@ def sloped_pool(
103
106
  *,
104
107
  origin: tuple[Length, Length, Length],
105
108
  ) -> Solid:
109
+ """Return a pool body ``length`` along X and ``width`` along Y whose top edge starts at ``origin``, sloping from ``shallow_depth`` to ``deep_depth`` below it along X."""
106
110
  _positive_lengths((length, width, shallow_depth, deep_depth), "Sloped-pool dimensions")
107
111
  if to_mm(deep_depth) < to_mm(shallow_depth):
108
112
  raise ModelValidationError("Sloped-pool deep depth must be at least the shallow depth")
@@ -124,6 +128,7 @@ def sloped_pool(
124
128
 
125
129
 
126
130
  def bounds(shape: Any) -> tuple[float, float, float, float, float, float]:
131
+ """Return a shape's bounding box as ``(xmin, ymin, zmin, xmax, ymax, zmax)`` in millimetres."""
127
132
  box_value = shape.bounding_box()
128
133
  return (
129
134
  float(box_value.min.X),
@@ -136,6 +141,7 @@ def bounds(shape: Any) -> tuple[float, float, float, float, float, float]:
136
141
 
137
142
 
138
143
  def combined_bounds(shapes: list[Any]) -> tuple[float, float, float, float, float, float]:
144
+ """Return the bounding box of all ``shapes`` in millimetres (all zeros when empty)."""
139
145
  values = [bounds(shape) for shape in shapes]
140
146
  if not values:
141
147
  return (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
@@ -176,6 +182,7 @@ def shared_tessellation() -> Iterator[None]:
176
182
 
177
183
 
178
184
  def tessellate(shape: Any, linear_deflection: float, angular_deflection: float) -> tuple[list[list[float]], list[list[int]]]:
185
+ """Return a shape's triangle mesh as ``(vertices, triangles)``, reusing one mesh per shape within a build."""
179
186
  cache = _TESSELLATIONS.get()
180
187
  key = (id(shape), float(linear_deflection), float(angular_deflection))
181
188
  if cache is not None:
@@ -226,10 +233,12 @@ def single_wrapped_solid(shape: Any) -> Solid | None:
226
233
 
227
234
 
228
235
  def is_valid_solid(shape: Any) -> bool:
236
+ """Return whether ``shape`` is a valid build123d ``Solid`` with positive volume."""
229
237
  return isinstance(shape, Solid) and bool(shape.is_valid) and float(shape.volume) > 0
230
238
 
231
239
 
232
240
  def diagonal(bounds_value: tuple[float, float, float, float, float, float]) -> float:
241
+ """Return the diagonal length of a ``bounds`` box in millimetres."""
233
242
  return sqrt(sum((bounds_value[index + 3] - bounds_value[index]) ** 2 for index in range(3)))
234
243
 
235
244
 
@@ -9,6 +9,7 @@ from typing import overload
9
9
 
10
10
  @dataclass(frozen=True, slots=True, order=True)
11
11
  class Length:
12
+ """A length stored in millimetres (``mm``); build values with ``mm``, ``inches``, ``feet`` or ``feet_inches`` and convert with ``to_mm``."""
12
13
  mm: float
13
14
 
14
15
  def __post_init__(self) -> None:
@@ -66,6 +67,7 @@ class Length:
66
67
 
67
68
  @dataclass(frozen=True, slots=True)
68
69
  class Area:
70
+ """An area in square millimetres (``mm2``), the product of two ``Length`` values."""
69
71
  mm2: float
70
72
 
71
73
  def __post_init__(self) -> None:
@@ -91,6 +93,7 @@ class Area:
91
93
 
92
94
  @dataclass(frozen=True, slots=True)
93
95
  class Volume:
96
+ """A volume in cubic millimetres (``mm3``), an ``Area`` times a ``Length``."""
94
97
  mm3: float
95
98
 
96
99
  def __post_init__(self) -> None:
@@ -111,50 +114,60 @@ FOOT = 12 * INCH
111
114
 
112
115
 
113
116
  def to_mm(value: Length) -> float:
117
+ """Return a ``Length`` as a float of millimetres, the geometry kernel's unit."""
114
118
  if not isinstance(value, Length):
115
119
  raise TypeError(f"Expected Length, got {type(value).__name__}")
116
120
  return float(value.mm)
117
121
 
118
122
 
119
123
  def mm(value: float) -> Length:
124
+ """Return a ``Length`` of ``value`` millimetres."""
120
125
  return value * MM
121
126
 
122
127
 
123
128
  def inches(value: float) -> Length:
129
+ """Return a ``Length`` of ``value`` inches."""
124
130
  return value * INCH
125
131
 
126
132
 
127
133
  def feet(value: float) -> Length:
134
+ """Return a ``Length`` of ``value`` feet."""
128
135
  return value * FOOT
129
136
 
130
137
 
131
138
  def feet_inches(feet_value: float, inches_value: float = 0) -> Length:
139
+ """Return a ``Length`` of ``feet_value`` feet plus ``inches_value`` inches."""
132
140
  return feet_value * FOOT + inches_value * INCH
133
141
 
134
142
 
135
143
  def square_feet(value: Area) -> float:
144
+ """Return an ``Area`` in square feet."""
136
145
  if not isinstance(value, Area):
137
146
  raise TypeError("square_feet expects Area")
138
147
  return value.mm2 / (304.8**2)
139
148
 
140
149
 
141
150
  def cubic_feet(value: Volume) -> float:
151
+ """Return a ``Volume`` in cubic feet."""
142
152
  if not isinstance(value, Volume):
143
153
  raise TypeError("cubic_feet expects Volume")
144
154
  return value.mm3 / (304.8**3)
145
155
 
146
156
 
147
157
  def cubic_yards(value: Volume) -> float:
158
+ """Return a ``Volume`` in cubic yards."""
148
159
  if not isinstance(value, Volume):
149
160
  raise TypeError("cubic_yards expects Volume")
150
161
  return value.mm3 / (914.4**3)
151
162
 
152
163
 
153
164
  def metres(value: Length) -> float:
165
+ """Return a ``Length`` in metres."""
154
166
  return to_mm(value) / 1000.0
155
167
 
156
168
 
157
169
  def square_metres(value: Area) -> float:
170
+ """Return an ``Area`` in square metres."""
158
171
  if not isinstance(value, Area):
159
172
  raise TypeError("square_metres expects Area")
160
173
  return value.mm2 / 1_000_000.0
@@ -50,6 +50,7 @@ _STABLE_ID = re.compile(r"[A-Za-z0-9._-]+\Z", re.ASCII)
50
50
 
51
51
  @dataclass(frozen=True, slots=True)
52
52
  class ValidationIssue:
53
+ """One model or build problem: a code, ``warning`` or ``error`` severity, a message and where it applies."""
53
54
  code: str
54
55
  severity: Literal["warning", "error"]
55
56
  message: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cad-tools
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: Typed, headless Python tooling for CAD/BIM models and artifacts
5
5
  Author: Brandon Benge
6
6
  License: AGPL-3.0-only
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.1.19",
3
+ "distance": 0,
4
+ "node": "gb3c8c85999c0abbb3136117d037dd1229a20dccb",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-20"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.1.18",
3
- "distance": 0,
4
- "node": "ge909d6f9394ae6f2a5ee80d99f5a8cac772d09de",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-09"
8
- }