detect interactivity

4 views
Skip to first unread message

Roald de Vries

unread,
Dec 29, 2009, 10:09:58 AM12/29/09
to pytho...@python.org
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.

Kind regards, Roald


Antoine Pitrou

unread,
Dec 29, 2009, 10:25:45 AM12/29/09
to pytho...@python.org
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


(*) http://docs.python.org/library/stdtypes.html#file.isatty

Dave Angel

unread,
Dec 29, 2009, 2:34:20 PM12/29/09
to Antoine Pitrou, pytho...@python.org
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
>
>
> (*) http://docs.python.org/library/stdtypes.html#file.isatty
>
>
>
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.


DaveA

Roald de Vries

unread,
Dec 29, 2009, 6:20:36 PM12/29/09
to Dave Angel, pytho...@python.org
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?

Steven D'Aprano

unread,
Dec 29, 2009, 7:50:49 PM12/29/09
to
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.

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

Steven D'Aprano

unread,
Dec 29, 2009, 7:52:22 PM12/29/09
to
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.


--
Steven

Dave Angel

unread,
Dec 29, 2009, 8:28:52 PM12/29/09
to Roald de Vries, pytho...@python.org
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???

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

Roald de Vries

unread,
Dec 29, 2009, 9:26:20 PM12/29/09
to Steven D'Aprano, pytho...@python.org

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

unread,
Dec 29, 2009, 9:33:18 PM12/29/09
to Dave Angel, pytho...@python.org

On Dec 30, 2009, at 2:28 AM, Dave Angel wrote:

> 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.

Steve Holden

unread,
Dec 29, 2009, 10:10:22 PM12/29/09
to pytho...@python.org, pytho...@python.org, Dave Angel
Roald de Vries wrote:
>
> On Dec 30, 2009, at 2:28 AM, Dave Angel wrote:
>
>> 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 :
> non-interactively. In that case, it would be a waste of CPU to load the

> function/class definitions meant for interactive use.
>
This is an extreme case of premature optimization. Write the code and
run it. Do you have any idea how much extra time and memory loading the
additional code will require? If not, it's a waste of your time to even
think about omitting the stuff required 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/

Steve Holden

unread,
Dec 29, 2009, 10:10:22 PM12/29/09
to Roald de Vries, pytho...@python.org, Dave Angel

Steven D'Aprano

unread,
Dec 30, 2009, 12:06:17 AM12/30/09
to
On Wed, 30 Dec 2009 03:26:20 +0100, Roald de Vries wrote:

> 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

Steven D'Aprano

unread,
Dec 30, 2009, 12:27:35 AM12/30/09
to
On Wed, 30 Dec 2009 03:33:18 +0100, Roald de Vries wrote:

> 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

Dave Angel

unread,
Dec 30, 2009, 1:28:32 AM12/30/09
to Steve Holden, pytho...@python.org, Roald de Vries
Steve Holden wrote:
> Roald de Vries wrote:
>
>> On Dec 30, 2009, at 2:28 AM, Dave Angel wrote:
>>
>>
>>> Roald de Vries wrote:
>>>
>>> <snip>

>>> mehow 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.
>>
>>
> This is an extreme case of premature optimization. Write the code and
> run it. Do you have any idea how much extra time and memory loading the
> additional code will require? If not, it's a waste of your time to even
> think about omitting the stuff required 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
>

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

Antoine Pitrou

unread,
Dec 30, 2009, 3:01:36 AM12/30/09
to pytho...@python.org
Le Wed, 30 Dec 2009 03:33:18 +0100, Roald de Vries a écrit :
>
> 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.

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.

Roald de Vries

unread,
Dec 30, 2009, 7:25:12 AM12/30/09
to Steve Holden, pytho...@python.org, Dave Angel
On Dec 30, 2009, at 4:10 AM, Steve Holden wrote:
> Roald de Vries wrote:
>>
>> On Dec 30, 2009, at 2:28 AM, Dave Angel wrote:
>>
>>> 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.
>>
> This is an extreme case of premature optimization. Write the code and
> run it. Do you have any idea how much extra time and memory loading
> the
> additional code will require? If not, it's a waste of your time to
> even
> think about omitting the stuff required 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.

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.

Vito 'ZeD' De Tullio

unread,
Dec 30, 2009, 8:42:12 AM12/30/09
to pytho...@python.org
Steven D'Aprano wrote:


>> 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

Steven D'Aprano

unread,
Dec 30, 2009, 5:29:40 PM12/30/09
to

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

Lie Ryan

unread,
Dec 30, 2009, 10:06:09 PM12/30/09
to
On 12/30/2009 11:25 PM, Roald de Vries wrote:
> 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.


XP summarizes it as: You ain't gonna need it
(http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it )

Reply all
Reply to author
Forward
0 new messages