]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-140348: Fix using | on unusual objects plus Unions (GH-140383) (#140948)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 3 Nov 2025 15:16:03 +0000 (16:16 +0100)
committerGitHub <noreply@github.com>
Mon, 3 Nov 2025 15:16:03 +0000 (15:16 +0000)
gh-140348: Fix using | on unusual objects plus Unions (GH-140383)
(cherry picked from commit 7a9437d98641e3c3749ab2fd9fb54eac7614f9af)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Lib/test/test_typing.py
Misc/NEWS.d/next/Library/2025-10-20-12-33-49.gh-issue-140348.SAKnQZ.rst [new file with mode: 0644]
Objects/unionobject.c

index 4b8280b647f647b9dff8e5b4efbbaa71b1f2b69d..b660368144b1cd3a23577b60c5dd392289a26943 100644 (file)
@@ -2277,6 +2277,15 @@ class UnionTests(BaseTestCase):
         self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__,
                          (Literal[1], Literal[Ints.B], Literal[True]))
 
+    def test_allow_non_types_in_or(self):
+        # gh-140348: Test that using | with a Union object allows things that are
+        # not allowed by is_unionable().
+        U1 = Union[int, str]
+        self.assertEqual(U1 | float, Union[int, str, float])
+        self.assertEqual(U1 | "float", Union[int, str, "float"])
+        self.assertEqual(float | U1, Union[float, int, str])
+        self.assertEqual("float" | U1, Union["float", int, str])
+
 
 class TupleTests(BaseTestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2025-10-20-12-33-49.gh-issue-140348.SAKnQZ.rst b/Misc/NEWS.d/next/Library/2025-10-20-12-33-49.gh-issue-140348.SAKnQZ.rst
new file mode 100644 (file)
index 0000000..16d5b2a
--- /dev/null
@@ -0,0 +1,3 @@
+Fix regression in Python 3.14.0 where using the ``|`` operator on a
+:class:`typing.Union` object combined with an object that is not a type
+would raise an error.
index c4ece0fe09f01854bc5494568203179f4061347c..a47d6193d7088977907c014bb28212ab08f31ff8 100644 (file)
@@ -393,8 +393,23 @@ static PyGetSetDef union_properties[] = {
     {0}
 };
 
+static PyObject *
+union_nb_or(PyObject *a, PyObject *b)
+{
+    unionbuilder ub;
+    if (!unionbuilder_init(&ub, true)) {
+        return NULL;
+    }
+    if (!unionbuilder_add_single(&ub, a) ||
+        !unionbuilder_add_single(&ub, b)) {
+        unionbuilder_finalize(&ub);
+        return NULL;
+    }
+    return make_union(&ub);
+}
+
 static PyNumberMethods union_as_number = {
-        .nb_or = _Py_union_type_or, // Add __or__ function
+        .nb_or = union_nb_or, // Add __or__ function
 };
 
 static const char* const cls_attrs[] = {