| 69 | |
| 70 | |
| 71 | class Hours: |
| 72 | h: int |
| 73 | _m: int |
| 74 | _s: float |
| 75 | |
| 76 | def __class_getitem__(cls, parts: Union[slice, float]) -> 'Hours': |
| 77 | if isinstance(parts, slice): |
| 78 | h = parts.start or 0 |
| 79 | m = valid_base_60(parts.stop or 0, 'minutes') |
| 80 | s = valid_base_60(parts.step or 0, 'seconds') |
| 81 | else: |
| 82 | h, m, s = normalize(parts * 3600) |
| 83 | return Hours(h, m, s) |
| 84 | |
| 85 | def __init__(self, h: float = 0, m: float = 0, s: float = 0): |
| 86 | if h < 0 or m < 0 or s < 0: |
| 87 | raise ValueError('invalid negative argument') |
| 88 | self.h, self.m, self.s = normalize(h * 3600 + m * 60 + s) |
| 89 | |
| 90 | def __repr__(self): |
| 91 | h, m, s = self |
| 92 | display_s = f'{s:06.3f}' |
| 93 | display_s = display_s.rstrip('0').rstrip('.') |
| 94 | if display_s == '00': |
| 95 | return f'{h}:{m:02d}' |
| 96 | return f'{h}:{m:02d}:{display_s}' |
| 97 | |
| 98 | def __float__(self): |
| 99 | return self.h + self.m / 60 + self.s / 3600 |
| 100 | |
| 101 | def __eq__(self, other): |
| 102 | return repr(self) == repr(other) |
| 103 | |
| 104 | def __iter__(self): |
| 105 | yield self.h |
| 106 | yield self.m |
| 107 | yield self.s |
| 108 | |
| 109 | def __add__(self, other): |
| 110 | if not isinstance(other, Hours): |
| 111 | return NotImplemented |
| 112 | return Hours(*(a + b for a, b in zip(self, other))) |
| 113 | |
| 114 | |
| 115 | H = Hours |
no outgoing calls
no test coverage detected