Represents a byte size.
| 11 | |
| 12 | @dataclass(frozen=True) |
| 13 | class ByteSize: |
| 14 | """Represents a byte size.""" |
| 15 | |
| 16 | bytes: int |
| 17 | |
| 18 | def __post_init__(self) -> None: |
| 19 | if self.bytes < 0: |
| 20 | raise ValueError('ByteSize cannot be negative') |
| 21 | |
| 22 | @classmethod |
| 23 | def validate(cls, value: Any) -> ByteSize: |
| 24 | if isinstance(value, ByteSize): |
| 25 | return value |
| 26 | |
| 27 | if not isinstance(value, (float, int)): |
| 28 | raise TypeError('Value must be numeric') |
| 29 | |
| 30 | return cls(int(value)) |
| 31 | |
| 32 | @classmethod |
| 33 | def from_kb(cls, kb: float) -> ByteSize: |
| 34 | return cls(int(kb * _BYTES_PER_KB)) |
| 35 | |
| 36 | @classmethod |
| 37 | def from_mb(cls, mb: float) -> ByteSize: |
| 38 | return cls(int(mb * _BYTES_PER_MB)) |
| 39 | |
| 40 | @classmethod |
| 41 | def from_gb(cls, gb: float) -> ByteSize: |
| 42 | return cls(int(gb * _BYTES_PER_GB)) |
| 43 | |
| 44 | @classmethod |
| 45 | def from_tb(cls, tb: float) -> ByteSize: |
| 46 | return cls(int(tb * _BYTES_PER_TB)) |
| 47 | |
| 48 | def to_kb(self) -> float: |
| 49 | return self.bytes / _BYTES_PER_KB |
| 50 | |
| 51 | def to_mb(self) -> float: |
| 52 | return self.bytes / _BYTES_PER_MB |
| 53 | |
| 54 | def to_gb(self) -> float: |
| 55 | return self.bytes / _BYTES_PER_GB |
| 56 | |
| 57 | def to_tb(self) -> float: |
| 58 | return self.bytes / _BYTES_PER_TB |
| 59 | |
| 60 | def __str__(self) -> str: |
| 61 | if self.bytes >= _BYTES_PER_TB: |
| 62 | return f'{self.to_tb():.2f} TB' |
| 63 | if self.bytes >= _BYTES_PER_GB: |
| 64 | return f'{self.to_gb():.2f} GB' |
| 65 | if self.bytes >= _BYTES_PER_MB: |
| 66 | return f'{self.to_mb():.2f} MB' |
| 67 | if self.bytes >= _BYTES_PER_KB: |
| 68 | return f'{self.to_kb():.2f} KB' |
| 69 | return f'{self.bytes} B' |
| 70 |
no outgoing calls