gh-140348: Fix using | on unusual objects plus Unions (#140383)

This commit is contained in:
Jelle Zijlstra
2025-11-03 06:50:37 -08:00
committed by GitHub
parent 248ce9fa8c
commit 7a9437d986
3 changed files with 28 additions and 1 deletions

View File

@@ -2283,6 +2283,15 @@ class UnionTests(BaseTestCase):
self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__, self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__,
(Literal[1], Literal[Ints.B], Literal[True])) (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): class TupleTests(BaseTestCase):

View File

@@ -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.

View File

@@ -393,8 +393,23 @@ static PyGetSetDef union_properties[] = {
{0} {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 = { 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[] = { static const char* const cls_attrs[] = {