]> granicus.if.org Git - python/commitdiff
PEP 3155 / issue #13448: Qualified name for classes and functions.
authorAntoine Pitrou <solipsis@pitrou.net>
Fri, 25 Nov 2011 17:56:07 +0000 (18:56 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Fri, 25 Nov 2011 17:56:07 +0000 (18:56 +0100)
21 files changed:
Doc/c-api/function.rst
Doc/data/refcounts.dat
Doc/glossary.rst
Doc/library/stdtypes.rst
Doc/reference/datamodel.rst
Include/funcobject.h
Include/object.h
Lib/pydoc.py
Lib/test/test_code.py
Lib/test/test_descr.py
Lib/test/test_dis.py
Lib/test/test_funcattrs.py
Lib/test/test_metaclass.py
Lib/test/test_reprlib.py
Lib/test/test_sys.py
Misc/NEWS
Objects/funcobject.c
Objects/typeobject.c
Python/ceval.c
Python/compile.c
Python/import.c

index 31805fd0ad1a57581026f91515a7a7fce87a9f5b..ad9832233f74d9f9f40dc5b80f7a12d785d7e98b 100644 (file)
@@ -38,6 +38,16 @@ There are a few functions specific to Python functions.
    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)
 
    Return the code object associated with the function object *op*.
index c7d7bd140af2942b18d881a84004d6e71f562446..a1004ad48df0b1835bb6de1a65149fa2c12c7b0d 100644 (file)
@@ -465,6 +465,11 @@ PyFunction_New:PyObject*::+1:
 PyFunction_New:PyObject*:code:+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:PyObject*:op:0:
 PyFunction_SetClosure:PyObject*:closure:+1:
index 04b3fbba4cabc18838026bc9c79c5777f98a3461..f5ca0d9c8dc100c0ccaa8d228ce8ece4911d0f6f 100644 (file)
@@ -544,6 +544,24 @@ Glossary
          for piece in food:
              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
       The number of references to an object.  When the reference count of an
       object drops to zero, it is deallocated.  Reference counting is
index 5bb4324d62a769173f72f18f387378a523733e91..ee76cd34013949712b94169aa0f310e75d1812a6 100644 (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.
 
 
+.. attribute:: class.__qualname__
+
+   The :term:`qualified name` of the class or type.
+
+   .. versionadded:: 3.3
+
+
 .. attribute:: class.__mro__
 
    This attribute is a tuple of classes that are considered when looking for
index a93c09afe1d528cd3ca124ac1da9456fef37a8c5..55fd76bd793d4cf43db95f79e954086a543813ea 100644 (file)
@@ -448,6 +448,11 @@ Callable types
       +-------------------------+-------------------------------+-----------+
       | :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  |
       |                         | function was defined in, or   |           |
       |                         | ``None`` if unavailable.      |           |
index 521d87bf9f16ffad9556ef79eac50c9f7be4dd98..cc1426cdc2eb79672224123e847cbdd5a6f67df9 100644 (file)
@@ -31,6 +31,7 @@ typedef struct {
     PyObject *func_weakreflist;        /* List of weak references */
     PyObject *func_module;     /* The __module__ attribute, can be anything */
     PyObject *func_annotations;        /* Annotations, a dict or NULL */
+    PyObject *func_qualname;    /* The qualified name */
 
     /* Invariant:
      *     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)
 
 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_GetGlobals(PyObject *);
 PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
index b97f716933a32911727e4149029080aebc426be1..3cd52975f3fa34c35d360bc56a8ba77da164920f 100644 (file)
@@ -418,7 +418,7 @@ typedef struct _heaptypeobject {
                                       a given operator (e.g. __getitem__).
                                       see add_operators() in typeobject.c . */
     PyBufferProcs as_buffer;
-    PyObject *ht_name, *ht_slots;
+    PyObject *ht_name, *ht_slots, *ht_qualname;
     /* here are optional user slots, followed by the members. */
 } PyHeapTypeObject;
 
index caae46ad10843d4688c9912a058639664e445c98..b5dbde651c2412bf15edf9ecc438c555b004ac00 100755 (executable)
@@ -166,7 +166,7 @@ def visiblename(name, all=None, obj=None):
     if name in {'__builtins__', '__doc__', '__file__', '__path__',
                      '__module__', '__name__', '__slots__', '__package__',
                      '__cached__', '__author__', '__credits__', '__date__',
-                     '__version__'}:
+                     '__version__', '__qualname__'}:
         return 0
     # Private names are hidden, but special names are displayed.
     if name.startswith('__') and name.endswith('__'): return 1
index e1c7a783de12c3472d5b7aad55a43c6e05273985..3377a7b07a8cd8f168285adc0dae866281875ea3 100644 (file)
@@ -16,7 +16,7 @@ cellvars: ('x',)
 freevars: ()
 nlocals: 2
 flags: 3
-consts: ('None', '<code object g>')
+consts: ('None', '<code object g>', "'f.<locals>.g'")
 
 >>> dump(f(4).__code__)
 name: g
index 15219db5703be151860a378c3a959b7ec286287f..4a7a9d21977457e564e0aa79eb06e4f7c7cf0a72 100644 (file)
@@ -4492,9 +4492,14 @@ class DictProxyTests(unittest.TestCase):
         self.assertEqual(type(C.__dict__), type(B.__dict__))
 
     def test_repr(self):
-        # Testing dict_proxy.__repr__
-        dict_ = {k: v for k, v in self.C.__dict__.items()}
-        self.assertEqual(repr(self.C.__dict__), 'dict_proxy({!r})'.format(dict_))
+        # Testing dict_proxy.__repr__.
+        # We can't blindly compare with the repr of another dict as ordering
+        # 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):
index 4b0b02af266db368e4720ed1ce521228910a0e24..be380079822ef610c4ff2d7a39e57cdd2f6c40a6 100644 (file)
@@ -339,6 +339,7 @@ Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
 Constants:
    0: None
    1: <code object f at (.*), file "(.*)", line (.*)>
+   2: 'tricky.<locals>.f'
 Variable names:
    0: x
    1: y
index 4d1936879ec3f664aeb12f5be705e27932fa518d..f4a38b961d820dca4132d335a77b777c8fa27118 100644 (file)
@@ -2,6 +2,15 @@ from test import support
 import types
 import unittest
 
+
+def global_function():
+    def inner_function():
+        class LocalClass:
+            pass
+        return LocalClass
+    return lambda: inner_function
+
+
 class FuncAttrsTest(unittest.TestCase):
     def setUp(self):
         class F:
@@ -96,6 +105,24 @@ class FunctionPropertiesTest(FuncAttrsTest):
         self.assertEqual(self.fi.a.__name__, 'a')
         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):
         num_one, num_two = 7, 8
         def a(): pass
index 6862900b01092bf06ce5973759716a30975265a2..e6fe20a107c239a64fc1e8bedfda2b159134f56f 100644 (file)
@@ -159,6 +159,7 @@ Use a __prepare__ method that returns an instrumented dict.
     ...     bar = 123
     ...
     d['__module__'] = 'test.test_metaclass'
+    d['__qualname__'] = 'C'
     d['foo'] = 4
     d['foo'] = 42
     d['bar'] = 123
@@ -177,12 +178,12 @@ Use a metaclass that doesn't derive from type.
     ...     b = 24
     ...
     meta: C ()
-    ns: [('__module__', 'test.test_metaclass'), ('a', 42), ('b', 24)]
+    ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
     kw: []
     >>> type(C) is dict
     True
     >>> 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.
@@ -199,11 +200,12 @@ And again, with a __prepare__ attribute.
     ...
     prepare: C () [('other', 'booh')]
     d['__module__'] = 'test.test_metaclass'
+    d['__qualname__'] = 'C'
     d['a'] = 1
     d['a'] = 2
     d['b'] = 3
     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')]
     >>>
 
index 439fa337947abd4078612299585a9fb35a4a413e..0365cea5ff157e4911980f03380b19ae61a9c840 100644 (file)
@@ -129,8 +129,8 @@ class ReprTests(unittest.TestCase):
         self.assertIn(s.find("..."), [12, 13])
 
     def test_lambda(self):
-        self.assertTrue(repr(lambda x: x).startswith(
-            "<function <lambda"))
+        r = repr(lambda x: x)
+        self.assertTrue(r.startswith("<function ReprTests.test_lambda.<locals>.<lambda"), r)
         # XXX anonymous functions?  see func_repr
 
     def test_builtin_function(self):
@@ -278,13 +278,14 @@ class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 ''')
         from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import qux
         # Unbound methods first
-        self.assertTrue(repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod).startswith(
-        '<function amethod'))
+        r = repr(qux.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod)
+        self.assertTrue(r.startswith('<function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.amethod'), r)
         # Bound method next
         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' \
-            % (qux.__name__,) ))
+            % (qux.__name__,) ), r)
 
     def test_builtin_function(self):
         # XXX test built-in functions and methods with really long names
index ba0b59210474da945b6ad7eaf6b0d438b3fc66ca..3169f67be8c0e87b456bb1e8485f6fab3d10c906 100644 (file)
@@ -730,7 +730,7 @@ class SizeofTest(unittest.TestCase):
         check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
         # function
         def func(): pass
-        check(func, size(h + '11P'))
+        check(func, size(h + '12P'))
         class c():
             @staticmethod
             def foo():
@@ -828,7 +828,7 @@ class SizeofTest(unittest.TestCase):
         # type
         # (PyTypeObject + PyNumberMethods + PyMappingMethods +
         #  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)
         # class
         class newstyleclass(object): pass
index 93169e4608b9562a8af83fa5368e0b1169bd6679..b789b5f4f0d3d4e748e64e7d29e34c7793c9670d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1?
 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
   an invalid integer value.
 
index 45f9f57578176252f6d82caae5a01a6050c75947..2839a247efed7165c5cf7e109b6044e763d59af5 100644 (file)
@@ -6,7 +6,7 @@
 #include "structmember.h"
 
 PyObject *
-PyFunction_New(PyObject *code, PyObject *globals)
+PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
 {
     PyFunctionObject *op = PyObject_GC_New(PyFunctionObject,
                                         &PyFunction_Type);
@@ -54,6 +54,11 @@ PyFunction_New(PyObject *code, PyObject *globals)
             Py_INCREF(module);
             op->func_module = module;
         }
+        if (qualname)
+            op->func_qualname = qualname;
+        else
+            op->func_qualname = op->func_name;
+        Py_INCREF(op->func_qualname);
     }
     else
         return NULL;
@@ -61,6 +66,12 @@ PyFunction_New(PyObject *code, PyObject *globals)
     return (PyObject *)op;
 }
 
+PyObject *
+PyFunction_New(PyObject *code, PyObject *globals)
+{
+    return PyFunction_NewWithQualName(code, globals, NULL);
+}
+
 PyObject *
 PyFunction_GetCode(PyObject *op)
 {
@@ -333,6 +344,32 @@ func_set_name(PyFunctionObject *op, PyObject *value)
     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 *
 func_get_defaults(PyFunctionObject *op)
 {
@@ -441,6 +478,7 @@ static PyGetSetDef func_getsetlist[] = {
      (setter)func_set_annotations},
     {"__dict__", (getter)func_get_dict, (setter)func_set_dict},
     {"__name__", (getter)func_get_name, (setter)func_set_name},
+    {"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname},
     {NULL} /* Sentinel */
 };
 
@@ -561,6 +599,7 @@ func_dealloc(PyFunctionObject *op)
     Py_XDECREF(op->func_dict);
     Py_XDECREF(op->func_closure);
     Py_XDECREF(op->func_annotations);
+    Py_XDECREF(op->func_qualname);
     PyObject_GC_Del(op);
 }
 
@@ -568,7 +607,7 @@ static PyObject*
 func_repr(PyFunctionObject *op)
 {
     return PyUnicode_FromFormat("<function %U at %p>",
-                               op->func_name, op);
+                               op->func_qualname, op);
 }
 
 static int
@@ -584,6 +623,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
     Py_VISIT(f->func_dict);
     Py_VISIT(f->func_closure);
     Py_VISIT(f->func_annotations);
+    Py_VISIT(f->func_qualname);
     return 0;
 }
 
index d53ae93ee70fa42faebd69e35d9d51df5587bc26..010120a4e80ef930f17903432dbfec1ee35b1fd5 100644 (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
 type_set_name(PyTypeObject *type, PyObject *value, void *context)
 {
@@ -286,6 +299,25 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context)
     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 *
 type_module(PyTypeObject *type, void *context)
 {
@@ -631,6 +663,7 @@ type___subclasscheck__(PyObject *type, PyObject *inst)
 
 static PyGetSetDef type_getsets[] = {
     {"__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},
     {"__module__", (getter)type_module, (setter)type_set_module, NULL},
     {"__abstractmethods__", (getter)type_abstractmethods,
@@ -652,7 +685,7 @@ type_repr(PyTypeObject *type)
         Py_DECREF(mod);
         mod = NULL;
     }
-    name = type_name(type, NULL);
+    name = type_qualname(type, NULL);
     if (name == NULL)
         return NULL;
 
@@ -1955,7 +1988,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
 {
     PyObject *name, *bases, *dict;
     static char *kwlist[] = {"name", "bases", "dict", 0};
-    PyObject *slots, *tmp, *newslots;
+    PyObject *qualname, *slots, *tmp, *newslots;
     PyTypeObject *type, *base, *tmptype, *winner;
     PyHeapTypeObject *et;
     PyMemberDef *mp;
@@ -2032,6 +2065,18 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
         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 */
     slots = PyDict_GetItemString(dict, "__slots__");
     nslots = 0;
@@ -2185,7 +2230,9 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
     /* Keep name and slots alive in the extended type object */
     et = (PyHeapTypeObject *)type;
     Py_INCREF(name);
+    Py_INCREF(qualname);
     et->ht_name = name;
+    et->ht_qualname = qualname;
     et->ht_slots = slots;
 
     /* Initialize tp_flags */
@@ -2369,6 +2416,8 @@ PyObject* PyType_FromSpec(PyType_Spec *spec)
     res->ht_name = PyUnicode_FromString(spec->name);
     if (!res->ht_name)
         goto fail;
+    res->ht_qualname = res->ht_name;
+    Py_INCREF(res->ht_qualname);
     res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name);
     if (!res->ht_type.tp_name)
         goto fail;
@@ -2568,6 +2617,7 @@ type_dealloc(PyTypeObject *type)
      */
     PyObject_Free((char *)type->tp_doc);
     Py_XDECREF(et->ht_name);
+    Py_XDECREF(et->ht_qualname);
     Py_XDECREF(et->ht_slots);
     Py_TYPE(type)->tp_free((PyObject *)type);
 }
@@ -2983,7 +3033,7 @@ object_repr(PyObject *self)
         Py_DECREF(mod);
         mod = NULL;
     }
-    name = type_name(type, NULL);
+    name = type_qualname(type, NULL);
     if (name == NULL)
         return NULL;
     if (mod != NULL && PyUnicode_CompareWithASCIIString(mod, "builtins"))
index 8d980fdc93905583ea48e90c8622b8fa6d02b164..ed82b9411a02471252a020c87543af0b465d78a6 100644 (file)
@@ -2687,9 +2687,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
             int kwdefaults = (oparg>>8) & 0xff;
             int num_annotations = (oparg >> 16) & 0x7fff;
 
+            w = POP(); /* qualname */
             v = POP(); /* code object */
-            x = PyFunction_New(v, f->f_globals);
+            x = PyFunction_NewWithQualName(v, f->f_globals, w);
             Py_DECREF(v);
+            Py_DECREF(w);
 
             if (x != NULL && opcode == MAKE_CLOSURE) {
                 v = POP();
index 906772289dde1cb205d562f42b3a357f277a1ca9..849f48785dcee50294e941bfbccac6d71a90633c 100644 (file)
@@ -90,6 +90,13 @@ struct fblockinfo {
     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.
    They must be saved and restored when returning to a block.
 */
@@ -97,6 +104,9 @@ struct compiler_unit {
     PySTEntryObject *u_ste;
 
     PyObject *u_name;
+    PyObject *u_qualname;  /* dot-separated qualified name (lazy) */
+    int u_scope_type;
+
     /* The following fields are dicts that map objects to
        the index of them in co_XXX.      The index is used as
        the argument for opcodes that refer to those collections.
@@ -149,7 +159,7 @@ struct compiler {
     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 basicblock *compiler_new_block(struct compiler *);
 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_name);
+    Py_CLEAR(u->u_qualname);
     Py_CLEAR(u->u_consts);
     Py_CLEAR(u->u_names);
     Py_CLEAR(u->u_varnames);
@@ -467,8 +478,8 @@ compiler_unit_free(struct compiler_unit *u)
 }
 
 static int
-compiler_enter_scope(struct compiler *c, identifier name, void *key,
-                     int lineno)
+compiler_enter_scope(struct compiler *c, identifier name,
+                     int scope_type, void *key, int lineno)
 {
     struct compiler_unit *u;
 
@@ -479,6 +490,7 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
         return 0;
     }
     memset(u, 0, sizeof(struct compiler_unit));
+    u->u_scope_type = scope_type;
     u->u_argcount = 0;
     u->u_kwonlyargcount = 0;
     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.
    Returns NULL on error.
 */
@@ -862,9 +927,9 @@ opcode_stack_effect(int opcode, int oparg)
         case CALL_FUNCTION_VAR_KW:
             return -NARGS(oparg)-2;
         case MAKE_FUNCTION:
-            return -NARGS(oparg) - ((oparg >> 16) & 0xffff);
+            return -1 -NARGS(oparg) - ((oparg >> 16) & 0xffff);
         case MAKE_CLOSURE:
-            return -1 - NARGS(oparg) - ((oparg >> 16) & 0xffff);
+            return -2 - NARGS(oparg) - ((oparg >> 16) & 0xffff);
 #undef NARGS
         case BUILD_SLICE:
             if (oparg == 3)
@@ -1194,7 +1259,7 @@ compiler_mod(struct compiler *c, mod_ty mod)
             return NULL;
     }
     /* 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;
     switch (mod->kind) {
     case Module_kind:
@@ -1270,11 +1335,15 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
 }
 
 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);
+    if (qualname == NULL)
+        qualname = co->co_name;
+
     if (free == 0) {
         ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+        ADDOP_O(c, LOAD_CONST, qualname, consts);
         ADDOP_I(c, MAKE_FUNCTION, args);
         return 1;
     }
@@ -1311,6 +1380,7 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, int args)
     }
     ADDOP_I(c, BUILD_TUPLE, free);
     ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts);
+    ADDOP_O(c, LOAD_CONST, qualname, consts);
     ADDOP_I(c, MAKE_CLOSURE, args);
     return 1;
 }
@@ -1452,7 +1522,7 @@ static int
 compiler_function(struct compiler *c, stmt_ty s)
 {
     PyCodeObject *co;
-    PyObject *first_const = Py_None;
+    PyObject *qualname, *first_const = Py_None;
     arguments_ty args = s->v.FunctionDef.args;
     expr_ty returns = s->v.FunctionDef.returns;
     asdl_seq* decos = s->v.FunctionDef.decorator_list;
@@ -1478,7 +1548,8 @@ compiler_function(struct compiler *c, stmt_ty s)
         return 0;
     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))
         return 0;
 
@@ -1500,14 +1571,19 @@ compiler_function(struct compiler *c, stmt_ty s)
         VISIT_IN_SCOPE(c, stmt, st);
     }
     co = assemble(c, 1);
+    qualname = compiler_scope_qualname(c);
     compiler_exit_scope(c);
-    if (co == NULL)
+    if (qualname == NULL || co == NULL) {
+        Py_XDECREF(qualname);
+        Py_XDECREF(co);
         return 0;
+    }
 
     arglength = asdl_seq_LEN(args->defaults);
     arglength |= kw_default_count << 8;
     arglength |= num_annotations << 16;
-    compiler_make_closure(c, co, arglength);
+    compiler_make_closure(c, co, arglength, qualname);
+    Py_DECREF(qualname);
     Py_DECREF(co);
 
     /* decorators */
@@ -1542,7 +1618,8 @@ compiler_class(struct compiler *c, stmt_ty s)
     */
 
     /* 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;
     /* this block represents what we do in the new scope */
     {
@@ -1572,6 +1649,21 @@ compiler_class(struct compiler *c, stmt_ty s)
             return 0;
         }
         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 */
         if (!compiler_body(c, s->v.ClassDef.body)) {
             compiler_exit_scope(c);
@@ -1608,7 +1700,7 @@ compiler_class(struct compiler *c, stmt_ty s)
     ADDOP(c, LOAD_BUILD_CLASS);
 
     /* 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);
 
     /* 4. load class name */
@@ -1659,6 +1751,7 @@ static int
 compiler_lambda(struct compiler *c, expr_ty e)
 {
     PyCodeObject *co;
+    PyObject *qualname;
     static identifier name;
     int kw_default_count = 0, arglength;
     arguments_ty args = e->v.Lambda.args;
@@ -1678,7 +1771,8 @@ compiler_lambda(struct compiler *c, expr_ty e)
     }
     if (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;
 
     /* 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);
     }
     co = assemble(c, 1);
+    qualname = compiler_scope_qualname(c);
     compiler_exit_scope(c);
-    if (co == NULL)
+    if (qualname == NULL || co == NULL)
         return 0;
 
     arglength = asdl_seq_LEN(args->defaults);
     arglength |= kw_default_count << 8;
-    compiler_make_closure(c, co, arglength);
+    compiler_make_closure(c, co, arglength, qualname);
+    Py_DECREF(qualname);
     Py_DECREF(co);
 
     return 1;
@@ -2916,11 +3012,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
 {
     PyCodeObject *co = NULL;
     expr_ty outermost_iter;
+    PyObject *qualname = NULL;
 
     outermost_iter = ((comprehension_ty)
                       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;
 
     if (type != COMP_GENEXP) {
@@ -2953,12 +3051,14 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
     }
 
     co = assemble(c, 1);
+    qualname = compiler_scope_qualname(c);
     compiler_exit_scope(c);
-    if (co == NULL)
+    if (qualname == NULL || co == NULL)
         goto error;
 
-    if (!compiler_make_closure(c, co, 0))
+    if (!compiler_make_closure(c, co, 0, qualname))
         goto error;
+    Py_DECREF(qualname);
     Py_DECREF(co);
 
     VISIT(c, expr, outermost_iter);
@@ -2968,6 +3068,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
 error_in_scope:
     compiler_exit_scope(c);
 error:
+    Py_XDECREF(qualname);
     Py_XDECREF(co);
     return 0;
 }
index 6c6d1f697a51aa394fbc38204d38a4b6214e2467..71992300987b9597d520cd216da00af19244392a 100644 (file)
@@ -103,6 +103,7 @@ typedef unsigned short mode_t;
                      tag: cpython-32
        Python 3.2a2  3180 (add DELETE_DEREF)
        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
@@ -115,7 +116,7 @@ typedef unsigned short mode_t;
 #define STRIFY(name) QUOTE(name)
 #define MAJOR STRIFY(PY_MAJOR_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 CACHEDIR "__pycache__"
 /* Current magic word and string tag as globals. */