[Python-checkins] [3.10] gh-98852: Fix subscription of types.GenericAlias instances (GH-98920) (GH-98969)
serhiy-storchaka
webhook-mailer at python.org
Tue Nov 1 14:14:43 EDT 2022
https://github.com/python/cpython/commit/9ca7b1561f8a298a1d5917dcaae5a654ac0766b1
commit: 9ca7b1561f8a298a1d5917dcaae5a654ac0766b1
branch: 3.10
author: Serhiy Storchaka <storchaka at gmail.com>
committer: serhiy-storchaka <storchaka at gmail.com>
date: 2022-11-01T20:14:38+02:00
summary:
[3.10] gh-98852: Fix subscription of types.GenericAlias instances (GH-98920) (GH-98969)
Fix subscription of types.GenericAlias instances containing bare generic types:
for example tuple[A, T][int], where A is a generic type, and T is a type
variable.
files:
A Misc/NEWS.d/next/Core and Builtins/2022-10-31-21-01-35.gh-issue-98852.MYaRN6.rst
M Lib/_collections_abc.py
M Lib/test/test_typing.py
M Objects/genericaliasobject.c
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index 40417dc1d313..72fd633cf9ac 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -441,6 +441,8 @@ def __new__(cls, origin, args):
def __parameters__(self):
params = []
for arg in self.__args__:
+ if isinstance(arg, type) and not isinstance(arg, GenericAlias):
+ continue
# Looks like a genericalias
if hasattr(arg, "__parameters__") and isinstance(arg.__parameters__, tuple):
params.extend(arg.__parameters__)
@@ -486,6 +488,9 @@ def __getitem__(self, item):
subst = dict(zip(self.__parameters__, item))
new_args = []
for arg in self.__args__:
+ if isinstance(arg, type) and not isinstance(arg, GenericAlias):
+ new_args.append(arg)
+ continue
if _is_typevarlike(arg):
if _is_param_expr(arg):
arg = subst[arg]
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 34f944416070..6c53154686c9 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -2498,6 +2498,61 @@ 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 (int, TypeVar, ParamSpec, types.GenericAlias, types.UnionType):
+ with self.subTest(generic=a, sub=b):
+ with self.assertRaisesRegex(TypeError,
+ '.* is not a generic class|'
+ 'no type variables left'):
+ a[b][str]
+ # Duck-typing anything that looks like it has __parameters__.
+ # C version of GenericAlias
+ self.assertEqual(list[A()].__parameters__, (T,))
+
+ def test_non_generic_subscript(self):
+ T = TypeVar('T')
+ class G(Generic[T]):
+ pass
+
+ for s in (int, G, List, list,
+ TypeVar, ParamSpec,
+ types.GenericAlias, types.UnionType):
+
+ for t in Tuple, tuple:
+ with self.subTest(tuple=t, sub=s):
+ self.assertEqual(t[s, T][int], t[s, int])
+ self.assertEqual(t[T, s][int], t[int, s])
+ a = t[s]
+ with self.assertRaises(TypeError):
+ a[int]
+
+ for c in Callable, collections.abc.Callable:
+ with self.subTest(callable=c, sub=s):
+ self.assertEqual(c[[s], T][int], c[[s], int])
+ self.assertEqual(c[[T], s][int], c[[int], s])
+ a = c[[s], s]
+ with self.assertRaises(TypeError):
+ a[int]
+
+
class ClassVarTests(BaseTestCase):
def test_basics(self):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-31-21-01-35.gh-issue-98852.MYaRN6.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-31-21-01-35.gh-issue-98852.MYaRN6.rst
new file mode 100644
index 000000000000..25c473717ca2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-31-21-01-35.gh-issue-98852.MYaRN6.rst
@@ -0,0 +1,3 @@
+Fix subscription of :class:`types.GenericAlias` instances containing bare
+generic types: for example ``tuple[A, T][int]``,
+where ``A`` is a generic type, and ``T`` is a type variable.
diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c
index f52bc974f4d8..9edb6d23725d 100644
--- a/Objects/genericaliasobject.c
+++ b/Objects/genericaliasobject.c
@@ -209,6 +209,9 @@ _Py_make_parameters(PyObject *args)
Py_ssize_t iparam = 0;
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
PyObject *t = PyTuple_GET_ITEM(args, iarg);
+ if (PyType_Check(t)) {
+ continue;
+ }
int typevar = is_typevar(t);
if (typevar < 0) {
Py_DECREF(parameters);
@@ -260,6 +263,11 @@ _Py_make_parameters(PyObject *args)
static PyObject *
subs_tvars(PyObject *obj, PyObject *params, PyObject **argitems)
{
+ if (PyType_Check(obj)) {
+ Py_INCREF(obj);
+ return obj;
+ }
+
_Py_IDENTIFIER(__parameters__);
PyObject *subparams;
if (_PyObject_LookupAttrId(obj, &PyId___parameters__, &subparams) < 0) {
More information about the Python-checkins
mailing list