give explicitly global functions and classes a global __qualname__ (closes #19301)
This commit is contained in:
parent
3586673703
commit
3d9e481ece
|
@ -369,12 +369,13 @@ def _call_with_frames_removed(f, *args, **kwds):
|
||||||
# free vars)
|
# free vars)
|
||||||
# Python 3.4a1 3270 (various tweaks to the __class__ closure)
|
# Python 3.4a1 3270 (various tweaks to the __class__ closure)
|
||||||
# Python 3.4a1 3280 (remove implicit class argument)
|
# 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
|
# MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||||
# longer be understood by older implementations of the eval loop (usually
|
# longer be understood by older implementations of the eval loop (usually
|
||||||
# due to the addition of new opcodes).
|
# 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
|
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||||
|
|
||||||
_PYCACHE = '__pycache__'
|
_PYCACHE = '__pycache__'
|
||||||
|
|
|
@ -4517,6 +4517,11 @@ order (MRO) for bases """
|
||||||
self.assertRaises(TypeError, type.__dict__['__qualname__'].__set__,
|
self.assertRaises(TypeError, type.__dict__['__qualname__'].__set__,
|
||||||
str, 'Oink')
|
str, 'Oink')
|
||||||
|
|
||||||
|
global Y
|
||||||
|
class Y:
|
||||||
|
pass
|
||||||
|
self.assertEqual(Y.__qualname__, 'Y')
|
||||||
|
|
||||||
def test_qualname_dict(self):
|
def test_qualname_dict(self):
|
||||||
ns = {'__qualname__': 'some.name'}
|
ns = {'__qualname__': 'some.name'}
|
||||||
tp = type('Foo', (), ns)
|
tp = type('Foo', (), ns)
|
||||||
|
|
|
@ -7,6 +7,9 @@ def global_function():
|
||||||
def inner_function():
|
def inner_function():
|
||||||
class LocalClass:
|
class LocalClass:
|
||||||
pass
|
pass
|
||||||
|
global inner_global_function
|
||||||
|
def inner_global_function():
|
||||||
|
pass
|
||||||
return LocalClass
|
return LocalClass
|
||||||
return lambda: inner_function
|
return lambda: inner_function
|
||||||
|
|
||||||
|
@ -116,6 +119,7 @@ class FunctionPropertiesTest(FuncAttrsTest):
|
||||||
'global_function.<locals>.inner_function')
|
'global_function.<locals>.inner_function')
|
||||||
self.assertEqual(global_function()()().__qualname__,
|
self.assertEqual(global_function()()().__qualname__,
|
||||||
'global_function.<locals>.inner_function.<locals>.LocalClass')
|
'global_function.<locals>.inner_function.<locals>.LocalClass')
|
||||||
|
self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
|
||||||
self.b.__qualname__ = 'c'
|
self.b.__qualname__ = 'c'
|
||||||
self.assertEqual(self.b.__qualname__, 'c')
|
self.assertEqual(self.b.__qualname__, 'c')
|
||||||
self.b.__qualname__ = 'd'
|
self.b.__qualname__ = 'd'
|
||||||
|
|
|
@ -10,6 +10,9 @@ Projected release date: 2013-10-20
|
||||||
Core and Builtins
|
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 #19279: UTF-7 decoder no more produces illegal strings.
|
||||||
|
|
||||||
- Issue #16612: Add "Argument Clinic", a compile-time preprocessor for
|
- Issue #16612: Add "Argument Clinic", a compile-time preprocessor for
|
||||||
|
|
|
@ -650,9 +650,10 @@ compiler_exit_scope(struct compiler *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
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(dot, ".");
|
||||||
_Py_static_string(locals, "<locals>");
|
_Py_static_string(locals, "<locals>");
|
||||||
struct compiler_unit *u;
|
struct compiler_unit *u;
|
||||||
|
@ -669,12 +670,29 @@ compiler_scope_qualname(struct compiler *c)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
stack_size = PyList_GET_SIZE(c->c_stack);
|
stack_size = PyList_GET_SIZE(c->c_stack);
|
||||||
for (i = 0; i < stack_size; 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);
|
||||||
|
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);
|
capsule = PyList_GET_ITEM(c->c_stack, i);
|
||||||
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
|
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
|
||||||
assert(u);
|
assert(u);
|
||||||
if (u->u_scope_type == COMPILER_SCOPE_MODULE)
|
assert(u->u_scope_type != COMPILER_SCOPE_MODULE);
|
||||||
continue;
|
|
||||||
if (PyList_Append(seq, u->u_name))
|
if (PyList_Append(seq, u->u_name))
|
||||||
goto _error;
|
goto _error;
|
||||||
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
|
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) {
|
||||||
|
@ -685,6 +703,8 @@ compiler_scope_qualname(struct compiler *c)
|
||||||
goto _error;
|
goto _error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u = c->u;
|
u = c->u;
|
||||||
if (PyList_Append(seq, u->u_name))
|
if (PyList_Append(seq, u->u_name))
|
||||||
goto _error;
|
goto _error;
|
||||||
|
@ -1649,7 +1669,7 @@ compiler_function(struct compiler *c, stmt_ty s)
|
||||||
VISIT_IN_SCOPE(c, stmt, st);
|
VISIT_IN_SCOPE(c, stmt, st);
|
||||||
}
|
}
|
||||||
co = assemble(c, 1);
|
co = assemble(c, 1);
|
||||||
qualname = compiler_scope_qualname(c);
|
qualname = compiler_scope_qualname(c, s->v.FunctionDef.name);
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
if (qualname == NULL || co == NULL) {
|
if (qualname == NULL || co == NULL) {
|
||||||
Py_XDECREF(qualname);
|
Py_XDECREF(qualname);
|
||||||
|
@ -1722,7 +1742,7 @@ compiler_class(struct compiler *c, stmt_ty s)
|
||||||
}
|
}
|
||||||
Py_DECREF(str);
|
Py_DECREF(str);
|
||||||
/* store the __qualname__ */
|
/* store the __qualname__ */
|
||||||
str = compiler_scope_qualname(c);
|
str = compiler_scope_qualname(c, s->v.ClassDef.name);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1862,7 +1882,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
|
||||||
ADDOP_IN_SCOPE(c, RETURN_VALUE);
|
ADDOP_IN_SCOPE(c, RETURN_VALUE);
|
||||||
}
|
}
|
||||||
co = assemble(c, 1);
|
co = assemble(c, 1);
|
||||||
qualname = compiler_scope_qualname(c);
|
qualname = compiler_scope_qualname(c, NULL);
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
if (qualname == NULL || co == NULL)
|
if (qualname == NULL || co == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3139,7 +3159,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
|
||||||
}
|
}
|
||||||
|
|
||||||
co = assemble(c, 1);
|
co = assemble(c, 1);
|
||||||
qualname = compiler_scope_qualname(c);
|
qualname = compiler_scope_qualname(c, NULL);
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
if (qualname == NULL || co == NULL)
|
if (qualname == NULL || co == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
6647
Python/importlib.h
6647
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue