[Python-checkins] bpo-44653: Support typing types in parameter substitution in the union type. (GH-27247)

ambv webhook-mailer at python.org
Thu Jul 22 17:57:11 EDT 2021


https://github.com/python/cpython/commit/2e3744d50b6e30ea24351e55b4352dcc58fd469e
commit: 2e3744d50b6e30ea24351e55b4352dcc58fd469e
branch: main
author: Serhiy Storchaka <storchaka at gmail.com>
committer: ambv <lukasz at langa.pl>
date: 2021-07-22T23:57:06+02:00
summary:

bpo-44653: Support typing types in parameter substitution in the union type. (GH-27247)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-07-19-20-49-06.bpo-44653.WcqGyI.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 6ed74714dc578..99b011e378665 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -772,6 +772,36 @@ def test_union_parameter_chaining(self):
         self.assertEqual((list[T] | list[S])[int, T], list[int] | list[T])
         self.assertEqual((list[T] | list[S])[int, int], list[int])
 
+    def test_union_parameter_substitution(self):
+        def eq(actual, expected):
+            self.assertEqual(actual, expected)
+            self.assertIs(type(actual), type(expected))
+
+        T = typing.TypeVar('T')
+        S = typing.TypeVar('S')
+        NT = typing.NewType('NT', str)
+        x = int | T | bytes
+
+        eq(x[str], int | str | bytes)
+        eq(x[list[int]], int | list[int] | bytes)
+        eq(x[typing.List], int | typing.List | bytes)
+        eq(x[typing.List[int]], int | typing.List[int] | bytes)
+        eq(x[typing.Hashable], int | typing.Hashable | bytes)
+        eq(x[collections.abc.Hashable],
+           int | collections.abc.Hashable | bytes)
+        eq(x[typing.Callable[[int], str]],
+           int | typing.Callable[[int], str] | bytes)
+        eq(x[collections.abc.Callable[[int], str]],
+           int | collections.abc.Callable[[int], str] | bytes)
+        eq(x[typing.Tuple[int, str]], int | typing.Tuple[int, str] | bytes)
+        eq(x[typing.Literal['none']], int | typing.Literal['none'] | bytes)
+        eq(x[str | list], int | str | list | bytes)
+        eq(x[typing.Union[str, list]], typing.Union[int, str, list, bytes])
+        eq(x[str | int], int | str | bytes)
+        eq(x[typing.Union[str, int]], typing.Union[int, str, bytes])
+        eq(x[NT], int | NT | bytes)
+        eq(x[S], int | S | bytes)
+
     def test_union_parameter_substitution_errors(self):
         T = typing.TypeVar("T")
         x = int | T
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-19-20-49-06.bpo-44653.WcqGyI.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-19-20-49-06.bpo-44653.WcqGyI.rst
new file mode 100644
index 0000000000000..8254d9bbad4a6
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-19-20-49-06.bpo-44653.WcqGyI.rst	
@@ -0,0 +1 @@
+Support :mod:`typing` types in parameter substitution in the union type.
diff --git a/Objects/unionobject.c b/Objects/unionobject.c
index c0c9a24bcc204..659346aac8211 100644
--- a/Objects/unionobject.c
+++ b/Objects/unionobject.c
@@ -446,23 +446,22 @@ union_getitem(PyObject *self, PyObject *item)
         return NULL;
     }
 
-    // Check arguments are unionable.
+    PyObject *res;
     Py_ssize_t nargs = PyTuple_GET_SIZE(newargs);
-    for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
-        PyObject *arg = PyTuple_GET_ITEM(newargs, iarg);
-        int is_arg_unionable = is_unionable(arg);
-        if (is_arg_unionable <= 0) {
-            Py_DECREF(newargs);
-            if (is_arg_unionable == 0) {
-                PyErr_Format(PyExc_TypeError,
-                             "Each union argument must be a type, got %.100R", arg);
+    if (nargs == 0) {
+        res = make_union(newargs);
+    }
+    else {
+        res = PyTuple_GET_ITEM(newargs, 0);
+        Py_INCREF(res);
+        for (Py_ssize_t iarg = 1; iarg < nargs; iarg++) {
+            PyObject *arg = PyTuple_GET_ITEM(newargs, iarg);
+            Py_SETREF(res, PyNumber_Or(res, arg));
+            if (res == NULL) {
+                break;
             }
-            return NULL;
         }
     }
-
-    PyObject *res = make_union(newargs);
-
     Py_DECREF(newargs);
     return res;
 }



More information about the Python-checkins mailing list