diff options
author | Matthew Rahtz <matthew.rahtz@gmail.com> | 2022-05-08 13:21:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-08 13:21:28 (GMT) |
commit | 4739997e141c4c84bd2241d4d887c3c658d92700 (patch) | |
tree | 1a9b1122fa1e67eef25e799896bb1f1b482a19f4 /Lib/typing.py | |
parent | 788ef54bc94b0a7aa2a93f626e4067ab8561424c (diff) | |
download | cpython-4739997e141c4c84bd2241d4d887c3c658d92700.zip cpython-4739997e141c4c84bd2241d4d887c3c658d92700.tar.gz cpython-4739997e141c4c84bd2241d4d887c3c658d92700.tar.bz2 |
gh-92261: Disallow iteration of Union (and other special forms) (GH-92262)
Diffstat (limited to 'Lib/typing.py')
-rw-r--r-- | Lib/typing.py | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/Lib/typing.py b/Lib/typing.py index bdc14e3..46ef2d9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -405,9 +405,24 @@ class _Immutable: return self +class _NotIterable: + """Mixin to prevent iteration, without being compatible with Iterable. + + That is, we could do: + def __iter__(self): raise TypeError() + But this would make users of this mixin duck type-compatible with + collections.abc.Iterable - isinstance(foo, Iterable) would be True. + + Luckily, we can instead prevent iteration by setting __iter__ to None, which + is treated specially. + """ + + __iter__ = None + + # Internal indicator of special typing constructs. # See __doc__ instance attribute for specific docs. -class _SpecialForm(_Final, _root=True): +class _SpecialForm(_Final, _NotIterable, _root=True): __slots__ = ('_name', '__doc__', '_getitem') def __init__(self, getitem): @@ -1498,7 +1513,7 @@ class _GenericAlias(_BaseGenericAlias, _root=True): # 1 for List and 2 for Dict. It may be -1 if variable number of # parameters are accepted (needs custom __getitem__). -class _SpecialGenericAlias(_BaseGenericAlias, _root=True): +class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True): def __init__(self, origin, nparams, *, inst=True, name=None): if name is None: name = origin.__name__ @@ -1541,7 +1556,7 @@ class _SpecialGenericAlias(_BaseGenericAlias, _root=True): def __ror__(self, left): return Union[left, self] -class _CallableGenericAlias(_GenericAlias, _root=True): +class _CallableGenericAlias(_NotIterable, _GenericAlias, _root=True): def __repr__(self): assert self._name == 'Callable' args = self.__args__ @@ -1606,7 +1621,7 @@ class _TupleType(_SpecialGenericAlias, _root=True): return self.copy_with(params) -class _UnionGenericAlias(_GenericAlias, _root=True): +class _UnionGenericAlias(_NotIterable, _GenericAlias, _root=True): def copy_with(self, params): return Union[params] @@ -2046,7 +2061,7 @@ class Protocol(Generic, metaclass=_ProtocolMeta): cls.__init__ = _no_init_or_replace_init -class _AnnotatedAlias(_GenericAlias, _root=True): +class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True): """Runtime representation of an annotated type. At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' |