[mdione@grulic.org.ar: modifying locals]

Forwarding as suggested in python-list... ----- Forwarded message from Marcos Dione <mdione@grulic.org.ar> ----- Date: Sun, 11 Oct 2015 15:30:05 +0200 From: Marcos Dione <mdione@grulic.org.ar> Subject: modifying locals To: help@python.org Message-ID: <20151011133005.GC2798@diablo.grulicueva.local> Content-Type: text/plain; charset=us-ascii First of all, I'm not subscribed to the list, so please CC me. I'm writing a language[1] heavily based on Python. The way I'm implementing it is by having my own parser (based/stolen from pypy), obtaining an AST, modifying it and running the result with Python3's exec(). One of its particular features is that I intend to support semi-transparent remote execution using paramiko. For that, there is a construction that looks like this: [local code 1] with remote(...): [remote code] [local code 2] The idea is that [remote code] is effectively executed in a remote machine specified in remote()'s parameters. This is implemented[3] by remote() being a context manager. Part of the transparency is that globals and locals at the remote() point will be accesible to the remote code (so far only variables), and that modifications to locals will be visible back to [local code 2]. So far I managed to do the first part, but not the second. I managed to transfer the locals back from the remote. My problem is modifying the locals in remote()'s __exit__() method. As I'm running the code using exec(), it's not just a matter of modifying locals()[2]. What I tried was the following: * When I execute the code, I pass an empty dictionary to hold the locals. I save a reference to it, and I try to use it to modify the locals [local code 2] sees, but as locals are related to stack frame, it doesn't work. * This leads to the second attempt: use the stack to modify remote()'s caller's locals by[4]: inception_locals= sys._getframe().f_back.f_locals inception_locals.update (locals) Somehow this doesn't work either, and it's driving me crazy. I run out of ideas, so maybe you could throw some? Thanks in advance. -- [1] if you're interested, check https://github.com/StyXman/ayrton/ [2] isn't it? Just by writing that I got my doubts... [3] https://github.com/StyXman/ayrton/blob/develop/ayrton/functions.py#L112 [4] https://github.com/StyXman/ayrton/blob/develop/ayrton/functions.py#L254 -- (Not so) Random fortune: They called me mad, and I called them mad, and damn them, they outvoted me. -- Nathaniel Lee ----- End forwarded message ----- -- (Not so) Random fortune: 20:45 < perrito666> la_rayis: la esperanza es lo ultimo que se pierde 20:45 * perrito666 se aferra a eso o ya estaria casado

Hi Marcos, On Wed, Oct 14, 2015 at 12:58 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
inception_locals= sys._getframe().f_back.f_locals inception_locals.update (locals)
I think this works if you *assign* to f_locals. When you only *read* f_locals, you get a copy of the dict. The assignment is needed to write the new values back into the frame's real ("optimized") locals: inception_locals= sys._getframe().f_back.f_locals inception_locals.update (locals) sys._getframe().f_back.f_locals = inception_locals A bientôt, Armin.

On Thu, Oct 15, 2015 at 04:14:02PM +0200, Armin Rigo wrote:
AttributeError: attribute 'f_locals' of 'frame' objects is not writable so no cigar here. on the other hand, this works: http://mike.verdone.ca/media/Dangerously%20Advanced%20Python.pdf [p21] so I'll keep investigating :-]
A bientôt,
À+ :) -- (Not so) Random fortune: Army General: [shouting] You told us that windows 98 would be faster, and more efficient with better access to the internet! Bill Gates: It IS faster! Over five million... [General shoots Bill Gates in the face and everyone cheers] -- South Park

On Thu, Oct 15, 2015 at 04:47:57PM +0200, Marcos Dione wrote:
maybe context managers add a stack frame/do something with them internally? -- (Not so) Random fortune: 02:46 < daemonkeeper> StyXman: Every good system administrator needs to configure sendmail at least once, a real good one won't do it a second time

Hi Marcos, On Thu, Oct 15, 2015 at 4:50 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
Sorry, you're right. Now it seems from looking at the CPython source code that there is no way. This is getting quite off-topic for the pypy-dev list, but maybe this CPython-only awful hack: import ctypes ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame), 0) A bientôt, Armin.

On Fri, Oct 16, 2015 at 08:32:36AM +0200, Armin Rigo wrote:
could you point me where in the code? maybe thereś a bug to fix, or at least a reason to understand.
cool, thanks, I'll try that today. -- (Not so) Random fortune: La razón por la que la industria de medios es tan amiga del término “piratería” es que inmediatamente evoca una imagen negativa, de violencia y saqueo, en la que ellos son las víctimas que se ven privadas de “su propiedad”. [...] en una conferencia que diera la abogada de la Federación Internacional de la Industria Fonográfica, [...] escuchamos cómo un abogado se alarmaba del hecho de que “la sociedad se está apropiando de la cultura”. -- http://federratas.codigolibre.net/?p=137

On Fri, Oct 16, 2015 at 09:07:27AM +0200, Marcos Dione wrote:
here's very good post on the subject: https://mail.python.org/pipermail/python-dev/2005-January/051018.html in short: f_locals is a built-on-the-fly dict that actually has the copy of the original data; it's modifiable, but those modifs don't go back to where that came from. he also suggests using PyFrame_LocalsToFast(), and the only two places where that function is called in in the implementation of from foo import * and some other place I hadn't figure out yet. and this seems to be like this since before py2.1. as for the hack itself, it works! \o/ thanks very much for the pointers :) Cheers, -- Marcos. -- (Not so) Random fortune: <smolski> windows s'enrichis, le libre t'enrichis

Hi Marcos, On Fri, Oct 16, 2015 at 8:16 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
as for the hack itself, it works! \o/ thanks very much for the pointers :) Cheers,
No problem. Actually, some Googling finds the very same hack used at various places and explained in blog posts... Armin

Hi Marcos, On Wed, Oct 14, 2015 at 12:58 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
inception_locals= sys._getframe().f_back.f_locals inception_locals.update (locals)
I think this works if you *assign* to f_locals. When you only *read* f_locals, you get a copy of the dict. The assignment is needed to write the new values back into the frame's real ("optimized") locals: inception_locals= sys._getframe().f_back.f_locals inception_locals.update (locals) sys._getframe().f_back.f_locals = inception_locals A bientôt, Armin.

On Thu, Oct 15, 2015 at 04:14:02PM +0200, Armin Rigo wrote:
AttributeError: attribute 'f_locals' of 'frame' objects is not writable so no cigar here. on the other hand, this works: http://mike.verdone.ca/media/Dangerously%20Advanced%20Python.pdf [p21] so I'll keep investigating :-]
A bientôt,
À+ :) -- (Not so) Random fortune: Army General: [shouting] You told us that windows 98 would be faster, and more efficient with better access to the internet! Bill Gates: It IS faster! Over five million... [General shoots Bill Gates in the face and everyone cheers] -- South Park

On Thu, Oct 15, 2015 at 04:47:57PM +0200, Marcos Dione wrote:
maybe context managers add a stack frame/do something with them internally? -- (Not so) Random fortune: 02:46 < daemonkeeper> StyXman: Every good system administrator needs to configure sendmail at least once, a real good one won't do it a second time

Hi Marcos, On Thu, Oct 15, 2015 at 4:50 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
Sorry, you're right. Now it seems from looking at the CPython source code that there is no way. This is getting quite off-topic for the pypy-dev list, but maybe this CPython-only awful hack: import ctypes ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame), 0) A bientôt, Armin.

On Fri, Oct 16, 2015 at 08:32:36AM +0200, Armin Rigo wrote:
could you point me where in the code? maybe thereś a bug to fix, or at least a reason to understand.
cool, thanks, I'll try that today. -- (Not so) Random fortune: La razón por la que la industria de medios es tan amiga del término “piratería” es que inmediatamente evoca una imagen negativa, de violencia y saqueo, en la que ellos son las víctimas que se ven privadas de “su propiedad”. [...] en una conferencia que diera la abogada de la Federación Internacional de la Industria Fonográfica, [...] escuchamos cómo un abogado se alarmaba del hecho de que “la sociedad se está apropiando de la cultura”. -- http://federratas.codigolibre.net/?p=137

On Fri, Oct 16, 2015 at 09:07:27AM +0200, Marcos Dione wrote:
here's very good post on the subject: https://mail.python.org/pipermail/python-dev/2005-January/051018.html in short: f_locals is a built-on-the-fly dict that actually has the copy of the original data; it's modifiable, but those modifs don't go back to where that came from. he also suggests using PyFrame_LocalsToFast(), and the only two places where that function is called in in the implementation of from foo import * and some other place I hadn't figure out yet. and this seems to be like this since before py2.1. as for the hack itself, it works! \o/ thanks very much for the pointers :) Cheers, -- Marcos. -- (Not so) Random fortune: <smolski> windows s'enrichis, le libre t'enrichis

Hi Marcos, On Fri, Oct 16, 2015 at 8:16 PM, Marcos Dione <mdione@grulic.org.ar> wrote:
as for the hack itself, it works! \o/ thanks very much for the pointers :) Cheers,
No problem. Actually, some Googling finds the very same hack used at various places and explained in blog posts... Armin
participants (2)
-
Armin Rigo
-
Marcos Dione