Enabling ShapeList + Shape
Some checks are pending
benchmarks / benchmarks (macos-13, 3.12) (push) Waiting to run
benchmarks / benchmarks (macos-14, 3.12) (push) Waiting to run
benchmarks / benchmarks (ubuntu-latest, 3.12) (push) Waiting to run
benchmarks / benchmarks (windows-latest, 3.12) (push) Waiting to run
Upload coverage reports to Codecov / run (push) Waiting to run
pylint / lint (3.10) (push) Waiting to run
Run type checker / typecheck (3.10) (push) Waiting to run
Run type checker / typecheck (3.13) (push) Waiting to run
Wheel building and publishing / Build wheel on ubuntu-latest (push) Waiting to run
Wheel building and publishing / upload_pypi (push) Blocked by required conditions
tests / tests (macos-13, 3.10) (push) Waiting to run
tests / tests (macos-13, 3.13) (push) Waiting to run
tests / tests (macos-14, 3.10) (push) Waiting to run
tests / tests (macos-14, 3.13) (push) Waiting to run
tests / tests (ubuntu-latest, 3.10) (push) Waiting to run
tests / tests (ubuntu-latest, 3.13) (push) Waiting to run
tests / tests (windows-latest, 3.10) (push) Waiting to run
tests / tests (windows-latest, 3.13) (push) Waiting to run

This commit is contained in:
gumyr 2025-05-19 19:56:27 -04:00
parent 1b69032211
commit cec429c5cc
2 changed files with 78 additions and 5 deletions

View file

@ -2326,10 +2326,27 @@ class ShapeList(list[T]):
# ---- Instance Methods ----
def __add__(self, other: ShapeList) -> ShapeList[T]: # type: ignore
"""Combine two ShapeLists together operator +"""
# return ShapeList(itertools.chain(self, other)) # breaks MacOS-13
return ShapeList(list(self) + list(other))
def __add__(self, other: Shape | Iterable[Shape]) -> ShapeList[T]: # type: ignore
"""Return a new ShapeList that includes other"""
if isinstance(other, (Vector, Shape)):
return ShapeList(tcast(list[T], list(self) + [other]))
if isinstance(other, Iterable) and all(
isinstance(o, (Shape, Vector)) for o in other
):
return ShapeList(list(self) + list(other))
raise TypeError(f"Cannot add object of type {type(other)} to ShapeList")
def __iadd__(self, other: Shape | Iterable[Shape]) -> Self: # type: ignore
"""In-place addition to this ShapeList"""
if isinstance(other, (Vector, Shape)):
self.append(tcast(T, other))
elif isinstance(other, Iterable) and all(
isinstance(o, (Shape, Vector)) for o in other
):
self.extend(other)
else:
raise TypeError(f"Cannot add object of type {type(other)} to ShapeList")
return self
def __and__(self, other: ShapeList) -> ShapeList[T]:
"""Intersect two ShapeLists operator &"""

View file

@ -64,7 +64,9 @@ class TestShapeList(unittest.TestCase):
actual_lines = actual.splitlines()
self.assertEqual(len(actual_lines), len(expected_lines))
for actual_line, expected_line in zip(actual_lines, expected_lines):
start, end = re.split(r"at 0x[0-9a-f]+", expected_line, maxsplit=2, flags=re.I)
start, end = re.split(
r"at 0x[0-9a-f]+", expected_line, maxsplit=2, flags=re.I
)
self.assertTrue(actual_line.startswith(start))
self.assertTrue(actual_line.endswith(end))
@ -403,5 +405,59 @@ class TestShapeList(unittest.TestCase):
)
class TestShapeListAddition(unittest.TestCase):
def setUp(self):
# Create distinct faces to test with
self.face1 = Box(1, 1, 1).faces().sort_by(Axis.Z)[0] # bottom face
self.face2 = Box(1, 1, 1).faces().sort_by(Axis.Z)[-1] # top face
self.face3 = Box(1, 1, 1).faces().sort_by(Axis.X)[0] # side face
def test_add_single_shape(self):
sl = ShapeList([self.face1])
result = sl + self.face2
self.assertIsInstance(result, ShapeList)
self.assertEqual(len(result), 2)
self.assertIn(self.face1, result)
self.assertIn(self.face2, result)
def test_add_shape_list(self):
sl1 = ShapeList([self.face1])
sl2 = ShapeList([self.face2, self.face3])
result = sl1 + sl2
self.assertIsInstance(result, ShapeList)
self.assertEqual(len(result), 3)
self.assertListEqual(result, [self.face1, self.face2, self.face3])
def test_iadd_single_shape(self):
sl = ShapeList([self.face1])
sl_id_before = id(sl)
sl += self.face2
self.assertEqual(id(sl), sl_id_before) # in-place mutation
self.assertEqual(len(sl), 2)
self.assertListEqual(sl, [self.face1, self.face2])
def test_iadd_shape_list(self):
sl = ShapeList([self.face1])
sl += ShapeList([self.face2, self.face3])
self.assertEqual(len(sl), 3)
self.assertListEqual(sl, [self.face1, self.face2, self.face3])
def test_add_vector(self):
vector = Vector(1, 2, 3)
sl = ShapeList([vector])
sl += Vector(4, 5, 6)
self.assertEqual(len(sl), 2)
self.assertIsInstance(sl[0], Vector)
self.assertIsInstance(sl[1], Vector)
def test_add_invalid_type(self):
sl = ShapeList([self.face1])
with self.assertRaises(TypeError):
_ = sl + 123 # type: ignore
with self.assertRaises(TypeError):
sl += "not a shape" # type: ignore
if __name__ == "__main__":
unittest.main()