|
3 | 3 |
|
4 | 4 | """Types for holding quantities with units.""" |
5 | 5 |
|
| 6 | +from __future__ import annotations |
| 7 | + |
6 | 8 | import math |
7 | | -from typing import Self |
| 9 | +from datetime import timedelta |
| 10 | +from typing import Self, overload |
8 | 11 |
|
9 | 12 |
|
10 | 13 | class Quantity: |
@@ -353,6 +356,53 @@ def as_megawatts(self) -> float: |
353 | 356 | """ |
354 | 357 | return self._base_value / 1e6 |
355 | 358 |
|
| 359 | + def __mul__(self, duration: timedelta) -> Energy: |
| 360 | + """Return an energy from multiplying this power by the given duration. |
| 361 | +
|
| 362 | + Args: |
| 363 | + duration: The duration to multiply by. |
| 364 | +
|
| 365 | + Returns: |
| 366 | + An energy from multiplying this power by the given duration. |
| 367 | + """ |
| 368 | + return Energy(self._base_value * duration.total_seconds() / 3600.0, exponent=0) |
| 369 | + |
| 370 | + @overload |
| 371 | + def __truediv__(self, other: Current) -> Voltage: |
| 372 | + """Return a voltage from dividing this power by the given current. |
| 373 | +
|
| 374 | + Args: |
| 375 | + other: The current to divide by. |
| 376 | + """ |
| 377 | + |
| 378 | + @overload |
| 379 | + def __truediv__(self, other: Voltage) -> Current: |
| 380 | + """Return a current from dividing this power by the given voltage. |
| 381 | +
|
| 382 | + Args: |
| 383 | + other: The voltage to divide by. |
| 384 | + """ |
| 385 | + |
| 386 | + def __truediv__(self, other: Current | Voltage) -> Voltage | Current: |
| 387 | + """Return a current or voltage from dividing this power by the given value. |
| 388 | +
|
| 389 | + Args: |
| 390 | + other: The current or voltage to divide by. |
| 391 | +
|
| 392 | + Returns: |
| 393 | + A current or voltage from dividing this power by the given value. |
| 394 | +
|
| 395 | + Raises: |
| 396 | + TypeError: If the given value is not a current or voltage. |
| 397 | + """ |
| 398 | + if isinstance(other, Current): |
| 399 | + return Voltage(self._base_value / other._base_value, exponent=0) |
| 400 | + if isinstance(other, Voltage): |
| 401 | + return Current(self._base_value / other._base_value, exponent=0) |
| 402 | + raise TypeError( |
| 403 | + f"unsupported operand type(s) for /: '{type(self)}' and '{type(other)}'" |
| 404 | + ) |
| 405 | + |
356 | 406 |
|
357 | 407 | class Current( |
358 | 408 | Quantity, |
@@ -403,6 +453,17 @@ def as_milliamperes(self) -> float: |
403 | 453 | """ |
404 | 454 | return self._base_value * 1e3 |
405 | 455 |
|
| 456 | + def __mul__(self, voltage: Voltage) -> Power: |
| 457 | + """Multiply the current by a voltage to get a power. |
| 458 | +
|
| 459 | + Args: |
| 460 | + voltage: The voltage. |
| 461 | +
|
| 462 | + Returns: |
| 463 | + The power. |
| 464 | + """ |
| 465 | + return Power(self._base_value * voltage._base_value, exponent=0) |
| 466 | + |
406 | 467 |
|
407 | 468 | class Voltage(Quantity, exponent_unit_map={0: "V", -3: "mV", 3: "kV"}): |
408 | 469 | """A voltage quantity.""" |
@@ -467,6 +528,17 @@ def as_kilovolts(self) -> float: |
467 | 528 | """ |
468 | 529 | return self._base_value / 1e3 |
469 | 530 |
|
| 531 | + def __mul__(self, current: Current) -> Power: |
| 532 | + """Multiply the voltage by the current to get the power. |
| 533 | +
|
| 534 | + Args: |
| 535 | + current: The current to multiply the voltage with. |
| 536 | +
|
| 537 | + Returns: |
| 538 | + The calculated power. |
| 539 | + """ |
| 540 | + return Power(self._base_value * current._base_value, exponent=0) |
| 541 | + |
470 | 542 |
|
471 | 543 | class Energy( |
472 | 544 | Quantity, |
@@ -537,3 +609,41 @@ def as_megawatt_hours(self) -> float: |
537 | 609 | The energy in megawatt hours. |
538 | 610 | """ |
539 | 611 | return self._base_value / 1e6 |
| 612 | + |
| 613 | + @overload |
| 614 | + def __truediv__(self, other: timedelta) -> Power: |
| 615 | + """Return a power from dividing this energy by the given duration. |
| 616 | +
|
| 617 | + Args: |
| 618 | + other: The duration to divide by. |
| 619 | + """ |
| 620 | + |
| 621 | + @overload |
| 622 | + def __truediv__(self, other: Power) -> timedelta: |
| 623 | + """Return a duration from dividing this energy by the given power. |
| 624 | +
|
| 625 | + Args: |
| 626 | + other: The power to divide by. |
| 627 | + """ |
| 628 | + |
| 629 | + def __truediv__(self, other: timedelta | Power) -> Power | timedelta: |
| 630 | + """Return a power or duration from dividing this energy by the given value. |
| 631 | +
|
| 632 | + Args: |
| 633 | + other: The power or duration to divide by. |
| 634 | +
|
| 635 | + Returns: |
| 636 | + A power or duration from dividing this energy by the given value. |
| 637 | +
|
| 638 | + Raises: |
| 639 | + TypeError: If the given value is not a power or duration. |
| 640 | + """ |
| 641 | + if isinstance(other, timedelta): |
| 642 | + return Power( |
| 643 | + self._base_value / (other.total_seconds() / 3600.0), exponent=0 |
| 644 | + ) |
| 645 | + if isinstance(other, Power): |
| 646 | + return timedelta(seconds=(self._base_value / other._base_value) * 3600.0) |
| 647 | + raise TypeError( |
| 648 | + f"unsupported operand type(s) for /: '{type(self)}' and '{type(other)}'" |
| 649 | + ) |
0 commit comments