https://github.com/python/cpython/commit/0fb82b46df7bc95c2ba816afba56ff6a6c51caaf
commit: 0fb82b46df7bc95c2ba816afba56ff6a6c51caaf
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-06-24T09:10:10-07:00
summary:
gh-151955: Allow more ParamSpec and TypeVarTuple bounds (#151956)
files:
A Misc/NEWS.d/next/Library/2026-06-22-18-01-00.gh-issue-151955.6u5iwm.rst
M Lib/test/test_typing.py
M Objects/typevarobject.c
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 042604ed7c1a42..ed07503cd63f12 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -1316,6 +1316,11 @@ def test_infer_variance(self):
def test_bound(self):
Ts_bound = TypeVarTuple('Ts_bound', bound=int)
self.assertIs(Ts_bound.__bound__, int)
+ Ts_tuple_bound = TypeVarTuple('Ts_tuple_bound', bound=(int, str))
+ self.assertEqual(Ts_tuple_bound.__bound__, (int, str))
+ obj = object()
+ Ts_object = TypeVarTuple('Ts_object', bound=obj)
+ self.assertIs(Ts_object.__bound__, obj)
Ts_no_bound = TypeVarTuple('Ts_no_bound')
self.assertIsNone(Ts_no_bound.__bound__)
@@ -10534,6 +10539,17 @@ def test_paramspec_in_nested_generics(self):
self.assertEqual(G2[[int, str], float], list[C])
self.assertEqual(G3[[int, str], float], list[C] | int)
+ def test_paramspec_bound(self):
+ P = ParamSpec('P', bound=[int, str])
+ self.assertEqual(P.__bound__, [int, str])
+ P2 = ParamSpec('P2', bound=(int, str))
+ self.assertEqual(P2.__bound__, (int, str))
+ obj = object()
+ P3 = ParamSpec('P3', bound=obj)
+ self.assertIs(P3.__bound__, obj)
+ P4 = ParamSpec('P4')
+ self.assertIs(P4.__bound__, None)
+
def test_paramspec_gets_copied(self):
# bpo-46581
P = ParamSpec('P')
diff --git
a/Misc/NEWS.d/next/Library/2026-06-22-18-01-00.gh-issue-151955.6u5iwm.rst
b/Misc/NEWS.d/next/Library/2026-06-22-18-01-00.gh-issue-151955.6u5iwm.rst
new file mode 100644
index 00000000000000..4cb5f04025327c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-22-18-01-00.gh-issue-151955.6u5iwm.rst
@@ -0,0 +1,2 @@
+Allow more types to be used in the ``bound`` argument to
+:class:`typing.ParamSpec` and :class:`typing.TypeVarTuple`.
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index 78750a955d2a49..b2c3c79c93ff19 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -1340,20 +1340,12 @@ paramspec_new_impl(PyTypeObject *type, PyObject *name,
PyObject *bound,
PyErr_SetString(PyExc_ValueError, "Variance cannot be specified with
infer_variance.");
return NULL;
}
- if (bound != NULL) {
- bound = type_check(bound, "Bound must be a type.");
- if (bound == NULL) {
- return NULL;
- }
- }
PyObject *module = caller();
if (module == NULL) {
- Py_XDECREF(bound);
return NULL;
}
PyObject *ps = (PyObject *)paramspec_alloc(
name, bound, default_value, covariant, contravariant, infer_variance,
module);
- Py_XDECREF(bound);
Py_DECREF(module);
return ps;
}
@@ -1634,23 +1626,12 @@ typevartuple_impl(PyTypeObject *type, PyObject *name,
PyObject *bound,
PyErr_SetString(PyExc_ValueError, "Variance cannot be specified with
infer_variance.");
return NULL;
}
- if (Py_IsNone(bound)) {
- bound = NULL;
- }
- if (bound != NULL) {
- bound = type_check(bound, "Bound must be a type.");
- if (bound == NULL) {
- return NULL;
- }
- }
PyObject *module = caller();
if (module == NULL) {
- Py_XDECREF(bound);
return NULL;
}
PyObject *result = (PyObject *)typevartuple_alloc(
name, bound, default_value, covariant, contravariant, infer_variance,
module);
- Py_XDECREF(bound);
Py_DECREF(module);
return result;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]