diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-07-09 05:20:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-09 05:20:43 (GMT) |
commit | b4e232c4b5d977578b3c6aa86d8b76085167c313 (patch) | |
tree | a8c08981ba28b0687a71cbdfd06bc695c1cd0f24 | |
parent | cb4359ccfc8f07cce6fbbd81f56fd252e1d7a6f5 (diff) | |
download | cpython-b4e232c4b5d977578b3c6aa86d8b76085167c313.zip cpython-b4e232c4b5d977578b3c6aa86d8b76085167c313.tar.gz cpython-b4e232c4b5d977578b3c6aa86d8b76085167c313.tar.bz2 |
gh-94607: Fix subclassing generics (GH-94610)
Co-authored-by: Serhiy Storchaka <3659035+serhiy-storchaka@users.noreply.github.com>
(cherry picked from commit 6442a9dd212fa18343db21849cf05c0181662c1f)
Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
-rw-r--r-- | Lib/test/test_typing.py | 29 | ||||
-rw-r--r-- | Lib/typing.py | 3 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-07-06-16-01-08.gh-issue-94607.Q6RYfz.rst | 2 | ||||
-rw-r--r-- | Objects/genericaliasobject.c | 4 |
4 files changed, 38 insertions, 0 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 634be90..2fd5782 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3644,6 +3644,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 1ebc3ce..3126927 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; |