diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 1957cadcbb1592..17cf57dd00b4bd 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2361,6 +2361,12 @@ without the dedicated syntax, as documented below. >>> Alias.__module__ '__main__' + This attribute is writable. + + .. versionchanged:: 3.15 + + The attribute is now writable. + .. attribute:: __type_params__ The type parameters of the type alias, or an empty tuple if the alias is diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index 9ceee565764c9a..05bc6a80888a06 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -372,6 +372,8 @@ def test_module(self): mod_generics_cache.__name__) self.assertEqual(mod_generics_cache.OldStyle.__module__, mod_generics_cache.__name__) + Alias.__module__ = "ham.spam.eggs" + self.assertEqual(Alias.__module__, "ham.spam.eggs") def test_unpack(self): type Alias = tuple[int, int] diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-30-01-35-09.gh-issue-149171.meXWpl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-30-01-35-09.gh-issue-149171.meXWpl.rst new file mode 100644 index 00000000000000..f8320dd4c6b3c2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-30-01-35-09.gh-issue-149171.meXWpl.rst @@ -0,0 +1,2 @@ +Allow assignment to the ``__module__`` attribute of +:class:`typing.TypeAliasType` instances. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index cdc0ea42eac263..68a8f1a465b470 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1983,8 +1983,12 @@ static PyObject * typealias_module(PyObject *self, void *Py_UNUSED(closure)) { typealiasobject *ta = typealiasobject_CAST(self); - if (ta->module != NULL) { - return Py_NewRef(ta->module); + PyObject *module; + Py_BEGIN_CRITICAL_SECTION(self); + module = Py_XNewRef(ta->module); + Py_END_CRITICAL_SECTION(); + if (module != NULL) { + return module; } if (ta->compute_value != NULL) { PyObject* mod = PyFunction_GetModule(ta->compute_value); @@ -1998,12 +2002,24 @@ typealias_module(PyObject *self, void *Py_UNUSED(closure)) Py_RETURN_NONE; } +static int +typealias_set_module(PyObject *self, PyObject *value, void *Py_UNUSED(closure)) +{ + typealiasobject *ta = typealiasobject_CAST(self); + Py_BEGIN_CRITICAL_SECTION(self); + old = ta->module; + ta->module = Py_XNewRef(value); + Py_END_CRITICAL_SECTION(); + Py_XDECREF(old); + return 0; +} + static PyGetSetDef typealias_getset[] = { {"__parameters__", typealias_parameters, NULL, NULL, NULL}, {"__type_params__", typealias_type_params, NULL, NULL, NULL}, {"__value__", typealias_value, NULL, NULL, NULL}, {"evaluate_value", typealias_evaluate_value, NULL, NULL, NULL}, - {"__module__", typealias_module, NULL, NULL, NULL}, + {"__module__", typealias_module, typealias_set_module, NULL, NULL}, {0} }; @@ -2203,7 +2219,9 @@ type checkers.\n\ At runtime, Alias is an instance of TypeAliasType. The __name__\n\ attribute holds the name of the type alias. The value of the type alias\n\ is stored in the __value__ attribute. It is evaluated lazily, so the\n\ -value is computed only if the attribute is accessed.\n\ +value is computed only if the attribute is accessed. The __module__\n\ +attribute holds the name of the module in which the type alias was\n\ +defined; it can be assigned to.\n\ \n\ Type aliases can also be generic::\n\ \n\