Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9ca7b15

Browse files
[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.
1 parent 8648c06 commit 9ca7b15

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

Lib/_collections_abc.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ def __new__(cls, origin, args):
441441
def __parameters__(self):
442442
params = []
443443
for arg in self.__args__:
444+
if isinstance(arg, type) and not isinstance(arg, GenericAlias):
445+
continue
444446
# Looks like a genericalias
445447
if hasattr(arg, "__parameters__") and isinstance(arg.__parameters__, tuple):
446448
params.extend(arg.__parameters__)
@@ -486,6 +488,9 @@ def __getitem__(self, item):
486488
subst = dict(zip(self.__parameters__, item))
487489
new_args = []
488490
for arg in self.__args__:
491+
if isinstance(arg, type) and not isinstance(arg, GenericAlias):
492+
new_args.append(arg)
493+
continue
489494
if _is_typevarlike(arg):
490495
if _is_param_expr(arg):
491496
arg = subst[arg]

Lib/test/test_typing.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,6 +2498,61 @@ def test_subclass_special_form(self):
24982498
class Foo(obj):
24992499
pass
25002500

2501+
def test_complex_subclasses(self):
2502+
T_co = TypeVar("T_co", covariant=True)
2503+
2504+
class Base(Generic[T_co]):
2505+
...
2506+
2507+
T = TypeVar("T")
2508+
2509+
# see gh-94607: this fails in that bug
2510+
class Sub(Base, Generic[T]):
2511+
...
2512+
2513+
def test_parameter_detection(self):
2514+
self.assertEqual(List[T].__parameters__, (T,))
2515+
self.assertEqual(List[List[T]].__parameters__, (T,))
2516+
class A:
2517+
__parameters__ = (T,)
2518+
# Bare classes should be skipped
2519+
for a in (List, list):
2520+
for b in (int, TypeVar, ParamSpec, types.GenericAlias, types.UnionType):
2521+
with self.subTest(generic=a, sub=b):
2522+
with self.assertRaisesRegex(TypeError,
2523+
'.* is not a generic class|'
2524+
'no type variables left'):
2525+
a[b][str]
2526+
# Duck-typing anything that looks like it has __parameters__.
2527+
# C version of GenericAlias
2528+
self.assertEqual(list[A()].__parameters__, (T,))
2529+
2530+
def test_non_generic_subscript(self):
2531+
T = TypeVar('T')
2532+
class G(Generic[T]):
2533+
pass
2534+
2535+
for s in (int, G, List, list,
2536+
TypeVar, ParamSpec,
2537+
types.GenericAlias, types.UnionType):
2538+
2539+
for t in Tuple, tuple:
2540+
with self.subTest(tuple=t, sub=s):
2541+
self.assertEqual(t[s, T][int], t[s, int])
2542+
self.assertEqual(t[T, s][int], t[int, s])
2543+
a = t[s]
2544+
with self.assertRaises(TypeError):
2545+
a[int]
2546+
2547+
for c in Callable, collections.abc.Callable:
2548+
with self.subTest(callable=c, sub=s):
2549+
self.assertEqual(c[[s], T][int], c[[s], int])
2550+
self.assertEqual(c[[T], s][int], c[[int], s])
2551+
a = c[[s], s]
2552+
with self.assertRaises(TypeError):
2553+
a[int]
2554+
2555+
25012556
class ClassVarTests(BaseTestCase):
25022557

25032558
def test_basics(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix subscription of :class:`types.GenericAlias` instances containing bare
2+
generic types: for example ``tuple[A, T][int]``,
3+
where ``A`` is a generic type, and ``T`` is a type variable.

Objects/genericaliasobject.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ _Py_make_parameters(PyObject *args)
209209
Py_ssize_t iparam = 0;
210210
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
211211
PyObject *t = PyTuple_GET_ITEM(args, iarg);
212+
if (PyType_Check(t)) {
213+
continue;
214+
}
212215
int typevar = is_typevar(t);
213216
if (typevar < 0) {
214217
Py_DECREF(parameters);
@@ -260,6 +263,11 @@ _Py_make_parameters(PyObject *args)
260263
static PyObject *
261264
subs_tvars(PyObject *obj, PyObject *params, PyObject **argitems)
262265
{
266+
if (PyType_Check(obj)) {
267+
Py_INCREF(obj);
268+
return obj;
269+
}
270+
263271
_Py_IDENTIFIER(__parameters__);
264272
PyObject *subparams;
265273
if (_PyObject_LookupAttrId(obj, &PyId___parameters__, &subparams) < 0) {

0 commit comments

Comments
 (0)