Skip to content

Commit

Permalink
Add error messages and tests for dunder methods
Browse files Browse the repository at this point in the history
  • Loading branch information
BPdeRooij committed Aug 12, 2024
1 parent 664337d commit f5c43ca
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 6 deletions.
23 changes: 17 additions & 6 deletions dlup/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,12 +976,14 @@ def __add__(self, other: WsiAnnotations | Point | Polygon | list[Point | Polygon

if isinstance(other, list):
if not all(isinstance(item, (Point, Polygon)) for item in other):
raise TypeError("")
raise TypeError("can only add list purely containing Point and Polygon objects to WsiAnnotations")

Check warning on line 979 in dlup/annotations.py

View check run for this annotation

Codecov / codecov/patch

dlup/annotations.py#L979

Added line #L979 was not covered by tests
new_layers = self._layers + other
new_tags = self.tags
elif isinstance(other, WsiAnnotations):
if self.sorting != other.sorting or self.offset_to_slide_bounds != other.offset_to_slide_bounds:
raise ValueError("")
raise ValueError(

Check warning on line 984 in dlup/annotations.py

View check run for this annotation

Codecov / codecov/patch

dlup/annotations.py#L984

Added line #L984 was not covered by tests
"Both sorting and offset_to_slide_bounds must be the same to add WsiAnnotations together."
)
new_layers = self._layers + other._layers
new_tags = self.tags if self.tags is not None else [] + other.tags if other.tags is not None else None
else:
Expand All @@ -996,14 +998,16 @@ def __iadd__(self, other: WsiAnnotations | Point | Polygon | list[Point | Polygo

if isinstance(other, list):
if not all(isinstance(item, (Point, Polygon)) for item in other):
raise TypeError("")
raise TypeError("can only add list purely containing Point and Polygon objects to WsiAnnotations")

Check warning on line 1001 in dlup/annotations.py

View check run for this annotation

Codecov / codecov/patch

dlup/annotations.py#L1001

Added line #L1001 was not covered by tests

self._layers += other
for item in other:
self._available_classes.add(item.annotation_class)
elif isinstance(other, WsiAnnotations):
if self.sorting != other.sorting or self.offset_to_slide_bounds != other.offset_to_slide_bounds:
raise ValueError("")
raise ValueError(

Check warning on line 1008 in dlup/annotations.py

View check run for this annotation

Codecov / codecov/patch

dlup/annotations.py#L1008

Added line #L1008 was not covered by tests
"Both sorting and offset_to_slide_bounds must be the same to add WsiAnnotations together."
)
self._layers += other._layers

if self._tags is None:
Expand All @@ -1019,10 +1023,17 @@ def __iadd__(self, other: WsiAnnotations | Point | Polygon | list[Point | Polygo
self._str_tree = STRtree(self._layers)
return self

def __radd__(self, other: WsiAnnotations | Point | Polygon) -> WsiAnnotations:
def __radd__(self, other: WsiAnnotations | Point | Polygon | list[Point | Polygon]) -> WsiAnnotations:
# in-place addition (+=) of Point and Polygon will raise a TypeError
if not isinstance(other, (WsiAnnotations, Point, Polygon)):
if not isinstance(other, (WsiAnnotations, Point, Polygon, list)):
return NotImplemented
if isinstance(other, list):
if not all(isinstance(item, (Point, Polygon)) for item in other):
raise TypeError("can only add list purely containing Point and Polygon objects to WsiAnnotations")

Check warning on line 1032 in dlup/annotations.py

View check run for this annotation

Codecov / codecov/patch

dlup/annotations.py#L1032

Added line #L1032 was not covered by tests
raise TypeError(
"use the __add__ or __iadd__ operator instead of __radd__ when working with lists to avoid \
unexpected behavior."
)
return self + other

def __sub__(self, other: WsiAnnotations | Point | Polygon) -> WsiAnnotations:
Expand Down
116 changes: 116 additions & 0 deletions tests/test_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ class TestAnnotations:
_v7_annotations = None
_v7_raster_annotations = None

additinoaL_point_a_cls = AnnotationClass(label="example", annotation_type=AnnotationType.POINT, color=(255, 0, 0))
additional_point = Point((1, 2), a_cls=additinoaL_point_a_cls)

additional_polygon_a_cls = AnnotationClass(
label="example", annotation_type=AnnotationType.POLYGON, color=(255, 0, 0), z_index=1
)
additional_polygon = Polygon([(0, 0), (4, 0), (4, 4), (0, 4)], a_cls=additional_polygon_a_cls)

@property
def v7_annotations(self):
if self._v7_annotations is None:
Expand Down Expand Up @@ -229,3 +237,111 @@ def test_annotation_filter(self):

annotations.filter(["non-existing"])
assert len(annotations._layers) == 0

def test_length(self):
annotations = self.geojson_annotations
assert len(annotations._layers) == len(annotations)

def test_dunder_add_methods_with_point(self):
annotations = self.geojson_annotations.copy()
initial_annotations_id = id(annotations)
initial_length = len(annotations)

# __add__
new_annotations = annotations + self.additional_point
assert initial_annotations_id != id(new_annotations)
assert initial_length + 1 == len(new_annotations)
assert self.additional_point in new_annotations

# __radd__
new_annotations = self.additional_point + annotations
assert initial_annotations_id != id(new_annotations)
assert initial_length + 1 == len(new_annotations)
assert self.additional_point in new_annotations
with pytest.raises(TypeError):
self.additional_point += annotations

# __iadd__
annotations += self.additional_point
assert initial_annotations_id == id(annotations)
assert initial_length + 1 == len(annotations)
assert self.additional_point in annotations

def test_add_with_polygon(self):
annotations = self.geojson_annotations.copy()
initial_annotations_id = id(annotations)
initial_length = len(annotations)

# __add__
new_annotations = annotations + self.additional_polygon
assert initial_annotations_id != id(new_annotations)
assert initial_length + 1 == len(new_annotations)
assert self.additional_polygon in new_annotations

# __radd__
new_annotations = self.additional_polygon + annotations
assert initial_annotations_id != id(new_annotations)
assert initial_length + 1 == len(new_annotations)
assert self.additional_polygon in new_annotations
with pytest.raises(TypeError):
self.additional_polygon += annotations

# __iadd__
annotations += self.additional_polygon
assert initial_annotations_id == id(annotations)
assert initial_length + 1 == len(annotations)
assert self.additional_polygon in annotations

def test_add_with_list(self):
annotations = self.geojson_annotations.copy()
initial_annotations_id = id(annotations)
initial_length = len(annotations)

# __add__
new_annotations = annotations + [self.additional_point, self.additional_polygon]
assert initial_annotations_id != id(new_annotations)
assert initial_length + 2 == len(new_annotations)
assert self.additional_polygon in new_annotations
assert self.additional_point in new_annotations

# __radd__
_annotations_list = [self.additional_point, self.additional_polygon]
with pytest.raises(TypeError):
new_annotations = _annotations_list + annotations

_annotations_list = [self.additional_point, self.additional_polygon]
with pytest.raises(TypeError):
_annotations_list += annotations

# __iadd__
annotations += [self.additional_point, self.additional_polygon]
assert initial_annotations_id == id(annotations)
assert initial_length + 2 == len(annotations)
assert all(ann in new_annotations for ann in annotations)

def test_add_with_wsi_annotations(self):
annotations = self.geojson_annotations.copy()
other_annotations = self.geojson_annotations.copy()
initial_annotations_id = id(annotations)
initial_length = len(annotations)

# __add__
new_annotations = annotations + other_annotations
assert initial_annotations_id != id(new_annotations)
assert len(annotations) + len(other_annotations) == len(new_annotations)
assert all(ann in new_annotations for ann in annotations)

# __iadd__
annotations += other_annotations
assert initial_annotations_id == id(annotations)
assert initial_length + len(other_annotations) == len(annotations)
assert all(ann in annotations for ann in other_annotations)

def test_add_with_invalid_type(self):
annotations = self.geojson_annotations.copy()
with pytest.raises(TypeError):
_ = annotations + "invalid type"
with pytest.raises(TypeError):
annotations += "invalid type"
with pytest.raises(TypeError):
_ = "invalid type" + annotations

0 comments on commit f5c43ca

Please sign in to comment.