mirror of
https://github.com/python/cpython.git
synced 2024-11-27 11:55:13 +08:00
gh-94607: Fix subclassing generics (GH-94610)
Co-authored-by: Serhiy Storchaka <3659035+serhiy-storchaka@users.noreply.github.com>
This commit is contained in:
parent
8a285df806
commit
6442a9dd21
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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.
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user