Skip to content
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

get_ipython() called from startup script #9791

Closed
elvis-sik opened this issue Jul 21, 2016 · 9 comments
Closed

get_ipython() called from startup script #9791

elvis-sik opened this issue Jul 21, 2016 · 9 comments
Milestone

Comments

@elvis-sik
Copy link

Hi, this is maybe more me asking for help than an issue per se.

Inside the startup folder of some IPython profile, I have the following script:

print('get_ipython() = ', get_ipython())
import weird

This module weird is elsewhere, and it is importable. It is merely:

get_ipython()

What happens is: the call to get_ipython inside the print statement in the body of the file inside the startup script goes smoothly. However, get_ipython is not visible inside the module weird. So it throws a NameError there.

Now, of course, after this phase of startup-file loading, I get a traceback and then an IPython REPL. There, I can import weird just fine.

There is code relying on get_ipython to know if it is being runned inside IPython. If I call this code inside my startup script, strange results happen. See here sympy/sympy#11419

If this behaviour is not considered a bug, maybe we could find some workaround.

@Carreau
Copy link
Member

Carreau commented Jul 22, 2016

ip is injected in the main namespace, though a module is executed by python in it's own namespace we don't have control over.

You can check for

from IPython.terminal.interactiveshell import TerminalInteractiveShell
TerminalInteractiveShell._instance # None if no IPython available.

It's, of course, private API (because of leading underscore).

@takluyver
Copy link
Member

I think we do inject get_ipython() into the builtins, so it's accessible to every module but possibly we only do that after the startup scripts have run. That's something we may want to fix. BuiltinTrap is the class that adds things to builtins.

BTW, it is possible to check for an initialised TIS using public APIs:

if TerminalInteractiveShell.initialized():   # Bool - True if it's instantiated
    ipshell = TerminalInteractiveShell.instance()

.instance() will create an instance if one doesn't already exist.

@elvis-sik
Copy link
Author

@takluyver I notice if I simply run from from the command line $ ipython a_module.py, the module cannot use the functions IPython adds to builtins (ie, no get_ipython). My understanding is that this is desired, right? When we call ipython from the command line, it should work as if we were calling python on the script.

When we are in a REPL, though, IPython's inclusions should be in scope. This is in contrast with the previous situation. In one case, get_ipython shouldn't be in scope. On the other one, it should.

It seems to me that scripts executed during startup are in a grey area in which we are not yet in a REPL, leading us to expect that get_ipython should not be in scope, but we are not executing some random script from the command line, but rather about to get into a REPL, so maybe get_ipython should be in scope.

But I do not know, just sharing my thoughts.

@takluyver
Copy link
Member

I'd be inclined to say that ipython some_script.py should expose get_ipython() to the script it runs, as it is being run in IPython. But I don't feel that strongly about it either way - I never use IPython like that myself.

@Carreau
Copy link
Member

Carreau commented Jul 25, 2016

I'd be inclined to say that ipython some_script.py should expose get_ipython() to the script it runs, as it is being run in IPython. But I don't feel that strongly about it either way - I never use IPython like that myself.

I'm more incline to think that even in the repl, getting the current shell should be something like

import IPython
ip = IPython.instance()

but I wouldn't be against making things consistent.

@takluyver
Copy link
Member

I think we've told people for quite a long time that the existence of get_ipython() can be used to check that you're inside IPython. Let's not break that.

@ludwigschwardt
Copy link

ludwigschwardt commented Jul 27, 2016

I've just stepped on this very problem in my code...

I have the following in a module I import:

try:
    # IPython 0.11 and above
    _ip = get_ipython()
except NameError:
    # IPython 0.10 and below (or normal Python shell)
    _ip = __builtins__.get('__IPYTHON__')

The problem was picked up with the ipython script.py incantation. In this case the module could not see get_ipython() but __IPYTHON__ existed and was set to True as opposed to a shell instance.

Maybe I should just drop support for IPython 0.10 and below :-) I mainly use the shell instance for adding tab completion hooks but the latest interface for that is much more convenient.

takluyver added a commit to takluyver/ipython that referenced this issue Jul 28, 2016
This makes get_ipython() available as a builtin when startup files run.

Closes ipythongh-9791
@takluyver
Copy link
Member

#9818 should fix this.

@minrk
Copy link
Member

minrk commented Jul 28, 2016

You can always get the current IPython without relying on any modification of builtins by importing get_ipython:

from IPython import get_ipython
ip = get_ipython()

This get_ipython() will return None if there is no IPython instance. Modules should generally not rely on get_ipython being injected into builtins, and should import this function instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants