Skip to content

IPython embed doesn't respect namespaces #954

certik opened this Issue Oct 31, 2011 · 5 comments

3 participants

certik commented Oct 31, 2011

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()
In [1]: c                                                                      
Out[1]: {'InteractiveShell': {'confirm_exit': False}}

In [2]: namespace                                                              
{'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).

IPython member
minrk commented Oct 31, 2011

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))
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
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.

IPython member
minrk commented Nov 15, 2011

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

certik commented Nov 15, 2011

I have fixed this in the commit:


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

        user_ns=namespace, banner1=banner).mainloop(local_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
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
Something went wrong with that request. Please try again.