Commit 86a36b50 authored by Antoine Pitrou's avatar Antoine Pitrou

PEP 3155 / issue #13448: Qualified name for classes and functions.

parent 0e86a584
...@@ -38,6 +38,16 @@ There are a few functions specific to Python functions. ...@@ -38,6 +38,16 @@ There are a few functions specific to Python functions.
object, the argument defaults and closure are set to *NULL*. object, the argument defaults and closure are set to *NULL*.
.. c:function:: PyObject* PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
As :c:func:`PyFunction_New`, but also allows to set the function object's
``__qualname__`` attribute. *qualname* should be a unicode object or NULL;
if NULL, the ``__qualname__`` attribute is set to the same value as its
``__name__`` attribute.
.. versionadded:: 3.3
.. c:function:: PyObject* PyFunction_GetCode(PyObject *op) .. c:function:: PyObject* PyFunction_GetCode(PyObject *op)
Return the code object associated with the function object *op*. Return the code object associated with the function object *op*.
......
...@@ -465,6 +465,11 @@ PyFunction_New:PyObject*::+1: ...@@ -465,6 +465,11 @@ PyFunction_New:PyObject*::+1:
PyFunction_New:PyObject*:code:+1: PyFunction_New:PyObject*:code:+1:
PyFunction_New:PyObject*:globals:+1: PyFunction_New:PyObject*:globals:+1:
PyFunction_NewWithQualName:PyObject*::+1:
PyFunction_NewWithQualName:PyObject*:code:+1:
PyFunction_NewWithQualName:PyObject*:globals:+1:
PyFunction_NewWithQualName:PyObject*:qualname:+1:
PyFunction_SetClosure:int::: PyFunction_SetClosure:int:::
PyFunction_SetClosure:PyObject*:op:0: PyFunction_SetClosure:PyObject*:op:0:
PyFunction_SetClosure:PyObject*:closure:+1: PyFunction_SetClosure:PyObject*:closure:+1:
......
...@@ -544,6 +544,24 @@ Glossary ...@@ -544,6 +544,24 @@ Glossary
for piece in food: for piece in food:
print(piece) print(piece)
qualified name
A dotted name showing the "path" from a module's global scope to a
class, function or method defined in that module, as defined in
:pep:`3155`. For top-level functions and classes, the qualified name
is the same as the object's name::
>>> class C:
... class D:
... def meth(self):
... pass
...
>>> C.__qualname__
'C'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__qualname__
'C.D.meth'
reference count reference count
The number of references to an object. When the reference count of an The number of references to an object. When the reference count of an
object drops to zero, it is deallocated. Reference counting is object drops to zero, it is deallocated. Reference counting is
......
...@@ -2824,6 +2824,13 @@ types, where they are relevant. Some of these are not reported by the ...@@ -2824,6 +2824,13 @@ types, where they are relevant. Some of these are not reported by the
The name of the class or type. The name of the class or type.
.. attribute:: class.__qualname__
The :term:`qualified name` of the class or type.
.. versionadded:: 3.3
.. attribute:: class.__mro__ .. attribute:: class.__mro__
This attribute is a tuple of classes that are considered when looking for This attribute is a tuple of classes that are considered when looking for
......
...@@ -448,6 +448,11 @@ Callable types ...@@ -448,6 +448,11 @@ Callable types
+-------------------------+-------------------------------+-----------+ +-------------------------+-------------------------------+-----------+
| :attr:`__name__` | The function's name | Writable | | :attr:`__name__` | The function's name | Writable |
+-------------------------+-------------------------------+-----------+ +-------------------------+-------------------------------+-----------+
| :attr:`__qualname__` | The function's | Writable |
| | :term:`qualified name` | |
| | | |
| | .. versionadded:: 3.3 | |
+-------------------------+-------------------------------+-----------+
| :attr:`__module__` | The name of the module the | Writable | | :attr:`__module__` | The name of the module the | Writable |
| | function was defined in, or | | | | function was defined in, or | |
| | ``None`` if unavailable. | | | | ``None`` if unavailable. | |
......
...@@ -31,6 +31,7 @@ typedef struct { ...@@ -31,6 +31,7 @@ typedef struct {
PyObject *func_weakreflist; /* List of weak references */ PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */ PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */ PyObject *func_annotations; /* Annotations, a dict or NULL */
PyObject *func_qualname; /* The qualified name */
/* Invariant: /* Invariant:
* func_closure contains the bindings for func_code->co_freevars, so * func_closure contains the bindings for func_code->co_freevars, so
...@@ -44,6 +45,7 @@ PyAPI_DATA(PyTypeObject) PyFunction_Type; ...@@ -44,6 +45,7 @@ PyAPI_DATA(PyTypeObject) PyFunction_Type;
#define PyFunction_Check(op) (Py_TYPE(op) == &PyFunction_Type) #define PyFunction_Check(op) (Py_TYPE(op) == &PyFunction_Type)
PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *); PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
......
...@@ -418,7 +418,7 @@ typedef struct _heaptypeobject { ...@@ -418,7 +418,7 @@ typedef struct _heaptypeobject {
a given operator (e.g. __getitem__). a given operator (e.g. __getitem__).
see add_operators() in typeobject.c . */ see add_operators() in typeobject.c . */
PyBufferProcs as_buffer; PyBufferProcs as_buffer;
PyObject *ht_name, *ht_slots; PyObject *ht_name, *ht_slots, *ht_qualname;
/* here are optional user slots, followed by the members. */ /* here are optional user slots, followed by the members. */
} PyHeapTypeObject; } PyHeapTypeObject;
......
...@@ -166,7 +166,7 @@ def visiblename(name, all=None, obj=None): ...@@ -166,7 +166,7 @@ def visiblename(name, all=None, obj=None):
if name in {'__builtins__', '__doc__', '__file__', '__path__', if name in {'__builtins__', '__doc__', '__file__', '__path__',
'__module__', '__name__', '__slots__', '__package__', '__module__', '__name__', '__slots__', '__package__',
'__cached__', '__author__', '__credits__', '__date__', '__cached__', '__author__', '__credits__', '__date__',
'__version__'}: '__version__', '__qualname__'}:
return 0 return 0
# Private names are hidden, but special names are displayed. # Private names are hidden, but special names are displayed.
if name.startswith('__') and name.endswith('__'): return 1 if name.startswith('__') and name.endswith('__'): return 1
......
...@@ -16,7 +16,7 @@ cellvars: ('x',) ...@@ -16,7 +16,7 @@ cellvars: ('x',)
freevars: () freevars: ()
nlocals: 2 nlocals: 2
flags: 3 flags: 3
consts: ('None', '<code object g>') consts: ('None', '<code object g>', "'f.<locals>.g'")
>>> dump(f(4).__code__) >>> dump(f(4).__code__)
name: g name: g
......
...@@ -4492,9 +4492,14 @@ class DictProxyTests(unittest.TestCase): ...@@ -4492,9 +4492,14 @@ class DictProxyTests(unittest.TestCase):
self.assertEqual(type(C.__dict__), type(B.__dict__)) self.assertEqual(type(C.__dict__), type(B.__dict__))
def test_repr(self): def test_repr(self):
# Testing dict_proxy.__repr__ # Testing dict_proxy.__repr__.
dict_ = {k: v for k, v in self.C.__dict__.items()} # We can't blindly compare with the repr of another dict as ordering
self.assertEqual(repr(self.C.__dict__), 'dict_proxy({!r})'.format(dict_)) # of keys and values is arbitrary and may differ.
r = repr(self.C.__dict__)
self.assertTrue(r.startswith('dict_proxy('), r)
self.assertTrue(r.endswith(')'), r)
for k, v in self.C.__dict__.items():
self.assertIn('{!r}: {!r}'.format(k, v), r)
class PTypesLongInitTest(unittest.TestCase): class PTypesLongInitTest(unittest.TestCase):
......
...@@ -339,6 +339,7 @@ Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR ...@@ -339,6 +339,7 @@ Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
Constants: Constants:
0: None 0: None
1: <code object f at (.*), file "(.*)", line (.*)> 1: <code object f at (.*), file "(.*)", line (.*)>
2: 'tricky.<locals>.f'
Variable names: Variable names:
0: x 0: x
1: y 1: y
......
...@@ -2,6 +2,15 @@ from test import support ...@@ -2,6 +2,15 @@ from test import support
import types import types
import unittest import unittest
def global_function():
def inner_function():
class LocalClass:
pass
return LocalClass
return lambda: inner_function
class FuncAttrsTest(unittest.TestCase): class FuncAttrsTest(unittest.TestCase):
def setUp(self): def setUp(self):
class F: class F:
...@@ -96,6 +105,24 @@ class FunctionPropertiesTest(FuncAttrsTest): ...@@ -96,6 +105,24 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(self.fi.a.__name__, 'a') self.assertEqual(self.fi.a.__name__, 'a')
self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError) self.cannot_set_attr(self.fi.a, "__name__", 'a', AttributeError)
def test___qualname__(self):
# PEP 3155
self.assertEqual(self.b.__qualname__, 'FuncAttrsTest.setUp.<locals>.b')
self.assertEqual(FuncAttrsTest.setUp.__qualname__, 'FuncAttrsTest.setUp')
self.assertEqual(global_function.__qualname__, 'global_function')
self.assertEqual(global_function().__qualname__,
'global_function.<locals>.<lambda>')
self.assertEqual(global_function()().__qualname__,
'global_function.<locals>.inner_function')
self.assertEqual(global_function()()().__qualname__,
'global_function.<locals>.inner_function.<locals>.LocalClass')
self.b.__qualname__ = 'c'
self.assertEqual(self.b.__qualname__, 'c')
self.b.__qualname__ = 'd'
self.assertEqual(self.b.__qualname__, 'd')
# __qualname__ must be a string
self.cannot_set_attr(self.b, '__qualname__', 7, TypeError)
def test___code__(self): def test___code__(self):
num_one, num_two = 7, 8 num_one, num_two = 7, 8
def a(): pass def a(): pass
......
...@@ -159,6 +159,7 @@ Use a __prepare__ method that returns an instrumented dict. ...@@ -159,6 +159,7 @@ Use a __prepare__ method that returns an instrumented dict.
... bar = 123 ... bar = 123
... ...
d['__module__'] = 'test.test_metaclass' d['__module__'] = 'test.test_metaclass'
d['__qualname__'] = 'C'
d['foo'] = 4 d['foo'] = 4
d['foo'] = 42 d['foo'] = 42
d['bar'] = 123 d['bar'] = 123
...@@ -177,12 +178,12 @@ Use a metaclass that doesn't derive from type. ...@@ -177,12 +178,12 @@ Use a metaclass that doesn't derive from type.
... b = 24 ... b = 24
... ...
meta: C () meta: C ()
ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)] ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
kw: [] kw: []
>>> type(C) is dict >>> type(C) is dict
True True
>>> print(sorted(C.items())) >>> print(sorted(C.items()))
[('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)] [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
>>> >>>
And again, with a __prepare__ attribute. And again, with a __prepare__ attribute.
...@@ -199,11 +200,12 @@ And again, with a __prepare__ attribute. ...@@ -199,11 +200,12 @@ And again, with a __prepare__ attribute.
... ...
prepare: C () [('other', 'booh')] prepare: C () [('other', 'booh')]
d['__module__'] = 'test.test_metaclass' d['__module__'] = 'test.test_metaclass'
d['__qualname__'] = 'C'
d['a'] = 1 d['a'] = 1
d['a'] = 2 d['a'] = 2
d['b'] = 3 d['b'] = 3
meta: C () meta: C ()
ns: [('__module__', 'test.test_metaclass'), ('a', 2), ('b', 3)] ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)]
kw: [('other', 'booh')] kw: [('other', 'booh')]
>>> >>>
......
...@@ -129,8 +129,8 @@ class ReprTests(unittest.TestCase): ...@@ -129,8 +129,8 @@ class ReprTests(unittest.TestCase):
self.assertIn(s.find("..."), [12, 13]) self.assertIn(s.find("..."), [12, 13])
def test_lambda(self): def test_lambda(self):
self.assertTrue(repr(lambda x: x).startswith( r = repr(lambda x: x)
"<function <lambda")) self.assertTrue(r.startswith("<function ReprTests.test_lambda.<locals>.<lambda"), r)
# XXX anonymous functions? see func_repr # XXX anonymous functions? see func_repr
def test_builtin_function(self): def test_builtin_function(self):
...@@ -278,13 +278,14 @@ class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ...@@ -278,13 +278,14 @@ class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
''') ''')
from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
# Unbound methods first # Unbound methods first
self.assertTrue(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod).startswith( r = repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod)
'<function amethod')) self.assertTrue(r.startswith('<function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod'), r)
# Bound method next # Bound method next
iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() iqux = qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
self.assertTrue(repr(iqux.amethod).startswith( r = repr(iqux.amethod)
self.assertTrue(r.startswith(
'<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <%s.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa object at 0x' \ '<bound method aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod of <%s.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa object at 0x' \
% (qux.__name__,) )) % (qux.__name__,) ), r)
def test_builtin_function(self): def test_builtin_function(self):
# XXX test built-in functions and methods with really long names # XXX test built-in functions and methods with really long names
......
...@@ -730,7 +730,7 @@ class SizeofTest(unittest.TestCase): ...@@ -730,7 +730,7 @@ class SizeofTest(unittest.TestCase):
check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
# function # function
def func(): pass def func(): pass
check(func, size(h + '11P')) check(func, size(h + '12P'))
class c(): class c():
@staticmethod @staticmethod
def foo(): def foo():
...@@ -828,7 +828,7 @@ class SizeofTest(unittest.TestCase): ...@@ -828,7 +828,7 @@ class SizeofTest(unittest.TestCase):
# type # type
# (PyTypeObject + PyNumberMethods + PyMappingMethods + # (PyTypeObject + PyNumberMethods + PyMappingMethods +
# PySequenceMethods + PyBufferProcs) # PySequenceMethods + PyBufferProcs)
s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 2P') s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 3P')
check(int, s) check(int, s)
# class # class
class newstyleclass(object): pass class newstyleclass(object): pass
......
...@@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1? ...@@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- PEP 3155 / issue #13448: Qualified name for classes and functions.
- Issue #13436: Fix a bogus error message when an AST object was passed - Issue #13436: Fix a bogus error message when an AST object was passed
an invalid integer value. an invalid integer value.
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "structmember.h" #include "structmember.h"
PyObject * PyObject *
PyFunction_New(PyObject *code, PyObject *globals) PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{ {
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, PyFunctionObject *op = PyObject_GC_New(PyFunctionObject,
&PyFunction_Type); &PyFunction_Type);
...@@ -54,6 +54,11 @@ PyFunction_New(PyObject *code, PyObject *globals) ...@@ -54,6 +54,11 @@ PyFunction_New(PyObject *code, PyObject *globals)
Py_INCREF(module); Py_INCREF(module);
op->func_module = module; op->func_module = module;
} }
if (qualname)
op->func_qualname = qualname;
else
op->func_qualname = op->func_name;
Py_INCREF(op->func_qualname);
} }
else else
return NULL; return NULL;
...@@ -61,6 +66,12 @@ PyFunction_New(PyObject *code, PyObject *globals) ...@@ -61,6 +66,12 @@ PyFunction_New(PyObject *code, PyObject *globals)
return (PyObject *)op; return (PyObject *)op;
} }
PyObject *
PyFunction_New(PyObject *code, PyObject *globals)
{
return PyFunction_NewWithQualName(code, globals, NULL);
}
PyObject * PyObject *
PyFunction_GetCode(PyObject *op) PyFunction_GetCode(PyObject *op)
{ {
...@@ -333,6 +344,32 @@ func_set_name(PyFunctionObject *op, PyObject *value) ...@@ -333,6 +344,32 @@ func_set_name(PyFunctionObject *op, PyObject *value)
return 0; return 0;
} }
static PyObject *
func_get_qualname(PyFunctionObject *op)
{
Py_INCREF(op->func_qualname);
return op->func_qualname;
}
static int
func_set_qualname(PyFunctionObject *op, PyObject *value)
{
PyObject *tmp;
/* Not legal to del f.__qualname__ or to set it to anything
* other than a string object. */
if (value == NULL || !PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"__qualname__ must be set to a string object");
return -1;
}
tmp = op->func_qualname;
Py_INCREF(value);
op->func_qualname = value;
Py_DECREF(tmp);
return 0;
}
static PyObject * static PyObject *
func_get_defaults(PyFunctionObject *op) func_get_defaults(PyFunctionObject *op)
{ {
...@@ -441,6 +478,7 @@ static PyGetSetDef func_getsetlist[] = { ...@@ -441,6 +478,7 @@ static PyGetSetDef func_getsetlist[] = {
(setter)func_set_annotations}, (setter)func_set_annotations},
{"__dict__", (getter)func_get_dict, (setter)func_set_dict}, {"__dict__", (getter)func_get_dict, (setter)func_set_dict},
{"__name__", (getter)func_get_name, (setter)func_set_name}, {"__name__", (getter)func_get_name, (setter)func_set_name},
{"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
...@@ -561,6 +599,7 @@ func_dealloc(PyFunctionObject *op) ...@@ -561,6 +599,7 @@ func_dealloc(PyFunctionObject *op)
Py_XDECREF(op->func_dict); Py_XDECREF(op->func_dict);
Py_XDECREF(op->func_closure); Py_XDECREF(op->func_closure);
Py_XDECREF(op->func_annotations); Py_XDECREF(op->func_annotations);
Py_XDECREF(op->func_qualname);
PyObject_GC_Del(op); PyObject_GC_Del(op);
} }
...@@ -568,7 +607,7 @@ static PyObject* ...@@ -568,7 +607,7 @@ static PyObject*
func_repr(PyFunctionObject *op) func_repr(PyFunctionObject *op)
{ {
return PyUnicode_FromFormat("<function %U at %p>", return PyUnicode_FromFormat("<function %U at %p>",
op->func_name, op); op->func_qualname, op);
} }
static int static int
...@@ -584,6 +623,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg) ...@@ -584,6 +623,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
Py_VISIT(f->func_dict); Py_VISIT(f->func_dict);
Py_VISIT(f->func_closure); Py_VISIT(f->func_closure);
Py_VISIT(f->func_annotations); Py_VISIT(f->func_annotations);
Py_VISIT(f->func_qualname);
return 0; return 0;
} }
......
...@@ -242,6 +242,19 @@ type_name(PyTypeObject *type, void *context) ...@@ -242,6 +242,19 @@ type_name(PyTypeObject *type, void *context)
} }
} }
static PyObject *
type_qualname(PyTypeObject *type, void *context)
{
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
PyHeapTypeObject* et = (PyHeapTypeObject*)type;
Py_INCREF(et->ht_qualname);
return et->ht_qualname;
}
else {
return type_name(type, context);
}
}
static int static int
type_set_name(PyTypeObject *type, PyObject *value, void *context) type_set_name(PyTypeObject *type, PyObject *value, void *context)
{ {
...@@ -286,6 +299,25 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context) ...@@ -286,6 +299,25 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context)
return 0; return 0;
} }
static int
type_set_qualname(PyTypeObject *type, PyObject *value, void *context)
{
PyHeapTypeObject* et;
if (!PyUnicode_Check(value)) {
PyErr_Format(PyExc_TypeError,
"can only assign string to %s.__qualname__, not '%s'",
type->tp_name, Py_TYPE(value)->tp_name);
return -1;
}
et = (PyHeapTypeObject*)type;
Py_INCREF(value);
Py_DECREF(et->ht_qualname);
et->ht_qualname = value;
return 0;
}
static PyObject * static PyObject *
type_module(PyTypeObject *type, void *context) type_module(PyTypeObject *type, void *context)
{ {
...@@ -631,6 +663,7 @@ type___subclasscheck__(PyObject *type, PyObject *inst) ...@@ -631,6 +663,7 @@ type___subclasscheck__(PyObject *type, PyObject *inst)
static PyGetSetDef type_getsets[] = { static PyGetSetDef type_getsets[] = {
{"__name__", (getter)type_name, (setter)type_set_name, NULL}, {"__name__", (getter)type_name, (setter)type_set_name, NULL},
{"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL},
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__abstractmethods__", (getter)type_abstractmethods, {"__abstractmethods__", (getter)type_abstractmethods,
...@@ -652,7 +685,7 @@ type_repr(PyTypeObject *type) ...@@ -652,7 +685,7 @@ type_repr(PyTypeObject *type)
Py_DECREF(mod); Py_DECREF(mod);
mod = NULL; mod = NULL;
} }
name = type_name(type, NULL); name = type_qualname(type, NULL);
if (name == NULL) if (name == NULL)
return NULL; return NULL;
...@@ -1955,7 +1988,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -1955,7 +1988,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
{ {
PyObject *name, *bases, *dict; PyObject *name, *bases, *dict;
static char *kwlist[] = {"name", "bases", "dict", 0}; static char *kwlist[] = {"name", "bases", "dict", 0};
PyObject *slots, *tmp, *newslots; PyObject *qualname, *slots, *tmp, *newslots;
PyTypeObject *type, *base, *tmptype, *winner; PyTypeObject *type, *base, *tmptype, *winner;
PyHeapTypeObject *et; PyHeapTypeObject *et;
PyMemberDef *mp; PyMemberDef *mp;
...@@ -2032,6 +2065,18 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -2032,6 +2065,18 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
/* Check for a __qualname__ variable in dict */
qualname = PyDict_GetItemString(dict, "__qualname__");
if (qualname == NULL) {
qualname = name;
}
else {
if (PyDict_DelItemString(dict, "__qualname__") < 0) {
Py_DECREF(bases);
return NULL;
}
}
/* Check for a __slots__ sequence variable in dict, and count it */ /* Check for a __slots__ sequence variable in dict, and count it */
slots = PyDict_GetItemString(dict, "__slots__"); slots = PyDict_GetItemString(dict, "__slots__");
nslots = 0; nslots = 0;
...@@ -2185,7 +2230,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) ...@@ -2185,7 +2230,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
/* Keep name and slots alive in the extended type object */ /* Keep name and slots alive in the extended type object */
et = (PyHeapTypeObject *)type; et = (PyHeapTypeObject *)type;
Py_INCREF(name); Py_INCREF(name);
Py_INCREF(qualname);
et->ht_name = name; et->ht_name = name;
et->ht_qualname = qualname;
et->ht_slots = slots; et->ht_slots = slots;
/* Initialize tp_flags */ /* Initialize tp_flags */
...@@ -2369,6 +2416,8 @@ PyObject* PyType_FromSpec(PyType_Spec *spec) ...@@ -2369,6 +2416,8 @@ PyObject* PyType_FromSpec(PyType_Spec *spec)
res->ht_name = PyUnicode_FromString(spec->name); res->ht_name = PyUnicode_FromString(spec->name);
if (!res->ht_name) if (!res->ht_name)
goto fail; goto fail;
res->ht_qualname = res->ht_name;
Py_INCREF(res->ht_qualname);
res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name); res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name);
if (!res->ht_type.tp_name) if (!res->ht_type.tp_name)
goto fail; goto fail;
...@@ -2568,6 +2617,7 @@ type_dealloc(PyTypeObject *type) ...@@ -2568,6 +2617,7 @@ type_dealloc(PyTypeObject *type)
*/ */
PyObject_Free((char *)type->tp_doc); PyObject_Free((char *)type->tp_doc);
Py_XDECREF(et->ht_name); Py_XDECREF(et->ht_name);
Py_XDECREF(et->ht_qualname);
Py_XDECREF(et->ht_slots); Py_XDECREF(et->ht_slots);
Py_TYPE(type)->tp_free((PyObject *)type); Py_TYPE(type)->tp_free((PyObject *)type);
} }
...@@ -2983,7 +3033,7 @@ object_repr(PyObject *self) ...@@ -2983,7 +3033,7 @@ object_repr(PyObject *self)
Py_DECREF(mod); Py_DECREF(mod);
mod = NULL; mod = NULL;
} }
name = type_name(type, NULL); name = type_qualname(type, NULL);
if (name == NULL) if (name == NULL)
return NULL; return NULL;
if (mod != NULL && PyUnicode_CompareWithASCIIString(mod, "builtins")) if (mod != NULL && PyUnicode_CompareWithASCIIString(mod, "builtins"))
......
...@@ -2687,9 +2687,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2687,9 +2687,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
int kwdefaults = (oparg>>8) & 0xff; int kwdefaults = (oparg>>8) & 0xff;
int num_annotations = (oparg >> 16) & 0x7fff; int num_annotations = (oparg >> 16) & 0x7fff;
w = POP(); /* qualname */
v = POP(); /* code object */ v = POP(); /* code object */
x = PyFunction_New(v, f->f_globals); x = PyFunction_NewWithQualName(v, f->f_globals, w);
Py_DECREF(v); Py_DECREF(v);
Py_DECREF(w);
if (x != NULL && opcode == MAKE_CLOSURE) { if (x != NULL && opcode == MAKE_CLOSURE) {
v = POP(); v = POP();
......
...@@ -90,6 +90,13 @@ struct fblockinfo { ...@@ -90,6 +90,13 @@ struct fblockinfo {
basicblock *fb_block; basicblock *fb_block;
}; };
enum {
COMPILER_SCOPE_MODULE,
COMPILER_SCOPE_CLASS,
COMPILER_SCOPE_FUNCTION,
COMPILER_SCOPE_COMPREHENSION,
};
/* The following items change on entry and exit of code blocks. /* The following items change on entry and exit of code blocks.
They must be saved and restored when returning to a block. They must be saved and restored when returning to a block.
*/ */
...@@ -97,6 +104,9 @@ struct compiler_unit { ...@@ -97,6 +104,9 @@ struct compiler_unit {
PySTEntryObject *u_ste; PySTEntryObject *u_ste;
PyObject *u_name; PyObject *u_name;
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
int u_scope_type;
/* The following fields are dicts that map objects to /* The following fields are dicts that map objects to
the index of them in co_XXX. The index is used as the index of them in co_XXX. The index is used as
the argument for opcodes that refer to those collections. the argument for opcodes that refer to those collections.
...@@ -149,7 +159,7 @@ struct compiler { ...@@ -149,7 +159,7 @@ struct compiler {
PyArena *c_arena; /* pointer to memory allocation arena */ PyArena *c_arena; /* pointer to memory allocation arena */
}; };
static int compiler_enter_scope(struct compiler *, identifier, void *, int); static int compiler_enter_scope(struct compiler *, identifier, int, void *, int);
static void compiler_free(struct compiler *); static void compiler_free(struct compiler *);
static basicblock *compiler_new_block(struct compiler *); static basicblock *compiler_new_block(struct compiler *);
static int compiler_next_instr(struct compiler *, basicblock *); static int compiler_next_instr(struct compiler *, basicblock *);
...@@ -457,6 +467,7 @@ compiler_unit_free(struct compiler_unit *u) ...@@ -457,6 +467,7 @@ compiler_unit_free(struct compiler_unit *u)
} }
Py_CLEAR(u->u_ste); Py_CLEAR(u->u_ste);
Py_CLEAR(u->u_name); Py_CLEAR(u->u_name);
Py_CLEAR(u->u_qualname);
Py_CLEAR(u->u_consts); Py_CLEAR(u->u_consts);
Py_CLEAR(u->u_names); Py_CLEAR(u->u_names);
Py_CLEAR(u->u_varnames); Py_CLEAR(u->u_varnames);
...@@ -467,8 +478,8 @@ compiler_unit_free(struct compiler_unit *u) ...@@ -467,8 +478,8 @@ compiler_unit_free(struct compiler_unit *u)
} }
static int static int
compiler_enter_scope(struct compiler *c, identifier name, void *key, compiler_enter_scope(struct compiler *c, identifier name,
int lineno) int scope_type, void *key, int lineno)
{ {
struct compiler_unit *u; struct compiler_unit *u;
...@@ -479,6 +490,7 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key, ...@@ -479,6 +490,7 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
return 0; return 0;
} }
memset(u, 0, sizeof(struct compiler_unit)); memset(u, 0, sizeof(struct compiler_unit));
u->u_scope_type = scope_type;
u->u_argcount = 0; u->u_argcount = 0;
u->u_kwonlyargcount = 0; u->u_kwonlyargcount = 0;
u->u_ste = PySymtable_Lookup(c->c_st, key); u->u_ste = PySymtable_Lookup(c->c_st, key);
...@@ -566,6 +578,59 @@ compiler_exit_scope(struct compiler *c) ...@@ -566,6 +578,59 @@ compiler_exit_scope(struct compiler *c)
} }
static PyObject *
compiler_scope_qualname(struct compiler *c)
{
Py_ssize_t stack_size, i;
_Py_static_string(dot, ".");
_Py_static_string(locals, "<locals>");
struct compiler_unit *u;
PyObject *capsule, *name, *seq, *dot_str, *locals_str;
u = c->u;
if (u->u_qualname != NULL) {
Py_INCREF(u->u_qualname);
return u->u_qualname;
}
seq = PyList_New(0);
if (seq == NULL)
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);
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)
goto _error;
if (PyList_Append(seq, locals_str))
goto _error;
}
}
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);
u->u_qualname = name;
Py_XINCREF(name);
return name;
_error:
Py_XDECREF(seq);
return NULL;
}
/* Allocate a new block and return a pointer to it. /* Allocate a new block and return a pointer to it.
Returns NULL on error. Returns NULL on error.
*/ */
...@@ -862,9 +927,9 @@ opcode_stack_effect(int opcode, int oparg) ...@@ -862,9 +927,9 @@ opcode_stack_effect(int opcode, int oparg)
case CALL_FUNCTION_VAR_KW: case CALL_FUNCTION_VAR_KW:
return -NARGS(oparg)-2; return -NARGS(oparg)-2;
case MAKE_FUNCTION: case MAKE_FUNCTION:
return -NARGS(oparg) - ((oparg >> 16) & 0xffff); return -1 -NARGS(oparg) - ((oparg >> 16) & 0xffff);
case MAKE_CLOSURE: case MAKE_CLOSURE:
return -1 - NARGS(oparg) - ((oparg >> 16) & 0xffff); return -2 - NARGS(oparg) - ((oparg >> 16) & 0xffff);
#undef NARGS #undef NARGS
case BUILD_SLICE: case BUILD_SLICE:
if (oparg == 3) if (oparg == 3)
...@@ -1194,7 +1259,7 @@ compiler_mod(struct compiler *c, mod_ty mod) ...@@ -1194,7 +1259,7 @@ compiler_mod(struct compiler *c, mod_ty mod)
return NULL; return NULL;
} }
/* Use 0 for firstlineno initially, will fixup in assemble(). */ /* Use 0 for firstlineno initially, will fixup in assemble(). */
if (!compiler_enter_scope(c, module, mod, 0)) if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 0))
return NULL; return NULL;
switch (mod->kind) { switch (mod->kind) {
case Module_kind: case Module_kind:
...@@ -1270,11 +1335,15 @@ compiler_lookup_arg(PyObject *dict, PyObject *name) ...@@ -1270,11 +1335,15 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
} }
static int static int
compiler_make_closure(struct compiler *c, PyCodeObject *co, int args) compiler_make_closure(struct compiler *c, PyCodeObject *co, int args, PyObject *qualname)
{ {
int i, free = PyCode_GetNumFree(co); int i, free = PyCode_GetNumFree(co);
if (qualname == NULL)
qualname = co->co_name;
if (free == 0) { if (free == 0) {
ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
ADDOP_O(c, LOAD_CONST, qualname, consts);
ADDOP_I(c, MAKE_FUNCTION, args); ADDOP_I(c, MAKE_FUNCTION, args);
return 1; return 1;
} }
...@@ -1311,6 +1380,7 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, int args) ...@@ -1311,6 +1380,7 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
} }
ADDOP_I(c, BUILD_TUPLE, free); ADDOP_I(c, BUILD_TUPLE, free);
ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
ADDOP_O(c, LOAD_CONST, qualname, consts);
ADDOP_I(c, MAKE_CLOSURE, args); ADDOP_I(c, MAKE_CLOSURE, args);
return 1; return 1;
} }
...@@ -1452,7 +1522,7 @@ static int ...@@ -1452,7 +1522,7 @@ static int
compiler_function(struct compiler *c, stmt_ty s) compiler_function(struct compiler *c, stmt_ty s)
{ {
PyCodeObject *co; PyCodeObject *co;
PyObject *first_const = Py_None; PyObject *qualname, *first_const = Py_None;
arguments_ty args = s->v.FunctionDef.args; arguments_ty args = s->v.FunctionDef.args;
expr_ty returns = s->v.FunctionDef.returns; expr_ty returns = s->v.FunctionDef.returns;
asdl_seq* decos = s->v.FunctionDef.decorator_list; asdl_seq* decos = s->v.FunctionDef.decorator_list;
...@@ -1478,7 +1548,8 @@ compiler_function(struct compiler *c, stmt_ty s) ...@@ -1478,7 +1548,8 @@ compiler_function(struct compiler *c, stmt_ty s)
return 0; return 0;
assert((num_annotations & 0xFFFF) == num_annotations); assert((num_annotations & 0xFFFF) == num_annotations);
if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s, if (!compiler_enter_scope(c, s->v.FunctionDef.name,
COMPILER_SCOPE_FUNCTION, (void *)s,
s->lineno)) s->lineno))
return 0; return 0;
...@@ -1500,14 +1571,19 @@ compiler_function(struct compiler *c, stmt_ty s) ...@@ -1500,14 +1571,19 @@ 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);
compiler_exit_scope(c); compiler_exit_scope(c);
if (co == NULL) if (qualname == NULL || co == NULL) {
Py_XDECREF(qualname);
Py_XDECREF(co);
return 0; return 0;
}
arglength = asdl_seq_LEN(args->defaults); arglength = asdl_seq_LEN(args->defaults);
arglength |= kw_default_count << 8; arglength |= kw_default_count << 8;
arglength |= num_annotations << 16; arglength |= num_annotations << 16;
compiler_make_closure(c, co, arglength); compiler_make_closure(c, co, arglength, qualname);
Py_DECREF(qualname);
Py_DECREF(co); Py_DECREF(co);
/* decorators */ /* decorators */
...@@ -1542,7 +1618,8 @@ compiler_class(struct compiler *c, stmt_ty s) ...@@ -1542,7 +1618,8 @@ compiler_class(struct compiler *c, stmt_ty s)
*/ */
/* 1. compile the class body into a code object */ /* 1. compile the class body into a code object */
if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, s->lineno)) if (!compiler_enter_scope(c, s->v.ClassDef.name,
COMPILER_SCOPE_CLASS, (void *)s, s->lineno))
return 0; return 0;
/* this block represents what we do in the new scope */ /* this block represents what we do in the new scope */
{ {
...@@ -1572,6 +1649,21 @@ compiler_class(struct compiler *c, stmt_ty s) ...@@ -1572,6 +1649,21 @@ compiler_class(struct compiler *c, stmt_ty s)
return 0; return 0;
} }
Py_DECREF(str); Py_DECREF(str);
/* store the __qualname__ */
str = compiler_scope_qualname(c);
if (!str) {
compiler_exit_scope(c);
return 0;
}
ADDOP_O(c, LOAD_CONST, str, consts);
Py_DECREF(str);
str = PyUnicode_InternFromString("__qualname__");
if (!str || !compiler_nameop(c, str, Store)) {
Py_XDECREF(str);
compiler_exit_scope(c);
return 0;
}
Py_DECREF(str);
/* compile the body proper */ /* compile the body proper */
if (!compiler_body(c, s->v.ClassDef.body)) { if (!compiler_body(c, s->v.ClassDef.body)) {
compiler_exit_scope(c); compiler_exit_scope(c);
...@@ -1608,7 +1700,7 @@ compiler_class(struct compiler *c, stmt_ty s) ...@@ -1608,7 +1700,7 @@ compiler_class(struct compiler *c, stmt_ty s)
ADDOP(c, LOAD_BUILD_CLASS); ADDOP(c, LOAD_BUILD_CLASS);
/* 3. load a function (or closure) made from the code object */ /* 3. load a function (or closure) made from the code object */
compiler_make_closure(c, co, 0); compiler_make_closure(c, co, 0, NULL);
Py_DECREF(co); Py_DECREF(co);
/* 4. load class name */ /* 4. load class name */
...@@ -1659,6 +1751,7 @@ static int ...@@ -1659,6 +1751,7 @@ static int
compiler_lambda(struct compiler *c, expr_ty e) compiler_lambda(struct compiler *c, expr_ty e)
{ {
PyCodeObject *co; PyCodeObject *co;
PyObject *qualname;
static identifier name; static identifier name;
int kw_default_count = 0, arglength; int kw_default_count = 0, arglength;
arguments_ty args = e->v.Lambda.args; arguments_ty args = e->v.Lambda.args;
...@@ -1678,7 +1771,8 @@ compiler_lambda(struct compiler *c, expr_ty e) ...@@ -1678,7 +1771,8 @@ compiler_lambda(struct compiler *c, expr_ty e)
} }
if (args->defaults) if (args->defaults)
VISIT_SEQ(c, expr, args->defaults); VISIT_SEQ(c, expr, args->defaults);
if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) if (!compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION,
(void *)e, e->lineno))
return 0; return 0;
/* Make None the first constant, so the lambda can't have a /* Make None the first constant, so the lambda can't have a
...@@ -1696,13 +1790,15 @@ compiler_lambda(struct compiler *c, expr_ty e) ...@@ -1696,13 +1790,15 @@ 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);
compiler_exit_scope(c); compiler_exit_scope(c);
if (co == NULL) if (qualname == NULL || co == NULL)
return 0; return 0;
arglength = asdl_seq_LEN(args->defaults); arglength = asdl_seq_LEN(args->defaults);
arglength |= kw_default_count << 8; arglength |= kw_default_count << 8;
compiler_make_closure(c, co, arglength); compiler_make_closure(c, co, arglength, qualname);
Py_DECREF(qualname);
Py_DECREF(co); Py_DECREF(co);
return 1; return 1;
...@@ -2916,11 +3012,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, ...@@ -2916,11 +3012,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
{ {
PyCodeObject *co = NULL; PyCodeObject *co = NULL;
expr_ty outermost_iter; expr_ty outermost_iter;
PyObject *qualname = NULL;
outermost_iter = ((comprehension_ty) outermost_iter = ((comprehension_ty)
asdl_seq_GET(generators, 0))->iter; asdl_seq_GET(generators, 0))->iter;
if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) if (!compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION,
(void *)e, e->lineno))
goto error; goto error;
if (type != COMP_GENEXP) { if (type != COMP_GENEXP) {
...@@ -2953,12 +3051,14 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, ...@@ -2953,12 +3051,14 @@ 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);
compiler_exit_scope(c); compiler_exit_scope(c);
if (co == NULL) if (qualname == NULL || co == NULL)
goto error; goto error;
if (!compiler_make_closure(c, co, 0)) if (!compiler_make_closure(c, co, 0, qualname))
goto error; goto error;
Py_DECREF(qualname);
Py_DECREF(co); Py_DECREF(co);
VISIT(c, expr, outermost_iter); VISIT(c, expr, outermost_iter);
...@@ -2968,6 +3068,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, ...@@ -2968,6 +3068,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
error_in_scope: error_in_scope:
compiler_exit_scope(c); compiler_exit_scope(c);
error: error:
Py_XDECREF(qualname);
Py_XDECREF(co); Py_XDECREF(co);
return 0; return 0;
} }
......
...@@ -103,6 +103,7 @@ typedef unsigned short mode_t; ...@@ -103,6 +103,7 @@ typedef unsigned short mode_t;
tag: cpython-32 tag: cpython-32
Python 3.2a2 3180 (add DELETE_DEREF) Python 3.2a2 3180 (add DELETE_DEREF)
Python 3.3a0 3190 __class__ super closure changed Python 3.3a0 3190 __class__ super closure changed
Python 3.3a0 3200 (__qualname__ added)
*/ */
/* MAGIC must change whenever the bytecode emitted by the compiler may no /* MAGIC must change whenever the bytecode emitted by the compiler may no
...@@ -115,7 +116,7 @@ typedef unsigned short mode_t; ...@@ -115,7 +116,7 @@ typedef unsigned short mode_t;
#define STRIFY(name) QUOTE(name) #define STRIFY(name) QUOTE(name)
#define MAJOR STRIFY(PY_MAJOR_VERSION) #define MAJOR STRIFY(PY_MAJOR_VERSION)
#define MINOR STRIFY(PY_MINOR_VERSION) #define MINOR STRIFY(PY_MINOR_VERSION)
#define MAGIC (3190 | ((long)'\r'<<16) | ((long)'\n'<<24)) #define MAGIC (3200 | ((long)'\r'<<16) | ((long)'\n'<<24))
#define TAG "cpython-" MAJOR MINOR; #define TAG "cpython-" MAJOR MINOR;
#define CACHEDIR "__pycache__" #define CACHEDIR "__pycache__"
/* Current magic word and string tag as globals. */ /* Current magic word and string tag as globals. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment