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

This commit is contained in:
Antoine Pitrou 2011-11-25 18:56:07 +01:00
parent 0e86a5842d
commit 86a36b500a
21 changed files with 322 additions and 43 deletions

View File

@ -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*.

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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. | |

View File

@ -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;
#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 *);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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):
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

View File

@ -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.
... 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.
... ...
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')]
>>> >>>

View File

@ -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
''') ''')
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

View File

@ -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):
# 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

View File

@ -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.

View File

@ -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)
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)
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)
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[] = {
(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)
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*
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)
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;
} }

View File

@ -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)
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)
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)
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)
{ {
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)
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)
/* 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)
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)
*/ */
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)
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"))

View File

@ -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();

View File

@ -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 {
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 {
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)
} }
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)
} }
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,
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)
} }
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)
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)
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)
} }
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)
} }
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
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)
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)
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)
*/ */
/* 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)
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)
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
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)
} }
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)
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,
{ {
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,
} }
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,
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;
} }

View File

@ -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;
#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. */