[pypy-commit] pypy default: Add __pypy__.locals_to_fast(), from an idea by Fabio Zadrozny to allow a
arigo
noreply at buildbot.pypy.org
Thu Feb 6 16:47:46 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r69087:e4876660324a
Date: 2014-02-06 16:46 +0100
http://bitbucket.org/pypy/pypy/changeset/e4876660324a/
Log: Add __pypy__.locals_to_fast(), from an idea by Fabio Zadrozny to
allow a Python debugger to modify local variables more freely. The
original is http://bugs.python.org/issue1654367 .
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -81,6 +81,7 @@
'newdict' : 'interp_dict.newdict',
'dictstrategy' : 'interp_dict.dictstrategy',
'set_debug' : 'interp_magic.set_debug',
+ 'locals_to_fast' : 'interp_magic.locals_to_fast',
}
if sys.platform == 'win32':
interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,5 +1,6 @@
from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.pyframe import PyFrame
from rpython.rlib.objectmodel import we_are_translated
from pypy.objspace.std.listobject import W_ListObject
from pypy.objspace.std.typeobject import MethodCache
@@ -111,3 +112,8 @@
@unwrap_spec(estimate=int)
def add_memory_pressure(estimate):
rgc.add_memory_pressure(estimate)
+
+ at unwrap_spec(w_frame=PyFrame)
+def locals_to_fast(space, w_frame):
+ assert isinstance(w_frame, PyFrame)
+ w_frame.locals2fast()
diff --git a/pypy/module/__pypy__/test/test_locals2fast.py b/pypy/module/__pypy__/test/test_locals2fast.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/test/test_locals2fast.py
@@ -0,0 +1,81 @@
+# Tests from Fabio Zadrozny
+
+
+class AppTestLocals2Fast:
+ """
+ Test setting locals in one function from another function
+ using several approaches.
+ """
+
+ def setup_class(cls):
+ cls.w_save_locals = cls.space.appexec([], """():
+ import sys
+ if '__pypy__' in sys.builtin_module_names:
+ import __pypy__
+ save_locals = __pypy__.locals_to_fast
+ else:
+ # CPython version
+ import ctypes
+ @staticmethod
+ def save_locals(frame):
+ ctypes.pythonapi.PyFrame_LocalsToFast(
+ ctypes.py_object(frame), ctypes.c_int(0))
+ return save_locals
+ """)
+
+ def test_set_locals_using_save_locals(self):
+ import sys
+ def use_save_locals(name, value):
+ frame = sys._getframe().f_back
+ locals_dict = frame.f_locals
+ locals_dict[name] = value
+ self.save_locals(frame)
+ def test_method(fn):
+ x = 1
+ # The method 'fn' should attempt to set x = 2 in the current frame.
+ fn('x', 2)
+ return x
+ x = test_method(use_save_locals)
+ assert x == 2
+
+ def test_frame_simple_change(self):
+ import sys
+ frame = sys._getframe()
+ a = 20
+ frame.f_locals['a'] = 50
+ self.save_locals(frame)
+ assert a == 50
+
+ def test_frame_co_freevars(self):
+ import sys
+ outer_var = 20
+ def func():
+ frame = sys._getframe()
+ frame.f_locals['outer_var'] = 50
+ self.save_locals(frame)
+ assert outer_var == 50
+ func()
+
+ def test_frame_co_cellvars(self):
+ import sys
+ def check_co_vars(a):
+ frame = sys._getframe()
+ def function2():
+ print a
+ assert 'a' in frame.f_code.co_cellvars
+ frame = sys._getframe()
+ frame.f_locals['a'] = 50
+ self.save_locals(frame)
+ assert a == 50
+ check_co_vars(1)
+
+ def test_frame_change_in_inner_frame(self):
+ import sys
+ def change(f):
+ assert f is not sys._getframe()
+ f.f_locals['a'] = 50
+ self.save_locals(f)
+ frame = sys._getframe()
+ a = 20
+ change(frame)
+ assert a == 50
More information about the pypy-commit
mailing list