Skip to content

Commit 6dec525

Browse files
[3.10] bpo-44635: Convert None to NoneType in the union type constructor (GH-27136). (GH-27142)
(cherry picked from commit b81cac0)
1 parent 016af14 commit 6dec525

File tree

3 files changed

+21
-9
lines changed

3 files changed

+21
-9
lines changed

Lib/test/test_types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ def test_or_types_operator(self):
612612
self.assertEqual(str | int, typing.Union[int, str])
613613
self.assertEqual(int | None, typing.Union[int, None])
614614
self.assertEqual(None | int, typing.Union[int, None])
615+
self.assertEqual(int | type(None), int | None)
616+
self.assertEqual(type(None) | int, None | int)
615617
self.assertEqual(int | str | list, typing.Union[int, str, list])
616618
self.assertEqual(int | (str | list), typing.Union[int, str, list])
617619
self.assertEqual(str | (int | list), typing.Union[int, str, list])
@@ -699,6 +701,13 @@ def test_or_type_operator_with_TypeVar(self):
699701
assert TV | str == typing.Union[TV, str]
700702
assert str | TV == typing.Union[str, TV]
701703

704+
def test_union_args(self):
705+
self.assertEqual((int | str).__args__, (int, str))
706+
self.assertEqual(((int | str) | list).__args__, (int, str, list))
707+
self.assertEqual((int | (str | list)).__args__, (int, str, list))
708+
self.assertEqual((int | None).__args__, (int, type(None)))
709+
self.assertEqual((int | type(None)).__args__, (int, type(None)))
710+
702711
def test_or_type_operator_with_forward(self):
703712
T = typing.TypeVar('T')
704713
ForwardAfter = T | 'Forward'
@@ -744,7 +753,11 @@ def test_or_type_operator_with_SpecialForm(self):
744753
assert typing.Union[int, bool] | str == typing.Union[int, bool, str]
745754

746755
def test_or_type_repr(self):
756+
assert repr(int | str) == "int | str"
757+
assert repr((int | str) | list) == "int | str | list"
758+
assert repr(int | (str | list)) == "int | str | list"
747759
assert repr(int | None) == "int | None"
760+
assert repr(int | type(None)) == "int | None"
748761
assert repr(int | typing.GenericAlias(list, int)) == "int | list[int]"
749762

750763
def test_or_type_operator_with_genericalias(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Convert ``None`` to ``type(None)`` in the union type constructor.

Objects/unionobject.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ union_instancecheck(PyObject *self, PyObject *instance)
6464
}
6565
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
6666
PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg);
67-
if (arg == Py_None) {
68-
arg = (PyObject *)&_PyNone_Type;
69-
}
7067
if (PyType_Check(arg)) {
7168
int res = PyObject_IsInstance(instance, arg);
7269
if (res < 0) {
@@ -96,9 +93,6 @@ union_subclasscheck(PyObject *self, PyObject *instance)
9693
Py_ssize_t nargs = PyTuple_GET_SIZE(alias->args);
9794
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
9895
PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg);
99-
if (arg == Py_None) {
100-
arg = (PyObject *)&_PyNone_Type;
101-
}
10296
if (PyType_Check(arg)) {
10397
int res = PyObject_IsSubclass(instance, arg);
10498
if (res < 0) {
@@ -172,9 +166,6 @@ union_richcompare(PyObject *a, PyObject *b, int op)
172166
Py_ssize_t b_arg_length = PyTuple_GET_SIZE(b_args);
173167
for (Py_ssize_t i = 0; i < b_arg_length; i++) {
174168
PyObject* arg = PyTuple_GET_ITEM(b_args, i);
175-
if (arg == (PyObject *)&_PyNone_Type) {
176-
arg = Py_None;
177-
}
178169
if (PySet_Add(b_set, arg) == -1) {
179170
Py_DECREF(b_args);
180171
goto exit;
@@ -236,6 +227,9 @@ flatten_args(PyObject* args)
236227
pos++;
237228
}
238229
} else {
230+
if (arg == Py_None) {
231+
arg = (PyObject *)&_PyNone_Type;
232+
}
239233
Py_INCREF(arg);
240234
PyTuple_SET_ITEM(flattened_args, pos, arg);
241235
pos++;
@@ -362,6 +356,10 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p)
362356
PyObject *r = NULL;
363357
int err;
364358

359+
if (p == (PyObject *)&_PyNone_Type) {
360+
return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4);
361+
}
362+
365363
if (_PyObject_LookupAttrId(p, &PyId___origin__, &tmp) < 0) {
366364
goto exit;
367365
}

0 commit comments

Comments
 (0)