[Python-checkins] cpython: cleanup the construction of __qualname__ (closes #19301 again)

benjamin.peterson python-checkins at python.org
Sun Oct 20 23:51:01 CEST 2013


http://hg.python.org/cpython/rev/bb2affc1e317
changeset:   86521:bb2affc1e317
user:        Benjamin Peterson <benjamin at python.org>
date:        Sun Oct 20 17:50:28 2013 -0400
summary:
  cleanup the construction of __qualname__ (closes #19301 again)

files:
  Lib/importlib/_bootstrap.py |    3 +-
  Lib/test/test_descr.py      |    4 +-
  Lib/test/test_funcattrs.py  |    5 +-
  Python/compile.c            |  154 +++++++------
  Python/importlib.h          |  270 ++++++++++++------------
  5 files changed, 227 insertions(+), 209 deletions(-)


diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -370,12 +370,13 @@
 #     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)
+#     Python 3.4a4  3300 (more 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 = (3290).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3300).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
@@ -4519,8 +4519,10 @@
 
         global Y
         class Y:
-            pass
+            class Inside:
+                pass
         self.assertEqual(Y.__qualname__, 'Y')
+        self.assertEqual(Y.Inside.__qualname__, 'Y.Inside')
 
     def test_qualname_dict(self):
         ns = {'__qualname__': 'some.name'}
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
@@ -9,7 +9,9 @@
             pass
         global inner_global_function
         def inner_global_function():
-            pass
+            def inner_function2():
+                pass
+            return inner_function2
         return LocalClass
     return lambda: inner_function
 
@@ -120,6 +122,7 @@
         self.assertEqual(global_function()()().__qualname__,
                          'global_function.<locals>.inner_function.<locals>.LocalClass')
         self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
+        self.assertEqual(inner_global_function().__qualname__, 'inner_global_function.<locals>.inner_function2')
         self.b.__qualname__ = 'c'
         self.assertEqual(self.b.__qualname__, 'c')
         self.b.__qualname__ = 'd'
diff --git a/Python/compile.c b/Python/compile.c
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -94,6 +94,7 @@
     COMPILER_SCOPE_MODULE,
     COMPILER_SCOPE_CLASS,
     COMPILER_SCOPE_FUNCTION,
+    COMPILER_SCOPE_LAMBDA,
     COMPILER_SCOPE_COMPREHENSION,
 };
 
@@ -104,6 +105,7 @@
     PySTEntryObject *u_ste;
 
     PyObject *u_name;
+    PyObject *u_qualname;  /* dot-separated qualified name (lazy) */
     int u_scope_type;
 
     /* The following fields are dicts that map objects to
@@ -199,6 +201,7 @@
                                 expr_ty starargs,
                                 expr_ty kwargs);
 static int compiler_try_except(struct compiler *, stmt_ty);
+static int compiler_set_qualname(struct compiler *);
 
 static PyCodeObject *assemble(struct compiler *, int addNone);
 static PyObject *__doc__;
@@ -506,6 +509,7 @@
     }
     Py_CLEAR(u->u_ste);
     Py_CLEAR(u->u_name);
+    Py_CLEAR(u->u_qualname);
     Py_CLEAR(u->u_consts);
     Py_CLEAR(u->u_names);
     Py_CLEAR(u->u_varnames);
@@ -620,6 +624,11 @@
     if (compiler_use_new_block(c) == NULL)
         return 0;
 
+    if (u->u_scope_type != COMPILER_SCOPE_MODULE) {
+        if (!compiler_set_qualname(c))
+            return 0;
+    }
+
     return 1;
 }
 
@@ -647,71 +656,77 @@
 
 }
 
-static PyObject *
-compiler_scope_qualname(struct compiler *c, identifier scope_name)
+static int
+compiler_set_qualname(struct compiler *c)
 {
+    _Py_static_string(dot, ".");
+    _Py_static_string(dot_locals, ".<locals>");
     Py_ssize_t stack_size;
-    int global_scope;
-    _Py_static_string(dot, ".");
-    _Py_static_string(locals, "<locals>");
-    struct compiler_unit *u;
-    PyObject *capsule, *name, *seq, *dot_str, *locals_str;
-
-    u = c->u;
-    seq = PyList_New(0);
-    if (seq == NULL)
-        return NULL;
-
+    struct compiler_unit *u = c->u;
+    PyObject *name, *base, *dot_str, *dot_locals_str;
+
+    base = NULL;
     stack_size = PyList_GET_SIZE(c->c_stack);
     assert(stack_size >= 1);
-    global_scope = stack_size == 1;
-    if (scope_name != NULL && !global_scope) {
-        int scope;
-        PyObject *mangled;
+    if (stack_size > 1) {
+        int scope, force_global = 0;
+        struct compiler_unit *parent;
+        PyObject *mangled, *capsule;
+
         capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
-        u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
-        assert(u);
-        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 (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;
+        parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
+        assert(parent);
+
+        if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) {
+            assert(u->u_name);
+            mangled = _Py_Mangle(parent->u_private, u->u_name);
+            if (!mangled)
+                return 0;
+            scope = PyST_GetScope(parent->u_ste, mangled);
+            Py_DECREF(mangled);
+            assert(scope != GLOBAL_IMPLICIT);
+            if (scope == GLOBAL_EXPLICIT)
+                force_global = 1;
+        }
+
+        if (!force_global) {
+            if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION
+                || parent->u_scope_type == COMPILER_SCOPE_LAMBDA) {
+                dot_locals_str = _PyUnicode_FromId(&dot_locals);
+                if (dot_locals_str == NULL)
+                    return 0;
+                base = PyUnicode_Concat(parent->u_qualname, dot_locals_str);
+                if (base == NULL)
+                    return 0;
+            }
+            else {
+                Py_INCREF(parent->u_qualname);
+                base = parent->u_qualname;
             }
         }
     }
 
-    u = c->u;
-    if (PyList_Append(seq, u->u_name))
-        goto _error;
-    dot_str = _PyUnicode_FromId(&dot);
-    if (dot_str == NULL)
-        goto _error;
-    name = PyUnicode_Join(dot_str, seq);
-    Py_DECREF(seq);
-    return name;
-
-_error:
-    Py_XDECREF(seq);
-    return NULL;
+    if (base != NULL) {
+        dot_str = _PyUnicode_FromId(&dot);
+        if (dot_str == NULL) {
+            Py_DECREF(base);
+            return 0;
+        }
+        name = PyUnicode_Concat(base, dot_str);
+        Py_DECREF(base);
+        if (name == NULL)
+            return 0;
+        PyUnicode_Append(&name, u->u_name);
+        if (name == NULL)
+            return 0;
+    }
+    else {
+        Py_INCREF(u->u_name);
+        name = u->u_name;
+    }
+    u->u_qualname = name;
+
+    return 1;
 }
 
 /* Allocate a new block and return a pointer to it.
@@ -1661,9 +1676,10 @@
         VISIT_IN_SCOPE(c, stmt, st);
     }
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c, s->v.FunctionDef.name);
+    qualname = c->u->u_qualname;
+    Py_INCREF(qualname);
     compiler_exit_scope(c);
-    if (qualname == NULL || co == NULL) {
+    if (co == NULL) {
         Py_XDECREF(qualname);
         Py_XDECREF(co);
         return 0;
@@ -1733,14 +1749,8 @@
             return 0;
         }
         Py_DECREF(str);
-        /* store the __qualname__ */
-        str = compiler_scope_qualname(c, s->v.ClassDef.name);
-        if (!str) {
-            compiler_exit_scope(c);
-            return 0;
-        }
-        ADDOP_O(c, LOAD_CONST, str, consts);
-        Py_DECREF(str);
+        assert(c->u->u_qualname);
+        ADDOP_O(c, LOAD_CONST, c->u->u_qualname, consts);
         str = PyUnicode_InternFromString("__qualname__");
         if (!str || !compiler_nameop(c, str, Store)) {
             Py_XDECREF(str);
@@ -1855,7 +1865,7 @@
         if (res < 0) return 0;
         kw_default_count = res;
     }
-    if (!compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION,
+    if (!compiler_enter_scope(c, name, COMPILER_SCOPE_LAMBDA,
                               (void *)e, e->lineno))
         return 0;
 
@@ -1874,9 +1884,10 @@
         ADDOP_IN_SCOPE(c, RETURN_VALUE);
     }
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c, NULL);
+    qualname = c->u->u_qualname;
+    Py_INCREF(qualname);
     compiler_exit_scope(c);
-    if (qualname == NULL || co == NULL)
+    if (co == NULL)
         return 0;
 
     arglength = asdl_seq_LEN(args->defaults);
@@ -3151,9 +3162,10 @@
     }
 
     co = assemble(c, 1);
-    qualname = compiler_scope_qualname(c, NULL);
+    qualname = c->u->u_qualname;
+    Py_INCREF(qualname);
     compiler_exit_scope(c);
-    if (qualname == NULL || co == NULL)
+    if (co == NULL)
         goto error;
 
     if (!compiler_make_closure(c, co, 0, qualname))
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