diff options
Diffstat (limited to 'Lib/typing.py')
-rw-r--r-- | Lib/typing.py | 223 |
1 files changed, 76 insertions, 147 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index 38e07ad..ddaec3e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -128,6 +128,8 @@ class TypingMeta(type): class Final: """Mix-in class to prevent instantiation.""" + __slots__ = () + def __new__(self, *args, **kwds): raise TypeError("Cannot instantiate %r" % self.__class__) @@ -176,6 +178,9 @@ class _ForwardRef(TypingMeta): self.__forward_evaluated__ = True return self.__forward_value__ + def __instancecheck__(self, obj): + raise TypeError("Forward references cannot be used with isinstance().") + def __subclasscheck__(self, cls): if not self.__forward_evaluated__: globalns = self.__forward_frame__.f_globals @@ -186,16 +191,6 @@ class _ForwardRef(TypingMeta): return False # Too early. return issubclass(cls, self.__forward_value__) - def __instancecheck__(self, obj): - if not self.__forward_evaluated__: - globalns = self.__forward_frame__.f_globals - localns = self.__forward_frame__.f_locals - try: - self._eval_type(globalns, localns) - except NameError: - return False # Too early. - return isinstance(obj, self.__forward_value__) - def __repr__(self): return '_ForwardRef(%r)' % (self.__forward_arg__,) @@ -211,6 +206,8 @@ class _TypeAlias: False. """ + __slots__ = ('name', 'type_var', 'impl_type', 'type_checker') + def __new__(cls, *args, **kwds): """Constructor. @@ -259,8 +256,7 @@ class _TypeAlias: self.impl_type, self.type_checker) def __instancecheck__(self, obj): - return (isinstance(obj, self.impl_type) and - isinstance(self.type_checker(obj), self.type_var)) + raise TypeError("Type aliases cannot be used with isinstance().") def __subclasscheck__(self, cls): if cls is Any: @@ -332,8 +328,8 @@ class AnyMeta(TypingMeta): self = super().__new__(cls, name, bases, namespace, _root=_root) return self - def __instancecheck__(self, instance): - return True + def __instancecheck__(self, obj): + raise TypeError("Any cannot be used with isinstance().") def __subclasscheck__(self, cls): if not isinstance(cls, type): @@ -349,6 +345,8 @@ class Any(Final, metaclass=AnyMeta, _root=True): - As a special case, Any and object are subclasses of each other. """ + __slots__ = () + class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True): """Type variable. @@ -447,7 +445,6 @@ KT = TypeVar('KT') # Key type. VT = TypeVar('VT') # Value type. T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. -KT_co = TypeVar('KT_co', covariant=True) # Key type covariant containers. VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. @@ -548,9 +545,8 @@ class UnionMeta(TypingMeta): def __hash__(self): return hash(self.__union_set_params__) - def __instancecheck__(self, instance): - return (self.__union_set_params__ is not None and - any(isinstance(instance, t) for t in self.__union_params__)) + def __instancecheck__(self, obj): + raise TypeError("Unions cannot be used with isinstance().") def __subclasscheck__(self, cls): if cls is Any: @@ -645,6 +641,8 @@ class Optional(Final, metaclass=OptionalMeta, _root=True): Optional[X] is equivalent to Union[X, type(None)]. """ + __slots__ = () + class TupleMeta(TypingMeta): """Metaclass for Tuple.""" @@ -709,18 +707,8 @@ class TupleMeta(TypingMeta): def __hash__(self): return hash(self.__tuple_params__) - def __instancecheck__(self, t): - if not isinstance(t, tuple): - return False - if self.__tuple_params__ is None: - return True - if self.__tuple_use_ellipsis__: - p = self.__tuple_params__[0] - return all(isinstance(x, p) for x in t) - else: - return (len(t) == len(self.__tuple_params__) and - all(isinstance(x, p) - for x, p in zip(t, self.__tuple_params__))) + def __instancecheck__(self, obj): + raise TypeError("Tuples cannot be used with isinstance().") def __subclasscheck__(self, cls): if cls is Any: @@ -754,6 +742,8 @@ class Tuple(Final, metaclass=TupleMeta, _root=True): To specify a variable-length tuple of homogeneous type, use Sequence[T]. """ + __slots__ = () + class CallableMeta(TypingMeta): """Metaclass for Callable.""" @@ -787,7 +777,10 @@ class CallableMeta(TypingMeta): def _eval_type(self, globalns, localns): if self.__args__ is None and self.__result__ is None: return self - args = [_eval_type(t, globalns, localns) for t in self.__args__] + if self.__args__ is Ellipsis: + args = self.__args__ + else: + args = [_eval_type(t, globalns, localns) for t in self.__args__] result = _eval_type(self.__result__, globalns, localns) if args == self.__args__ and result == self.__result__: return self @@ -826,57 +819,14 @@ class CallableMeta(TypingMeta): def __hash__(self): return hash(self.__args__) ^ hash(self.__result__) - def __instancecheck__(self, instance): - if not callable(instance): - return False + def __instancecheck__(self, obj): + # For unparametrized Callable we allow this, because + # typing.Callable should be equivalent to + # collections.abc.Callable. if self.__args__ is None and self.__result__ is None: - return True - assert self.__args__ is not None - assert self.__result__ is not None - my_args, my_result = self.__args__, self.__result__ - import inspect # TODO: Avoid this import. - # Would it be better to use Signature objects? - try: - (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, - annotations) = inspect.getfullargspec(instance) - except TypeError: - return False # We can't find the signature. Give up. - msg = ("When testing isinstance(<callable>, Callable[...], " - "<calleble>'s annotations must be types.") - if my_args is not Ellipsis: - if kwonlyargs and (not kwonlydefaults or - len(kwonlydefaults) < len(kwonlyargs)): - return False - if isinstance(instance, types.MethodType): - # For methods, getfullargspec() includes self/cls, - # but it's not part of the call signature, so drop it. - del args[0] - min_call_args = len(args) - if defaults: - min_call_args -= len(defaults) - if varargs: - max_call_args = 999999999 - if len(args) < len(my_args): - args += [varargs] * (len(my_args) - len(args)) - else: - max_call_args = len(args) - if not min_call_args <= len(my_args) <= max_call_args: - return False - for my_arg_type, name in zip(my_args, args): - if name in annotations: - annot_type = _type_check(annotations[name], msg) - else: - annot_type = Any - if not issubclass(my_arg_type, annot_type): - return False - # TODO: If mutable type, check invariance? - if 'return' in annotations: - annot_return_type = _type_check(annotations['return'], msg) - # Note contravariance here! - if not issubclass(annot_return_type, my_result): - return False - # Can't find anything wrong... - return True + return isinstance(obj, collections_abc.Callable) + else: + raise TypeError("Callable[] cannot be used with isinstance().") def __subclasscheck__(self, cls): if cls is Any: @@ -900,6 +850,8 @@ class Callable(Final, metaclass=CallableMeta, _root=True): such function types are rarely used as callback types. """ + __slots__ = () + def _gorg(a): """Return the farthest origin of a generic class.""" @@ -1010,6 +962,8 @@ class GenericMeta(TypingMeta, abc.ABCMeta): if not isinstance(p, TypeVar): raise TypeError("Initial parameters must be " "type variables; got %s" % p) + if len(set(params)) != len(params): + raise TypeError("All type variables in Generic[...] must be distinct.") else: if len(params) != len(self.__parameters__): raise TypeError("Cannot change parameter count from %d to %d" % @@ -1073,13 +1027,6 @@ class GenericMeta(TypingMeta, abc.ABCMeta): return False return issubclass(cls, self.__extra__) - def __instancecheck__(self, obj): - if super().__instancecheck__(obj): - return True - if self.__extra__ is None: - return False - return isinstance(obj, self.__extra__) - class Generic(metaclass=GenericMeta): """Abstract base class for generic types. @@ -1109,6 +1056,8 @@ class Generic(metaclass=GenericMeta): # Same body as above. """ + __slots__ = () + def __new__(cls, *args, **kwds): next_in_mro = object # Look for the last occurrence of Generic or Generic[...]. @@ -1234,6 +1183,9 @@ class _ProtocolMeta(GenericMeta): from Generic. """ + def __instancecheck__(self, obj): + raise TypeError("Protocols cannot be used with isinstance().") + def __subclasscheck__(self, cls): if not self._is_protocol: # No structural checks since this isn't a protocol. @@ -1272,6 +1224,7 @@ class _ProtocolMeta(GenericMeta): attr != '__abstractmethods__' and attr != '_is_protocol' and attr != '__dict__' and + attr != '__slots__' and attr != '_get_protocol_attrs' and attr != '__parameters__' and attr != '__origin__' and @@ -1289,6 +1242,8 @@ class _Protocol(metaclass=_ProtocolMeta): such as Hashable). """ + __slots__ = () + _is_protocol = True @@ -1299,14 +1254,15 @@ Hashable = collections_abc.Hashable # Not generic. class Iterable(Generic[T_co], extra=collections_abc.Iterable): - pass + __slots__ = () class Iterator(Iterable[T_co], extra=collections_abc.Iterator): - pass + __slots__ = () class SupportsInt(_Protocol): + __slots__ = () @abstractmethod def __int__(self) -> int: @@ -1314,6 +1270,7 @@ class SupportsInt(_Protocol): class SupportsFloat(_Protocol): + __slots__ = () @abstractmethod def __float__(self) -> float: @@ -1321,6 +1278,7 @@ class SupportsFloat(_Protocol): class SupportsComplex(_Protocol): + __slots__ = () @abstractmethod def __complex__(self) -> complex: @@ -1328,30 +1286,34 @@ class SupportsComplex(_Protocol): class SupportsBytes(_Protocol): + __slots__ = () @abstractmethod def __bytes__(self) -> bytes: pass -class SupportsAbs(_Protocol[T]): +class SupportsAbs(_Protocol[T_co]): + __slots__ = () @abstractmethod - def __abs__(self) -> T: + def __abs__(self) -> T_co: pass -class SupportsRound(_Protocol[T]): +class SupportsRound(_Protocol[T_co]): + __slots__ = () @abstractmethod - def __round__(self, ndigits: int = 0) -> T: + def __round__(self, ndigits: int = 0) -> T_co: pass -class Reversible(_Protocol[T]): +class Reversible(_Protocol[T_co]): + __slots__ = () @abstractmethod - def __reversed__(self) -> 'Iterator[T]': + def __reversed__(self) -> 'Iterator[T_co]': pass @@ -1359,7 +1321,7 @@ Sized = collections_abc.Sized # Not generic. class Container(Generic[T_co], extra=collections_abc.Container): - pass + __slots__ = () # Callable was defined earlier. @@ -1374,7 +1336,8 @@ class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet): pass -class Mapping(Sized, Iterable[KT_co], Container[KT_co], Generic[KT_co, VT_co], +# NOTE: Only the value type is covariant. +class Mapping(Sized, Iterable[KT], Container[KT], Generic[VT_co], extra=collections_abc.Mapping): pass @@ -1399,19 +1362,7 @@ class ByteString(Sequence[int], extra=collections_abc.ByteString): ByteString.register(type(memoryview(b''))) -class _ListMeta(GenericMeta): - - def __instancecheck__(self, obj): - if not super().__instancecheck__(obj): - return False - itemtype = self.__parameters__[0] - for x in obj: - if not isinstance(x, itemtype): - return False - return True - - -class List(list, MutableSequence[T], metaclass=_ListMeta): +class List(list, MutableSequence[T]): def __new__(cls, *args, **kwds): if _geqv(cls, List): @@ -1420,19 +1371,7 @@ class List(list, MutableSequence[T], metaclass=_ListMeta): return list.__new__(cls, *args, **kwds) -class _SetMeta(GenericMeta): - - def __instancecheck__(self, obj): - if not super().__instancecheck__(obj): - return False - itemtype = self.__parameters__[0] - for x in obj: - if not isinstance(x, itemtype): - return False - return True - - -class Set(set, MutableSet[T], metaclass=_SetMeta): +class Set(set, MutableSet[T]): def __new__(cls, *args, **kwds): if _geqv(cls, Set): @@ -1441,7 +1380,7 @@ class Set(set, MutableSet[T], metaclass=_SetMeta): return set.__new__(cls, *args, **kwds) -class _FrozenSetMeta(_SetMeta): +class _FrozenSetMeta(GenericMeta): """This metaclass ensures set is not a subclass of FrozenSet. Without this metaclass, set would be considered a subclass of @@ -1454,13 +1393,9 @@ class _FrozenSetMeta(_SetMeta): return False return super().__subclasscheck__(cls) - def __instancecheck__(self, obj): - if issubclass(obj.__class__, Set): - return False - return super().__instancecheck__(obj) - class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta): + __slots__ = () def __new__(cls, *args, **kwds): if _geqv(cls, FrozenSet): @@ -1473,13 +1408,13 @@ class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView): pass -class KeysView(MappingView[KT_co], AbstractSet[KT_co], +class KeysView(MappingView[KT], AbstractSet[KT], extra=collections_abc.KeysView): pass -# TODO: Enable Set[Tuple[KT_co, VT_co]] instead of Generic[KT_co, VT_co]. -class ItemsView(MappingView, Generic[KT_co, VT_co], +# TODO: Enable Set[Tuple[KT, VT_co]] instead of Generic[KT, VT_co]. +class ItemsView(MappingView, Generic[KT, VT_co], extra=collections_abc.ItemsView): pass @@ -1488,20 +1423,7 @@ class ValuesView(MappingView[VT_co], extra=collections_abc.ValuesView): pass -class _DictMeta(GenericMeta): - - def __instancecheck__(self, obj): - if not super().__instancecheck__(obj): - return False - keytype, valuetype = self.__parameters__ - for key, value in obj.items(): - if not (isinstance(key, keytype) and - isinstance(value, valuetype)): - return False - return True - - -class Dict(dict, MutableMapping[KT, VT], metaclass=_DictMeta): +class Dict(dict, MutableMapping[KT, VT]): def __new__(cls, *args, **kwds): if _geqv(cls, Dict): @@ -1521,6 +1443,7 @@ else: class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co], extra=_G_base): + __slots__ = () def __new__(cls, *args, **kwds): if _geqv(cls, Generator): @@ -1564,6 +1487,8 @@ class IO(Generic[AnyStr]): way to track the other distinctions in the type system. """ + __slots__ = () + @abstractproperty def mode(self) -> str: pass @@ -1648,6 +1573,8 @@ class IO(Generic[AnyStr]): class BinaryIO(IO[bytes]): """Typed version of the return of open() in binary mode.""" + __slots__ = () + @abstractmethod def write(self, s: Union[bytes, bytearray]) -> int: pass @@ -1660,6 +1587,8 @@ class BinaryIO(IO[bytes]): class TextIO(IO[str]): """Typed version of the return of open() in text mode.""" + __slots__ = () + @abstractproperty def buffer(self) -> BinaryIO: pass |