Skip to content

Commit 7678193

Browse files
authored
Consolidate duplicated annotation properties (#201)
1 parent af953be commit 7678193

1 file changed

Lines changed: 81 additions & 182 deletions

File tree

virl2_client/models/annotation.py

Lines changed: 81 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,71 @@
115115
_ANNOTATION_TYPES = ["text", "line", "ellipse", "rectangle"]
116116

117117

118+
class _CoordinateXY2Mixin:
119+
"""Mixin providing x2/y2 coordinate properties for annotation subclasses."""
120+
121+
@property
122+
def x2(self) -> int:
123+
"""X2 coordinate.
124+
125+
:returns: The x2 coordinate value.
126+
"""
127+
self._lab.sync_topology_if_outdated()
128+
return self._x2
129+
130+
@x2.setter
131+
@locked
132+
def x2(self, value: int) -> None:
133+
"""Set x2 coordinate.
134+
135+
:param value: The x2 coordinate value to set.
136+
"""
137+
self._set_annotation_property("x2", value)
138+
self._x2 = value
139+
140+
@property
141+
def y2(self) -> int:
142+
"""Y2 coordinate.
143+
144+
:returns: The y2 coordinate value.
145+
"""
146+
self._lab.sync_topology_if_outdated()
147+
return self._y2
148+
149+
@y2.setter
150+
@locked
151+
def y2(self, value: int) -> None:
152+
"""Set y2 coordinate.
153+
154+
:param value: The y2 coordinate value to set.
155+
"""
156+
self._set_annotation_property("y2", value)
157+
self._y2 = value
158+
159+
160+
class _RotationMixin:
161+
"""Mixin providing rotation property for annotation subclasses."""
162+
163+
@property
164+
def rotation(self) -> int:
165+
"""Rotation of an object, in degrees.
166+
167+
:returns: The rotation value in degrees.
168+
"""
169+
self._lab.sync_topology_if_outdated()
170+
return self._rotation
171+
172+
@rotation.setter
173+
@locked
174+
def rotation(self, value: int) -> None:
175+
"""Set rotation of an object, in degrees.
176+
177+
:param value: The rotation value in degrees to set.
178+
"""
179+
self._set_annotation_property("rotation", value)
180+
self._rotation = value
181+
182+
118183
class Annotation:
119184
"""Base class for VIRL2 lab annotations (text, line, ellipse, rectangle)."""
120185

@@ -380,7 +445,7 @@ def get_default_property_values(cls, annotation_type: str) -> dict[str, Any]:
380445
for ppty in ANNOTATION_PROPERTY_MAP:
381446
if ppty == "type":
382447
continue
383-
if not ANNOTATION_MAP[annotation_type] & ANNOTATION_PROPERTY_MAP[ppty]:
448+
if not cls._is_property_valid_for_type(annotation_type, ppty):
384449
continue
385450
ppty_default = ANNOTATION_PROPERTIES_DEFAULTS[ppty]
386451
if isinstance(ppty_default, dict):
@@ -401,14 +466,19 @@ def is_valid_property(
401466
:param _property: The property name to validate.
402467
:returns: True if the property is valid for the given type, False otherwise.
403468
"""
404-
if (
405-
annotation_type not in _ANNOTATION_TYPES
406-
or _property not in ANNOTATION_PROPERTY_MAP
407-
):
408-
return False
409469
return (
470+
annotation_type in _ANNOTATION_TYPES
471+
and _property in ANNOTATION_PROPERTY_MAP
472+
and cls._is_property_valid_for_type(annotation_type, _property)
473+
)
474+
475+
@classmethod
476+
def _is_property_valid_for_type(
477+
cls, annotation_type: AnnotationTypeString, _property: str
478+
) -> bool:
479+
return bool(
410480
ANNOTATION_MAP[annotation_type] & ANNOTATION_PROPERTY_MAP[_property]
411-
) > 0
481+
)
412482

413483
@locked
414484
def as_dict(self) -> dict[str, Any]:
@@ -503,7 +573,7 @@ def _set_annotation_properties(self, annotation_data: dict[str, Any]) -> None:
503573
# ~~~~~< Annotation subclasses >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
504574

505575

506-
class AnnotationRectangle(Annotation):
576+
class AnnotationRectangle(_CoordinateXY2Mixin, _RotationMixin, Annotation):
507577
"""
508578
Annotation class representing rectangle annotation.
509579
"""
@@ -556,65 +626,8 @@ def border_radius(self, value: int) -> None:
556626
self._set_annotation_property("border_radius", value)
557627
self._border_radius = value
558628

559-
@property
560-
def x2(self) -> int:
561-
"""X2 coordinate.
562-
563-
:returns: The x2 coordinate value.
564-
"""
565-
self._lab.sync_topology_if_outdated()
566-
return self._x2
567-
568-
@x2.setter
569-
@locked
570-
def x2(self, value: int) -> None:
571-
"""Set x2 coordinate.
572-
573-
:param value: The x2 coordinate value to set.
574-
"""
575-
self._set_annotation_property("x2", value)
576-
self._x2 = value
577-
578-
@property
579-
def y2(self) -> int:
580-
"""Y2 coordinate.
581-
582-
:returns: The y2 coordinate value.
583-
"""
584-
self._lab.sync_topology_if_outdated()
585-
return self._y2
586-
587-
@y2.setter
588-
@locked
589-
def y2(self, value: int) -> None:
590-
"""Set y2 coordinate.
591-
592-
:param value: The y2 coordinate value to set.
593-
"""
594-
self._set_annotation_property("y2", value)
595-
self._y2 = value
596-
597-
@property
598-
def rotation(self) -> int:
599-
"""Rotation of an object, in degrees.
600-
601-
:returns: The rotation value in degrees.
602-
"""
603-
self._lab.sync_topology_if_outdated()
604-
return self._rotation
605-
606-
@rotation.setter
607-
@locked
608-
def rotation(self, value: int) -> None:
609-
"""Set rotation of an object, in degrees.
610-
611-
:param value: The rotation value in degrees to set.
612-
"""
613-
self._set_annotation_property("rotation", value)
614-
self._rotation = value
615629

616-
617-
class AnnotationEllipse(Annotation):
630+
class AnnotationEllipse(_CoordinateXY2Mixin, _RotationMixin, Annotation):
618631
"""
619632
Annotation class representing ellipse annotation.
620633
"""
@@ -645,65 +658,8 @@ def __init__(
645658
if annotation_data:
646659
self._update(annotation_data, push_to_server=False)
647660

648-
@property
649-
def x2(self) -> int:
650-
"""X2 coordinate.
651-
652-
:returns: The x2 coordinate value.
653-
"""
654-
self._lab.sync_topology_if_outdated()
655-
return self._x2
656-
657-
@x2.setter
658-
@locked
659-
def x2(self, value: int) -> None:
660-
"""Set x2 coordinate.
661-
662-
:param value: The x2 coordinate value to set.
663-
"""
664-
self._set_annotation_property("x2", value)
665-
self._x2 = value
666-
667-
@property
668-
def y2(self) -> int:
669-
"""Y2 coordinate.
670-
671-
:returns: The y2 coordinate value.
672-
"""
673-
self._lab.sync_topology_if_outdated()
674-
return self._y2
675-
676-
@y2.setter
677-
@locked
678-
def y2(self, value: int) -> None:
679-
"""Set y2 coordinate.
680-
681-
:param value: The y2 coordinate value to set.
682-
"""
683-
self._set_annotation_property("y2", value)
684-
self._y2 = value
685-
686-
@property
687-
def rotation(self) -> int:
688-
"""Rotation of an object, in degrees.
689-
690-
:returns: The rotation value in degrees.
691-
"""
692-
self._lab.sync_topology_if_outdated()
693-
return self._rotation
694661

695-
@rotation.setter
696-
@locked
697-
def rotation(self, value: int) -> None:
698-
"""Set rotation of an object, in degrees.
699-
700-
:param value: The rotation value in degrees to set.
701-
"""
702-
self._set_annotation_property("rotation", value)
703-
self._rotation = value
704-
705-
706-
class AnnotationLine(Annotation):
662+
class AnnotationLine(_CoordinateXY2Mixin, Annotation):
707663
"""
708664
Annotation class representing line annotation.
709665
"""
@@ -737,44 +693,6 @@ def __init__(
737693
if annotation_data:
738694
self._update(annotation_data, push_to_server=False)
739695

740-
@property
741-
def x2(self) -> int:
742-
"""X2 coordinate.
743-
744-
:returns: The x2 coordinate value.
745-
"""
746-
self._lab.sync_topology_if_outdated()
747-
return self._x2
748-
749-
@x2.setter
750-
@locked
751-
def x2(self, value: int) -> None:
752-
"""Set x2 coordinate.
753-
754-
:param value: The x2 coordinate value to set.
755-
"""
756-
self._set_annotation_property("x2", value)
757-
self._x2 = value
758-
759-
@property
760-
def y2(self) -> int:
761-
"""Y2 coordinate.
762-
763-
:returns: The y2 coordinate value.
764-
"""
765-
self._lab.sync_topology_if_outdated()
766-
return self._y2
767-
768-
@y2.setter
769-
@locked
770-
def y2(self, value: int) -> None:
771-
"""Set y2 coordinate.
772-
773-
:param value: The y2 coordinate value to set.
774-
"""
775-
self._set_annotation_property("y2", value)
776-
self._y2 = value
777-
778696
@property
779697
def line_start(self) -> str | None:
780698
"""Line arrow start style.
@@ -814,7 +732,7 @@ def line_end(self, value: str | None) -> None:
814732
self._line_end = value
815733

816734

817-
class AnnotationText(Annotation):
735+
class AnnotationText(_RotationMixin, Annotation):
818736
"""
819737
Annotation class representing text annotation.
820738
"""
@@ -863,25 +781,6 @@ def __init__(
863781
if annotation_data:
864782
self._update(annotation_data, push_to_server=False)
865783

866-
@property
867-
def rotation(self) -> int:
868-
"""Rotation of an object, in degrees.
869-
870-
:returns: The rotation value in degrees.
871-
"""
872-
self._lab.sync_topology_if_outdated()
873-
return self._rotation
874-
875-
@rotation.setter
876-
@locked
877-
def rotation(self, value: int) -> None:
878-
"""Set rotation of an object, in degrees.
879-
880-
:param value: The rotation value in degrees to set.
881-
"""
882-
self._set_annotation_property("rotation", value)
883-
self._rotation = value
884-
885784
@property
886785
def text_bold(self) -> bool:
887786
"""Text boldness.

0 commit comments

Comments
 (0)