From: Eric Mark Martin Date: Sat, 2 May 2026 17:28:08 +0000 (-0400) Subject: gh-149171: Make TypeAliasType __module__ writable (#149172) X-Git-Tag: v3.15.0b1~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a65611e7f52dae341915e79eb28c47aec930f077;p=thirdparty%2FPython%2Fcpython.git gh-149171: Make TypeAliasType __module__ writable (#149172) closes #149171. --- diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 1957cadcbb15..17cf57dd00b4 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 9ceee565764c..05bc6a80888a 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -372,6 +372,8 @@ class TypeAliasTypeTest(unittest.TestCase): 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 000000000000..f8320dd4c6b3 --- /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 cdc0ea42eac2..8ad590cc6e60 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,25 @@ typealias_module(PyObject *self, void *Py_UNUSED(closure)) Py_RETURN_NONE; } +static int +typealias_set_module(PyObject *self, PyObject *value, void *Py_UNUSED(closure)) +{ + PyObject *old; + 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 +2220,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\