]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-104549: Set __module__ on TypeAliasType (#104550)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Thu, 18 May 2023 22:56:15 +0000 (15:56 -0700)
committerGitHub <noreply@github.com>
Thu, 18 May 2023 22:56:15 +0000 (15:56 -0700)
Include/internal/pycore_global_objects.h
Include/internal/pycore_typevarobject.h
Lib/test/mod_generics_cache.py
Lib/test/test_type_aliases.py
Modules/_typingmodule.c
Objects/object.c
Objects/typevarobject.c
Objects/unionobject.c
Tools/c-analyzer/cpython/globals-to-fix.tsv

index 40cc04d5d1702c9e54d2af503ce070242ccf016f..5a3fb132c745ab2ec64efb1221736a4723fe3c82 100644 (file)
@@ -75,7 +75,6 @@ struct _Py_interp_cached_objects {
     PyTypeObject *paramspec_type;
     PyTypeObject *paramspecargs_type;
     PyTypeObject *paramspeckwargs_type;
-    PyTypeObject *typealias_type;
 };
 
 #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \
index 2035e47e92305927e96966a0176c93c559e19230..c9fa97d68207571614f046c7b2501e98f92458e2 100644 (file)
@@ -16,6 +16,8 @@ extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *);
 extern int _Py_initialize_generic(PyInterpreterState *);
 extern void _Py_clear_generic_types(PyInterpreterState *);
 
+extern PyTypeObject _PyTypeAlias_Type;
+
 #ifdef __cplusplus
 }
 #endif
index 9d8b56cf03c364867cba8a4b56f68245cd977121..6c1ee2fec8374d44d71f01b7ee26d9e1643c904d 100644 (file)
@@ -1,6 +1,6 @@
 """Module for testing the behavior of generics across different modules."""
 
-from typing import TypeVar, Generic, Optional
+from typing import TypeVar, Generic, Optional, TypeAliasType
 
 default_a: Optional['A'] = None
 default_b: Optional['B'] = None
@@ -19,3 +19,6 @@ class B(Generic[T]):
     my_inner_a1: 'B.A'
     my_inner_a2: A
     my_outer_a: 'A'  # unless somebody calls get_type_hints with localns=B.__dict__
+
+type Alias = int
+OldStyle = TypeAliasType("OldStyle", int)
index d2abb932f589f7837d38eb329a1d117313c97b97..56d150d67afb6f413d3e677556c764af0fcdfd01 100644 (file)
@@ -1,6 +1,8 @@
+import pickle
 import types
 import unittest
 from test.support import check_syntax_error, run_code
+from test import mod_generics_cache
 
 from typing import Callable, TypeAliasType, TypeVar, get_args
 
@@ -155,6 +157,7 @@ class TypeAliasConstructorTest(unittest.TestCase):
         self.assertEqual(TA.__name__, "TA")
         self.assertIs(TA.__value__, int)
         self.assertEqual(TA.__type_params__, ())
+        self.assertEqual(TA.__module__, __name__)
 
     def test_generic(self):
         T = TypeVar("T")
@@ -162,12 +165,14 @@ class TypeAliasConstructorTest(unittest.TestCase):
         self.assertEqual(TA.__name__, "TA")
         self.assertEqual(TA.__value__, list[T])
         self.assertEqual(TA.__type_params__, (T,))
+        self.assertEqual(TA.__module__, __name__)
 
     def test_keywords(self):
         TA = TypeAliasType(name="TA", value=int)
         self.assertEqual(TA.__name__, "TA")
         self.assertIs(TA.__value__, int)
         self.assertEqual(TA.__type_params__, ())
+        self.assertEqual(TA.__module__, __name__)
 
     def test_errors(self):
         with self.assertRaises(TypeError):
@@ -202,3 +207,18 @@ class TypeAliasTypeTest(unittest.TestCase):
         union3 = list[range] | Alias1
         self.assertIsInstance(union3, types.UnionType)
         self.assertEqual(get_args(union3), (list[range], Alias1))
+
+    def test_module(self):
+        self.assertEqual(TypeAliasType.__module__, "typing")
+        type Alias = int
+        self.assertEqual(Alias.__module__, __name__)
+        self.assertEqual(mod_generics_cache.Alias.__module__,
+                         mod_generics_cache.__name__)
+        self.assertEqual(mod_generics_cache.OldStyle.__module__,
+                         mod_generics_cache.__name__)
+
+    def test_pickling(self):
+        pickled = pickle.dumps(mod_generics_cache.Alias)
+        self.assertIs(pickle.loads(pickled), mod_generics_cache.Alias)
+        pickled = pickle.dumps(mod_generics_cache.OldStyle)
+        self.assertIs(pickle.loads(pickled), mod_generics_cache.OldStyle)
index ed2999c0b68b24b23235d0aaf50896b07ff953b6..39a124a26adf3166c80accc1e4c97dc761b6da95 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "Python.h"
 #include "internal/pycore_interp.h"
+#include "internal/pycore_typevarobject.h"
 #include "clinic/_typingmodule.c.h"
 
 /*[clinic input]
@@ -56,9 +57,11 @@ _typing_exec(PyObject *m)
     EXPORT_TYPE("ParamSpec", paramspec_type);
     EXPORT_TYPE("ParamSpecArgs", paramspecargs_type);
     EXPORT_TYPE("ParamSpecKwargs", paramspeckwargs_type);
-    EXPORT_TYPE("TypeAliasType", typealias_type);
     EXPORT_TYPE("Generic", generic_type);
 #undef EXPORT_TYPE
+    if (PyModule_AddObjectRef(m, "TypeAliasType", (PyObject *)&_PyTypeAlias_Type) < 0) {
+        return -1;
+    }
     return 0;
 }
 
index f3118665430d9fc99685f9be5207a255772377eb..ece0c5e21e77faaa5b70aad4a7d4a704802e815a 100644 (file)
@@ -14,7 +14,7 @@
 #include "pycore_pymem.h"         // _PyMem_IsPtrFreed()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_symtable.h"      // PySTEntry_Type
-#include "pycore_typevarobject.h" // _PyTypeVar_Type etc., _Py_initialize_generic
+#include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_initialize_generic
 #include "pycore_typeobject.h"    // _PyBufferWrapper_Type
 #include "pycore_unionobject.h"   // _PyUnion_Type
 #include "pycore_interpreteridobject.h"  // _PyInterpreterID_Type
@@ -2112,6 +2112,7 @@ static PyTypeObject* static_types[] = {
     &_PyWeakref_CallableProxyType,
     &_PyWeakref_ProxyType,
     &_PyWeakref_RefType,
+    &_PyTypeAlias_Type,
 
     // subclasses: _PyTypes_FiniTypes() deallocates them before their base
     // class
index 4464e7a9da89db8a3e6075e56e6c71c0e65c82eb..6730ebfc064e356980ecf342ef4432e4cdea9234 100644 (file)
@@ -48,6 +48,7 @@ typedef struct {
     PyObject *type_params;
     PyObject *compute_value;
     PyObject *value;
+    PyObject *module;
 } typealiasobject;
 
 #include "clinic/typevarobject.c.h"
@@ -1252,6 +1253,7 @@ typealias_dealloc(PyObject *self)
     Py_XDECREF(ta->type_params);
     Py_XDECREF(ta->compute_value);
     Py_XDECREF(ta->value);
+    Py_XDECREF(ta->module);
     Py_TYPE(self)->tp_free(self);
     Py_DECREF(tp);
 }
@@ -1309,19 +1311,33 @@ typealias_type_params(PyObject *self, void *unused)
     return Py_NewRef(ta->type_params);
 }
 
+static PyObject *
+typealias_module(PyObject *self, void *unused)
+{
+    typealiasobject *ta = (typealiasobject *)self;
+    if (ta->module != NULL) {
+        return Py_NewRef(ta->module);
+    }
+    if (ta->compute_value != NULL) {
+        // PyFunction_GetModule() returns a borrowed reference
+        return Py_NewRef(PyFunction_GetModule(ta->compute_value));
+    }
+    Py_RETURN_NONE;
+}
+
 static PyGetSetDef typealias_getset[] = {
     {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL},
     {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL},
     {"__value__", typealias_value, (setter)NULL, NULL, NULL},
+    {"__module__", typealias_module, (setter)NULL, NULL, NULL},
     {0}
 };
 
 static typealiasobject *
 typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
-                PyObject *value)
+                PyObject *value, PyObject *module)
 {
-    PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typealias_type;
-    typealiasobject *ta = PyObject_GC_New(typealiasobject, tp);
+    typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
     if (ta == NULL) {
         return NULL;
     }
@@ -1329,6 +1345,7 @@ typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
     ta->type_params = Py_IsNone(type_params) ? NULL : Py_XNewRef(type_params);
     ta->compute_value = Py_XNewRef(compute_value);
     ta->value = Py_XNewRef(value);
+    ta->module = Py_XNewRef(module);
     _PyObject_GC_TRACK(ta);
     return ta;
 }
@@ -1339,6 +1356,7 @@ typealias_traverse(typealiasobject *self, visitproc visit, void *arg)
     Py_VISIT(self->type_params);
     Py_VISIT(self->compute_value);
     Py_VISIT(self->value);
+    Py_VISIT(self->module);
     return 0;
 }
 
@@ -1348,6 +1366,7 @@ typealias_clear(typealiasobject *self)
     Py_CLEAR(self->type_params);
     Py_CLEAR(self->compute_value);
     Py_CLEAR(self->value);
+    Py_CLEAR(self->module);
     return 0;
 }
 
@@ -1401,7 +1420,14 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
         PyErr_SetString(PyExc_TypeError, "type_params must be a tuple");
         return NULL;
     }
-    return (PyObject *)typealias_alloc(name, type_params, NULL, value);
+    PyObject *module = caller();
+    if (module == NULL) {
+        return NULL;
+    }
+    PyObject *ta = (PyObject *)typealias_alloc(name, type_params, NULL, value,
+                                               module);
+    Py_DECREF(module);
+    return ta;
 }
 
 PyDoc_STRVAR(typealias_doc,
@@ -1412,28 +1438,32 @@ Type aliases are created through the type statement:\n\
   type Alias = int\n\
 ");
 
-static PyType_Slot typealias_slots[] = {
-    {Py_tp_doc, (void *)typealias_doc},
-    {Py_tp_members, typealias_members},
-    {Py_tp_methods, typealias_methods},
-    {Py_tp_getset, typealias_getset},
-    {Py_mp_subscript, typealias_subscript},
-    {Py_tp_dealloc, typealias_dealloc},
-    {Py_tp_alloc, PyType_GenericAlloc},
-    {Py_tp_new, typealias_new},
-    {Py_tp_free, PyObject_GC_Del},
-    {Py_tp_traverse, (traverseproc)typealias_traverse},
-    {Py_tp_clear, (inquiry)typealias_clear},
-    {Py_tp_repr, typealias_repr},
-    {Py_nb_or, _Py_union_type_or},
-    {0, 0},
+static PyNumberMethods typealias_as_number = {
+    .nb_or = _Py_union_type_or,
+};
+
+static PyMappingMethods typealias_as_mapping = {
+    .mp_subscript = typealias_subscript,
 };
 
-PyType_Spec typealias_spec = {
-    .name = "typing.TypeAliasType",
-    .basicsize = sizeof(typealiasobject),
-    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC,
-    .slots = typealias_slots,
+PyTypeObject _PyTypeAlias_Type = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    .tp_name = "typing.TypeAliasType",
+    .tp_basicsize = sizeof(typealiasobject),
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC,
+    .tp_doc = typealias_doc,
+    .tp_members = typealias_members,
+    .tp_methods = typealias_methods,
+    .tp_getset = typealias_getset,
+    .tp_alloc = PyType_GenericAlloc,
+    .tp_dealloc = typealias_dealloc,
+    .tp_new = typealias_new,
+    .tp_free = PyObject_GC_Del,
+    .tp_traverse = (traverseproc)typealias_traverse,
+    .tp_clear = (inquiry)typealias_clear,
+    .tp_repr = typealias_repr,
+    .tp_as_number = &typealias_as_number,
+    .tp_as_mapping = &typealias_as_mapping,
 };
 
 PyObject *
@@ -1445,7 +1475,8 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args)
     assert(PyUnicode_Check(name));
     PyObject *type_params = PyTuple_GET_ITEM(args, 1);
     PyObject *compute_value = PyTuple_GET_ITEM(args, 2);
-    return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL);
+    assert(PyFunction_Check(compute_value));
+    return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL);
 }
 
 PyDoc_STRVAR(generic_doc,
@@ -1603,7 +1634,6 @@ int _Py_initialize_generic(PyInterpreterState *interp)
     MAKE_TYPE(paramspec);
     MAKE_TYPE(paramspecargs);
     MAKE_TYPE(paramspeckwargs);
-    MAKE_TYPE(typealias);
 #undef MAKE_TYPE
     return 0;
 }
@@ -1616,5 +1646,4 @@ void _Py_clear_generic_types(PyInterpreterState *interp)
     Py_CLEAR(interp->cached_objects.paramspec_type);
     Py_CLEAR(interp->cached_objects.paramspecargs_type);
     Py_CLEAR(interp->cached_objects.paramspeckwargs_type);
-    Py_CLEAR(interp->cached_objects.typealias_type);
 }
index 9806678b8048574cbc59d16887c9949d67b34a4c..f509a161bb9564a6fad3a6b583da139bb75a74ab 100644 (file)
@@ -1,6 +1,7 @@
 // types.UnionType -- used to represent e.g. Union[int, str], int | str
 #include "Python.h"
 #include "pycore_object.h"  // _PyObject_GC_TRACK/UNTRACK
+#include "pycore_typevarobject.h"  // _PyTypeAlias_Type
 #include "pycore_unionobject.h"
 #include "structmember.h"
 
@@ -150,11 +151,11 @@ is_unionable(PyObject *obj)
     if (obj == Py_None ||
         PyType_Check(obj) ||
         _PyGenericAlias_Check(obj) ||
-        _PyUnion_Check(obj)) {
+        _PyUnion_Check(obj) ||
+        Py_IS_TYPE(obj, &_PyTypeAlias_Type)) {
         return 1;
     }
-    PyInterpreterState *interp = PyInterpreterState_Get();
-    return Py_IS_TYPE(obj, interp->cached_objects.typealias_type);
+    return 0;
 }
 
 PyObject *
index e2b93a3a2ec274b184ac5aaa017d8b9b92e1a5d6..622c98d16283a8a5decaf240d2fc3e9fbeb12616 100644 (file)
@@ -90,6 +90,7 @@ Objects/typeobject.c  -       _PyBufferWrapper_Type   -
 Objects/typeobject.c   -       PyBaseObject_Type       -
 Objects/typeobject.c   -       PySuper_Type    -
 Objects/typeobject.c   -       PyType_Type     -
+Objects/typevarobject.c        -       _PyTypeAlias_Type       -
 Objects/unicodeobject.c        -       PyUnicodeIter_Type      -
 Objects/unicodeobject.c        -       PyUnicode_Type  -
 Objects/weakrefobject.c        -       _PyWeakref_CallableProxyType    -