Author: Armin Rigo <ar...@tunes.org>
Branch: py3.5-corowrapper
Changeset: r87179:4411daaf0ffe
Date: 2016-09-17 17:35 +0200
http://bitbucket.org/pypy/pypy/changeset/4411daaf0ffe/

Log:    Setting __name__ on generator-iterator objects (uh?)

diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -36,6 +36,7 @@
                           'closure?[*]',
                           'defs_w?[*]',
                           'name?',
+                          'qualname?',
                           'w_kw_defs?']
 
     w_kw_defs = None
@@ -117,7 +118,7 @@
                 for i in funccallunrolling:
                     if i < nargs:
                         new_frame.locals_cells_stack_w[i] = args_w[i]
-                return new_frame.run()
+                return new_frame.run(self.name, self.qualname)
         elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1:
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
             return code.funcrun_obj(self, args_w[0],
@@ -184,7 +185,7 @@
             w_arg = frame.peekvalue(nargs-1-i)
             new_frame.locals_cells_stack_w[i] = w_arg
 
-        return new_frame.run()
+        return new_frame.run(self.name, self.qualname)
 
     @jit.unroll_safe
     def _flat_pycall_defaults(self, code, nargs, frame, defs_to_load):
@@ -201,7 +202,7 @@
         for j in xrange(start, ndefs):
             new_frame.locals_cells_stack_w[i] = self.defs_w[j]
             i += 1
-        return new_frame.run()
+        return new_frame.run(self.name, self.qualname)
 
     def getdict(self, space):
         if self.w_func_dict is None:
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -23,6 +23,7 @@
             self.register_finalizer(self.space)
 
     def get_name(self):
+        # 'name' is a byte string that is valid utf-8
         if self._name is not None:
             return self._name
         elif self.pycode is None:
@@ -31,9 +32,10 @@
             return self.pycode.co_name
 
     def get_qualname(self):
+        # 'qualname' is a unicode string
         if self._qualname is not None:
             return self._qualname
-        return self.get_name()
+        return self.get_name().decode('utf-8')
 
     def descr__repr__(self, space):
         addrstring = self.getaddrstring(space)
@@ -292,11 +294,27 @@
             return space.w_None
 
     def descr__name__(self, space):
-        return space.wrap(self.get_name())
+        return space.wrap(self.get_name().decode('utf-8'))
+
+    def descr_set__name__(self, space, w_name):
+        if space.isinstance_w(w_name, space.w_unicode):
+            self._name = space.str_w(w_name)
+        else:
+            raise oefmt(space.w_TypeError,
+                        "__name__ must be set to a string object")
 
     def descr__qualname__(self, space):
         return space.wrap(self.get_qualname())
 
+    def descr_set__qualname__(self, space, w_name):
+        try:
+            self._qualname = space.unicode_w(w_name)
+        except OperationError as e:
+            if e.match(space, space.w_TypeError):
+                raise oefmt(space.w_TypeError,
+                            "__qualname__ must be set to a string object")
+            raise
+
     def _finalize_(self):
         # This is only called if the CO_YIELD_INSIDE_TRY flag is set
         # on the code object.  If the frame is still not finished and
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -265,7 +265,7 @@
         args.parse_into_scope(None, fresh_frame.locals_cells_stack_w, 
func.name,
                               sig, func.defs_w, func.w_kw_defs)
         fresh_frame.init_cells()
-        return frame.run()
+        return frame.run(func.name, func.qualname)
 
     def funcrun_obj(self, func, w_obj, args):
         frame = self.space.createframe(self, func.w_func_globals,
@@ -277,7 +277,7 @@
         args.parse_into_scope(w_obj, fresh_frame.locals_cells_stack_w, 
func.name,
                               sig, func.defs_w, func.w_kw_defs)
         fresh_frame.init_cells()
-        return frame.run()
+        return frame.run(func.name, func.qualname)
 
     def getvarnames(self):
         return self.co_varnames
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -244,22 +244,26 @@
         return (self.getcode().co_flags & (pycode.CO_COROUTINE |
                                            pycode.CO_GENERATOR)) != 0
 
-    def run(self):
+    def run(self, name=None, qualname=None):
         """Start this frame's execution."""
         if self._is_generator_or_coroutine():
-            if self.getcode().co_flags & pycode.CO_COROUTINE:
-                from pypy.interpreter.generator import Coroutine
-                gen = Coroutine(self)
-            else:
-                from pypy.interpreter.generator import GeneratorIterator
-                gen = GeneratorIterator(self)
-            if self.space.config.translation.rweakref:
-                self.f_generator_wref = rweakref.ref(gen)
-            else:
-                self.f_generator_nowref = gen
-            return self.space.wrap(gen)
+            return self.initialize_as_generator(name, qualname)
         else:
             return self.execute_frame()
+    run._always_inline_ = True
+
+    def initialize_as_generator(self, name, qualname):
+        if self.getcode().co_flags & pycode.CO_COROUTINE:
+            from pypy.interpreter.generator import Coroutine
+            gen = Coroutine(self, name, qualname)
+        else:
+            from pypy.interpreter.generator import GeneratorIterator
+            gen = GeneratorIterator(self, name, qualname)
+        if self.space.config.translation.rweakref:
+            self.f_generator_wref = rweakref.ref(gen)
+        else:
+            self.f_generator_nowref = gen
+        return self.space.wrap(gen)
 
     def execute_frame(self, in_generator=None, w_arg_or_err=None):
         """Execute this frame.  Main entry point to the interpreter.
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
@@ -32,6 +32,12 @@
         assert f.__qualname__ == 'qualname'
         raises(TypeError, "f.__qualname__ = b'name'")
 
+    def test_qualname_method(self):
+        class A:
+            def f(self):
+                pass
+        assert A.f.__qualname__ == 'test_qualname_method.<locals>.A.f'
+
     def test_annotations(self):
         def f(): pass
         ann = f.__annotations__
diff --git a/pypy/interpreter/test/test_generator.py 
b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -379,6 +379,22 @@
             assert False, 'Expected StopIteration'
             """
 
+    def test_set_name_qualname(self):
+        class A:
+            def f(self):
+                yield 5
+        g = A().f()
+        assert g.__name__ == "f"
+        assert g.__qualname__ == "test_set_name_qualname.<locals>.A.f"
+        g.__name__ = "h.i"
+        g.__qualname__ = "j.k"
+        assert g.__name__ == "h.i"
+        assert g.__qualname__ == "j.k"
+        raises(TypeError, "g.__name__ = 42")
+        raises(TypeError, "g.__qualname__ = 42")
+        raises((TypeError, AttributeError), "del g.__name__")
+        raises((TypeError, AttributeError), "del g.__qualname__")
+
 
 def test_should_not_inline(space):
     from pypy.interpreter.generator import should_not_inline
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -796,8 +796,10 @@
     gi_frame   = GetSetProperty(GeneratorIterator.descr_gicr_frame),
     gi_code    = interp_attrproperty_w('pycode', cls=GeneratorIterator),
     gi_yieldfrom=interp_attrproperty_w('w_yielded_from', 
cls=GeneratorIterator),
-    __name__   = GetSetProperty(GeneratorIterator.descr__name__),
-    __qualname__ = GetSetProperty(GeneratorIterator.descr__qualname__),
+    __name__   = GetSetProperty(GeneratorIterator.descr__name__,
+                                GeneratorIterator.descr_set__name__),
+    __qualname__ = GetSetProperty(GeneratorIterator.descr__qualname__,
+                                  GeneratorIterator.descr_set__qualname__),
     __weakref__ = make_weakref_descr(GeneratorIterator),
 )
 assert not GeneratorIterator.typedef.acceptable_as_base_class  # no __new__
@@ -824,8 +826,10 @@
     cr_frame   = GetSetProperty(Coroutine.descr_gicr_frame),
     cr_code    = interp_attrproperty_w('pycode', cls=Coroutine),
     cr_await   = interp_attrproperty_w('w_yielded_from', cls=Coroutine),
-    __name__   = GetSetProperty(Coroutine.descr__name__),
-    __qualname__ = GetSetProperty(Coroutine.descr__qualname__),
+    __name__   = GetSetProperty(Coroutine.descr__name__,
+                                Coroutine.descr_set__name__),
+    __qualname__ = GetSetProperty(Coroutine.descr__qualname__,
+                                  Coroutine.descr_set__qualname__),
     __weakref__ = make_weakref_descr(Coroutine),
 )
 assert not Coroutine.typedef.acceptable_as_base_class  # no __new__
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to