python-cad-tools 0.1.13__tar.gz → 0.1.16__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.
- python_cad_tools-0.1.16/.opencode/tools/specrepo-autocommit.py +259 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/CHANGELOG.md +60 -0
- {python_cad_tools-0.1.13/src/python_cad_tools.egg-info → python_cad_tools-0.1.16}/PKG-INFO +7 -1
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/README.md +6 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/neutral-model.md +107 -5
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/project-configuration.md +14 -4
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/public-api.md +3 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_project_loader.py +53 -1
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/artifacts.py +20 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/build-info.json +1 -1
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/cli.py +20 -2
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/elements.py +5 -1
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/ifc.py +187 -17
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/manifests.py +23 -0
- python_cad_tools-0.1.16/src/python_cad_tools/recipes.py +293 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/validation.py +226 -5
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16/src/python_cad_tools.egg-info}/PKG-INFO +7 -1
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/SOURCES.txt +1 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/scm_file_list.json +2 -0
- python_cad_tools-0.1.16/src/python_cad_tools.egg-info/scm_version.json +8 -0
- python_cad_tools-0.1.13/.opencode/tools/specrepo-autocommit.py +0 -205
- python_cad_tools-0.1.13/src/python_cad_tools.egg-info/scm_version.json +0 -8
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.gitattributes +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.githooks/pre-push +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.github/workflows/ci.yml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.github/workflows/downstream-compatibility.yml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.github/workflows/release-candidate.yml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.github/workflows/release.yml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.gitignore +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.opencode/commands/autocommit.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/.opencode/tools/specrepo-autocommit.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/AGENTS.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/CLAUDE.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/LICENSE +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/MANIFEST.in +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/build-semantics.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/drawing-extensions.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/manifests.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/spikes/format-feasibility.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/toolchain.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/two-tier-contract.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/docs/viewer-delivery.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/pyproject.toml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/setup.cfg +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/__init__.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/__main__.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_locking.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_project_state.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_scaffold.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_transaction.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/app.webmanifest +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/asset-manifest.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/animationGroup-d5_0GqzW.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/bakedVertexAnimation-BTnhNnCG.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/basisTextureLoader-B1WedbgE.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/brdfTextureTools-DIdTXZSR.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/bumpFragment-C_S7LReC.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/bumpVertex-9p8w1w7z.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/bumpVertexDeclaration-B8rpdm3U.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/clipPlaneFragment-A-1cS0Wr.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/clipPlaneVertex-B34pEy_z.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/cubemapToSphericalPolynomial-BAw8ctMB.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/dds-BDxArwXs.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/dds.pure-D_Zw5OEt.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/ddsTextureLoader-DeQLZozV.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/default.fragment-BI3GAR2C.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/default.vertex-CQ4MILUZ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/defaultUboDeclaration-DOBRS3iS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/dumpTools-DCMMRWtL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/envTextureLoader-C-7LpDe_.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/exrTextureLoader-oNqXrLmH.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyForceBlock-DUMH2798.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyImpulseBlock-DUvs7iqs.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphArrayIndexBlock-B-qeUHG6.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphBezierCurveEasingBlock-Cjm4_L1J.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphBinaryOperationBlock-CXnNy9QR.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphBranchBlock-DLUVB1dZ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphCachedOperationBlock-BkfdjQtr.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphCancelDelayBlock-DwzbjNTQ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphCodeExecutionBlock-CzFaSgik.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphConditionalDataBlock-DsMUDoGH.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphConsoleLogBlock-CVWywmBY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphConstantBlock-BNIgu4QC.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphContextBlock-DuQCYIgK.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphCounterBlock-DxCqjQc8.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphDataSwitchBlock-BOncXvGP.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphDebounceBlock-43eNp_3W.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphDebugBlock-CYRuaSbJ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphDoNBlock-Du-7uIwS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphEasingBlock-C6lQQb9c.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphFlipFlopBlock-Ba-WebLx.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphForLoopBlock-CC4ZykmE.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphFunctionReferenceBlock-Cc8odCYm.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGLTFDataProvider-Bs8eI-tc.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAngularVelocityBlock-BR2ioMLJ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAssetBlock-DD4Eo4N8.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetLinearVelocityBlock-CiXY_22u.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPhysicsMassPropertiesBlock-BFuYrykd.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPropertyBlock-yylHk0Tj.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetSoundVolumeBlock-Yoy3NMR4.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphGetVariableBlock-DP0lG6uk.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphIndexOfBlock-Dp46lAXL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphInterpolationBlock-DAAojSot.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphIsKeyPressedBlock-BzyaFJtY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphIsSoundPlayingBlock-4qIsPViO.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphJsonPointerParserBlock-BZG5ehwx.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyDownEventBlock-rpKm7KQS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyUpEventBlock-DZ0cYho3.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyboardEventBlock-CiAmYMbH.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphMathBlocks-CbJDlFUY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphMathCombineExtractBlocks-DICrYBP4.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphMatrixMathBlocks-ftOIDo5d.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphMeshPickEventBlock-DTChczhf.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphMultiGateBlock-DdupWV9J.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseAnimationBlock-DBsgO-6v.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseSoundBlock-DWcr1ULl.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPhysicsCollisionEventBlock-CVKDMyoo.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPlayAnimationBlock-BXVH0aEG.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPlaySoundBlock-LNU38ZaS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerDownEventBlock-L9Wzp4sm.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerMoveEventBlock-Cgf9rHw2.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOutEventBlock-0bOFbyCB.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOverEventBlock-CJQEfL96.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerUpEventBlock-Dr4yXdtL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphReceiveCustomEventBlock-DpKjQPwo.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneReadyEventBlock-CTK4Ndci.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneTickEventBlock-CzJbobbg.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSendCustomEventBlock-DBQ1n5eJ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSequenceBlock-oBhLC7Vj.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetAngularVelocityBlock-DXlS3umF.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetDelayBlock-DhrCI14Z.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetLinearVelocityBlock-DdNE9BcN.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPhysicsMotionTypeBlock-Be7qTZ0l.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPropertyBlock-Bx8fCC87.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetSoundVolumeBlock-Bmh5show.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSetVariableBlock-BP87cysh.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSoundEndedEventBlock-DPK4HFJ5.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphStopAnimationBlock-9n5l3RYF.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphStopSoundBlock-BkqUQ3IX.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphSwitchBlock-CzYmr0Rg.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphThrottleBlock-C72DA8Ot.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphTransformCoordinatesSystemBlock-B57atF6V.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphTypeToTypeBlocks-BwO8ctcl.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphUnaryOperationBlock-B5xQ7raL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphVectorMathBlocks-BSQ0Jp6s.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphWaitAllBlock-DkjMKncY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/flowGraphWhileLoopBlock-DiDLbXDS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/fogFragment-QU9YOYuH.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-CBvJqSQF.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-EGwqbpHv.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-CG3O4l2t.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-CYV0OcvY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-DU77eH5y.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-s8IsAoDR.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-Bt1AWZNn.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-luoOzTyP.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-m9aQdgcg.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-xDMDxXMl.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-C_-6JJr4.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-oisMFtj8.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-CBkXTBVF.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-DQDqvDk5.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/glowBlurPostProcess.fragment-QolNMgw6.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.fragment-DRwn6uC2.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.vertex-BPPwu0E9.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.fragment-ODjisfEL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.vertex-DB7eIwXj.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/harmonicsFunctions-B2jlXPLE.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/hdrTextureLoader-BGQvgh0h.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/helperFunctions-B6Z1LJrO.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/iesTextureLoader-8wFKF-ak.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/index-BnAaL7KS.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/index-CnrKUEff.css +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-C0PAazdd.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-DmepFK-C.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-CQTyg7d5.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-C_mnrqaY.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-DCLBcYIA.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-DuoJgAZp.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/ktxTextureLoader-CIypOERT.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/lightFragment-BinX63GB.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/logDepthDeclaration-D8jcsZiW.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/logDepthVertex-CAoFmcco.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/mainUVVaryingDeclaration-oF31v9Zp.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/mesh.vertexData.functions-ayNlGC5K.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/meshUboDeclaration-BXrkHWWW.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/oitFragment-2x3JPdq6.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-B5ZDpeFy.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-CpT08ThE.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-BaGhkjmV.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DAeXubyL.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrMaterial.pure-BXY_lClt.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrMaterialLoadingAdapter-MpirTHMd.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-CHHhh58w.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-DthxrR9-.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration--Zhq0q7d.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-CXcZlREH.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/packingFunctions-Bo_ikKLB.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/packingFunctions-u3uWRkpF.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pass.fragment-slK02MnO.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-C13WHRV7.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-DnuA3v4l.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbr.fragment-8v2GDfO1.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbr.vertex-BuCPFkDX.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrBRDFFunctions-5nHUuKRr.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrDebug-C8fLVEpD.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrIBLFunctions-BM49sbQB.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrMaterial.pure-B6n6Ic80.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrMaterialLoadingAdapter-C0d04FRz.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/pbrUboDeclaration-CL7R5LTR.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/postprocess.vertex-BhCyZbyQ.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-Cb5DsSFx.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-W-IcNTXE.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/reflectionFunction-DYrae64q.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/rgbdDecode.fragment-CFpIpdxk.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-BIBfrJET.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-yPbrkGKz.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/sceneUboDeclaration-D5YHSknt.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-GSzJSZKX.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-NwUMt_sy.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/tgaTextureLoader-Z9HWdnv1.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/assets/vertexColorMixing-DkZl_JUT.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/favicon.svg +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/index.html +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/_viewer_static/sw.js +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/build.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/context.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/determinism.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/drawings/__init__.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/drawings/_catalog.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/drawings/_validation.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exceptions.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/__init__.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/base.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/__init__.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/annotations.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/dxf.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/model.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/pdf.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/primitives.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/projection.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/drawings/svg.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/glb.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/quantities.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/exporters/step.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/geometry.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/project_config.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/py.typed +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/runtime_sync.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/build-manifest-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/design-manifest-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/download-manifest-2.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/drawing-annotations-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/glb-manifest-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/ifc-validation-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/quantities-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/run-metadata-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/site-metadata-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/schemas/step-validation-1.json +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/site.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/.gitignore +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/README.md +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/config.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/drawing_annotations.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/generated/.gitkeep +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/model.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/templates/project/pyproject.toml +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools/units.py +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/dependency_links.txt +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/entry_points.txt +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/requires.txt +0 -0
- {python_cad_tools-0.1.13 → python_cad_tools-0.1.16}/src/python_cad_tools.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Run the LangChain AutoCommit CLI for a verified SpecRepo change."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import shutil
|
|
8
|
+
import site
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import NoReturn
|
|
13
|
+
|
|
14
|
+
AUTOCOMMIT_REPOSITORY = "git+https://github.com/brandon-benge/langchain_autocommit.git"
|
|
15
|
+
CONFIGURATION_GUIDE = "https://github.com/brandon-benge/langchain_autocommit/blob/main/README.md#config-overrides"
|
|
16
|
+
EX_USAGE = 64
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def print_usage() -> None:
|
|
20
|
+
print(
|
|
21
|
+
'Usage: specrepo-autocommit "<summary of what changed>" [--no-push] '
|
|
22
|
+
"[--config-file <path>] [--env-var-name <NAME>] [--base-url <URL>] "
|
|
23
|
+
"[--model <MODEL>]\n\n"
|
|
24
|
+
"Runs autocommit on the current git branch.\n"
|
|
25
|
+
"--config-file points to the YAML configuration to use; defaults to "
|
|
26
|
+
"AUTOCOMMIT_PARAMS, then to .autoconfig.yaml in this repository.\n"
|
|
27
|
+
"--no-push commits locally without pushing to the remote.\n"
|
|
28
|
+
"--env-var-name, --base-url, and --model override the LLM API key "
|
|
29
|
+
"environment variable, base URL, and model that .autoconfig.yaml "
|
|
30
|
+
"otherwise supplies, e.g. to point at the AI Settings selected in "
|
|
31
|
+
"the Mac app.",
|
|
32
|
+
file=sys.stderr,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def fail(message: str, *, config_path: Path | None = None, code: int = 1) -> NoReturn:
|
|
37
|
+
print(message, file=sys.stderr)
|
|
38
|
+
if config_path is not None:
|
|
39
|
+
print(f"AUTOCOMMIT_PARAMS location: {config_path}", file=sys.stderr)
|
|
40
|
+
print(
|
|
41
|
+
f"Update that file as needed. Configuration guide: {CONFIGURATION_GUIDE}",
|
|
42
|
+
file=sys.stderr,
|
|
43
|
+
)
|
|
44
|
+
raise SystemExit(code)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_config_path(explicit_path: str | None = None) -> Path:
|
|
48
|
+
if explicit_path:
|
|
49
|
+
config_path = Path(os.path.expandvars(explicit_path)).expanduser().resolve()
|
|
50
|
+
print(f"--config-file is set to: {config_path}", flush=True)
|
|
51
|
+
else:
|
|
52
|
+
raw_path = os.environ.get("AUTOCOMMIT_PARAMS", "").strip()
|
|
53
|
+
if raw_path:
|
|
54
|
+
config_path = Path(os.path.expandvars(raw_path)).expanduser().resolve()
|
|
55
|
+
print(f"AUTOCOMMIT_PARAMS is set to: {config_path}", flush=True)
|
|
56
|
+
else:
|
|
57
|
+
config_path = (
|
|
58
|
+
Path(__file__).resolve().parent.parent.parent / ".autoconfig.yaml"
|
|
59
|
+
)
|
|
60
|
+
print(f"AUTOCOMMIT_PARAMS not set, using local fallback: {config_path}", flush=True)
|
|
61
|
+
|
|
62
|
+
if not config_path.is_file():
|
|
63
|
+
fail(
|
|
64
|
+
"Autocommit blocked: the configuration file does not exist or is not a regular file.",
|
|
65
|
+
config_path=config_path,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return config_path
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_current_branch(config_path: Path) -> str:
|
|
72
|
+
try:
|
|
73
|
+
symbolic_ref = subprocess.run(
|
|
74
|
+
["git", "symbolic-ref", "--quiet", "--short", "HEAD"],
|
|
75
|
+
check=False,
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
)
|
|
79
|
+
branch = symbolic_ref.stdout.strip()
|
|
80
|
+
|
|
81
|
+
if not branch:
|
|
82
|
+
revision = subprocess.run(
|
|
83
|
+
["git", "rev-parse", "--short", "HEAD"],
|
|
84
|
+
check=False,
|
|
85
|
+
capture_output=True,
|
|
86
|
+
text=True,
|
|
87
|
+
)
|
|
88
|
+
branch = revision.stdout.strip()
|
|
89
|
+
except OSError as error:
|
|
90
|
+
fail(
|
|
91
|
+
f"Autocommit blocked: could not run git: {error}",
|
|
92
|
+
config_path=config_path,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if not branch:
|
|
96
|
+
fail(
|
|
97
|
+
"Autocommit blocked: could not determine the current git branch.",
|
|
98
|
+
config_path=config_path,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return branch
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def find_autocommit() -> str | None:
|
|
105
|
+
executable = shutil.which("autocommit")
|
|
106
|
+
if executable:
|
|
107
|
+
return executable
|
|
108
|
+
|
|
109
|
+
scripts_directory = Path(site.getuserbase()) / ("Scripts" if os.name == "nt" else "bin")
|
|
110
|
+
candidate = scripts_directory / ("autocommit.exe" if os.name == "nt" else "autocommit")
|
|
111
|
+
return str(candidate) if candidate.is_file() else None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def ensure_autocommit_installed(config_path: Path) -> str:
|
|
115
|
+
executable = find_autocommit()
|
|
116
|
+
if executable:
|
|
117
|
+
return executable
|
|
118
|
+
|
|
119
|
+
print("autocommit CLI not found. Installing it with the current Python...")
|
|
120
|
+
try:
|
|
121
|
+
installation = subprocess.run(
|
|
122
|
+
[
|
|
123
|
+
sys.executable,
|
|
124
|
+
"-m",
|
|
125
|
+
"pip",
|
|
126
|
+
"install",
|
|
127
|
+
"--user",
|
|
128
|
+
AUTOCOMMIT_REPOSITORY,
|
|
129
|
+
],
|
|
130
|
+
check=False,
|
|
131
|
+
)
|
|
132
|
+
except OSError as error:
|
|
133
|
+
fail(
|
|
134
|
+
f"Autocommit installation failed: {error}",
|
|
135
|
+
config_path=config_path,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if installation.returncode != 0:
|
|
139
|
+
fail(
|
|
140
|
+
f"Autocommit installation failed with exit code {installation.returncode}.",
|
|
141
|
+
config_path=config_path,
|
|
142
|
+
code=installation.returncode,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
executable = find_autocommit()
|
|
146
|
+
if not executable:
|
|
147
|
+
fail(
|
|
148
|
+
"Autocommit was installed but its executable could not be found.",
|
|
149
|
+
config_path=config_path,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
print("autocommit installed successfully.")
|
|
153
|
+
return executable
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def run_autocommit(
|
|
157
|
+
executable: str,
|
|
158
|
+
config_path: Path,
|
|
159
|
+
summary: str,
|
|
160
|
+
branch: str,
|
|
161
|
+
no_push: bool = False,
|
|
162
|
+
env_var_name: str | None = None,
|
|
163
|
+
base_url: str | None = None,
|
|
164
|
+
model: str | None = None,
|
|
165
|
+
) -> None:
|
|
166
|
+
print(f"Running autocommit on branch {branch}.")
|
|
167
|
+
command = [
|
|
168
|
+
executable,
|
|
169
|
+
"--yes",
|
|
170
|
+
"--config-file",
|
|
171
|
+
str(config_path),
|
|
172
|
+
"-c",
|
|
173
|
+
summary,
|
|
174
|
+
]
|
|
175
|
+
if no_push:
|
|
176
|
+
command.append("--no-push")
|
|
177
|
+
if env_var_name:
|
|
178
|
+
command += ["--env-var", "--env-var-name", env_var_name]
|
|
179
|
+
if base_url:
|
|
180
|
+
command += ["--base-url", base_url]
|
|
181
|
+
if model:
|
|
182
|
+
command += ["--model", model]
|
|
183
|
+
try:
|
|
184
|
+
result = subprocess.run(command, check=False)
|
|
185
|
+
except OSError as error:
|
|
186
|
+
fail(
|
|
187
|
+
f"Autocommit failed to start: {error}",
|
|
188
|
+
config_path=config_path,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if result.returncode != 0:
|
|
192
|
+
fail(
|
|
193
|
+
f"Autocommit failed with exit code {result.returncode}.",
|
|
194
|
+
config_path=config_path,
|
|
195
|
+
code=result.returncode if result.returncode > 0 else 1,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def main(argv: list[str]) -> int:
|
|
200
|
+
# Extract --no-push, --config-file <path>, and the LLM override flags
|
|
201
|
+
# before joining the remainder into the summary.
|
|
202
|
+
no_push = False
|
|
203
|
+
config_file: str | None = None
|
|
204
|
+
env_var_name: str | None = None
|
|
205
|
+
base_url: str | None = None
|
|
206
|
+
model: str | None = None
|
|
207
|
+
positional: list[str] = []
|
|
208
|
+
args_iter = iter(argv[1:])
|
|
209
|
+
for arg in args_iter:
|
|
210
|
+
if arg == "--no-push":
|
|
211
|
+
no_push = True
|
|
212
|
+
elif arg in ("--config-file", "--env-var-name", "--base-url", "--model"):
|
|
213
|
+
try:
|
|
214
|
+
value = next(args_iter)
|
|
215
|
+
except StopIteration:
|
|
216
|
+
print_usage()
|
|
217
|
+
fail(
|
|
218
|
+
f"Autocommit blocked: {arg} requires a value argument.",
|
|
219
|
+
code=EX_USAGE,
|
|
220
|
+
)
|
|
221
|
+
if arg == "--config-file":
|
|
222
|
+
config_file = value
|
|
223
|
+
elif arg == "--env-var-name":
|
|
224
|
+
env_var_name = value
|
|
225
|
+
elif arg == "--base-url":
|
|
226
|
+
base_url = value
|
|
227
|
+
else:
|
|
228
|
+
model = value
|
|
229
|
+
else:
|
|
230
|
+
positional.append(arg)
|
|
231
|
+
|
|
232
|
+
config_path = get_config_path(config_file)
|
|
233
|
+
|
|
234
|
+
if not positional or not " ".join(positional).strip():
|
|
235
|
+
print_usage()
|
|
236
|
+
fail(
|
|
237
|
+
"Autocommit blocked: a summary of what changed is required.",
|
|
238
|
+
config_path=config_path,
|
|
239
|
+
code=EX_USAGE,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
summary = " ".join(positional).strip()
|
|
243
|
+
branch = get_current_branch(config_path)
|
|
244
|
+
executable = ensure_autocommit_installed(config_path)
|
|
245
|
+
run_autocommit(
|
|
246
|
+
executable,
|
|
247
|
+
config_path,
|
|
248
|
+
summary,
|
|
249
|
+
branch,
|
|
250
|
+
no_push=no_push,
|
|
251
|
+
env_var_name=env_var_name,
|
|
252
|
+
base_url=base_url,
|
|
253
|
+
model=model,
|
|
254
|
+
)
|
|
255
|
+
return 0
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
if __name__ == "__main__":
|
|
259
|
+
raise SystemExit(main(sys.argv))
|
|
@@ -7,6 +7,66 @@ stable release is published.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.16] - 2026-09-22
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `python-cad --version` (and every other CLI invocation) no longer requires
|
|
15
|
+
`build123d`/the rest of the CAD toolchain to be importable: `cli.py`'s
|
|
16
|
+
`ValidationIssue` import — annotation-only, never evaluated at runtime
|
|
17
|
+
under this module's `from __future__ import annotations` — moved behind
|
|
18
|
+
`TYPE_CHECKING`. This was silently blocking every release since 0.1.14:
|
|
19
|
+
`build-publish` requires `tests/packaging` to pass, and its
|
|
20
|
+
clean-install-then-`--version` check installs the wheel with `--no-deps`,
|
|
21
|
+
which cannot satisfy the transitive `build123d` import `--version` didn't
|
|
22
|
+
actually need. 0.1.14 and 0.1.15 were tagged but never reached PyPI as a
|
|
23
|
+
result; 0.1.13 remained the latest published release throughout.
|
|
24
|
+
|
|
25
|
+
## [0.1.15] - 2026-09-22
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `models/**/*.py` no longer needs an explicit `source-inputs` entry, at any
|
|
30
|
+
package depth and whether or not it has an `__init__.py`. `models/` is the
|
|
31
|
+
one directory a project is expected to keep adding files to over its
|
|
32
|
+
lifetime — one new module per new design object — so requiring a
|
|
33
|
+
`pyproject.toml` edit for each new file added no safety benefit: the build
|
|
34
|
+
manifest's `source_set_hash` already covers every file actually imported,
|
|
35
|
+
declared or not. `config.py`, `model.py`, `drawing_annotations.py`, and
|
|
36
|
+
`pyproject.toml` itself are unaffected and still require explicit
|
|
37
|
+
declaration, as does any other project-root Python file or data file read
|
|
38
|
+
through the public context. See `docs/project-configuration.md`.
|
|
39
|
+
|
|
40
|
+
## [0.1.14] - 2026-08-13
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- New public `python_cad_tools.recipes` module: an opt-in, declarative
|
|
45
|
+
construction-recipe vocabulary (`RectangleProfile`, `CircleProfile`,
|
|
46
|
+
`ExtrudedProfile`, `DifferenceRecipe`, `evaluate`) that lets Tier 1
|
|
47
|
+
authoring produce parametric BREP IFC geometry
|
|
48
|
+
(`IfcExtrudedAreaSolid`/`SweptSolid`, `IfcBooleanResult`/`CSG`) instead of
|
|
49
|
+
only tessellated meshes. New `DesignElement.recipe` field, appended last;
|
|
50
|
+
`geometry` may now be `None` when a recipe is present. Recipes are
|
|
51
|
+
strictly opt-in per element — a model with no recipes produces IFC output
|
|
52
|
+
byte-identical to before this change, since neither recipe type adds a
|
|
53
|
+
unit-assignment entry. See `docs/neutral-model.md#construction-recipes`.
|
|
54
|
+
- The IFC validation sidecar gains additive `element_representation_types`
|
|
55
|
+
and `element_topology` keys; the design manifest gains additive
|
|
56
|
+
`recipe_kind` and `topology` per-element keys. `schema_version` is
|
|
57
|
+
unchanged on both.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- The IFC sidecar's `bounds_mm` is now the union of tessellation-derived
|
|
62
|
+
bounds and evaluated-solid bounds, so BREP-only and mixed models report
|
|
63
|
+
correct bounds (a BREP element emits no `IfcCartesianPointList3D`, which
|
|
64
|
+
the previous derivation depended on exclusively).
|
|
65
|
+
- `python-cad validate`'s CLI error message now includes each failing
|
|
66
|
+
issue's `element_id` (formatted as `code[element_id]: message`) when the
|
|
67
|
+
issue has one, instead of only `code: message`. Issues without an
|
|
68
|
+
element, such as `model-id`, are unaffected.
|
|
69
|
+
|
|
10
70
|
## [0.1.11] - 2026-08-11
|
|
11
71
|
|
|
12
72
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-cad-tools
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
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
|
|
@@ -187,6 +187,12 @@ Project code should preserve stable semantic IDs, keep geometry parametric, and
|
|
|
187
187
|
create geometry and metadata together. Generated artifacts are outputs, never
|
|
188
188
|
design inputs.
|
|
189
189
|
|
|
190
|
+
`python_cad_tools.recipes` lets an element opt into parametric BREP IFC
|
|
191
|
+
geometry (`IfcExtrudedAreaSolid`/`SweptSolid`, `IfcBooleanResult`/`CSG`)
|
|
192
|
+
instead of the default tessellated mesh, verified by a topology round-trip
|
|
193
|
+
after every build. See
|
|
194
|
+
[`docs/neutral-model.md#construction-recipes`](docs/neutral-model.md#construction-recipes).
|
|
195
|
+
|
|
190
196
|
Project-owned drawing annotations use the typed, renderer-independent boundary
|
|
191
197
|
documented in [`docs/drawing-extensions.md`](docs/drawing-extensions.md). One
|
|
192
198
|
annotation set is validated and rendered consistently to SVG, DXF, and PDF
|
|
@@ -131,6 +131,12 @@ Project code should preserve stable semantic IDs, keep geometry parametric, and
|
|
|
131
131
|
create geometry and metadata together. Generated artifacts are outputs, never
|
|
132
132
|
design inputs.
|
|
133
133
|
|
|
134
|
+
`python_cad_tools.recipes` lets an element opt into parametric BREP IFC
|
|
135
|
+
geometry (`IfcExtrudedAreaSolid`/`SweptSolid`, `IfcBooleanResult`/`CSG`)
|
|
136
|
+
instead of the default tessellated mesh, verified by a topology round-trip
|
|
137
|
+
after every build. See
|
|
138
|
+
[`docs/neutral-model.md#construction-recipes`](docs/neutral-model.md#construction-recipes).
|
|
139
|
+
|
|
134
140
|
Project-owned drawing annotations use the typed, renderer-independent boundary
|
|
135
141
|
documented in [`docs/drawing-extensions.md`](docs/drawing-extensions.md). One
|
|
136
142
|
annotation set is validated and rendered consistently to SVG, DXF, and PDF
|
|
@@ -14,7 +14,7 @@ dimensions), and the validator invocation model. See
|
|
|
14
14
|
| `id` | `str` | Stable, unique identifier. Used to derive every downstream IFC `GlobalId` and to key manifests. |
|
|
15
15
|
| `name` | `str` | Human-readable display name. |
|
|
16
16
|
| `category` | `str` | Free-text classification, exported as `ObjectType` in IFC. |
|
|
17
|
-
| `geometry` | `Any` | A build123d-compatible solid, shell, wire, or edge. Required and opaque — the framework does not restrict how it was built. |
|
|
17
|
+
| `geometry` | `Any` | A build123d-compatible solid, shell, wire, or edge. Required and opaque — the framework does not restrict how it was built. May be `None` when `recipe` is present; the framework materializes it. |
|
|
18
18
|
| `geometry_kind` | `"solid" \| "shell" \| "wire" \| "edge" \| "reference"` | Declares the geometry's topological kind. Physical elements must be `"solid"`. |
|
|
19
19
|
| `placement` | `Placement` | Translation (mm) and rotation (degrees, XYZ) applied on top of `geometry`'s own coordinates. |
|
|
20
20
|
| `dimensions` | `Dimensions` | Declared, author-stated extents. Independent of the geometry's actual bounds; exported into `Pset_PythonCadDesign`. |
|
|
@@ -31,6 +31,7 @@ dimensions), and the validator invocation model. See
|
|
|
31
31
|
| `physical` | `bool` | Physical elements must be `"solid"` and require a material; non-physical (reference) elements are excluded from IFC, quantities, and mass. |
|
|
32
32
|
| `parent_id` | `str \| None` | Parent element ID, exported as an `IfcRelAggregates` relationship when both ends are IFC-exported. |
|
|
33
33
|
| `openings` | `list[Opening]` | Semantic voids in this host element. See "Openings" below. |
|
|
34
|
+
| `recipe` | `ConstructionRecipe \| None` | Opt-in declarative geometry. See "Construction recipes" below. |
|
|
34
35
|
|
|
35
36
|
## `IfcMapping`
|
|
36
37
|
|
|
@@ -131,8 +132,109 @@ returning a `list[ValidationIssue]`. `fatal_issues(...)` filters to
|
|
|
131
132
|
`severity == "error"`; `python-cad build`/`validate` fail on any fatal issue
|
|
132
133
|
before export begins.
|
|
133
134
|
|
|
134
|
-
## Construction recipes
|
|
135
|
+
## Construction recipes
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
`python_cad_tools.recipes` lets Tier 1 authoring produce **parametric BREP**
|
|
138
|
+
IFC geometry instead of only tessellated meshes, for the two shapes
|
|
139
|
+
evidenced as needed by real downstream models: an extruded 2D profile, and
|
|
140
|
+
one extruded profile with a second subtracted from it. Recipes are strictly
|
|
141
|
+
**opt-in per element** — omitting `DesignElement.recipe` preserves today's
|
|
142
|
+
tessellated output byte-for-byte.
|
|
143
|
+
|
|
144
|
+
### Type vocabulary
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
RectangleProfile(x_dim_mm: float, y_dim_mm: float, position: Placement = Placement()) # -> IfcRectangleProfileDef
|
|
148
|
+
CircleProfile(radius_mm: float, position: Placement = Placement()) # -> IfcCircleProfileDef
|
|
149
|
+
Profile = RectangleProfile | CircleProfile
|
|
150
|
+
|
|
151
|
+
ExtrudedProfile(profile: Profile, direction: tuple[float, float, float], depth_mm: float) # -> IfcExtrudedAreaSolid
|
|
152
|
+
DifferenceRecipe(base: ExtrudedProfile, tool: ExtrudedProfile) # -> IfcBooleanResult(Operator=DIFFERENCE)
|
|
153
|
+
ConstructionRecipe = ExtrudedProfile | DifferenceRecipe
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Both profile types are centered at the origin, matching IFC's own
|
|
157
|
+
`IfcRectangleProfileDef`/`IfcCircleProfileDef` semantics. `direction` and
|
|
158
|
+
`depth_mm` are independent fields, mirroring `IfcExtrudedAreaSolid`'s
|
|
159
|
+
`ExtrudedDirection`/`Depth` split — `direction`'s magnitude is ignored, only
|
|
160
|
+
its direction matters. `DifferenceRecipe.base`/`.tool` are typed as
|
|
161
|
+
`ExtrudedProfile`, not `ConstructionRecipe`: nesting is structurally
|
|
162
|
+
impossible, not merely unvalidated. There is no `RevolvedProfile`,
|
|
163
|
+
`PolygonProfile`, or general recursive boolean type — each would be a new
|
|
164
|
+
SpecRepo request; see `specrepo/rejected/2026-08-12-...-brep-recipes/` for
|
|
165
|
+
why the original, broader vocabulary was withdrawn in favor of this one.
|
|
166
|
+
|
|
167
|
+
### Three authoring shapes
|
|
168
|
+
|
|
169
|
+
- **Recipe only** (`recipe` set, `geometry=None`) — the framework evaluates
|
|
170
|
+
the recipe through build123d and assigns the result to `geometry`.
|
|
171
|
+
Recommended: the same solid then feeds STEP, GLB, drawings, quantities,
|
|
172
|
+
bounds, and the tessellated fallback, while IFC additionally gets the
|
|
173
|
+
parametric BREP.
|
|
174
|
+
- **Recipe and geometry** (both set) — the framework evaluates the recipe
|
|
175
|
+
and verifies it against the supplied `geometry` (volume relative
|
|
176
|
+
tolerance `1e-6`, bounds absolute tolerance `1e-6` mm, equal face and
|
|
177
|
+
edge counts). A mismatch is an error-severity
|
|
178
|
+
`ValidationIssue("recipe-geometry-mismatch", ...)`. The supplied
|
|
179
|
+
`geometry` object is kept — only its equivalence is asserted.
|
|
180
|
+
Evaluation for this comparison happens in `validate_model`, not the
|
|
181
|
+
loader, and does not overwrite `geometry`.
|
|
182
|
+
- **No recipe** — today's behavior, unchanged in every respect.
|
|
183
|
+
|
|
184
|
+
### Recipe → IFC entity map
|
|
185
|
+
|
|
186
|
+
| Recipe | IFC entity | `RepresentationType` |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| `ExtrudedProfile` | `IfcExtrudedAreaSolid` | `"SweptSolid"` |
|
|
189
|
+
| `DifferenceRecipe` | `IfcBooleanResult` (`Operator=DIFFERENCE`) over two `IfcExtrudedAreaSolid` operands | `"CSG"` |
|
|
190
|
+
| *(no recipe)* | `IfcTriangulatedFaceSet` | `"Tessellation"` |
|
|
191
|
+
|
|
192
|
+
Neither recipe type carries an angle measure, so the IFC unit assignment is
|
|
193
|
+
unchanged — no `PLANEANGLEUNIT` entry, and no existing project's IFC hash
|
|
194
|
+
changes, including for projects that adopt a recipe.
|
|
195
|
+
|
|
196
|
+
### Topology round-trip verification
|
|
197
|
+
|
|
198
|
+
After writing the file, for each element with a recipe the exporter
|
|
199
|
+
reloads it, parses the emitted representation item back into a recipe,
|
|
200
|
+
asserts it is structurally equal to the authored recipe (floating-point
|
|
201
|
+
precision, relative/absolute tolerance `1e-9`), re-evaluates the parsed
|
|
202
|
+
recipe, and compares the result against the authored solid
|
|
203
|
+
(`element.geometry`) on face count, edge count, and volume (relative
|
|
204
|
+
tolerance `1e-6`), plus bounds (absolute tolerance `1e-6` mm) as a sanity
|
|
205
|
+
check. Any mismatch raises `BuildExportError` naming the element and the
|
|
206
|
+
differing measure. This parses-and-re-evaluates rather than reading
|
|
207
|
+
topology out of the reloaded BREP directly, because the framework pins
|
|
208
|
+
`cadquery-ocp-novtk` (OCP) rather than pythonocc (OCC); `ifcopenshell.geom`'s
|
|
209
|
+
OCC integration is unavailable and its default iterator path triangulates,
|
|
210
|
+
destroying the topology the check is meant to compare.
|
|
211
|
+
|
|
212
|
+
The IFC validation sidecar records `element_representation_types` (element
|
|
213
|
+
id → `"Tessellation"` / `"SweptSolid"` / `"CSG"`) and `element_topology`
|
|
214
|
+
(element id → face count, edge count, volume, for recipe elements only).
|
|
215
|
+
The design manifest records the same information per element as
|
|
216
|
+
`recipe_kind` (`null` / `"extruded_profile"` / `"difference"`) and, for
|
|
217
|
+
recipe elements, `topology`. `bounds_mm` in the sidecar is the union of
|
|
218
|
+
tessellation-derived bounds and evaluated-solid bounds, since a BREP-only
|
|
219
|
+
element emits no `IfcCartesianPointList3D` for the older derivation to read.
|
|
220
|
+
|
|
221
|
+
### Relationship to `openings`
|
|
222
|
+
|
|
223
|
+
`DesignElement.openings` (see "Openings" above) never subtracts material
|
|
224
|
+
from the host's own geometry — it only declares an `IfcOpeningElement`/
|
|
225
|
+
`IfcRelVoidsElement` semantic relationship on top of whatever geometry the
|
|
226
|
+
host already has. `DifferenceRecipe` is what makes the host's actual solid
|
|
227
|
+
have material missing where a door or window belongs — the two mechanisms
|
|
228
|
+
are complementary, not alternatives. A fully-converted host wall uses both:
|
|
229
|
+
`DifferenceRecipe` for the real notch, `openings` for the semantic
|
|
230
|
+
annotation. A project that only wants the semantic annotation keeps that
|
|
231
|
+
option without adopting a recipe at all.
|
|
232
|
+
|
|
233
|
+
### Display trade-off
|
|
234
|
+
|
|
235
|
+
A single `DifferenceRecipe` is a common, well-supported IFC authoring
|
|
236
|
+
pattern, but any `IfcBooleanResult`/`CSG` representation may still render
|
|
237
|
+
less cleanly in some BIM viewers than a plain `SweptSolid`. Prefer a bare
|
|
238
|
+
`ExtrudedProfile` over `DifferenceRecipe` wherever the notch isn't actually
|
|
239
|
+
needed as real geometry — falling back to `openings` alone for the semantic
|
|
240
|
+
relationship.
|
|
@@ -24,7 +24,15 @@ duplicate inputs fail before project Python runs.
|
|
|
24
24
|
absolute paths, backslashes, traversal components, missing files, and
|
|
25
25
|
directories are rejected. It must include `pyproject.toml`. Every project-root
|
|
26
26
|
Python file imported during an operation and every data file read through the
|
|
27
|
-
public context must be listed
|
|
27
|
+
public context must be listed, with one exception: any `models/**/*.py` file
|
|
28
|
+
is always authoritative and never needs a `source-inputs` entry, at any
|
|
29
|
+
package depth and whether or not it has an `__init__.py`. `models/` is the
|
|
30
|
+
one directory a project is expected to keep adding files to over its
|
|
31
|
+
lifetime -- one new module per new design object -- so it is exempt from
|
|
32
|
+
declaration; everything else still has no recursive source guessing. The
|
|
33
|
+
build manifest's `source_set_hash` still covers every file actually
|
|
34
|
+
imported, declared or not, so this exemption changes only what must be
|
|
35
|
+
declared up front, not what a build's determinism claim is based on.
|
|
28
36
|
|
|
29
37
|
## Entry points
|
|
30
38
|
|
|
@@ -64,9 +72,11 @@ with context.open_source("data/materials.csv") as stream:
|
|
|
64
72
|
materials = stream.read()
|
|
65
73
|
```
|
|
66
74
|
|
|
67
|
-
These paths must also appear in `source-inputs
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
These paths must also appear in `source-inputs` -- the `models/**/*.py`
|
|
76
|
+
exemption above covers imported Python modules only, not data files read
|
|
77
|
+
through this API, even when the path happens to fall under `models/`.
|
|
78
|
+
`BuildContext` contains only `project_root`, `config`, `source_revision`, and
|
|
79
|
+
`source_dirty`; it has no output or staging path.
|
|
70
80
|
|
|
71
81
|
## Isolation and environment
|
|
72
82
|
|
|
@@ -22,6 +22,9 @@ of optional runtime imports.
|
|
|
22
22
|
`ElevationMarker`, `TableRow`, `Table`, `SheetAnnotations`, and
|
|
23
23
|
`DrawingAnnotationSet`.
|
|
24
24
|
- `python_cad_tools.validation`: `ValidationIssue`.
|
|
25
|
+
- `python_cad_tools.recipes`: `RectangleProfile`, `CircleProfile`, `Profile`,
|
|
26
|
+
`ExtrudedProfile`, `DifferenceRecipe`, `ConstructionRecipe`, and
|
|
27
|
+
`evaluate`. See [Construction recipes](neutral-model.md#construction-recipes).
|
|
25
28
|
- `python_cad_tools.build`: `FormatName`, `BuildOptions`, `ValidationOptions`,
|
|
26
29
|
`BuildResult`, `ValidationReport`, `build_project`, `validate_project`, and
|
|
27
30
|
`clean_project`.
|
|
@@ -18,6 +18,8 @@ from pathlib import Path
|
|
|
18
18
|
from types import ModuleType
|
|
19
19
|
from typing import Any, cast
|
|
20
20
|
|
|
21
|
+
from build123d import Standard_ConstructionError, Standard_Failure, StdFail_NotDone
|
|
22
|
+
|
|
21
23
|
from ._project_state import authoritative_path, begin_source_tracking, end_source_tracking, record_source
|
|
22
24
|
from .context import BuildContext, DrawingContext
|
|
23
25
|
from .drawings import DrawingAnnotationSet, DrawingSheet
|
|
@@ -26,8 +28,20 @@ from .drawings._validation import validate_annotation_set
|
|
|
26
28
|
from .elements import DesignModel
|
|
27
29
|
from .exceptions import BuildLockedError, CadToolsError, ModelValidationError, ProjectConfigError
|
|
28
30
|
from .project_config import ProjectConfig, load_project_config, split_callable_target
|
|
31
|
+
from .recipes import evaluate as evaluate_recipe
|
|
29
32
|
from .validation import ValidationIssue, validate_model
|
|
30
33
|
|
|
34
|
+
# Recipe evaluation failures are intentionally swallowed here (geometry is
|
|
35
|
+
# left None) rather than raised: validate_model's own recipe rule
|
|
36
|
+
# re-evaluates and reports a proper ValidationIssue. This keeps failure
|
|
37
|
+
# reporting on one path instead of having the loader partially duplicate it.
|
|
38
|
+
_RECIPE_EVALUATION_EXCEPTIONS = (
|
|
39
|
+
ModelValidationError,
|
|
40
|
+
Standard_Failure,
|
|
41
|
+
Standard_ConstructionError,
|
|
42
|
+
StdFail_NotDone,
|
|
43
|
+
)
|
|
44
|
+
|
|
31
45
|
_PROJECT_EXECUTION_LOCK = threading.Lock()
|
|
32
46
|
_PROJECT_EXECUTION_LOCAL = threading.local()
|
|
33
47
|
_NAMESPACE_COUNTER = itertools.count()
|
|
@@ -144,6 +158,7 @@ def _load_project_model_locked(project_root: Path, *, include_drawings: bool) ->
|
|
|
144
158
|
raise ModelValidationError(
|
|
145
159
|
f"Model entry point {project_config.model_target!r} returned {type(model).__name__}; expected DesignModel"
|
|
146
160
|
)
|
|
161
|
+
_evaluate_recipes(model)
|
|
147
162
|
issues = tuple(validate_model(model))
|
|
148
163
|
drawing_sheets: tuple[DrawingSheet, ...] = ()
|
|
149
164
|
annotations: DrawingAnnotationSet | None = None
|
|
@@ -169,7 +184,11 @@ def _load_project_model_locked(project_root: Path, *, include_drawings: bool) ->
|
|
|
169
184
|
accessed.update(_project_module_sources(project_root, snapshot.modules))
|
|
170
185
|
accessed.update(end_source_tracking(token))
|
|
171
186
|
tracking_active = False
|
|
172
|
-
undeclared = sorted(
|
|
187
|
+
undeclared = sorted(
|
|
188
|
+
path
|
|
189
|
+
for path in accessed - project_config.declared_sources
|
|
190
|
+
if not _is_always_authoritative(path)
|
|
191
|
+
)
|
|
173
192
|
if undeclared:
|
|
174
193
|
raise ProjectConfigError(
|
|
175
194
|
"Loaded authoritative project input(s) missing from source-inputs: " + ", ".join(undeclared)
|
|
@@ -192,6 +211,39 @@ def _load_project_model_locked(project_root: Path, *, include_drawings: bool) ->
|
|
|
192
211
|
snapshot.restore()
|
|
193
212
|
|
|
194
213
|
|
|
214
|
+
def _is_always_authoritative(relative_path: str) -> bool:
|
|
215
|
+
"""``models/**/*.py`` never needs an explicit ``source-inputs`` entry.
|
|
216
|
+
|
|
217
|
+
Every other authoritative input -- ``pyproject.toml``, ``config.py``, ``model.py``,
|
|
218
|
+
``drawing-annotations`` -- is a single, fixed entry point that a project declares once
|
|
219
|
+
and rarely changes; requiring it in ``source-inputs`` catches an accidental undeclared
|
|
220
|
+
import. ``models/`` is different by design (see docs/project-configuration.md): it is
|
|
221
|
+
the one directory a project is expected to keep adding files to over its lifetime, one
|
|
222
|
+
new module per new design object, with no fixed membership to declare up front. Making
|
|
223
|
+
each new file a `source-inputs` edit before it can be imported would turn an expected,
|
|
224
|
+
routine addition into a two-file change for no safety benefit -- the manifest hash
|
|
225
|
+
already covers every accessed path regardless of declaration (`accessed`, not
|
|
226
|
+
`declared_sources`, feeds `source_inputs` on `LoadedProject` below), so this exemption
|
|
227
|
+
narrows only the *validation gate*, not what a build's determinism claim is based on.
|
|
228
|
+
"""
|
|
229
|
+
return relative_path.startswith("models/") and relative_path.endswith(".py")
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _evaluate_recipes(model: DesignModel) -> None:
|
|
233
|
+
"""Materialize ``element.geometry`` from ``element.recipe`` before
|
|
234
|
+
validation, but only when ``geometry`` is not already supplied — the
|
|
235
|
+
recipe+geometry authoring shape keeps the author's object identity, and
|
|
236
|
+
its equivalence check happens independently inside ``validate_model``.
|
|
237
|
+
"""
|
|
238
|
+
for element in model.walk():
|
|
239
|
+
if element.recipe is None or element.geometry is not None:
|
|
240
|
+
continue
|
|
241
|
+
try:
|
|
242
|
+
element.geometry = evaluate_recipe(element.recipe)
|
|
243
|
+
except _RECIPE_EVALUATION_EXCEPTIONS:
|
|
244
|
+
continue
|
|
245
|
+
|
|
246
|
+
|
|
195
247
|
def _install_namespace(namespace: str, project_root: Path) -> None:
|
|
196
248
|
package = ModuleType(namespace)
|
|
197
249
|
package.__file__ = None
|
|
@@ -20,6 +20,7 @@ from .validation import ValidationIssue
|
|
|
20
20
|
BUILD_MANIFEST_RELATIVE = "manifests/build-manifest.json"
|
|
21
21
|
_HEX = re.compile(r"[0-9a-f]{64}\Z")
|
|
22
22
|
_ARTIFACT_FIELDS = {"path", "size", "sha256", "media_type", "producer", "schema_id", "schema_version", "volatile"}
|
|
23
|
+
_EXPECTED_REPRESENTATION_TYPE = {None: "Tessellation", "extruded_profile": "SweptSolid", "difference": "CSG"}
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
@dataclass(frozen=True, slots=True)
|
|
@@ -432,6 +433,25 @@ def _reconcile_ifc_extensions(
|
|
|
432
433
|
}
|
|
433
434
|
if actual_openings != expected_openings:
|
|
434
435
|
raise ArtifactIntegrityError("IFC openings do not match the design manifest")
|
|
436
|
+
expected_representation_types = {
|
|
437
|
+
item["id"]: _EXPECTED_REPRESENTATION_TYPE[item["recipe_kind"]] for item in expected_elements
|
|
438
|
+
}
|
|
439
|
+
actual_representation_types = report.get("element_representation_types", {})
|
|
440
|
+
if actual_representation_types != expected_representation_types:
|
|
441
|
+
raise ArtifactIntegrityError("IFC representation types do not match the design manifest")
|
|
442
|
+
expected_topology = {
|
|
443
|
+
item["id"]: item["topology"] for item in expected_elements if item.get("recipe_kind") is not None
|
|
444
|
+
}
|
|
445
|
+
actual_topology = report.get("element_topology", {})
|
|
446
|
+
if set(actual_topology) != set(expected_topology):
|
|
447
|
+
raise ArtifactIntegrityError("IFC topology does not match the design manifest")
|
|
448
|
+
for element_id, expected_values in expected_topology.items():
|
|
449
|
+
actual_values = actual_topology[element_id]
|
|
450
|
+
for key in ("face_count", "edge_count"):
|
|
451
|
+
if expected_values[key] != actual_values[key]:
|
|
452
|
+
raise ArtifactIntegrityError(f"IFC topology {key} mismatch for {element_id}")
|
|
453
|
+
if abs(expected_values["volume_mm3"] - actual_values["volume_mm3"]) > 1e-6:
|
|
454
|
+
raise ArtifactIntegrityError(f"IFC topology volume_mm3 mismatch for {element_id}")
|
|
435
455
|
if "quantities" in formats:
|
|
436
456
|
quantities = load_json_document(root / "quantities/quantities.json")
|
|
437
457
|
records_by_id = {record["element_id"]: record for record in quantities["records"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"distribution":"python-cad-tools","schema_id":"urn:python-cad-tools:schema:package-build-info:1","schema_version":1,"source_commit":"
|
|
1
|
+
{"distribution":"python-cad-tools","schema_id":"urn:python-cad-tools:schema:package-build-info:1","schema_version":1,"source_commit":"88544bff4c35b1b804776231bf4db8aac1b5c5f1","source_dirty":true,"version":"0.1.14.dev1","viewer_shell_sha256":"2dac2bfef7884c40edb8abab348d7a574cda2037b5a3bbe8808acc7662e27d54"}
|