Skip to content

Commit 2e3744d

Browse files
authoredJul 22, 2021
bpo-44653: Support typing types in parameter substitution in the union type. (GH-27247)
1 parent 96c4cbd commit 2e3744d

File tree

3 files changed

+43
-13
lines changed

3 files changed

+43
-13
lines changed
 

‎Lib/test/test_types.py

+30
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,36 @@ def test_union_parameter_chaining(self):
772772
self.assertEqual((list[T] | list[S])[int, T], list[int] | list[T])
773773
self.assertEqual((list[T] | list[S])[int, int], list[int])
774774

775+
def test_union_parameter_substitution(self):
776+
def eq(actual, expected):
777+
self.assertEqual(actual, expected)
778+
self.assertIs(type(actual), type(expected))
779+
780+
T = typing.TypeVar('T')
781+
S = typing.TypeVar('S')
782+
NT = typing.NewType('NT', str)
783+
x = int | T | bytes
784+
785+
eq(x[str], int | str | bytes)
786+
eq(x[list[int]], int | list[int] | bytes)
787+
eq(x[typing.List], int | typing.List | bytes)
788+
eq(x[typing.List[int]], int | typing.List[int] | bytes)
789+
eq(x[typing.Hashable], int | typing.Hashable | bytes)
790+
eq(x[collections.abc.Hashable],
791+
int | collections.abc.Hashable | bytes)
792+
eq(x[typing.Callable[[int], str]],
793+
int | typing.Callable[[int], str] | bytes)
794+
eq(x[collections.abc.Callable[[int], str]],
795+
int | collections.abc.Callable[[int], str] | bytes)
796+
eq(x[typing.Tuple[int, str]], int | typing.Tuple[int, str] | bytes)
797+
eq(x[typing.Literal['none']], int | typing.Literal['none'] | bytes)
798+
eq(x[str | list], int | str | list | bytes)
799+
eq(x[typing.Union[str, list]], typing.Union[int, str, list, bytes])
800+
eq(x[str | int], int | str | bytes)
801+
eq(x[typing.Union[str, int]], typing.Union[int, str, bytes])
802+
eq(x[NT], int | NT | bytes)
803+
eq(x[S], int | S | bytes)
804+
775805
def test_union_parameter_substitution_errors(self):
776806
T = typing.TypeVar("T")
777807
x = int | T
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support :mod:`typing` types in parameter substitution in the union type.

‎Objects/unionobject.c

+12-13
Original file line numberDiff line numberDiff line change
@@ -446,23 +446,22 @@ union_getitem(PyObject *self, PyObject *item)
446446
return NULL;
447447
}
448448

449-
// Check arguments are unionable.
449+
PyObject *res;
450450
Py_ssize_t nargs = PyTuple_GET_SIZE(newargs);
451-
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
452-
PyObject *arg = PyTuple_GET_ITEM(newargs, iarg);
453-
int is_arg_unionable = is_unionable(arg);
454-
if (is_arg_unionable <= 0) {
455-
Py_DECREF(newargs);
456-
if (is_arg_unionable == 0) {
457-
PyErr_Format(PyExc_TypeError,
458-
"Each union argument must be a type, got %.100R", arg);
451+
if (nargs == 0) {
452+
res = make_union(newargs);
453+
}
454+
else {
455+
res = PyTuple_GET_ITEM(newargs, 0);
456+
Py_INCREF(res);
457+
for (Py_ssize_t iarg = 1; iarg < nargs; iarg++) {
458+
PyObject *arg = PyTuple_GET_ITEM(newargs, iarg);
459+
Py_SETREF(res, PyNumber_Or(res, arg));
460+
if (res == NULL) {
461+
break;
459462
}
460-
return NULL;
461463
}
462464
}
463-
464-
PyObject *res = make_union(newargs);
465-
466465
Py_DECREF(newargs);
467466
return res;
468467
}

0 commit comments

Comments
 (0)