[Python-checkins] bpo-44635: Convert None to NoneType in the union type constructor (GH-27136)

serhiy-storchaka webhook-mailer at python.org
Wed Jul 14 12:54:58 EDT 2021


https://github.com/python/cpython/commit/b81cac05606c84958b52ada09f690463a3c7e949
commit: b81cac05606c84958b52ada09f690463a3c7e949
branch: main
author: Serhiy Storchaka <storchaka at gmail.com>
committer: serhiy-storchaka <storchaka at gmail.com>
date: 2021-07-14T19:54:54+03:00
summary:

bpo-44635: Convert None to NoneType in the union type constructor (GH-27136)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-07-14-13-54-07.bpo-44635.7ZMAdB.rst
M Lib/test/test_types.py
M Objects/unionobject.c

diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index f2c64649e1b67..bc7e6a6613b6e 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -612,6 +612,8 @@ def test_or_types_operator(self):
         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 @@ def test_or_type_operator_with_TypeVar(self):
         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 @@ def test_or_type_operator_with_SpecialForm(self):
         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 0000000000000..ea00554aeeda6
--- /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 cf04de1bcc809..bdcdb747459db 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;
     }



More information about the Python-checkins mailing list