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