33

I need to determine whether the shell which invoked my Python script was in interactive mode or not. If it was in interactive mode, the program should pipe output to less(1) for easy reading. If not, it should simply print its output to stdout, to allow it to be piped away to a printer, file, or a different pager.

In a shell script, I would have checked if the prompt variable $PS1 was defined, or looked for the -i option among the flags stored in the $- variable.

What is the preferred method for testing interactivity from within Python?

jforberg
  • 6,537
  • 3
  • 29
  • 47

5 Answers5

43

This is often works well enough

import os, sys
if os.isatty(sys.stdout.fileno()):
    ...
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 24
    `sys.stdout.isatty()` is shorter. –  May 24 '11 at 09:52
  • 15
    And `sys.__stdin__.isatty()` more reliable. (not affected by `stdin` redirect and allows piping out) – Evpok May 24 '11 at 10:00
  • 1
    @Evpok: The OP asked for *stdout*, stdin is totally unrelated. In order to find out whether to page *output* or not, stdin is really the wrong stream to check, because the user can pipe something into the program (thus redirection stdin and disconnecting it from the tty) and still want to see the output in a pager (because stdout is not redirected). –  May 24 '11 at 10:20
  • 1
    @Evpok, do you mean `sys.__stdout__.isatty()`. It's possible for the output to be a tty when the input isn't, and the OP seems to be interested in the output – John La Rooy May 24 '11 at 10:31
  • 4
    @lunaryom Yes, I know. But he did write "If it was in interactive mode, the program should pipe output to less(1) for easy reading" for me it implies that he checks `stdin` and redirects `stdout` according to the nature of it. – Evpok May 24 '11 at 11:02
  • @Evpok, @lunaryom I'm making a man(1)-ish program. I want it to behave roughly as man does, i.e. pipe output to less(1) if interactive, but simply print it out if not. So I probably want to check whether stdout is a tty. – jforberg May 24 '11 at 19:24
2

From this link you can use the same way and test if stdin is associated to a terminate(tty), you can do this using os.isatty(), example:

>>> os.isatty(0)
True

N.B: From the same link this will fails when you invoke the command remotely via ssh, the solution given is to test if stdin is associated to a pipe.

mouad
  • 67,571
  • 18
  • 114
  • 106
  • 3
    I prefer the more obvious `sys.__stdin__.isatty()` – Evpok May 24 '11 at 09:48
  • @Evpok: Yes agree, i forgot about the file object method isatty(), thanks :) – mouad May 24 '11 at 09:52
  • This seems to be equivalent to gnibbler's answer, except that the reader must know enough unix to know that file 0 is stdin. Is there a difference between checking isatty() on stdin or stdout, do you think? – jforberg May 24 '11 at 09:53
  • @jforberg: yes agree, and i think the best one is @Evpok comment, `sys.__stdin__.isatty()`,and AFAIK interactive mode mean stdin is associate to terminal not stdout, correct me if i'm wrong :) – mouad May 24 '11 at 09:54
  • Yes, Evpok's solution is the most elegant and readable in my eyes. Thanks! – jforberg May 24 '11 at 10:09
-4

If you already have a dependency on matplotlib, or you don't mind introducing one, you can always just call matplotlib.is_interactive()

  • 1
    Look at line 1049 of https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/__init__.py . is_interactive() just reads a global variable in matplotlib. I see no guarantees that it would refer to the interactivity of the parent shell. – jforberg Dec 16 '12 at 12:24
-5
if sys.flags.interactive:
    #interactive
else:
    #not interactive 

http://docs.python.org/library/sys.html#sys.flags

Simon Warta
  • 10,850
  • 5
  • 40
  • 78
Pych
  • 241
  • 2
  • 3
  • 4
    This only results in true if Python was started with the -i option. Starting it with the -i option will drop Python into interpreter mode after the script is run. sys.flags.interactive can not be used to determine the nature of the current shell environment. – chiborg Oct 12 '11 at 13:46
-9

I make a cover class for testing.

For example you have :

class SuperInteractiveClass(object):
   def get_data_from_stdin(self):
      '... a lot of code here ...'
   '... and a lot of other function'

I make a second class, just for testing

class TestSuperInteractiveClass(SuperInteractiveClass):
    prepared_data = []
    def add_prepared_data(self,data):
        self.prepared_data.append(data)
    def get_data_from_stdin(self):
          return self.prepared_data.pop(0)
Oduvan
  • 2,607
  • 3
  • 24
  • 24