| 349 | |
| 350 | @dataclass |
| 351 | class Size: |
| 352 | value: int |
| 353 | unit: Unit |
| 354 | sector_size: SectorSize |
| 355 | |
| 356 | def json(self) -> _SizeSerialization: |
| 357 | return { |
| 358 | 'value': self.value, |
| 359 | 'unit': self.unit.name, |
| 360 | 'sector_size': self.sector_size.json(), |
| 361 | } |
| 362 | |
| 363 | @classmethod |
| 364 | def parse_args(cls, size_arg: _SizeSerialization) -> Self: |
| 365 | sector_size = size_arg['sector_size'] |
| 366 | |
| 367 | return cls( |
| 368 | size_arg['value'], |
| 369 | Unit[size_arg['unit']], |
| 370 | SectorSize.parse_args(sector_size), |
| 371 | ) |
| 372 | |
| 373 | def convert( |
| 374 | self, |
| 375 | target_unit: Unit, |
| 376 | sector_size: SectorSize | None = None, |
| 377 | ) -> Size: |
| 378 | if target_unit == Unit.sectors and sector_size is None: |
| 379 | raise ValueError('If target has unit sector, a sector size must be provided') |
| 380 | |
| 381 | if self.unit == target_unit: |
| 382 | return self |
| 383 | elif self.unit == Unit.sectors: |
| 384 | norm = self._normalize() |
| 385 | return Size(norm, Unit.B, self.sector_size).convert(target_unit, sector_size) |
| 386 | else: |
| 387 | if target_unit == Unit.sectors and sector_size is not None: |
| 388 | norm = self._normalize() |
| 389 | sectors = math.ceil(norm / sector_size.value) |
| 390 | return Size(sectors, Unit.sectors, sector_size) |
| 391 | else: |
| 392 | value = int(self._normalize() / target_unit.value) |
| 393 | return Size(value, target_unit, self.sector_size) |
| 394 | |
| 395 | def as_text(self) -> str: |
| 396 | return self.format_size( |
| 397 | self.unit, |
| 398 | self.sector_size, |
| 399 | ) |
| 400 | |
| 401 | def format_size( |
| 402 | self, |
| 403 | target_unit: Unit, |
| 404 | sector_size: SectorSize | None = None, |
| 405 | include_unit: bool = True, |
| 406 | ) -> str: |
| 407 | target_size = self.convert(target_unit, sector_size) |
| 408 |
no outgoing calls
no test coverage detected