diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index f2c64649e1b..bc7e6a6613b 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -612,6 +612,8 @@ class TypesTests(unittest.TestCase): self.assertEqual(str | int, typing.Union[int, str]) self.assertEqual(int | None, typing.Union[int, None]) self.assertEqual(None | int, typing.Union[int, None]) + self.assertEqual(int | type(None), int | None) + self.assertEqual(type(None) | int, None | int) self.assertEqual(int | str | list, typing.Union[int, str, list]) self.assertEqual(int | (str | list), typing.Union[int, str, list]) self.assertEqual(str | (int | list), typing.Union[int, str, list]) @@ -699,6 +701,13 @@ class TypesTests(unittest.TestCase): assert TV | str == typing.Union[TV, str] assert str | TV == typing.Union[str, TV] + def test_union_args(self): + self.assertEqual((int | str).__args__, (int, str)) + self.assertEqual(((int | str) | list).__args__, (int, str, list)) + self.assertEqual((int | (str | list)).__args__, (int, str, list)) + self.assertEqual((int | None).__args__, (int, type(None))) + self.assertEqual((int | type(None)).__args__, (int, type(None))) + def test_union_parameter_chaining(self): T = typing.TypeVar("T") S = typing.TypeVar("S") @@ -754,7 +763,11 @@ class TypesTests(unittest.TestCase): assert typing.Union[int, bool] | str == typing.Union[int, bool, str] def test_or_type_repr(self): + assert repr(int | str) == "int | str" + assert repr((int | str) | list) == "int | str | list" + assert repr(int | (str | list)) == "int | str | list" assert repr(int | None) == "int | None" + assert repr(int | type(None)) == "int | None" assert repr(int | typing.GenericAlias(list, int)) == "int | list[int]" def test_or_type_operator_with_genericalias(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-14-13-54-07.bpo-44635.7ZMAdB.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-14-13-54-07.bpo-44635.7ZMAdB.rst new file mode 100644 index 00000000000..ea00554aeed --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-14-13-54-07.bpo-44635.7ZMAdB.rst @@ -0,0 +1 @@ +Convert ``None`` to ``type(None)`` in the union type constructor. diff --git a/Objects/unionobject.c b/Objects/unionobject.c index cf04de1bcc8..bdcdb747459 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -67,9 +67,6 @@ union_instancecheck(PyObject *self, PyObject *instance) } for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); - if (arg == Py_None) { - arg = (PyObject *)&_PyNone_Type; - } if (PyType_Check(arg)) { int res = PyObject_IsInstance(instance, arg); if (res < 0) { @@ -99,9 +96,6 @@ union_subclasscheck(PyObject *self, PyObject *instance) Py_ssize_t nargs = PyTuple_GET_SIZE(alias->args); for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); - if (arg == Py_None) { - arg = (PyObject *)&_PyNone_Type; - } if (PyType_Check(arg)) { int res = PyObject_IsSubclass(instance, arg); if (res < 0) { @@ -175,9 +169,6 @@ union_richcompare(PyObject *a, PyObject *b, int op) Py_ssize_t b_arg_length = PyTuple_GET_SIZE(b_args); for (Py_ssize_t i = 0; i < b_arg_length; i++) { PyObject* arg = PyTuple_GET_ITEM(b_args, i); - if (arg == (PyObject *)&_PyNone_Type) { - arg = Py_None; - } if (PySet_Add(b_set, arg) == -1) { Py_DECREF(b_args); goto exit; @@ -239,6 +230,9 @@ flatten_args(PyObject* args) pos++; } } else { + if (arg == Py_None) { + arg = (PyObject *)&_PyNone_Type; + } Py_INCREF(arg); PyTuple_SET_ITEM(flattened_args, pos, arg); pos++; @@ -365,6 +359,10 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p) PyObject *r = NULL; int err; + if (p == (PyObject *)&_PyNone_Type) { + return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4); + } + if (_PyObject_LookupAttrId(p, &PyId___origin__, &tmp) < 0) { goto exit; }