1010from collections .abc import Callable , Iterator
1111from dataclasses import dataclass
1212from datetime import datetime , timezone
13- from typing import Generic , Self , overload
13+ from typing import Generic , Protocol , Self , SupportsFloat , overload
1414
15- from ._quantities import Power , QuantityT
15+ from ._quantities import Power
1616
1717UNIX_EPOCH = datetime .fromtimestamp (0.0 , tz = timezone .utc )
1818"""The UNIX epoch (in UTC)."""
1919
2020
21+ class Comparable (Protocol ):
22+ def __lt__ (self , other : Self ) -> bool :
23+ ...
24+
25+ def __gt__ (self , other : Self ) -> bool :
26+ ...
27+
28+ def __le__ (self , other : Self ) -> bool :
29+ ...
30+
31+ def __ge__ (self , other : Self ) -> bool :
32+ ...
33+
34+
35+ _T = typing .TypeVar ("_T" )
36+ SupportsFloatT = typing .TypeVar ("SupportsFloatT" , bound = SupportsFloat )
37+ """Type variable for types that support conversion to float."""
38+
39+ ComparableT = typing .TypeVar ("ComparableT" , bound = Comparable )
40+
41+
2142@dataclass (frozen = True , order = True )
22- class Sample (Generic [QuantityT ]):
43+ class Sample (Generic [_T ]):
2344 """A measurement taken at a particular point in time.
2445
2546 The `value` could be `None` if a component is malfunctioning or data is
@@ -30,12 +51,12 @@ class Sample(Generic[QuantityT]):
3051 timestamp : datetime
3152 """The time when this sample was generated."""
3253
33- value : QuantityT | None = None
54+ value : _T | None = None
3455 """The value of this sample."""
3556
3657
3758@dataclass (frozen = True )
38- class Sample3Phase (Generic [QuantityT ]):
59+ class Sample3Phase (Generic [ComparableT ]):
3960 """A 3-phase measurement made at a particular point in time.
4061
4162 Each of the `value` fields could be `None` if a component is malfunctioning
@@ -46,16 +67,16 @@ class Sample3Phase(Generic[QuantityT]):
4667
4768 timestamp : datetime
4869 """The time when this sample was generated."""
49- value_p1 : QuantityT | None
70+ value_p1 : ComparableT | None
5071 """The value of the 1st phase in this sample."""
5172
52- value_p2 : QuantityT | None
73+ value_p2 : ComparableT | None
5374 """The value of the 2nd phase in this sample."""
5475
55- value_p3 : QuantityT | None
76+ value_p3 : ComparableT | None
5677 """The value of the 3rd phase in this sample."""
5778
58- def __iter__ (self ) -> Iterator [QuantityT | None ]:
79+ def __iter__ (self ) -> Iterator [ComparableT | None ]:
5980 """Return an iterator that yields values from each of the phases.
6081
6182 Yields:
@@ -66,14 +87,14 @@ def __iter__(self) -> Iterator[QuantityT | None]:
6687 yield self .value_p3
6788
6889 @overload
69- def max (self , default : QuantityT ) -> QuantityT :
90+ def max (self , default : ComparableT ) -> ComparableT :
7091 ...
7192
7293 @overload
73- def max (self , default : None = None ) -> QuantityT | None :
94+ def max (self , default : None = None ) -> ComparableT | None :
7495 ...
7596
76- def max (self , default : QuantityT | None = None ) -> QuantityT | None :
97+ def max (self , default : ComparableT | None = None ) -> ComparableT | None :
7798 """Return the max value among all phases, or default if they are all `None`.
7899
79100 Args:
@@ -84,21 +105,21 @@ def max(self, default: QuantityT | None = None) -> QuantityT | None:
84105 """
85106 if not any (self ):
86107 return default
87- value : QuantityT = functools .reduce (
108+ value : ComparableT = functools .reduce (
88109 lambda x , y : x if x > y else y ,
89110 filter (None , self ),
90111 )
91112 return value
92113
93114 @overload
94- def min (self , default : QuantityT ) -> QuantityT :
115+ def min (self , default : ComparableT ) -> ComparableT :
95116 ...
96117
97118 @overload
98- def min (self , default : None = None ) -> QuantityT | None :
119+ def min (self , default : None = None ) -> ComparableT | None :
99120 ...
100121
101- def min (self , default : QuantityT | None = None ) -> QuantityT | None :
122+ def min (self , default : ComparableT | None = None ) -> ComparableT | None :
102123 """Return the min value among all phases, or default if they are all `None`.
103124
104125 Args:
@@ -109,16 +130,16 @@ def min(self, default: QuantityT | None = None) -> QuantityT | None:
109130 """
110131 if not any (self ):
111132 return default
112- value : QuantityT = functools .reduce (
133+ value : ComparableT = functools .reduce (
113134 lambda x , y : x if x < y else y ,
114135 filter (None , self ),
115136 )
116137 return value
117138
118139 def map (
119140 self ,
120- function : Callable [[QuantityT ], QuantityT ],
121- default : QuantityT | None = None ,
141+ function : Callable [[ComparableT ], ComparableT ],
142+ default : ComparableT | None = None ,
122143 ) -> Self :
123144 """Apply the given function on each of the phase values and return the result.
124145
@@ -140,9 +161,6 @@ def map(
140161 )
141162
142163
143- _T = typing .TypeVar ("_T" )
144-
145-
146164@dataclass (frozen = True )
147165class Bounds (Generic [_T ]):
148166 """Lower and upper bound values."""
0 commit comments