8000 [3.11] gh-94607: Fix subclassing generics (GH-94610) by miss-islington · Pull Request #94704 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

[3.11] gh-94607: Fix subclassing generics (GH-94610) #94704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
gh-94607: Fix subclassing generics (GH-94610)
Co-authored-by: Serhiy Storchaka <3659035+serhiy-storchaka@users.noreply.github.com>
(cherry picked from commit 6442a9d)

Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com>
  • Loading branch information
Fidget-Spinner authored and miss-islington committed Jul 9, 2022
commit 5719e7fe915630ce8936b884d43486c856721adc
29 changes: 29 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3644,6 +3644,35 @@ def test_subclass_special_form(self):
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):
Expand Down
3 changes: 3 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 4 additions & 0 deletions Objects/genericaliasobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
0