Skip to content
Snippets Groups Projects
Unverified Commit 6442a9dd authored by Ken Jin's avatar Ken Jin Committed by GitHub
Browse files

gh-94607: Fix subclassing generics (GH-94610)

parent 8a285df8
No related branches found
No related tags found
No related merge requests found
...@@ -3650,6 +3650,35 @@ def test_subclass_special_form(self): ...@@ -3650,6 +3650,35 @@ def test_subclass_special_form(self):
class Foo(obj): class Foo(obj):
pass 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): class ClassVarTests(BaseTestCase):
def test_basics(self): def test_basics(self):
......
...@@ -250,6 +250,9 @@ def _collect_parameters(args): ...@@ -250,6 +250,9 @@ def _collect_parameters(args):
""" """
parameters = [] parameters = []
for t in args: 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 hasattr(t, '__typing_subst__'):
if t not in parameters: if t not in parameters:
parameters.append(t) parameters.append(t)
......
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) ...@@ -219,6 +219,10 @@ _Py_make_parameters(PyObject *args)
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
PyObject *t = PyTuple_GET_ITEM(args, iarg); PyObject *t = PyTuple_GET_ITEM(args, iarg);
PyObject *subst; 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) { if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) {
Py_DECREF(parameters); Py_DECREF(parameters);
return NULL; return NULL;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment