IPython embed doesn't respect namespaces #954

Closed
certik opened this Issue Oct 31, 2011 · 5 comments

Projects

None yet

3 participants

@certik

In Qsnake, where we embed IPython manually, the local namespace from Qsnake is exposed to IPython, which is a bug. Here is a simple script to reproduce the problem:


ondrej@eagle:~$ qsnake --shell
Type CTRL-D to exit the Qsnake shell.
Qsnake: ondrej@eagle:~$ python
Python 2.6.4 (r264:75706, May  7 2011, 22:48:31) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import IPython
>>> c = IPython.config.loader.Config()
>>> c.InteractiveShell.confirm_exit = False
>>> banner = "test"
>>> namespace = {}
>>> IPython.frontend.terminal.embed.InteractiveShellEmbed(config=c,
...             user_ns=namespace, banner1=banner).mainloop()
test
In [1]: c                                                                      
Out[1]: {'InteractiveShell': {'confirm_exit': False}}

In [2]: namespace                                                              
Out[2]: 
{'IPython': <module 'IPython' from '/home/ondrej/repos/qsnake/local/lib/python2.6/site-packages/IPython/__init__.pyc'>,
 'In': ['', u'c', u'namespace'],
 'Out': {1: {'InteractiveShell': {'confirm_exit': False}}},
 '_': {'InteractiveShell': {'confirm_exit': False}},
 '_1': {'InteractiveShell': {'confirm_exit': False}},
 '__': '',
 '___': '',
 '__builtin__': <module '__builtin__' (built-in)>,
 '__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__name__': '__main__',
 '__package__': None,
 '_dh': [u'/home/ondrej'],
 '_i': u'c',
 '_i1': u'c',
 '_i2': u'namespace',
 '_ih': ['', u'c', u'namespace'],
 '_ii': u'',
 '_iii': u'',
 '_oh': {1: {'InteractiveShell': {'confirm_exit': False}}},
 '_sh': <module 'IPython.core.shadowns' from '/home/ondrej/repos/qsnake/local/lib/python2.6/site-packages/IPython/core/shadowns.pyc'>,
 'banner': 'test',
 'c': {'InteractiveShell': {'confirm_exit': False}},
 'exit': <IPython.core.autocall.ExitAutocall at 0x28a7410>,
 'get_ipython': <bound method InteractiveShellEmbed.get_ipython of <IPython.frontend.terminal.embed.InteractiveShellEmbed object at 0x7f1517bce990>>,
 'help': Type help() for interactive help, or help(object) for help about object.,
 'namespace': {...},
 'quit': <IPython.core.autocall.ExitAutocall at 0x28a7410>}

In [3]: banner                                                                 
Out[3]: 'test'

As you can see, the c, banner and namespace variables are declared in Python above, but somehow they get propagated to IPython. What is worse, if you do:

In [4]: from sympy import var                                                  

In [5]: var("c")                                                               
Out[5]: c

In [6]: c                                                                      
Out[6]: {'InteractiveShell': {'confirm_exit': False}}

So the c variable can't be used in sympy (that's how I discovered this problem).

@minrk
IPython member

I believe that the point of embed is to load IPython in the calling scope. If you want to clobber that behavior, you have to set the local_ns and global_ns arguments to shell.mainloop, which default to inspecting the calling frame:

>>> import IPython
>>> c = IPython.config.loader.Config()
>>> c.InteractiveShell.confirm_exit = False
>>> banner = "test"
>>> namespace = dict(a=5)
>>> shell = IPython.frontend.terminal.embed.InteractiveShellEmbed(config=c, user_ns=namespace, banner1=banner)
>>> shell.mainloop(local_ns=dict(b=10), global_ns=dict(d=32))
test
In [1]: a
Out[1]: 5

In [2]: b
Out[2]: 10

In [3]: c
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/Users/minrk/dev/ip/mine/<ipython-input-3-2cd6ee2c70b0> in <module>()
----> 1 c

NameError: name 'c' is not defined

In [4]: d
Out[4]: 32
@takluyver
IPython member

N.B. global_ns might at some point turn into module (I've had a PR open for some time). You might want to look at instantiating TerminalInteractiveShell, rather than calling embed(). Have a look at the examples here.

@minrk
IPython member

@takluyver - should this be closed as 'not an Issue', because embed seems to behave precisely as intended?

@certik

I have fixed this in the commit:

qsnake/qsnake@4daa75d

so I am closing this issue. Here is the line, that I use now:

IPython.frontend.terminal.embed.InteractiveShellEmbed(config=c,
        user_ns=namespace, banner1=banner).mainloop(local_ns={},
                global_ns={})

What is confusing to me is that there is user_ns and also local_ns (and global_ns). But I simply set local_ns and global_ns to an empty dictionary and use user_ns as the local namespace and things work as expected.

Thanks for the help!

@certik certik closed this Nov 15, 2011
@takluyver
IPython member

There's probably an issue that it's a bit unclear. I'll try to get round to having a look at it in my usermod branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment