Tell if Python is in interactive mode
Asked Answered
M

7

71

In a Python script, is there any way to tell if the interpreter is in interactive mode? This would be useful so that, for instance, when you run an interactive Python session and import a module, slightly different code is executed (for example, logging is turned off).

I've looked at tell whether python is in -i mode and tried the code there, however, that function only returns true if Python has been invoked with the -i flag and not when the command used to invoke interactive mode is python with no arguments.

What I mean is something like this:

if __name__=="__main__":
    #do stuff
elif __pythonIsInteractive__:
    #do other stuff
else:
    exit()
Microbarograph answered 1/3, 2010 at 14:20 Comment(1)
Consider using the logging module for logging in libraries, so users can control it with a shared configuration.Snobbery
S
72

__main__.__file__ doesn't exist in the interactive interpreter:

import __main__ as main
print hasattr(main, '__file__')

This also goes for code run via python -c, but not python -m.

Stingy answered 1/3, 2010 at 14:25 Comment(5)
This is also the case in, for example, py2exe executables.Siclari
Unfortunately this doesn't work inside an embedded shell. I.e. a shell started with IPython.embed()Photima
bool(getattr(sys, 'ps1', sys.flags.interactive)), py2.6+Desilva
So far none of the solutions seems to be able to detect PYTHONSTARTUP=script.py python3. The expression 'readline' in sys.modules can, as well as python3 -i script.py and python3 -ic 'import script' (tested with Python 3.8.2 on Ubuntu focal), but it's highly non-portable.Tahoe
This is the only answer that worked for ptpython interactive session started via python -m ptpython.Willmert
A
57

I compared all the methods I found and made a table of results. The best one seems to be this:

hasattr(sys, 'ps1')

enter image description here

If anyone has other scenarios that might differ, comment and I'll add it

Asperse answered 25/10, 2020 at 12:38 Comment(3)
Hey thank you for doing the hard work, would you be able to check Windows vs Linux vs Mac?Infamous
hasattr(sys, 'ps1') returns False in PyCharm 2022.1.4 (CE) console on Windows 11Domett
I i forgot to mention that the interpreter is Python 3.10.6Domett
E
29

sys.ps1 and sys.ps2 are only defined in interactive mode.

Exploration answered 1/3, 2010 at 14:27 Comment(3)
@Keith seems to work fine for me in iPython 3.2.1 REPL using python 2.7.9Apollyon
Agreed, I just checked in 4.0 and it works there as well. May have been an issue with older versions of IPython.Americana
Seems to me that sys.ps1 and sys.ps2 are defined even when iPython is run not in interactive mode.Rosenzweig
P
19

Use sys.flags:

if sys.flags.interactive:
    #interactive
else:
    #not interactive 
Photic answered 29/7, 2011 at 21:9 Comment(2)
This only checks for command line argument python -i and is not a test of being in the Python interactive mode by typing python alone.Proposition
bool(getattr(sys, 'ps1', sys.flags.interactive))Desilva
D
7

From TFM: If no interface option is given, -i is implied, sys.argv[0] is an empty string ("") and the current directory will be added to the start of sys.path.

If the user invoked the interpreter with python and no arguments, as you mentioned, you could test this with if sys.argv[0] == ''. This also returns true if started with python -i, but according to the docs, they're functionally the same.

Declinometer answered 1/3, 2010 at 14:30 Comment(3)
Uh oh. Direct violation of the Zen of Python, then :)Roomette
Heh... Though I think @echoback's version is the only obvious(ish) one. I didn't accept this simply because in C et al., it is theoretically possible that argv[0] is NULL or an empty string and I don't really feel like debugging any potential errors caused by that...Microbarograph
This may be problematic for other interpreters, however. For example, when using IPython, sys.argv = ['/usr/bin/ipython']Americana
B
1

The following works both with and without the -i switch:

#!/usr/bin/python
import sys
# Set the interpreter bool
try:
    if sys.ps1: interpreter = True
except AttributeError:
    interpreter = False
    if sys.flags.interactive: interpreter = True

# Use the interpreter bool
if interpreter: print 'We are in the Interpreter'
else: print 'We are running from the command line'
Brannon answered 13/7, 2014 at 16:13 Comment(8)
if sys.ps1: interpreter = True => interpreter = sys.ps1 or interpreter = bool(sys.ps1).Jampacked
@CristianCiupitu: You might want to actually test your code before you post it. Even if it was valid Python it would throw an AttribeError exception when run from the command line.Brannon
Did I recommend removing the try ... except statement? I only recommended replacing an if with a plain assignment.Jampacked
@CristianCiupitu: You made no such recommendation. Apparently you thought that the => communicated a whole lot more than it actually does. Of course, once one understands what you meant to say rather than what you said, your solution is longer and more compute intensive, but whatever floats your boat I suppose.Brannon
My bad for being elliptic, but I fail to understand how 27 characters are longer than 30 or why is it more compute intensive when if also needs the boolean value of sys.ps1.Jampacked
I mistook the last "or" as a Python statement rather than an English word, so as you say "my bad" on that. Now that I see that, your first proposal will assign ">>> " to sys.ps1 thereby causing a cast every time you use it, and also introducing an inconsistency where the type of "interpreter" is different depending upon runtime mode. On my system the pyc file for my solution is 3 bytes smaller than your second solution: You can try it yourself to verify, obviously.Brannon
You're right about that inconsistency, that's why I also proposed a second variant. I have python-2.7.5-13.fc20.x86_64 and the corresponding pyc is indeed bigger with 5 bytes for the bool variant. But if I also change the except code to interpreter = bool(sys.flags.interactive), the file is smaller with 27 bytes :-DJampacked
NECROMANCY!: bool(getattr(sys, 'ps1', sys.flags.interactive))Desilva
D
-4

Here's something that would work. Put the following code snippet in a file, and assign the path to that file to the PYTHONSTARTUP environment variable.

__pythonIsInteractive__ = None

And then you can use

if __name__=="__main__":
    #do stuff
elif '__pythonIsInteractive__' in globals():
    #do other stuff
else:
    exit()

http://docs.python.org/tutorial/interpreter.html#the-interactive-startup-file

Diseuse answered 7/7, 2011 at 18:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.