ipython - Hook the global name lookup in a python interpreter -
here thing, have proxy holding reference remote module, , put of these proxies sys.modules
such can use local modules. other objects put in __builtin__
module @ remote environment (like magic variable convenience of debugging or referencing). don't want reference these vars conn.__builtin__.var
, , have either replace local __builtin__
(which seems not working replace sys.modules['__builtin__']
or hook global name finding rules. how? module can overload getattr
this. in interactive interpreter ipython
, main module or how this? update: pointed out @nizam mohamed, yes can __main__
module, still can't modify name lookup role of it.
i'd turn local environment remote 1 (for debugging console)
update
for iterate __builtin__.__dict__
, if there name isn't in local __builtin__
. add name local's __builtin__
. it's not dynamic compare name lookup rule if can't find name in local __builtin__
try remote one.
here similar discussion.
and this question gives simulation of module replace object in sys.modules
. won't work __builtin__
name lookup, i've tried replace __builtin__.__getattribute__
custom 1 first use original lookup followed custom 1 when failed. global name lookup of __builtin__
never called __builtin__.__getattribute__
__builtin__.__getattribute__('name')
returns desired value, __builtin__.name
or name
never returns one.
use ast transformation of ipython shell
as @asmeurer said, can write simple ast transformer "hook" variable name lookup. base class ast.nodetransformer
provide visit_name method can manipulate. need overload method redefine variables existing in remote module not locally.
the following module can used ipython extension:
testast.py
import ast modname = "undefined" modattr = [] user_ns = {} class mytransformer(ast.nodetransformer): def visit_name(self, node): if node.id in modattr , not node.id in user_ns: return self.getname(node) return node def getname(self, namenode): return ast.attribute(value=ast.name(id=modname, ctx=ast.load()), attr = namenode.id, ctx = namenode.ctx) def magic_import(self, line): global modname, modattr, user_ns modname = str(line) if not self.shell.run_code( compile('import {0}'.format(line), '<string>', 'exec') ): user_ns = self.shell.user_ns modattr = user_ns[line.strip()].__dict__ self.shell.ast_transformers.append(mytransformer()) print modname, 'imported' def load_ipython_extension(ip): ip.define_magic('magic_import', magic_import)
dummymodule.py
robot=" world"
usage:
in [1]: %load_ext testast in [2]: %magic_import dummymodule in [3]: print "hello" , robot hello world in [4]: dummymodule.robot_ii = "human" in [5]: print "hi", robot_ii hi human
the benefit of method modification remote module takes effect because lookup done in language level , no object copied , cached.
one drawback of method not being able handle dynamic lookup. if that's important you, maybe python_line_transforms
hook more suitable.
Comments
Post a Comment