Is it possible for a Python script to detect whether it is running
interactively? It can be useful for e.g. defining functions that are
only useful in interactive mode.
Kind regards, Roald
> Dear all,
>
> Is it possible for a Python script to detect whether it is running
> interactively? It can be useful for e.g. defining functions that are
> only useful in interactive mode.
Try the isatty() method (*) on e.g. stdin:
$ python -c "import sys; print sys.stdin.isatty()"
True
$ echo "" | python -c "import sys; print sys.stdin.isatty()"
False
(*) http://docs.python.org/library/stdtypes.html#file.isatty
DaveA
That was my question indeed. Is it possible?
> Dear all,
>
> Is it possible for a Python script to detect whether it is running
> interactively? It can be useful for e.g. defining functions that are
> only useful in interactive mode.
Check __name__. It's set to '__main__' when running as a (non-
interactive) script, and to the name of the module when imported.
[steve@sylar ~]$ cat interactive.py
print __name__
[steve@sylar ~]$ python interactive.py
__main__
[steve@sylar ~]$ python
Python 2.5 (r25:51908, Nov 6 2007, 16:54:01)
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import interactive
interactive
>>>
The only complications are that it doesn't work well with the -i command
line switch (it still reports that __name__ == '__main__'), and if you
start an interactive session __name__ is also set to '__main__'.
Sadly, sys.argv doesn't report the switches used, but in Python 2.6 and
better you can look at sys.flags to see if the -i switch is being used.
http://docs.python.org/library/sys.html#sys.flags
--
Steven
> Dear all,
>
> Is it possible for a Python script to detect whether it is running
> interactively? It can be useful for e.g. defining functions that are
> only useful in interactive mode.
Ah, I should have looked more carefully at the docs...
http://docs.python.org/library/sys.html#sys.ps1
sys.ps1 and sys.ps2 are documented as only existing if you are running
interactively.
--
Steven
The sneaky answer would be that a script cannot be used interactively,
as once you import it from the interpreter, it's a module, not a
script. So you can detect that it's not a script, by examing __name__
in the usual way. If it's a script, it'll have a value of "__main__".
But that won't tell you if you're running inside an IDE, or using the -i
switch on the Python command line, or probably a bunch of other
questions. I don't know of any "correct" answer, and I'm not sure what
the real use case is for knowing. Are you really going to somehow
define a different set of functions???
But I'm sure someone else will know something more explicitly tied to
the interactive session. If that's indeed what you want to test for.
DaveA
This doesn't really work. In ipython, sys.ps1 is not defined. But also
if I run 'python <<< "import sys; print(sys.ps1)"', I get an error.
> Roald de Vries wrote:
>> On Dec 29, 2009, at 8:34 PM, Dave Angel wrote:
>>> Antoine Pitrou wrote:
>>>> Le Tue, 29 Dec 2009 16:09:58 +0100, Roald de Vries a écrit :
>>>>
>>>>
>>>>> Dear all,
>>>>>
>>>>> Is it possible for a Python script to detect whether it is running
>>>>> interactively? It can be useful for e.g. defining functions that
>>>>> are
>>>>> only useful in interactive mode.
>>>>>
>>>>
>>>> Try the isatty() method (*) on e.g. stdin:
>>>>
>>>> $ python -c "import sys; print sys.stdin.isatty()"
>>>> True
>>>> $ echo "" | python -c "import sys; print sys.stdin.isatty()"
>>>> False
>>>>
>>> Your test determines whether input is redirected. But I think the
>>> OP was asking how to detect whether the script was being run from
>>> an interpreter prompt.
>>
>> That was my question indeed. Is it possible?
>>
>>
> If I had had a good answer, I would have supplied it in my earlier
> message.
>
> The sneaky answer would be that a script cannot be used
> interactively, as once you import it from the interpreter, it's a
> module, not a script. So you can detect that it's not a script, by
> examing __name__ in the usual way. If it's a script, it'll have a
> value of "__main__".
>
> But that won't tell you if you're running inside an IDE, or using
> the -i switch on the Python command line, or probably a bunch of
> other questions. I don't know of any "correct" answer, and I'm not
> sure what the real use case is for knowing. Are you really going to
> somehow define a different set of functions???
I'm using a database, and want to use python interactively to
manipulate it. On the other hand, I also want to be able to use it non-
interactively. In that case, it would be a waste of CPU to load the
function/class definitions meant for interactive use.
Once you get a handle on the structures and functions required for
interactive vs. non-interactive use you can consider refactoring the
code so that the non-interactive programs don't need to import the stuff
that's exclusively for interactive use. But frankly I wouldn't waste
your time.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
> On Dec 30, 2009, at 1:52 AM, Steven D'Aprano wrote:
>> On Tue, 29 Dec 2009 16:09:58 +0100, Roald de Vries wrote:
>>
>>> Dear all,
>>>
>>> Is it possible for a Python script to detect whether it is running
>>> interactively? It can be useful for e.g. defining functions that are
>>> only useful in interactive mode.
>>
>> Ah, I should have looked more carefully at the docs...
>>
>> http://docs.python.org/library/sys.html#sys.ps1
>>
>> sys.ps1 and sys.ps2 are documented as only existing if you are running
>> interactively.
>
> This doesn't really work. In ipython, sys.ps1 is not defined.
Then ipython is not a valid implementation of Python, since it breaks a
promise of the language. You should report this to the ipython people as
a serious bug.
> But also
> if I run 'python <<< "import sys; print(sys.ps1)"', I get an error.
Of course you do, because you're not running interactively and so sys.ps1
doesn't exist. You need to check the existence of ps1:
try:
sys.ps1
except AttributeError:
print "Not running interactively."
else:
print "Running interactively."
Alternatively:
if hasattr(sys, 'ps1'):
print "Running interactively."
else:
print "Not running interactively."
--
Steven
> I'm using a database, and want to use python interactively to manipulate
> it. On the other hand, I also want to be able to use it non-
> interactively. In that case, it would be a waste of CPU to load the
> function/class definitions meant for interactive use.
Premature optimization is the root of all evil.
The code for interactive use almost certainly won't be a significant
drain on the computer's resources, unless you're using some sort of
embedded device. And if it is, then the natural overhead of merely
running Python at all is almost certainly even more of a drain -- Python
is not a language designed for the efficiency of the CPU, but for the
programmer instead.
But even if we give you the benefit of the doubt, and assume that you've
profiled your code and determined that, in this case, such optimization
is needed, I see at least two problems with that approach.
Problem #1: the benefit won't be as much as you might expect.
If your approach is the following:
# common code used both interactively and non-interactively
def parrot():
pass
def spanish_inquisition():
pass
# interactive code only:
if interactive(): # however you determine this
def cheeseshop():
pass
then the approach you are trying isn't doing what you think it does.
Python still has to parse the definition of cheeseshop and compile it
before running the module code, so the benefit of making it optional is
minimal.
You might think that the better approach is to move it into another
module:
if interactive(): # however you determine this
from interactive_code import *
but even this means that the benefit is relatively small, since the
interactive_code module will be compiled to a .pyc file, and therefore
most of the effort of parsing it, compiling it etc. will be skipped. And
now you have to deal with the problem of circular imports.
Problem #2: if you have code that only appears at certain times, how do
you test it to be sure it works correctly?
Since test code (unit tests, doc tests, etc.) generally are run non-
interactively, your code will be missing all the interactive functions,
which means you can't test them easily. Any automated test suite will
skip half your code!
--
Steven
Ron:
You'd be surprised how little additional space and time a few functions
take up.
But in any case, if (after measurement) you decide you really want them
to be optional, then just have a different module that the interactive
users import than the one that you run in production. Have both modules
import the bulk of the code, and keep the differences in one place.
It's also possible to build stubs for the missing functions, and import
them and overwrite the stubs, upon first reference. I've done that sort
of thing in other language environments, when it made a definite
measurable difference (like say 50%)
DaveA
Why don't you write a separate writer script for the interactive
behaviour? This would be much simpler than trying to guess whether the
current Python process is "interactive", since the latter is ill-defined.
Remember, explicit is better than implicit.
Actually, performance is not much if an issue for what I want to do;
it's mainly interest in 'how should I do this in general'. I'll just
leave in all the code, and if it becomes a real issue, I'll separate
the code over an interactive and a non-interactive script. Thanks for
your inputs.
>> if I run 'python <<< "import sys; print(sys.ps1)"', I get an error.
>
> Of course you do, because you're not running interactively
Excuse me, why do you say that?
--
By ZeD
Two reasons.
First, because sys.ps1 is documented as only existing in an interactive
environment, and sure enough, sys.ps1 fails to exist when you run the
above.
And secondly, and much more importantly, if you run that command, you do
not get an interactive prompt.
The format of the command being run is a bash "here string", more-or-less
equivalent to either of:
echo "import sys; print(sys.ps1)" | python
python -c "import sys; print(sys.ps1)"
both of which also exit with AttributeError.
If you really want to see what's going on, have a look at this:
[steve@sylar ~]$ python -i -c "import sys; print(sys.ps1)"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: 'module' object has no attribute 'ps1'
>>> sys.ps1
'>>> '
The -c switch tells Python to execute whatever comes next, and the -i
switch tells Python to enter interactive mode afterwards. At first,
sys.ps1 does not exist and you get an AttributeError, but then the -i
switch kicks in, sys.ps1 is defined and you get a prompt.
--
Steven
XP summarizes it as: You ain't gonna need it
(http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it )