Coverage for qubalab/objects/classification.py: 90%
49 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-10-22 18:11 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-10-22 18:11 +0000
1from __future__ import annotations
2import random
3from typing import Optional, Union
6class Classification(object):
7 """
8 Simple class to store the names and color of a classification.
10 Each Classification with the same names is the same object, retrieved from a cache.
11 Therefore updating the color of a Classification will update all similarly classified objects.
12 """
14 _cached_classifications: dict[tuple[str], Classification] = {}
16 def __new__(
17 cls, names: Union[str, tuple[str]], color: Optional[tuple[int, int, int]] = None
18 ):
19 if isinstance(names, str):
20 names = (names,)
21 elif isinstance(names, list):
22 names = tuple(names)
23 if names is None:
24 return None
25 if not isinstance(names, tuple):
26 raise TypeError("names should be str or tuple[str]")
28 classification = Classification._cached_classifications.get(names)
29 if classification is None:
30 classification = super().__new__(cls)
31 Classification._cached_classifications[names] = classification
33 if color is not None:
34 classification.color = color
35 return classification
37 def __init__(
38 self,
39 names: Union[str, tuple[str]],
40 color: Optional[tuple[int, int, int]] = None,
41 ):
42 """
43 :param names: the names of the classification
44 :param color: the RGB color (each component between 0 and 255) of the classification. Can be None to use a random color
45 """
46 if isinstance(names, str):
47 names = (names,)
48 elif isinstance(names, list):
49 names = tuple(names)
50 if not isinstance(names, tuple):
51 raise TypeError("names should be a tuple, list or string")
52 self._names = names
53 self._color: tuple = (
54 tuple(random.randint(0, 255) for _ in range(3)) if color is None else color
55 )
57 @property
58 def names(self) -> tuple[str]:
59 """
60 The names of the classification.
61 """
62 return self._names
64 @property
65 def color(self) -> tuple[int, int, int]:
66 """
67 The color of the classification.
68 """
69 return self._color ## todo: pylance type hints problem
71 @color.setter
72 def color(self, value: tuple[int, int, int]) -> None:
73 """
74 Change the color of the classification.
75 :param value: the new 8-bit RGB color
76 """
77 self._color = value
79 def __str__(self):
80 return f"Classification {self.names} of color {self.color}"
82 def __repr__(self):
83 return f"Classification('{self.names}', {self.color})"
85 def __eq__(self, other):
86 if isinstance(other, Classification):
87 return (self is other) or (self.names == other.names)
88 return False
90 def __hash__(self):
91 return hash(self.names)