blob: 501bf4dcaa7ce0e7fd090df27d69bffc04ce21cf [file] [log] [blame]
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Any
from typing import TypeVar
WT = TypeVar("WT", bound="WrapperType")
if TYPE_CHECKING: # pragma: no cover
# Define _CustomList and _CustomDict as a workaround for:
# https://github.com/python/mypy/issues/11427
#
# According to this issue, the typeshed contains a "lie"
# (it adds MutableSequence to the ancestry of list and MutableMapping to
# the ancestry of dict) which completely messes with the type inference for
# Table, InlineTable, Array and Container.
#
# Importing from builtins is preferred over simple assignment, see issues:
# https://github.com/python/mypy/issues/8715
# https://github.com/python/mypy/issues/10068
from builtins import dict as _CustomDict
from builtins import float as _CustomFloat
from builtins import int as _CustomInt
from builtins import list as _CustomList
from typing import Callable
from typing import Concatenate
from typing import ParamSpec
from typing import Protocol
P = ParamSpec("P")
class WrapperType(Protocol):
def _new(self: WT, value: Any) -> WT: ...
else:
from collections.abc import MutableMapping
from collections.abc import MutableSequence
from numbers import Integral
from numbers import Real
class _CustomList(MutableSequence, list):
"""Adds MutableSequence mixin while pretending to be a builtin list"""
def __add__(self, other):
new_list = self.copy()
new_list.extend(other)
return new_list
def __iadd__(self, other):
self.extend(other)
return self
class _CustomDict(MutableMapping, dict):
"""Adds MutableMapping mixin while pretending to be a builtin dict"""
def __or__(self, other):
new_dict = self.copy()
new_dict.update(other)
return new_dict
def __ior__(self, other):
self.update(other)
return self
class _CustomInt(Integral, int):
"""Adds Integral mixin while pretending to be a builtin int"""
class _CustomFloat(Real, float):
"""Adds Real mixin while pretending to be a builtin float"""
def wrap_method(
original_method: Callable[Concatenate[WT, P], Any],
) -> Callable[Concatenate[WT, P], Any]:
def wrapper(self: WT, *args: P.args, **kwargs: P.kwargs) -> Any:
result = original_method(self, *args, **kwargs)
if result is NotImplemented:
return result
return self._new(result)
return wrapper