summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>2022-07-09 04:18:01 (GMT)
committerGitHub <noreply@github.com>2022-07-09 04:18:01 (GMT)
commit6442a9dd212fa18343db21849cf05c0181662c1f (patch)
tree469397015575dee1c5969762b7323508857053cd
parent8a285df806816805484fed36dce5fd5b77a215a6 (diff)
downloadcpython-6442a9dd212fa18343db21849cf05c0181662c1f.zip
cpython-6442a9dd212fa18343db21849cf05c0181662c1f.tar.gz
cpython-6442a9dd212fa18343db21849cf05c0181662c1f.tar.bz2
gh-94607: Fix subclassing generics (GH-94610)
Co-authored-by: Serhiy Storchaka <3659035+serhiy-storchaka@users.noreply.github.com>
-rw-r--r--Lib/test/test_typing.py29
-rw-r--r--Lib/typing.py3
-rw-r--r--Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst2
-rw-r--r--Objects/genericaliasobject.c4
4 files changed, 38 insertions, 0 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 6850b88..3f41014 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -3650,6 +3650,35 @@ class GenericTests(BaseTestCase):
class Foo(obj):
pass
+ def test_complex_subclasses(self):
+ T_co = TypeVar("T_co", covariant=True)
+
+ class Base(Generic[T_co]):
+ ...
+
+ T = TypeVar("T")
+
+ # see gh-94607: this fails in that bug
+ class Sub(Base, Generic[T]):
+ ...
+
+ def test_parameter_detection(self):
+ self.assertEqual(List[T].__parameters__, (T,))
+ self.assertEqual(List[List[T]].__parameters__, (T,))
+ class A:
+ __parameters__ = (T,)
+ # Bare classes should be skipped
+ for a in (List, list):
+ for b in (A, int, TypeVar, TypeVarTuple, ParamSpec, types.GenericAlias, types.UnionType):
+ with self.subTest(generic=a, sub=b):
+ with self.assertRaisesRegex(TypeError, '.* is not a generic class'):
+ a[b][str]
+ # Duck-typing anything that looks like it has __parameters__.
+ # These tests are optional and failure is okay.
+ self.assertEqual(List[A()].__parameters__, (T,))
+ # C version of GenericAlias
+ self.assertEqual(list[A()].__parameters__, (T,))
+
class ClassVarTests(BaseTestCase):
def test_basics(self):
diff --git a/Lib/typing.py b/Lib/typing.py
index 25ae19f..66c26e4 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -250,6 +250,9 @@ def _collect_parameters(args):
"""
parameters = []
for t in args:
+ # We don't want __parameters__ descriptor of a bare Python class.
+ if isinstance(t, type):
+ continue
if hasattr(t, '__typing_subst__'):
if t not in parameters:
parameters.append(t)
diff --git a/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst b/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst
new file mode 100644
index 0000000..3bbb917
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst
@@ -0,0 +1,2 @@
+Fix subclassing complex generics with type variables in :mod:`typing`. Previously an error message saying ``Some type variables ... are not listed in Generic[...]`` was shown.
+:mod:`typing` no longer populates ``__parameters__`` with the ``__parameters__`` of a Python class.
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index b2636d5..19f011f 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -219,6 +219,10 @@ _Py_make_parameters(PyObject *args)
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
PyObject *t = PyTuple_GET_ITEM(args, iarg);
PyObject *subst;
+ // We don't want __parameters__ descriptor of a bare Python class.
+ if (PyType_Check(t)) {
+ continue;
+ }
if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) {
Py_DECREF(parameters);
return NULL;