iter_x = iter(t)
del iter_x
+ def test_paramspec_specialization(self):
+ # gh-124445
+ T = TypeVar("T")
+ U = TypeVar("U")
+ type X[**P] = Callable[P, int]
+
+ generic = X[[T]]
+ self.assertEqual(generic.__args__, ([T],))
+ self.assertEqual(generic.__parameters__, (T,))
+ specialized = generic[str]
+ self.assertEqual(specialized.__args__, ([str],))
+ self.assertEqual(specialized.__parameters__, ())
+
+ generic = X[(T,)]
+ self.assertEqual(generic.__args__, (T,))
+ self.assertEqual(generic.__parameters__, (T,))
+ specialized = generic[str]
+ self.assertEqual(specialized.__args__, (str,))
+ self.assertEqual(specialized.__parameters__, ())
+
+ generic = X[[T, U]]
+ self.assertEqual(generic.__args__, ([T, U],))
+ self.assertEqual(generic.__parameters__, (T, U))
+ specialized = generic[str, int]
+ self.assertEqual(specialized.__args__, ([str, int],))
+ self.assertEqual(specialized.__parameters__, ())
+
+ generic = X[(T, U)]
+ self.assertEqual(generic.__args__, (T, U))
+ self.assertEqual(generic.__parameters__, (T, U))
+ specialized = generic[str, int]
+ self.assertEqual(specialized.__args__, (str, int))
+ self.assertEqual(specialized.__parameters__, ())
+
+ def test_nested_paramspec_specialization(self):
+ # gh-124445
+ type X[**P, T] = Callable[P, T]
+
+ x_list = X[[int, str], float]
+ self.assertEqual(x_list.__args__, ([int, str], float))
+ self.assertEqual(x_list.__parameters__, ())
+
+ x_tuple = X[(int, str), float]
+ self.assertEqual(x_tuple.__args__, ((int, str), float))
+ self.assertEqual(x_tuple.__parameters__, ())
+
+ U = TypeVar("U")
+ V = TypeVar("V")
+
+ multiple_params_list = X[[int, U], V]
+ self.assertEqual(multiple_params_list.__args__, ([int, U], V))
+ self.assertEqual(multiple_params_list.__parameters__, (U, V))
+ multiple_params_list_specialized = multiple_params_list[str, float]
+ self.assertEqual(multiple_params_list_specialized.__args__, ([int, str], float))
+ self.assertEqual(multiple_params_list_specialized.__parameters__, ())
+
+ multiple_params_tuple = X[(int, U), V]
+ self.assertEqual(multiple_params_tuple.__args__, ((int, U), V))
+ self.assertEqual(multiple_params_tuple.__parameters__, (U, V))
+ multiple_params_tuple_specialized = multiple_params_tuple[str, float]
+ self.assertEqual(multiple_params_tuple_specialized.__args__, ((int, str), float))
+ self.assertEqual(multiple_params_tuple_specialized.__parameters__, ())
+
+ deeply_nested = X[[U, [V], int], V]
+ self.assertEqual(deeply_nested.__args__, ([U, [V], int], V))
+ self.assertEqual(deeply_nested.__parameters__, (U, V))
+ deeply_nested_specialized = deeply_nested[str, float]
+ self.assertEqual(deeply_nested_specialized.__args__, ([str, [float], int], float))
+ self.assertEqual(deeply_nested_specialized.__parameters__, ())
+
class TypeIterationTests(unittest.TestCase):
_UNITERABLE_TYPES = (list, tuple)
PyObject *
_Py_make_parameters(PyObject *args)
{
+ assert(PyTuple_Check(args) || PyList_Check(args));
+ const bool is_args_list = PyList_Check(args);
+ PyObject *tuple_args = NULL;
+ if (is_args_list) {
+ args = tuple_args = PySequence_Tuple(args);
+ if (args == NULL) {
+ return NULL;
+ }
+ }
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
Py_ssize_t len = nargs;
PyObject *parameters = PyTuple_New(len);
- if (parameters == NULL)
+ if (parameters == NULL) {
+ Py_XDECREF(tuple_args);
return NULL;
+ }
Py_ssize_t iparam = 0;
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
PyObject *t = PyTuple_GET_ITEM(args, iarg);
int rc = PyObject_HasAttrWithError(t, &_Py_ID(__typing_subst__));
if (rc < 0) {
Py_DECREF(parameters);
+ Py_XDECREF(tuple_args);
return NULL;
}
if (rc) {
if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__),
&subparams) < 0) {
Py_DECREF(parameters);
+ Py_XDECREF(tuple_args);
return NULL;
}
+ if (!subparams && (PyTuple_Check(t) || PyList_Check(t))) {
+ // Recursively call _Py_make_parameters for lists/tuples and
+ // add the results to the current parameters.
+ subparams = _Py_make_parameters(t);
+ if (subparams == NULL) {
+ Py_DECREF(parameters);
+ Py_XDECREF(tuple_args);
+ return NULL;
+ }
+ }
if (subparams && PyTuple_Check(subparams)) {
Py_ssize_t len2 = PyTuple_GET_SIZE(subparams);
Py_ssize_t needed = len2 - 1 - (iarg - iparam);
if (_PyTuple_Resize(¶meters, len) < 0) {
Py_DECREF(subparams);
Py_DECREF(parameters);
+ Py_XDECREF(tuple_args);
return NULL;
}
}
if (iparam < len) {
if (_PyTuple_Resize(¶meters, iparam) < 0) {
Py_XDECREF(parameters);
+ Py_XDECREF(tuple_args);
return NULL;
}
}
+ Py_XDECREF(tuple_args);
return parameters;
}
t = list[T]; t[int] -> newargs = [int]
t = dict[str, T]; t[int] -> newargs = [str, int]
t = dict[T, list[S]]; t[str, int] -> newargs = [str, list[int]]
+ t = list[[T]]; t[str] -> newargs = [[str]]
*/
+ assert (PyTuple_Check(args) || PyList_Check(args));
+ const bool is_args_list = PyList_Check(args);
+ PyObject *tuple_args = NULL;
+ if (is_args_list) {
+ args = tuple_args = PySequence_Tuple(args);
+ if (args == NULL) {
+ return NULL;
+ }
+ }
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
PyObject *newargs = PyTuple_New(nargs);
if (newargs == NULL) {
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return NULL;
}
for (Py_ssize_t iarg = 0, jarg = 0; iarg < nargs; iarg++) {
jarg++;
continue;
}
-
+ // Recursively substitute params in lists/tuples.
+ if (PyTuple_Check(arg) || PyList_Check(arg)) {
+ PyObject *subargs = _Py_subs_parameters(self, arg, parameters, item);
+ if (subargs == NULL) {
+ Py_DECREF(newargs);
+ Py_DECREF(item);
+ Py_XDECREF(tuple_args);
+ return NULL;
+ }
+ if (PyTuple_Check(arg)) {
+ PyTuple_SET_ITEM(newargs, jarg, subargs);
+ }
+ else {
+ // _Py_subs_parameters returns a tuple. If the original arg was a list,
+ // convert subargs to a list as well.
+ PyObject *subargs_list = PySequence_List(subargs);
+ Py_DECREF(subargs);
+ if (subargs_list == NULL) {
+ Py_DECREF(newargs);
+ Py_DECREF(item);
+ Py_XDECREF(tuple_args);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(newargs, jarg, subargs_list);
+ }
+ jarg++;
+ continue;
+ }
int unpack = _is_unpacked_typevartuple(arg);
if (unpack < 0) {
Py_DECREF(newargs);
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return NULL;
}
PyObject *subst;
if (PyObject_GetOptionalAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) {
Py_DECREF(newargs);
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return NULL;
}
if (subst) {
if (arg == NULL) {
Py_DECREF(newargs);
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return NULL;
}
if (unpack) {
Py_DECREF(arg);
if (jarg < 0) {
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return NULL;
}
}
}
Py_DECREF(item);
+ Py_XDECREF(tuple_args);
return newargs;
}