]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-151955: Allow more ParamSpec and TypeVarTuple bounds (#151956)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Wed, 24 Jun 2026 16:10:10 +0000 (09:10 -0700)
committerGitHub <noreply@github.com>
Wed, 24 Jun 2026 16:10:10 +0000 (09:10 -0700)
Lib/test/test_typing.py
Misc/NEWS.d/next/Library/2026-06-22-18-01-00.gh-issue-151955.6u5iwm.rst [new file with mode: 0644]
Objects/typevarobject.c

index 042604ed7c1a42399279068c22dd4bdb62b5aa3d..ed07503cd63f12b83ec8dffabc3837a23d5c8f83 100644 (file)
@@ -1316,6 +1316,11 @@ class TypeVarTupleTests(BaseTestCase):
     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 @@ class ParamSpecTests(BaseTestCase):
         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 (file)
index 0000000..4cb5f04
--- /dev/null
@@ -0,0 +1,2 @@
+Allow more types to be used in the ``bound`` argument to
+:class:`typing.ParamSpec` and :class:`typing.TypeVarTuple`.
index 78750a955d2a4924d064833291b9cdb955afa976..b2c3c79c93ff1952ca19edfc5a7b544737de2af1 100644 (file)
@@ -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;
 }