if (isinstance(arg, _GenericAlias) and
arg.__origin__ in invalid_generic_forms):
raise TypeError(f"{arg} is not valid as type argument")
- if (isinstance(arg, _SpecialForm) and arg not in (Any, NoReturn) or
- arg in (Generic, Protocol)):
+ if arg in (Any, NoReturn):
+ return arg
+ if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol):
raise TypeError(f"Plain {arg} is not valid as type argument")
if isinstance(arg, (type, TypeVar, ForwardRef)):
return arg
return self
-class _SpecialForm(_Final, _Immutable, _root=True):
- """Internal indicator of special typing constructs.
- See _doc instance attribute for specific docs.
- """
-
- __slots__ = ('_name', '_doc')
-
- def __new__(cls, *args, **kwds):
- """Constructor.
-
- This only exists to give a better error message in case
- someone tries to subclass a special typing object (not a good idea).
- """
- if (len(args) == 3 and
- isinstance(args[0], str) and
- isinstance(args[1], tuple)):
- # Close enough.
- raise TypeError(f"Cannot subclass {cls!r}")
- return super().__new__(cls)
-
- def __init__(self, name, doc):
- self._name = name
- self._doc = doc
-
- @property
- def __doc__(self):
- return self._doc
+# Internal indicator of special typing constructs.
+# See __doc__ instance attribute for specific docs.
+class _SpecialForm(_Final, _root=True):
+ __slots__ = ('_name', '__doc__', '_getitem')
- def __eq__(self, other):
- if not isinstance(other, _SpecialForm):
- return NotImplemented
- return self._name == other._name
+ def __init__(self, getitem):
+ self._getitem = getitem
+ self._name = getitem.__name__
+ self.__doc__ = getitem.__doc__
- def __hash__(self):
- return hash((self._name,))
+ def __mro_entries__(self, bases):
+ raise TypeError(f"Cannot subclass {self!r}")
def __repr__(self):
return 'typing.' + self._name
@_tp_cache
def __getitem__(self, parameters):
- if self._name in ('ClassVar', 'Final'):
- item = _type_check(parameters, f'{self._name} accepts only single type.')
- return _GenericAlias(self, (item,))
- if self._name == 'Union':
- if parameters == ():
- raise TypeError("Cannot take a Union of no types.")
- if not isinstance(parameters, tuple):
- parameters = (parameters,)
- msg = "Union[arg, ...]: each arg must be a type."
- parameters = tuple(_type_check(p, msg) for p in parameters)
- parameters = _remove_dups_flatten(parameters)
- if len(parameters) == 1:
- return parameters[0]
- return _GenericAlias(self, parameters)
- if self._name == 'Optional':
- arg = _type_check(parameters, "Optional[t] requires a single type.")
- return Union[arg, type(None)]
- if self._name == 'Literal':
- # There is no '_type_check' call because arguments to Literal[...] are
- # values, not types.
- return _GenericAlias(self, parameters)
- raise TypeError(f"{self} is not subscriptable")
-
-
-Any = _SpecialForm('Any', doc=
+ return self._getitem(self, parameters)
+
+@_SpecialForm
+def Any(self, parameters):
"""Special type indicating an unconstrained type.
- Any is compatible with every type.
Note that all the above statements are true from the point of view of
static type checkers. At runtime, Any should not be used with instance
or class checks.
- """)
+ """
+ raise TypeError(f"{self} is not subscriptable")
-NoReturn = _SpecialForm('NoReturn', doc=
+@_SpecialForm
+def NoReturn(self, parameters):
"""Special type indicating functions that never return.
Example::
This type is invalid in other positions, e.g., ``List[NoReturn]``
will fail in static type checkers.
- """)
+ """
+ raise TypeError(f"{self} is not subscriptable")
-ClassVar = _SpecialForm('ClassVar', doc=
+@_SpecialForm
+def ClassVar(self, parameters):
"""Special type construct to mark class variables.
An annotation wrapped in ClassVar indicates that a given
Note that ClassVar is not a class itself, and should not
be used with isinstance() or issubclass().
- """)
+ """
+ item = _type_check(parameters, f'{self} accepts only single type.')
+ return _GenericAlias(self, (item,))
-Final = _SpecialForm('Final', doc=
+@_SpecialForm
+def Final(self, parameters):
"""Special typing construct to indicate final names to type checkers.
A final name cannot be re-assigned or overridden in a subclass.
TIMEOUT = 1 # Error reported by type checker
There is no runtime checking of these properties.
- """)
+ """
+ item = _type_check(parameters, f'{self} accepts only single type.')
+ return _GenericAlias(self, (item,))
-Union = _SpecialForm('Union', doc=
+@_SpecialForm
+def Union(self, parameters):
"""Union type; Union[X, Y] means either X or Y.
To define a union, use e.g. Union[int, str]. Details:
- You cannot subclass or instantiate a union.
- You can use Optional[X] as a shorthand for Union[X, None].
- """)
-
-Optional = _SpecialForm('Optional', doc=
+ """
+ if parameters == ():
+ raise TypeError("Cannot take a Union of no types.")
+ if not isinstance(parameters, tuple):
+ parameters = (parameters,)
+ msg = "Union[arg, ...]: each arg must be a type."
+ parameters = tuple(_type_check(p, msg) for p in parameters)
+ parameters = _remove_dups_flatten(parameters)
+ if len(parameters) == 1:
+ return parameters[0]
+ return _GenericAlias(self, parameters)
+
+@_SpecialForm
+def Optional(self, parameters):
"""Optional type.
Optional[X] is equivalent to Union[X, None].
- """)
+ """
+ arg = _type_check(parameters, f"{self} requires a single type.")
+ return Union[arg, type(None)]
-Literal = _SpecialForm('Literal', doc=
+@_SpecialForm
+def Literal(self, parameters):
"""Special typing form to define literal types (a.k.a. value types).
This form can be used to indicate to type checkers that the corresponding
open_helper('/some/path', 'r') # Passes type check
open_helper('/other/path', 'typo') # Error in type checker
- Literal[...] cannot be subclassed. At runtime, an arbitrary value
- is allowed as type argument to Literal[...], but type checkers may
- impose restrictions.
- """)
+ Literal[...] cannot be subclassed. At runtime, an arbitrary value
+ is allowed as type argument to Literal[...], but type checkers may
+ impose restrictions.
+ """
+ # There is no '_type_check' call because arguments to Literal[...] are
+ # values, not types.
+ return _GenericAlias(self, parameters)
class ForwardRef(_Final, _root=True):