Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6b4f780

Browse files
committed
cleanup the construction of __qualname__ (closes #19301 again)
1 parent a7a150c commit 6b4f780

5 files changed

Lines changed: 226 additions & 208 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,13 @@ def _call_with_frames_removed(f, *args, **kwds):
370370
# Python 3.4a1 3270 (various tweaks to the __class__ closure)
371371
# Python 3.4a1 3280 (remove implicit class argument)
372372
# Python 3.4a4 3290 (changes to __qualname__ computation)
373+
# Python 3.4a4 3300 (more changes to __qualname__ computation)
373374
#
374375
# MAGIC must change whenever the bytecode emitted by the compiler may no
375376
# longer be understood by older implementations of the eval loop (usually
376377
# due to the addition of new opcodes).
377378

378-
MAGIC_NUMBER = (3290).to_bytes(2, 'little') + b'\r\n'
379+
MAGIC_NUMBER = (3300).to_bytes(2, 'little') + b'\r\n'
379380
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
380381

381382
_PYCACHE = '__pycache__'

Lib/test/test_descr.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4519,8 +4519,10 @@ class X:
45194519

45204520
global Y
45214521
class Y:
4522-
pass
4522+
class Inside:
4523+
pass
45234524
self.assertEqual(Y.__qualname__, 'Y')
4525+
self.assertEqual(Y.Inside.__qualname__, 'Y.Inside')
45244526

45254527
def test_qualname_dict(self):
45264528
ns = {'__qualname__': 'some.name'}

Lib/test/test_funcattrs.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ class LocalClass:
99
pass
1010
global inner_global_function
1111
def inner_global_function():
12-
pass
12+
def inner_function2():
13+
pass
14+
return inner_function2
1315
return LocalClass
1416
return lambda: inner_function
1517

@@ -120,6 +122,7 @@ def test___qualname__(self):
120122
self.assertEqual(global_function()()().__qualname__,
121123
'global_function.<locals>.inner_function.<locals>.LocalClass')
122124
self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
125+
self.assertEqual(inner_global_function().__qualname__, 'inner_global_function.<locals>.inner_function2')
123126
self.b.__qualname__ = 'c'
124127
self.assertEqual(self.b.__qualname__, 'c')
125128
self.b.__qualname__ = 'd'

Python/compile.c

Lines changed: 82 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ enum {
9494
COMPILER_SCOPE_MODULE,
9595
COMPILER_SCOPE_CLASS,
9696
COMPILER_SCOPE_FUNCTION,
97+
COMPILER_SCOPE_LAMBDA,
9798
COMPILER_SCOPE_COMPREHENSION,
9899
};
99100

@@ -104,6 +105,7 @@ struct compiler_unit {
104105
PySTEntryObject *u_ste;
105106

106107
PyObject *u_name;
108+
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
107109
int u_scope_type;
108110

109111
/* The following fields are dicts that map objects to
@@ -199,6 +201,7 @@ static int compiler_call_helper(struct compiler *c, int n,
199201
expr_ty starargs,
200202
expr_ty kwargs);
201203
static int compiler_try_except(struct compiler *, stmt_ty);
204+
static int compiler_set_qualname(struct compiler *);
202205

203206
static PyCodeObject *assemble(struct compiler *, int addNone);
204207
static PyObject *__doc__;
@@ -506,6 +509,7 @@ compiler_unit_free(struct compiler_unit *u)
506509
}
507510
Py_CLEAR(u->u_ste);
508511
Py_CLEAR(u->u_name);
512+
Py_CLEAR(u->u_qualname);
509513
Py_CLEAR(u->u_consts);
510514
Py_CLEAR(u->u_names);
511515
Py_CLEAR(u->u_varnames);
@@ -620,6 +624,11 @@ compiler_enter_scope(struct compiler *c, identifier name,
620624
if (compiler_use_new_block(c) == NULL)
621625
return 0;
622626

627+
if (u->u_scope_type != COMPILER_SCOPE_MODULE) {
628+
if (!compiler_set_qualname(c))
629+
return 0;
630+
}
631+
623632
return 1;
624633
}
625634

@@ -647,71 +656,77 @@ compiler_exit_scope(struct compiler *c)
647656

648657
}
649658

650-
static PyObject *
651-
compiler_scope_qualname(struct compiler *c, identifier scope_name)
659+
static int
660+
compiler_set_qualname(struct compiler *c)
652661
{
653-
Py_ssize_t stack_size;
654-
int global_scope;
655662
_Py_static_string(dot, ".");
656-
_Py_static_string(locals, "<locals>");
657-
struct compiler_unit *u;
658-
PyObject *capsule, *name, *seq, *dot_str, *locals_str;
659-
660-
u = c->u;
661-
seq = PyList_New(0);
662-
if (seq == NULL)
663-
return NULL;
663+
_Py_static_string(dot_locals, ".<locals>");
664+
Py_ssize_t stack_size;
665+
struct compiler_unit *u = c->u;
666+
PyObject *name, *base, *dot_str, *dot_locals_str;
664667

668+
base = NULL;
665669
stack_size = PyList_GET_SIZE(c->c_stack);
666670
assert(stack_size >= 1);
667-
global_scope = stack_size == 1;
668-
if (scope_name != NULL && !global_scope) {
669-
int scope;
670-
PyObject *mangled;
671+
if (stack_size > 1) {
672+
int scope, force_global = 0;
673+
struct compiler_unit *parent;
674+
PyObject *mangled, *capsule;
675+
671676
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
672-
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
673-
assert(u);
674-
mangled = _Py_Mangle(u->u_private, scope_name);
675-
if (!mangled)
676-
return NULL;
677-
scope = PyST_GetScope(u->u_ste, mangled);
678-
Py_DECREF(mangled);
679-
assert(scope != GLOBAL_IMPLICIT);
680-
if (scope == GLOBAL_EXPLICIT)
681-
global_scope = 1;
682-
}
683-
if (!global_scope) {
684-
Py_ssize_t i;
685-
for (i = 1; i < stack_size; i++) {
686-
capsule = PyList_GET_ITEM(c->c_stack, i);
687-
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
688-
assert(u);
689-
assert(u->u_scope_type != COMPILER_SCOPE_MODULE);
690-
if (PyList_Append(seq, u->u_name))
691-
goto _error;
692-
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
693-
locals_str = _PyUnicode_FromId(&locals);
694-
if (locals_str == NULL)
695-
goto _error;
696-
if (PyList_Append(seq, locals_str))
697-
goto _error;
677+
parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
678+
assert(parent);
679+
680+
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) {
681+
assert(u->u_name);
682+
mangled = _Py_Mangle(parent->u_private, u->u_name);
683+
if (!mangled)
684+
return 0;
685+
scope = PyST_GetScope(parent->u_ste, mangled);
686+
Py_DECREF(mangled);
687+
assert(scope != GLOBAL_IMPLICIT);
688+
if (scope == GLOBAL_EXPLICIT)
689+
force_global = 1;
690+
}
691+
692+
if (!force_global) {
693+
if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION
694+
|| parent->u_scope_type == COMPILER_SCOPE_LAMBDA) {
695+
dot_locals_str = _PyUnicode_FromId(&dot_locals);
696+
if (dot_locals_str == NULL)
697+
return 0;
698+
base = PyUnicode_Concat(parent->u_qualname, dot_locals_str);
699+
if (base == NULL)
700+
return 0;
701+
}
702+
else {
703+
Py_INCREF(parent->u_qualname);
704+
base = parent->u_qualname;
698705
}
699706
}
700707
}
701708

702-
u = c->u;
703-
if (PyList_Append(seq, u->u_name))
704-
goto _error;
705-
dot_str = _PyUnicode_FromId(&dot);
706-
if (dot_str == NULL)
707-
goto _error;
708-
name = PyUnicode_Join(dot_str, seq);
709-
Py_DECREF(seq);
710-
return name;
711-
712-
_error:
713-
Py_XDECREF(seq);
714-
return NULL;
709+
if (base != NULL) {
710+
dot_str = _PyUnicode_FromId(&dot);
711+
if (dot_str == NULL) {
712+
Py_DECREF(base);
713+
return 0;
714+
}
715+
name = PyUnicode_Concat(base, dot_str);
716+
Py_DECREF(base);
717+
if (name == NULL)
718+
return 0;
719+
PyUnicode_Append(&name, u->u_name);
720+
if (name == NULL)
721+
return 0;
722+
}
723+
else {
724+
Py_INCREF(u->u_name);
725+
name = u->u_name;
726+
}
727+
u->u_qualname = name;
728+
729+
return 1;
715730
}
716731

717732
/* Allocate a new block and return a pointer to it.
@@ -1661,9 +1676,10 @@ compiler_function(struct compiler *c, stmt_ty s)
16611676
VISIT_IN_SCOPE(c, stmt, st);
16621677
}
16631678
co = assemble(c, 1);
1664-
qualname = compiler_scope_qualname(c, s->v.FunctionDef.name);
1679+
qualname = c->u->u_qualname;
1680+
Py_INCREF(qualname);
16651681
compiler_exit_scope(c);
1666-
if (qualname == NULL || co == NULL) {
1682+
if (co == NULL) {
16671683
Py_XDECREF(qualname);
16681684
Py_XDECREF(co);
16691685
return 0;
@@ -1733,14 +1749,8 @@ compiler_class(struct compiler *c, stmt_ty s)
17331749
return 0;
17341750
}
17351751
Py_DECREF(str);
1736-
/* store the __qualname__ */
1737-
str = compiler_scope_qualname(c, s->v.ClassDef.name);
1738-
if (!str) {
1739-
compiler_exit_scope(c);
1740-
return 0;
1741-
}
1742-
ADDOP_O(c, LOAD_CONST, str, consts);
1743-
Py_DECREF(str);
1752+
assert(c->u->u_qualname);
1753+
ADDOP_O(c, LOAD_CONST, c->u->u_qualname, consts);
17441754
str = PyUnicode_InternFromString("__qualname__");
17451755
if (!str || !compiler_nameop(c, str, Store)) {
17461756
Py_XDECREF(str);
@@ -1855,7 +1865,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
18551865
if (res < 0) return 0;
18561866
kw_default_count = res;
18571867
}
1858-
if (!compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION,
1868+
if (!compiler_enter_scope(c, name, COMPILER_SCOPE_LAMBDA,
18591869
(void *)e, e->lineno))
18601870
return 0;
18611871

@@ -1874,9 +1884,10 @@ compiler_lambda(struct compiler *c, expr_ty e)
18741884
ADDOP_IN_SCOPE(c, RETURN_VALUE);
18751885
}
18761886
co = assemble(c, 1);
1877-
qualname = compiler_scope_qualname(c, NULL);
1887+
qualname = c->u->u_qualname;
1888+
Py_INCREF(qualname);
18781889
compiler_exit_scope(c);
1879-
if (qualname == NULL || co == NULL)
1890+
if (co == NULL)
18801891
return 0;
18811892

18821893
arglength = asdl_seq_LEN(args->defaults);
@@ -3151,9 +3162,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
31513162
}
31523163

31533164
co = assemble(c, 1);
3154-
qualname = compiler_scope_qualname(c, NULL);
3165+
qualname = c->u->u_qualname;
3166+
Py_INCREF(qualname);
31553167
compiler_exit_scope(c);
3156-
if (qualname == NULL || co == NULL)
3168+
if (co == NULL)
31573169
goto error;
31583170

31593171
if (!compiler_make_closure(c, co, 0, qualname))

0 commit comments

Comments
 (0)