New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IPythonShellEmbed fails to recognize local variables #136
Comments
Hmm, where did you define 'foo'? If you just run call foo outside of the function bar, foo should not exist (and obvously it doesn't). When you instead run "sum(f.values[x] for x in f.indices)" you get 15 again... |
Quite correct. However, I'm refering to the use of |
Is this likely to be the same issue as #62? |
No, @takluyver: this is a separate issue and indeed a real bug in our embedding code. I was hoping your recent work with namespaces would have fixed it, but it didn't. For reference, here's the example code to run with the current embedding api: class Foo(object):
""" Container-like object """
def __setattr__(self, obj, val):
self.__dict__[obj] = val
def __getattr__(self, obj, val):
return self.__dict__[obj]
f = Foo()
f.indices = set([1,2,3,4,5])
f.values = {}
for x in f.indices:
f.values[x] = x
def bar(foo):
import IPython
IPython.embed()
return sum(foo.values[x] for x in foo.indices)
print bar(f) Then, in the spawned, embedded IPython, this fails:
And it doesn't work even if we pass to the embed call
It looks like our embedding machinery is in pretty bad shape... |
Assigned this to myself to look at. |
Excellent, thanks. |
Unfortunately, I think this is a limitation of Python itself. It appears code compiled dynamically cannot define a closure, which is essentially what we're doing here with a generator expression. Here is a minimal test case:
Which gives:
Note that you can still see local variables in IPython - in the example given, plain |
I think it may be possible to make this work using |
Is it acceptable to up-vote, 👍 ? This affects me as well. I can add my use-case if requested. |
I would be 100% okay if the fix for this only worked on Python 3. |
I am also having the same problem under Python 3. Thanks for re-openning. |
Same problem here 👍 both in Python 2 and 3. |
I have this issue in both Python 2 and 3. It affects me on a daily basis. |
I looked into this issue a bit, and it's definitely fixable (though maintaining fixes for both Python 2 and 3 may be messy). The ChainMap solution would be easiest to include into IPython proper. However, there's a slight catch that eval/exec require globals to be a I also wrote a Python 3.5+ fix based on a different strategy of simulating closure cells and forcing the python compiler to emit the correct bytecode to work with them. The relevant file is here, part of my xdbg demo. It works by replacing As far as I can tell, the two approaches differ only in their handling of closures. When |
IPython 6.0 and later versions only work in Python 3, so if @nikitakit or anyone else wants to open a pulll request with a test case and a fix for this, that would be welcome. |
It's been a year since my last comment here, and during this time my understanding of the issue has changed a bit. Interactively inspecting local scope remains an important feature to me, but there are actually a number of inter-related issues regarding local variables and the embedding machinery. For example, modifying local variables inside an embedded shell doesn't work: >>> import IPython
>>> def test():
... x = 5
... IPython.embed()
... print('x is', x)
...
>>> test()
Python 3.5.1 |Continuum Analytics, Inc.| (default, Dec 7 2015, 11:24:55)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: x
Out[1]: 5
In [2]: x = 6
In [3]:
Do you really want to exit ([y]/n)? y
x is 5 A Another question is what happens when closures defined inside an embedded shell are leaked out into the global scope. Consider running the same code as above, but inputting something along the lines of Given the complexity of the situation, I've decided to focus my efforts on a more comprehensive approach to the problem (which also better aligns with my own usage of IPython). This has led to the development of xdbg, which is essentially a debugger that integrates with IPython. The key idea is to extend the IPython shell by offering debugger commands via magics (e.g. I don't currently plan on pull-requesting a narrowly-targeted bugfix to core IPython. However, I'm very interested to know what IPython users and devs think about using a debugger-inspired interface for local code inspection. IPython (and now also Jupyter) have had a huge impact on the ability to do interactive coding in Python, but there are still many improvements to be made in how it interacts with heavy encapsulation using classes/functions/modules. |
I've been burned a bunch of times by this bug. E.g.
I'm not sure what can be done, but just adding my voice to the choir. |
Based on https://bugs.python.org/issue13557 and the fact that explicitly passing locals() and globals() to an exec fixes @takluyver's reproduction of the bug, it seems like this ought to be possible to fix in IPython by passing the correct local and global namespaces.
|
As a work around, you can use |
Issue
Embedded IPython shells can lose track of local variables.
Test Case
Minimal test case:
To see the error, first run the code in Python (or IPython) and exit from the spawned shell; the final print statement correctly displays '15'. Run the code again, but this time type
sum(foo.values[x] for x in foo.indices)
in the spawned shell, and we receive the errorThe text was updated successfully, but these errors were encountered: