I’ve written a remote Python debugger and one of the features I need is to execute arbitrary code while stopped at a breakpoint. My debugger uses the following to execute code received from the remote debugger:
exec (compile(code, '<string>', 'single') , frame.f_globals, frame.f_locals)
This works fine for the most part, but I’ve noticed a couple issues.
-
Assignment statements aren’t actually applied to the original locals dictionary. This is probably due to the fact that f_locals is supposed to be read-only.
-
If stopped within a class method, accessing protected attributes (names beginning with double underscore) does not work. I’m assuming this is due to the name mangling that Python performs on protected attributes.
So my question is, is there a way around these limitations? Can I trick Python into thinking that the code is being executed in the actual local scope of that frame?
I’m using CPython 2.7, and I’m willing to accept a solution/hack specific to this version.
Not exactly, but the bytecode for the function will not look at
locals, using rather a simple but crucial optimization whereby local variables are in a simple array, avoiding runtime lookups. The only way to avoid this (and make the function much, much slower) is compiling different code, e.g. code starting with anexec ''to force the compiler to avoid the optimization (in Python 2; no way, in Python 3). If you need to work with existing bytecode, you’re out of luck: there is no way to accomplish what you desire.Yep, so this issue does allow a workaround: prepend
_Classnameto the name to mimic what the compiler does. Note that double-underscore prefixes means private: protected would be a single underscore (and would give you no trouble). Private names are specifically meant to avoid accidental classes with names bound in subclasses (and work decently for that one purpose, though not perfectly, and not for anything else;-).