Skip to content

Instantly share code, notes, and snippets.

@thepaul
Created September 9, 2011 17:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thepaul/1206753 to your computer and use it in GitHub Desktop.
Save thepaul/1206753 to your computer and use it in GitHub Desktop.
the Right Way(tm) to Popen a curses-using subprocess
# works on Mac OS X and Linux. haven't tried BSD. obviously windows is out.
import os
import subprocess
import signal
def get_tty_fg():
# make a new process group within the same session as the parent. we
# do this so that if the user hits ctrl-c, etc in the curses program
# that's about to be exec'd, the SIGINT and friends won't be sent to
# the parent.
os.setpgrp()
# don't stop the process when we get SIGTTOU. since this is now in a
# background process group, SIGTTOU will be sent to this process when
# we call tcsetpgrp(), below. the default action when receiving that
# signal is to stop (process mode T).
hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)
# open a file handle to the current tty
tty = os.open('/dev/tty', os.O_RDWR)
# ask for our new process group to be the foreground one on the
# controlling tty.
os.tcsetpgrp(tty, os.getpgrp())
# replace the old signal handler to minimize the chance of the child
# getting confused by a non-standard starting signal table.
signal.signal(signal.SIGTTOU, hdlr)
def spawn_pager(path):
# should always allow users to configure their own pager. "pager" by
# itself is a better default than less on Debian-based systems, but
# that's not everywhere. Best default to "less" for maximum
# compatibility.
pager = os.environ.get('PAGER', 'less')
# if your calling process also expects to use the tty, you'll need to
# do some extra stuff here to stop using it and handle SIGTTOU, SIGHUP,
# and possibly SIGTTIN, as appropriate, until the child is done.
# run with our tty-foreground code in the child before exec'ing the
# pager. return the pager process object.
return subprocess.Popen([pager, path], preexec_fn=get_tty_fg)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment