|
32 | 32 |
|
33 | 33 | # stdlib
|
34 | 34 | from abc import abstractmethod
|
| 35 | +from numbers import Real |
35 | 36 | from pprint import pformat
|
36 | 37 | from typing import (
|
37 | 38 | Any,
|
|
41 | 42 | List,
|
42 | 43 | MutableSequence,
|
43 | 44 | Optional,
|
| 45 | + SupportsFloat, |
| 46 | + SupportsRound, |
44 | 47 | Tuple,
|
45 | 48 | Type,
|
46 | 49 | TypeVar,
|
|
50 | 53 |
|
51 | 54 | # 3rd party
|
52 | 55 | import pydash # type: ignore
|
| 56 | +from typing_extensions import Protocol |
53 | 57 |
|
54 | 58 | # this package
|
55 | 59 | from domdf_python_tools.doctools import prettify_docstrings
|
56 | 60 |
|
57 |
| -__all__ = ["Dictable", "NamedList", "namedlist", "UserList"] |
| 61 | +__all__ = ["Dictable", "NamedList", "namedlist", "UserList", "UserFloat"] |
58 | 62 |
|
59 | 63 | _V = TypeVar("_V")
|
60 | 64 |
|
@@ -353,6 +357,165 @@ def extend(self, other: Iterable[_T]) -> None:
|
353 | 357 | self.data.extend(other)
|
354 | 358 |
|
355 | 359 |
|
| 360 | +class _SupportsIndex(Protocol): |
| 361 | + |
| 362 | + def __index__(self) -> int: |
| 363 | + ... |
| 364 | + |
| 365 | + |
| 366 | +_F = TypeVar("_F", bound="UserFloat") |
| 367 | + |
| 368 | + |
| 369 | +@prettify_docstrings |
| 370 | +class UserFloat(Real, SupportsRound): |
| 371 | + """ |
| 372 | + Class that simulates a float. |
| 373 | +
|
| 374 | + :param value: Values to initialise the :class:`~domdf_python_tools.bases.UserFloat` with. |
| 375 | +
|
| 376 | + .. versionadded:: 1.6.0 |
| 377 | + """ |
| 378 | + |
| 379 | + def __init__(self, value: Union[SupportsFloat, _SupportsIndex, str, bytes, bytearray] = 0.0): |
| 380 | + self._value = (float(value), ) |
| 381 | + |
| 382 | + def as_integer_ratio(self) -> Tuple[int, int]: |
| 383 | + return float(self).as_integer_ratio() |
| 384 | + |
| 385 | + def hex(self) -> str: |
| 386 | + return float(self).hex() |
| 387 | + |
| 388 | + def is_integer(self) -> bool: |
| 389 | + return float(self).is_integer() |
| 390 | + |
| 391 | + @classmethod |
| 392 | + def fromhex(cls: Type[_F], __s: str) -> _F: |
| 393 | + return cls(float.fromhex(__s)) |
| 394 | + |
| 395 | + def __add__(self: _F, other: float) -> _F: |
| 396 | + return self.__class__(float(self).__add__(other)) |
| 397 | + |
| 398 | + def __sub__(self: _F, other: float) -> _F: |
| 399 | + return self.__class__(float(self).__sub__(other)) |
| 400 | + |
| 401 | + def __mul__(self: _F, other: float) -> _F: |
| 402 | + return self.__class__(float(self).__mul__(other)) |
| 403 | + |
| 404 | + def __floordiv__(self: _F, other: float) -> _F: # type: ignore |
| 405 | + return self.__class__(float(self).__floordiv__(other)) |
| 406 | + |
| 407 | + def __truediv__(self: _F, other: float) -> _F: |
| 408 | + return self.__class__(float(self).__truediv__(other)) |
| 409 | + |
| 410 | + def __mod__(self: _F, other: float) -> _F: |
| 411 | + return self.__class__(float(self).__mod__(other)) |
| 412 | + |
| 413 | + def __divmod__(self: _F, other: float) -> Tuple[_F, _F]: |
| 414 | + return tuple(self.__class__(x) for x in float(self).__divmod__(other)) # type: ignore |
| 415 | + |
| 416 | + def __pow__(self: _F, other: float, mod=None) -> _F: |
| 417 | + return self.__class__(float(self).__pow__(other, mod)) |
| 418 | + |
| 419 | + def __radd__(self: _F, other: float) -> _F: |
| 420 | + return self.__class__(float(self).__radd__(other)) |
| 421 | + |
| 422 | + def __rsub__(self: _F, other: float) -> _F: |
| 423 | + return self.__class__(float(self).__rsub__(other)) |
| 424 | + |
| 425 | + def __rmul__(self: _F, other: float) -> _F: |
| 426 | + return self.__class__(float(self).__rmul__(other)) |
| 427 | + |
| 428 | + def __rfloordiv__(self: _F, other: float) -> _F: # type: ignore |
| 429 | + return self.__class__(float(self).__rfloordiv__(other)) |
| 430 | + |
| 431 | + def __rtruediv__(self: _F, other: float) -> _F: |
| 432 | + return self.__class__(float(self).__rtruediv__(other)) |
| 433 | + |
| 434 | + def __rmod__(self: _F, other: float) -> _F: |
| 435 | + return self.__class__(float(self).__rmod__(other)) |
| 436 | + |
| 437 | + def __rdivmod__(self: _F, other: float) -> Tuple[_F, _F]: |
| 438 | + return tuple(self.__class__(x) for x in float(self).__rdivmod__(other)) # type: ignore |
| 439 | + |
| 440 | + def __rpow__(self: _F, other: float, mod=None) -> _F: |
| 441 | + return self.__class__(float(self).__rpow__(other, mod)) |
| 442 | + |
| 443 | + def __getnewargs__(self) -> Tuple[float]: |
| 444 | + return self._value |
| 445 | + |
| 446 | + def __trunc__(self) -> int: |
| 447 | + return float(self).__trunc__() |
| 448 | + |
| 449 | + def __round__(self, ndigits: Optional[int] = None) -> Union[int, float]: # type: ignore |
| 450 | + return float(self).__round__(ndigits) |
| 451 | + |
| 452 | + def __eq__(self, other: object) -> bool: |
| 453 | + if isinstance(other, UserFloat): |
| 454 | + return self._value == other._value |
| 455 | + else: |
| 456 | + return float(self).__eq__(other) |
| 457 | + |
| 458 | + def __ne__(self, other: object) -> bool: |
| 459 | + if isinstance(other, UserFloat): |
| 460 | + return self._value != other._value |
| 461 | + else: |
| 462 | + return float(self).__ne__(other) |
| 463 | + |
| 464 | + def __lt__(self, other: Union[float, "UserFloat"]) -> bool: |
| 465 | + if isinstance(other, UserFloat): |
| 466 | + return self._value < other._value |
| 467 | + else: |
| 468 | + return float(self).__lt__(other) |
| 469 | + |
| 470 | + def __le__(self, other: Union[float, "UserFloat"]) -> bool: |
| 471 | + if isinstance(other, UserFloat): |
| 472 | + return self._value <= other._value |
| 473 | + else: |
| 474 | + return float(self).__le__(other) |
| 475 | + |
| 476 | + def __gt__(self, other: Union[float, "UserFloat"]) -> bool: |
| 477 | + if isinstance(other, UserFloat): |
| 478 | + return self._value > other._value |
| 479 | + else: |
| 480 | + return float(self).__gt__(other) |
| 481 | + |
| 482 | + def __ge__(self, other: Union[float, "UserFloat"]) -> bool: |
| 483 | + if isinstance(other, UserFloat): |
| 484 | + return self._value >= other._value |
| 485 | + else: |
| 486 | + return float(self).__ge__(other) |
| 487 | + |
| 488 | + def __neg__(self: _F) -> _F: |
| 489 | + return self.__class__(float(self).__neg__()) |
| 490 | + |
| 491 | + def __pos__(self: _F) -> _F: |
| 492 | + return self.__class__(float(self).__pos__()) |
| 493 | + |
| 494 | + def __str__(self) -> str: |
| 495 | + return str(float(self)) |
| 496 | + |
| 497 | + def __int__(self) -> int: |
| 498 | + return int(float(self)) |
| 499 | + |
| 500 | + def __float__(self) -> float: |
| 501 | + return self._value[0] |
| 502 | + |
| 503 | + def __abs__(self: _F) -> _F: |
| 504 | + return self.__class__(float(self).__abs__()) |
| 505 | + |
| 506 | + def __hash__(self) -> int: |
| 507 | + return float(self).__hash__() |
| 508 | + |
| 509 | + def __repr__(self) -> str: |
| 510 | + return str(self) |
| 511 | + |
| 512 | + def __ceil__(self): |
| 513 | + raise NotImplementedError |
| 514 | + |
| 515 | + def __floor__(self): |
| 516 | + raise NotImplementedError |
| 517 | + |
| 518 | + |
356 | 519 | @prettify_docstrings
|
357 | 520 | class NamedList(UserList[_T]):
|
358 | 521 | """
|
|
0 commit comments