import abc import typing from typing import ( # noqa # These are imported for re-export. ClassVar, Type, Generic, Callable, GenericMeta, TypingMeta, Counter, DefaultDict, Deque, TypeVar, Tuple, Final, final, NewType, overload, Text, TYPE_CHECKING, Literal, TypedDict, Protocol, SupportsIndex, runtime_checkable, # We use internal typing helpers here, but this significantly reduces # code duplication. (Also this is only until Protocol is in typing.) _type_vars, _tp_cache, _type_check, ) # Please keep __all__ alphabetized within each category. __all__ = [ # Super-special typing primitives. 'ClassVar', 'Final', 'Protocol', 'Type', 'TypedDict', # Concrete collection types. 'ContextManager', 'Counter', 'Deque', 'DefaultDict', # Structural checks, a.k.a. protocols. 'SupportsIndex', # One-off things. 'final', 'IntVar', 'Literal', 'NewType', 'overload', 'runtime_checkable', 'Text', 'TYPE_CHECKING', ] if hasattr(typing, 'NoReturn'): NoReturn = typing.NoReturn else: # TODO: Remove once typing.py has been updated class _NoReturnMeta(typing.TypingMeta): """Metaclass for NoReturn.""" def __new__(cls, name, bases, namespace): cls.assert_no_subclassing(bases) self = super(_NoReturnMeta, cls).__new__(cls, name, bases, namespace) return self class _NoReturn(typing._FinalTypingBase): """Special type indicating functions that never return. Example:: from typing import NoReturn def stop() -> NoReturn: raise Exception('no way') This type is invalid in other positions, e.g., ``List[NoReturn]`` will fail in static type checkers. """ __metaclass__ = _NoReturnMeta __slots__ = () def __instancecheck__(self, obj): raise TypeError("NoReturn cannot be used with isinstance().") def __subclasscheck__(self, cls): raise TypeError("NoReturn cannot be used with issubclass().") NoReturn = _NoReturn(_root=True) T_co = typing.TypeVar('T_co', covariant=True) if hasattr(typing, 'ContextManager'): ContextManager = typing.ContextManager else: # TODO: Remove once typing.py has been updated class ContextManager(typing.Generic[T_co]): __slots__ = () def __enter__(self): return self @abc.abstractmethod def __exit__(self, exc_type, exc_value, traceback): return None @classmethod def __subclasshook__(cls, C): if cls is ContextManager: # In Python 3.6+, it is possible to set a method to None to # explicitly indicate that the class does not implement an ABC # (https://bugs.python.org/issue25958), but we do not support # that pattern here because this fallback class is only used # in Python 3.5 and earlier. if (any("__enter__" in B.__dict__ for B in C.__mro__) and any("__exit__" in B.__dict__ for B in C.__mro__)): return True return NotImplemented def IntVar(name): return TypeVar(name) def _is_dunder(name): """Returns True if name is a __dunder_variable_name__.""" return len(name) > 4 and name.startswith('__') and name.endswith('__') class AnnotatedMeta(GenericMeta): """Metaclass for Annotated""" def __new__(cls, name, bases, namespace, **kwargs): if any(b is not object for b in bases): raise TypeError("Cannot subclass %s" % Annotated) return super(AnnotatedMeta, cls).__new__(cls, name, bases, namespace, **kwargs) @property def __metadata__(self): return self._subs_tree()[2] def _tree_repr(self, tree): cls, origin, metadata = tree if not isinstance(origin, tuple): tp_repr = typing._type_repr(origin) else: tp_repr = origin[0]._tree_repr(origin) metadata_reprs = ", ".join(repr(arg) for arg in metadata) return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs) def _subs_tree(self, tvars=None, args=None): if self is Annotated: return Annotated res = super(AnnotatedMeta, self)._subs_tree(tvars=tvars, args=args) # Flatten nested Annotated if isinstance(res[1], tuple) and res[1][0] is Annotated: sub_tp = res[1][1] sub_annot = res[1][2] return (Annotated, sub_tp, sub_annot + res[2]) return res def _get_cons(self): """Return the class used to create instance of this type.""" if self.__origin__ is None: raise TypeError("Cannot get the underlying type of a non-specialized " "Annotated type.") tree = self._subs_tree() while isinstance(tree, tuple) and tree[0] is Annotated: tree = tree[1] if isinstance(tree, tuple): return tree[0] else: return tree @_tp_cache def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) if self.__origin__ is not None: # specializing an instantiated type return super(AnnotatedMeta, self).__getitem__(params) elif not isinstance(params, tuple) or len(params) < 2: raise TypeError("Annotated[...] should be instantiated with at " "least two arguments (a type and an annotation).") else: msg = "Annotated[t, ...]: t must be a type." tp = typing._type_check(params[0], msg) metadata = tuple(params[1:]) return self.__class__( self.__name__, self.__bases__, dict(self.__dict__), tvars=_type_vars((tp,)), # Metadata is a tuple so it won't be touched by _replace_args et al. args=(tp, metadata), origin=self, ) def __call__(self, *args, **kwargs): cons = self._get_cons() result = cons(*args, **kwargs) try: result.__orig_class__ = self except AttributeError: pass return result def __getattr__(self, attr): # For simplicity we just don't relay all dunder names if self.__origin__ is not None and not _is_dunder(attr): return getattr(self._get_cons(), attr) raise AttributeError(attr) def __setattr__(self, attr, value): if _is_dunder(attr) or attr.startswith('_abc_'): super(AnnotatedMeta, self).__setattr__(attr, value) elif self.__origin__ is None: raise AttributeError(attr) else: setattr(self._get_cons(), attr, value) class Annotated(object): """Add context specific metadata to a type. Example: Annotated[int, runtime_check.Unsigned] indicates to the hypothetical runtime_check module that this type is an unsigned int. Every other consumer of this type can ignore this metadata and treat this type as int. The first argument to Annotated must be a valid type, the remaining arguments are kept as a tuple in the __metadata__ field. Details: - It's an error to call `Annotated` with less than two arguments. - Nested Annotated are flattened:: Annotated[Annotated[int, Ann1, Ann2], Ann3] == Annotated[int, Ann1, Ann2, Ann3] - Instantiating an annotated type is equivalent to instantiating the underlying type:: Annotated[C, Ann1](5) == C(5) - Annotated can be used as a generic type alias:: Optimized = Annotated[T, runtime.Optimize()] Optimized[int] == Annotated[int, runtime.Optimize()] OptimizedList = Annotated[List[T], runtime.Optimize()] OptimizedList[int] == Annotated[List[int], runtime.Optimize()] """ __metaclass__ = AnnotatedMeta __slots__ = () class _TypeAliasMeta(typing.TypingMeta): """Metaclass for TypeAlias""" def __new__(cls, name, bases, namespace): cls.assert_no_subclassing(bases) self = super(_TypeAliasMeta, cls).__new__(cls, name, bases, namespace) return self def __repr__(self): return 'typing_extensions.TypeAlias' class _TypeAliasBase(typing._FinalTypingBase): """Special marker indicating that an assignment should be recognized as a proper type alias definition by type checkers. For example:: Predicate = Callable[..., bool] # type: TypeAlias It's invalid when used anywhere except as in the example above. """ __metaclass__ = _TypeAliasMeta __slots__ = () def __instancecheck__(self, obj): raise TypeError("TypeAlias cannot be used with isinstance().") def __subclasscheck__(self, cls): raise TypeError("TypeAlias cannot be used with issubclass().") def __repr__(self): return 'typing_extensions.TypeAlias' TypeAlias = _TypeAliasBase(_root=True) # This alias exists for backwards compatibility. runtime = runtime_checkable