Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
821aa1e
Initial commit with colors and locations working for simple assemblies
jmwright Feb 26, 2025
c3d5573
Trying to fix mypy error
jmwright Feb 26, 2025
da9844a
Jumping through hoops to make mypy happy
jmwright Feb 26, 2025
7b674c8
Lint fix
jmwright Feb 26, 2025
288c0a0
Refactored method interface based on suggestion
jmwright Feb 27, 2025
4045c58
Use Self and @classmethod
adam-urbanczyk Mar 3, 2025
d708acd
Lint fix
jmwright Mar 3, 2025
aa09d31
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright Mar 3, 2025
f88ad35
Added a test specifically for testing metadata
jmwright Mar 18, 2025
6493135
Merging master and fixing conflicts
jmwright Apr 16, 2025
e51a7cb
Seeing if coverage and tests will pass
jmwright Apr 18, 2025
36d7035
Added name loading from STEP file
jmwright Apr 21, 2025
f29056e
Made name a public property of Assembly
jmwright Apr 22, 2025
14e002b
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright Apr 28, 2025
687bc2b
Trying to increase test coverage a bit
jmwright Apr 29, 2025
6b360c2
Syncing up some experiments
jmwright May 13, 2025
73f007e
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright May 22, 2025
5e19332
Got color and layer search working, still need to get name search wor…
jmwright May 22, 2025
5f4c4c2
Got tests working for layer and color info import
jmwright May 23, 2025
e5bccb2
Got shape name loading to work
jmwright May 27, 2025
d5bc317
Trying to get approximate tuple comparison working
jmwright May 27, 2025
9b48507
Black fix
jmwright May 27, 2025
65f38c8
Added a test for a bad filename, and added a custom color
jmwright May 28, 2025
54e23ee
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright May 28, 2025
2810bc2
Increase test coverage a bit and improve color name check
jmwright May 28, 2025
3438df7
Removing code that should never be hit
jmwright May 28, 2025
086fa8a
Still trying to increase test coverage
jmwright May 29, 2025
6365512
Added a test for a plain assembly
jmwright May 29, 2025
578fd60
Refactored a bit to support nested assemblies better in the future
jmwright Jun 3, 2025
c90e476
Fixed location handling for components of the assembly
jmwright Jun 3, 2025
31557e2
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright Jun 10, 2025
83a433f
Fix the default color to not be black
jmwright Jun 10, 2025
cafad47
Fixed bug with parent location not being applied when needed
jmwright Jun 12, 2025
43e2e00
Fixed importer for Assembly.export method
jmwright Jun 23, 2025
26a64f3
Fixed comment
jmwright Jun 23, 2025
c85ec9c
Removed a stray import that was probably added by AI somewhere along …
jmwright Jun 30, 2025
46c84c6
Implement some of the suggestions
jmwright Jul 2, 2025
c75d0c8
Added a test for nested subassemblies on import
jmwright Jul 4, 2025
d0714fd
Merge branch 'master' of github.com:CadQuery/cadquery into assembly-i…
jmwright Jul 24, 2025
d69856a
Rework which covers everything except subshapes and layers
jmwright Jul 25, 2025
c8e0c08
Added layer name support back in
jmwright Jul 25, 2025
7639fdf
Added a round-trip test and fixed issues that it revealed
jmwright Jul 28, 2025
eedc16f
mypy fixes
jmwright Jul 28, 2025
ee2b834
More mypy fixes
jmwright Jul 28, 2025
2b8a8eb
Missed a cast
jmwright Jul 28, 2025
c7821ee
More mypy fixes
jmwright Jul 29, 2025
f88aa9a
Tried to remove the attribute iterator and could not, but moved some …
jmwright Jul 30, 2025
71e309a
Fixes and simplifications based on codecov checks
jmwright Jul 30, 2025
7da1eab
More cleanup to try to get code coverage high enough without creating…
jmwright Jul 30, 2025
8251d92
Fix lack of application to the top-level assembly
jmwright Aug 4, 2025
1543908
Trying to increase test coverage high enough
jmwright Aug 4, 2025
f7ce6c0
Implemented changes based on PR from Adam
jmwright Aug 25, 2025
d958c2b
Fix mypy errors
jmwright Aug 27, 2025
a32f0fa
Add isSubshape
adam-urbanczyk Sep 5, 2025
4326a59
Add __getitem__
adam-urbanczyk Sep 5, 2025
e9bd7e4
Mypy fix and a usability tweak.
adam-urbanczyk Sep 6, 2025
8b895e4
Generic support for subshape metadata
adam-urbanczyk Sep 6, 2025
ba8b452
Rework assy import
adam-urbanczyk Sep 6, 2025
2cc3989
Start reworking tests
adam-urbanczyk Sep 6, 2025
d73fb20
Streamline a bit
adam-urbanczyk Sep 6, 2025
705aafb
Add validation when adding subshapes
adam-urbanczyk Sep 6, 2025
74c31da
Fix pickling
adam-urbanczyk Sep 7, 2025
330101e
Simplify assy import
adam-urbanczyk Sep 7, 2025
59f44d1
Fix subshape name handling
adam-urbanczyk Sep 7, 2025
a8f2fda
Simplify
adam-urbanczyk Sep 7, 2025
16e2dc0
Additional test
adam-urbanczyk Sep 7, 2025
3c9cc06
Better test
adam-urbanczyk Sep 7, 2025
99aab0b
Remove some changes
adam-urbanczyk Sep 8, 2025
6e1651c
Fix some warnings
adam-urbanczyk Sep 9, 2025
045b2fb
Initial commit
adam-urbanczyk Sep 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 108 additions & 16 deletions cadquery/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
cast,
get_args,
)
from typing_extensions import Literal
from typing_extensions import Literal, Self
from typish import instance_of
from uuid import uuid1 as uuid
from warnings import warn

from .cq import Workplane
from .occ_impl.shapes import Shape, Compound
from .occ_impl.shapes import Shape, Compound, isSubshape, compound
from .occ_impl.geom import Location
from .occ_impl.assembly import Color
from .occ_impl.solver import (
Expand All @@ -34,6 +35,7 @@
exportGLTF,
STEPExportModeLiterals,
)
from .occ_impl.importers.assembly import importStep as _importStep

from .selectors import _expression_grammar as _selector_grammar
from .utils import deprecate
Expand Down Expand Up @@ -155,6 +157,10 @@ def _copy(self) -> "Assembly":

rv = self.__class__(self.obj, self.loc, self.name, self.color, self.metadata)

rv._subshape_colors = dict(self._subshape_colors)
rv._subshape_names = dict(self._subshape_names)
rv._subshape_layers = dict(self._subshape_layers)

for ch in self.children:
ch_copy = ch._copy()
ch_copy.parent = rv
Expand All @@ -172,7 +178,7 @@ def add(
loc: Optional[Location] = None,
name: Optional[str] = None,
color: Optional[Color] = None,
) -> "Assembly":
) -> Self:
"""
Add a subassembly to the current assembly.

Expand All @@ -194,7 +200,7 @@ def add(
name: Optional[str] = None,
color: Optional[Color] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> "Assembly":
) -> Self:
"""
Add a subassembly to the current assembly with explicit location and name.

Expand Down Expand Up @@ -342,11 +348,11 @@ def _subloc(self, name: str) -> Tuple[Location, str]:
@overload
def constrain(
self, q1: str, q2: str, kind: ConstraintKind, param: Any = None
) -> "Assembly":
) -> Self:
...

@overload
def constrain(self, q1: str, kind: ConstraintKind, param: Any = None) -> "Assembly":
def constrain(self, q1: str, kind: ConstraintKind, param: Any = None) -> Self:
...

@overload
Expand All @@ -358,13 +364,13 @@ def constrain(
s2: Shape,
kind: ConstraintKind,
param: Any = None,
) -> "Assembly":
) -> Self:
...

@overload
def constrain(
self, id1: str, s1: Shape, kind: ConstraintKind, param: Any = None,
) -> "Assembly":
) -> Self:
...

def constrain(self, *args, param=None):
Expand Down Expand Up @@ -409,7 +415,7 @@ def constrain(self, *args, param=None):

return self

def solve(self, verbosity: int = 0) -> "Assembly":
def solve(self, verbosity: int = 0) -> Self:
"""
Solve the constraints.
"""
Expand Down Expand Up @@ -504,7 +510,7 @@ def save(
tolerance: float = 0.1,
angularTolerance: float = 0.1,
**kwargs,
) -> "Assembly":
) -> Self:
"""
Save assembly to a file.

Expand Down Expand Up @@ -560,7 +566,7 @@ def export(
tolerance: float = 0.1,
angularTolerance: float = 0.1,
**kwargs,
) -> "Assembly":
) -> Self:
"""
Save assembly to a file.

Expand Down Expand Up @@ -609,9 +615,26 @@ def export(
return self

@classmethod
def load(cls, path: str) -> "Assembly":
def importStep(cls, path: str) -> Self:
"""
Reads an assembly from a STEP file.

:param path: Path and filename for writing.
:return: An Assembly object.
"""

assy = cls()
_importStep(assy, path)

return assy

@classmethod
def load(cls, path: str) -> Self:
"""
Alias of importStep for now.
"""

raise NotImplementedError
return cls.importStep(path)

@property
def shapes(self) -> List[Shape]:
Expand Down Expand Up @@ -712,12 +735,81 @@ def addSubshape(
:return: The modified assembly.
"""

# check if the subshape belongs to the stored object
if any(isSubshape(s, obj) for obj in self.shapes):
assy = self
else:
warn(
"Current node does not contain any Shapes, searching in subnodes. In the future this will result in an error."
)

found = False
for ch in self.children:
if any(isSubshape(s, obj) for obj in ch.shapes):
assy = ch
found = True
break

if not found:
raise ValueError(
f"{s} is not a subshape of the current node or its children"
)

# Handle any metadata we were passed
if name:
self._subshape_names[s] = name
assy._subshape_names[s] = name
if color:
self._subshape_colors[s] = color
assy._subshape_colors[s] = color
if layer:
self._subshape_layers[s] = layer
assy._subshape_layers[s] = layer

return self

def __getitem__(self, name: str) -> "Assembly":
"""
[] based access to children.
"""

return self.objects[name]

def _ipython_key_completions_(self) -> List[str]:
"""
IPython autocompletion helper.
"""

return list(self.objects.keys())

def __contains__(self, name: str) -> bool:

return name in self.objects

def __getattr__(self, name: str) -> "Assembly":
"""
. based access to children.
"""

if name in self.objects:
return self.objects[name]

raise AttributeError

def __dir__(self):
"""
Modified __dir__ for autocompletion.
"""

return list(self.__dict__) + list(ch.name for ch in self.children)

def __getstate__(self):
"""
Explicit getstate needed due to getattr.
"""

return self.__dict__

def __setstate__(self, d):
"""
Explicit setstate needed due to getattr.
"""

self.__dict__ = d
1 change: 1 addition & 0 deletions cadquery/func.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@
setThreads,
project,
faceOn,
isSubshape,
)
Loading