[pypy-commit] pypy py3.3: Really implement __qualname__ for nested blocks.

amauryfa noreply at buildbot.pypy.org
Thu Dec 18 22:38:43 CET 2014


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.3
Changeset: r75022:9ebba4eb7768
Date: 2014-12-18 22:36 +0100
http://bitbucket.org/pypy/pypy/changeset/9ebba4eb7768/

Log:	Really implement __qualname__ for nested blocks.

diff --git a/lib-python/3/importlib/_bootstrap.py b/lib-python/3/importlib/_bootstrap.py
--- a/lib-python/3/importlib/_bootstrap.py
+++ b/lib-python/3/importlib/_bootstrap.py
@@ -405,8 +405,10 @@
 due to the addition of new opcodes).
 
 """
-_RAW_MAGIC_NUMBER = 3230 | ord('\r') << 16 | ord('\n') << 24
-_MAGIC_BYTES = bytes(_RAW_MAGIC_NUMBER >> n & 0xff for n in range(0, 25, 8))
+
+# PyPy change
+import _imp
+_MAGIC_BYTES = _imp.get_magic()
 
 _PYCACHE = '__pycache__'
 
diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -157,6 +157,7 @@
     def __init__(self, space, name, first_lineno, scope, compile_info):
         self.space = space
         self.name = name
+        self.qualname = name
         self.first_lineno = first_lineno
         self.compile_info = compile_info
         self.first_block = self.new_block()
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -205,7 +205,8 @@
         """Convenience function for compiling a sub scope."""
         generator = kind(self.space, name, node, lineno, self.symbols,
                          self.compile_info)
-        return generator.assemble()
+        generator.qualname = '%s.%s' % (self.qualname, name)
+        return generator.assemble(), generator.qualname
 
     def push_frame_block(self, kind, block):
         self.frame_blocks.append((kind, block))
@@ -282,9 +283,11 @@
         self.add_none_to_final_return = False
         mod.body.walkabout(self)
 
-    def _make_function(self, code, num_defaults=0):
+    def _make_function(self, code, num_defaults=0, qualname=None):
         """Emit the opcodes to turn a code object into a function."""
         code_index = self.add_const(code)
+        w_qualname = self.space.wrap(qualname or code.co_name)
+        qualname_index = self.add_const(w_qualname)
         if code.co_freevars:
             # Load cell and free vars to pass on.
             for free in code.co_freevars:
@@ -296,9 +299,11 @@
                 self.emit_op_arg(ops.LOAD_CLOSURE, index)
             self.emit_op_arg(ops.BUILD_TUPLE, len(code.co_freevars))
             self.emit_op_arg(ops.LOAD_CONST, code_index)
+            self.emit_op_arg(ops.LOAD_CONST, qualname_index)
             self.emit_op_arg(ops.MAKE_CLOSURE, num_defaults)
         else:
             self.emit_op_arg(ops.LOAD_CONST, code_index)
+            self.emit_op_arg(ops.LOAD_CONST, qualname_index)
             self.emit_op_arg(ops.MAKE_FUNCTION, num_defaults)
 
     def _visit_kwonlydefaults(self, args):
@@ -359,9 +364,9 @@
         oparg = num_defaults
         oparg |= kw_default_count << 8
         oparg |= num_annotations << 16
-        code = self.sub_scope(FunctionCodeGenerator, func.name, func,
-                              func.lineno)
-        self._make_function(code, oparg)
+        code, qualname = self.sub_scope(FunctionCodeGenerator, func.name, func,
+                                        func.lineno)
+        self._make_function(code, oparg, qualname=qualname)
         # Apply decorators.
         if func.decorator_list:
             for i in range(len(func.decorator_list)):
@@ -377,20 +382,22 @@
             kw_default_count = self._visit_kwonlydefaults(args)
         self.visit_sequence(args.defaults)
         default_count = len(args.defaults) if args.defaults is not None else 0
-        code = self.sub_scope(LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
+        code, qualname = self.sub_scope(
+            LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
         oparg = default_count
         oparg |= kw_default_count << 8
-        self._make_function(code, oparg)
+        self._make_function(code, oparg, qualname=qualname)
 
     def visit_ClassDef(self, cls):
         self.update_position(cls.lineno, True)
         self.visit_sequence(cls.decorator_list)
         # 1. compile the class body into a code object
-        code = self.sub_scope(ClassCodeGenerator, cls.name, cls, cls.lineno)
+        code, qualname = self.sub_scope(
+            ClassCodeGenerator, cls.name, cls, cls.lineno)
         # 2. load the 'build_class' function
         self.emit_op(ops.LOAD_BUILD_CLASS)
         # 3. load a function (or closure) made from the code object
-        self._make_function(code, 0)
+        self._make_function(code, qualname=qualname)
         # 4. load class name
         self.load_const(self.space.wrap(cls.name.decode('utf-8')))
         # 5. generate the rest of the code for the call
@@ -1140,9 +1147,9 @@
         self.use_next_block(anchor)
 
     def _compile_comprehension(self, node, name, sub_scope):
-        code = self.sub_scope(sub_scope, name, node, node.lineno)
+        code, qualname = self.sub_scope(sub_scope, name, node, node.lineno)
         self.update_position(node.lineno)
-        self._make_function(code)
+        self._make_function(code, qualname=qualname)
         first_comp = node.get_generators()[0]
         assert isinstance(first_comp, ast.comprehension)
         first_comp.iter.walkabout(self)
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -36,10 +36,10 @@
                           'w_kw_defs?']
 
     def __init__(self, space, code, w_globals=None, defs_w=[], w_kw_defs=None,
-                 closure=None, w_ann=None, forcename=None):
+                 closure=None, w_ann=None, forcename=None, qualname=None):
         self.space = space
         self.name = forcename or code.co_name
-        self.qualname = self.name.decode('utf-8')  # So far
+        self.qualname = qualname or self.name.decode('utf-8')
         self.w_doc = None   # lazily read from code.getdocstring()
         self.code = code       # Code instance
         self.w_func_globals = w_globals  # the globals dictionary
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -36,7 +36,7 @@
 # different value for the highest 16 bits. Bump pypy_incremental_magic every
 # time you make pyc files incompatible
 
-pypy_incremental_magic = 48 # bump it by 16
+pypy_incremental_magic = 64 # bump it by 16
 assert pypy_incremental_magic % 16 == 0
 assert pypy_incremental_magic < 3000 # the magic number of Python 3. There are
                                      # no known magic numbers below this value
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1215,6 +1215,8 @@
     @jit.unroll_safe
     def _make_function(self, oparg, freevars=None):
         space = self.space
+        w_qualname = self.popvalue()
+        qualname = self.space.unicode_w(w_qualname)
         w_codeobj = self.popvalue()
         codeobj = self.space.interp_w(PyCode, w_codeobj)
         if freevars is not None:
@@ -1238,7 +1240,7 @@
                 w_def = self.popvalue()
                 space.setitem(w_kw_defs, w_def, w_name)
         fn = function.Function(space, codeobj, self.w_globals, defaultarguments,
-                               w_kw_defs, freevars, w_ann)
+                               w_kw_defs, freevars, w_ann, qualname=qualname)
         self.pushvalue(space.wrap(fn))
 
     def MAKE_FUNCTION(self, oparg, next_instr):
@@ -1246,7 +1248,7 @@
 
     @jit.unroll_safe
     def MAKE_CLOSURE(self, oparg, next_instr):
-        w_freevarstuple = self.peekvalue(1)
+        w_freevarstuple = self.peekvalue(2)
         freevars = [self.space.interp_w(Cell, cell)
                     for cell in self.space.fixedview(w_freevarstuple)]
         self._make_function(oparg, freevars)
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -23,7 +23,7 @@
 
     def test_qualname(self):
         def f(): pass
-        assert f.__qualname__ == 'f'
+        assert f.__qualname__ == 'test_qualname.f'
         f.__qualname__ = 'qualname'
         assert f.__qualname__ == 'qualname'
         raises(TypeError, "f.__qualname__ = b'name'")


More information about the pypy-commit mailing list