[Python-checkins] cpython: give explicitly global functions and classes a global __qualname__ (closes

benjamin.peterson python-checkins at python.org
Sat Oct 19 22:06:18 CEST 2013


http://hg.python.org/cpython/rev/35b384ed594b
changeset:   86491:35b384ed594b
user:        Benjamin Peterson <benjamin at python.org>
date:        Sat Oct 19 16:01:13 2013 -0400
summary:
  give explicitly global functions and classes a global __qualname__ (closes #19301)

files:
  Lib/importlib/_bootstrap.py |     3 +-
  Lib/test/test_descr.py      |     5 +
  Lib/test/test_funcattrs.py  |     4 +
  Misc/NEWS                   |     3 +
  Python/compile.c            |    54 +-
  Python/importlib.h          |  6645 +++++++++++-----------
  6 files changed, 3262 insertions(+), 3452 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -369,12 +369,13 @@
 #                        free vars)
 #     Python 3.4a1  3270 (various tweaks to the __class__ closure)
 #     Python 3.4a1  3280 (remove implicit class argument)
+#     Python 3.4a4  3290 (changes to __qualname__ computation)
 #
 # MAGIC must change whenever the bytecode emitted by the compiler may no
 # longer be understood by older implementations of the eval loop (usually
 # due to the addition of new opcodes).
 
-MAGIC_NUMBER = (3280).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3290).to_bytes(2, 'little') + b'\r\n'
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
 _PYCACHE = '__pycache__'
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4517,6 +4517,11 @@
         self.assertRaises(TypeError, type.__dict__['__qualname__'].__set__,
                           str, 'Oink')
 
+        global Y
+        class Y:
+            pass
+        self.assertEqual(Y.__qualname__, 'Y')
+
     def test_qualname_dict(self):
         ns = {'__qualname__': 'some.name'}
         tp = type('Foo', (), ns)
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -7,6 +7,9 @@
     def inner_function():
         class LocalClass:
             pass
+        global inner_global_function
+        def inner_global_function():
+            pass
         return LocalClass
     return lambda: inner_function
 
@@ -116,6 +119,7 @@
                          'global_function.<locals>.inner_function')
         self.assertEqual(global_function()()().__qualname__,
                          'global_function.<locals>.inner_function.<locals>.LocalClass')
+        self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
         self.b.__qualname__ = 'c'
         self.assertEqual(self.b.__qualname__, 'c')
         self.b.__qualname__ = 'd'
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
 Core and Builtins
 -----------------
 
+- Issue #19301: Give classes and functions that are explicitly marked global a
+  global qualname.
+
 - Issue #19279: UTF-7 decoder no more produces illegal strings.
 
 - Issue #16612: Add "Argument Clinic", a compile-time preprocessor for
diff --git a/Python/compile.c b/Python/compile.c
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -650,9 +650,10 @@
 }
 
 static PyObject *
-compiler_scope_qualname(struct compiler *c)
+compiler_scope_qualname(struct compiler *c, identifier scope_name)
 {
-    Py_ssize_t stack_size, i;
+    Py_ssize_t stack_size;
+    int global_scope;
     _Py_static_string(dot, ".");
     _Py_static_string(locals, "<locals>");
     struct compiler_unit *u;
@@ -669,22 +670,41 @@
         return NULL;
 
     stack_size = PyList_GET_SIZE(c->c_stack);
-    for (i = 0; i < stack_size; i++) {
-        capsule = PyList_GET_ITEM(c->c_stack, i);
+    global_scope = stack_size <= 1;
+    if (scope_name != NULL && !global_scope) {
+        int scope;
+        PyObject *mangled;
+        capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
         u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
         assert(u);
-        if (u->u_scope_type == COMPILER_SCOPE_MODULE)
-            continue;
-        if (PyList_Append(seq, u->u_name))
-            goto _error;
-        if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
-            locals_str = _PyUnicode_FromId(&locals);
-            if (locals_str == NULL)
+        mangled = _Py_Mangle(u->u_private, scope_name);
+        if (!mangled)
+            return NULL;
+        scope = PyST_GetScope(u->u_ste, mangled);
+        Py_DECREF(mangled);
+        assert(scope != GLOBAL_IMPLICIT);
+        if (scope == GLOBAL_EXPLICIT)
+            global_scope = 1;
+    }
+    if (!global_scope) {
+        Py_ssize_t i;
+        for (i = 1; i < stack_size; i++) {
+            capsule = PyList_GET_ITEM(c->c_stack, i);
+            u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
+            assert(u);
+            assert(u->u_scope_type != COMPILER_SCOPE_MODULE);
+            if (PyList_Append(seq, u->u_name))
                 goto _error;
-            if (PyList_Append(seq, locals_str))
-                goto _error;
+            if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
+                locals_str = _PyUnicode_FromId(&locals);
+                if (locals_str == NULL)
+                    goto _error;
+                if (PyList_Append(seq, locals_str))
+                    goto _error;
+            }
         }
     }
+
     u = c->u;
     if (PyList_Append(seq, u->u_name))
         goto _error;
@@ -1649,7 +1669,7 @@
         VISIT_IN_SCOPE(c, stmt, st);
     }
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c);
+    qualname = compiler_scope_qualname(c, s->v.FunctionDef.name);
     compiler_exit_scope(c);
     if (qualname == NULL || co == NULL) {
         Py_XDECREF(qualname);
@@ -1722,7 +1742,7 @@
         }
         Py_DECREF(str);
         /* store the __qualname__ */
-        str = compiler_scope_qualname(c);
+        str = compiler_scope_qualname(c, s->v.ClassDef.name);
         if (!str) {
             compiler_exit_scope(c);
             return 0;
@@ -1862,7 +1882,7 @@
         ADDOP_IN_SCOPE(c, RETURN_VALUE);
     }
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c);
+    qualname = compiler_scope_qualname(c, NULL);
     compiler_exit_scope(c);
     if (qualname == NULL || co == NULL)
         return 0;
@@ -3139,7 +3159,7 @@
     }
 
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c);
+    qualname = compiler_scope_qualname(c, NULL);
     compiler_exit_scope(c);
     if (qualname == NULL || co == NULL)
         goto error;
diff --git a/Python/importlib.h b/Python/importlib.h
--- a/Python/importlib.h
+++ b/Python/importlib.h
[stripped]

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list