Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

IPython embed doesn't respect namespaces #954

Closed
certik opened this Issue · 5 comments

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
Owner

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
Owner

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
Owner

@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
@takluyver
Owner

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.