summaryrefslogtreecommitdiffstats
path: root/Lib/typing.py
diff options
context:
space:
mode:
authorMatthew Rahtz <matthew.rahtz@gmail.com>2022-05-08 13:21:28 (GMT)
committerGitHub <noreply@github.com>2022-05-08 13:21:28 (GMT)
commit4739997e141c4c84bd2241d4d887c3c658d92700 (patch)
tree1a9b1122fa1e67eef25e799896bb1f1b482a19f4 /Lib/typing.py
parent788ef54bc94b0a7aa2a93f626e4067ab8561424c (diff)
downloadcpython-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.py25
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'