[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