aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/typing-extensions/py2/src_py2/typing_extensions.py
blob: 62d1e46c7217d63f11200ae74d2c7519aeee1cef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
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