From 8182c8329c709f42218a8a17d81639ece5b7b627 Mon Sep 17 00:00:00 2001 From: Yurii Karabas <1998uriyyo@gmail.com> Date: Thu, 29 Jul 2021 22:44:48 +0300 Subject: [PATCH] bpo-44662: Add ability to annotate types.Union (#27214) Co-authored-by: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> --- Lib/test/test_typing.py | 10 ++++++++ .../2021-07-17-13-41-58.bpo-44662.q22kWR.rst | 3 +++ Objects/unionobject.c | 24 ++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-07-17-13-41-58.bpo-44662.q22kWR.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3aed26bbfc3..bc9021addbe 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3015,6 +3015,16 @@ class GetTypeHintTests(BaseTestCase): get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"], BA2 ) + BA3 = typing.Annotated[int | float, "const"] + def barfoo4(x: BA3): ... + self.assertEqual( + get_type_hints(barfoo4, globals(), locals()), + {"x": int | float} + ) + self.assertEqual( + get_type_hints(barfoo4, globals(), locals(), include_extras=True), + {"x": typing.Annotated[int | float, "const"]} + ) def test_get_type_hints_annotated_refs(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-07-17-13-41-58.bpo-44662.q22kWR.rst b/Misc/NEWS.d/next/Core and Builtins/2021-07-17-13-41-58.bpo-44662.q22kWR.rst new file mode 100644 index 00000000000..c165774a4ca --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-07-17-13-41-58.bpo-44662.q22kWR.rst @@ -0,0 +1,3 @@ +Add ``__module__`` to ``types.Union``. This also fixes +``types.Union`` issues with ``typing.Annotated``. Patch provided by +Yurii Karabas. diff --git a/Objects/unionobject.c b/Objects/unionobject.c index 9e670b47b7e..80c70389ab3 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -422,6 +422,28 @@ static PyNumberMethods union_as_number = { .nb_or = _Py_union_type_or, // Add __or__ function }; +static const char* const cls_attrs[] = { + "__module__", // Required for compatibility with typing module + NULL, +}; + +static PyObject * +union_getattro(PyObject *self, PyObject *name) +{ + unionobject *alias = (unionobject *)self; + if (PyUnicode_Check(name)) { + for (const char * const *p = cls_attrs; ; p++) { + if (*p == NULL) { + break; + } + if (_PyUnicode_EqualToASCIIString(name, *p)) { + return PyObject_GetAttr((PyObject *) Py_TYPE(alias), name); + } + } + } + return PyObject_GenericGetAttr(self, name); +} + PyTypeObject _PyUnion_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "types.UnionType", @@ -435,7 +457,7 @@ PyTypeObject _PyUnion_Type = { .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = union_traverse, .tp_hash = union_hash, - .tp_getattro = PyObject_GenericGetAttr, + .tp_getattro = union_getattro, .tp_members = union_members, .tp_methods = union_methods, .tp_richcompare = union_richcompare,