##// END OF EJS Templates
Backport PR #2924: safe_run_module: Silence SystemExit codes 0 and None....
Backport PR #2924: safe_run_module: Silence SystemExit codes 0 and None. In `safe_execfile` we ignore SystemExit exceptions with codes 0 and 1. We don't do this for `safe_run_module` which leads to the following mismatch of tracebacks between Python and IPython: ``` $ cat > exit0.py import sys sys.exit(0) $ python -m exit0 $ ipython -m exit0 --------------------------------------------------------------------------- SystemExit Traceback (most recent call last) /usr/lib/python2.7/runpy.pyc in run_module(mod_name, init_globals, run_name, alter_sys) 174 if alter_sys: 175 return _run_module_code(code, init_globals, run_name, --> 176 fname, loader, pkg_name) 177 else: 178 # Leave the sys module alone /usr/lib/python2.7/runpy.pyc in _run_module_code(code, init_globals, mod_name, mod_fname, mod_loader, pkg_name) 80 mod_globals = temp_module.module.__dict__ 81 _run_code(code, mod_globals, init_globals, ---> 82 mod_name, mod_fname, mod_loader, pkg_name) 83 # Copy the globals of the temporary module, as they 84 # may be cleared when the temporary module goes away /usr/lib/python2.7/runpy.pyc in _run_code(code, run_globals, init_globals, mod_name, mod_fname, mod_loader, pkg_name) 70 __loader__ = mod_loader, 71 __package__ = pkg_name) ---> 72 exec code in run_globals 73 return run_globals 74 /tmp/exit0.py in <module>() 1 import sys ----> 2 sys.exit(0) SystemExit: 0 WARNING: Unknown failure executing module: <exit0> ``` The attached pull request silences SystemExit exceptions with codes 0 and None.

File last commit:

r7547:36062053
r9972:8ab632a4
Show More
_process_posix.py
198 lines | 7.6 KiB | text/x-python | PythonLexer
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 """Posix-specific implementation of process utilities.
This file is only meant to be imported by process.py, not by end-users.
"""
#-----------------------------------------------------------------------------
Matthias BUSSONNIER
update copyright to 2011/20xx-2011...
r5390 # Copyright (C) 2010-2011 The IPython Development Team
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 #
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
# Stdlib
import subprocess as sp
import sys
Thomas Kluyver
Decode output from unix subprocesses using platform default encoding.
r4836 from IPython.external import pexpect
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908
# Our own
from .autoattr import auto_attr
Jörgen Stenarson
Moving posix version of arg_split to _process_common.
r5537 from ._process_common import getoutput, arg_split
Thomas Kluyver
Decode output from unix subprocesses using platform default encoding.
r4836 from IPython.utils import text
Thomas Kluyver
Fix almost all IPython.core tests for Python 3.
r4896 from IPython.utils import py3compat
Brandon Parsons
saner default encoding mechanism
r6716 from IPython.utils.encoding import DEFAULT_ENCODING
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908
#-----------------------------------------------------------------------------
# Function definitions
#-----------------------------------------------------------------------------
def _find_cmd(cmd):
"""Find the full path to a command using which."""
Thomas Kluyver
Fix almost all IPython.core tests for Python 3.
r4896 path = sp.Popen(['/usr/bin/env', 'which', cmd],
MinRK
swallow stderr of which in utils.process.find_cmd...
r7547 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
Thomas Kluyver
Fix almost all IPython.core tests for Python 3.
r4896 return py3compat.bytes_to_str(path)
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908
class ProcessHandler(object):
"""Execute subprocesses under the control of pexpect.
"""
# Timeout in seconds to wait on each reading of the subprocess' output.
# This should not be set too low to avoid cpu overusage from our side,
# since we read in a loop whose period is controlled by this timeout.
read_timeout = 0.05
# Timeout to give a process if we receive SIGINT, between sending the
# SIGINT to the process and forcefully terminating it.
terminate_timeout = 0.2
# File object where stdout and stderr of the subprocess will be written
logfile = None
# Shell to call for subprocesses to execute
sh = None
@auto_attr
def sh(self):
sh = pexpect.which('sh')
if sh is None:
raise OSError('"sh" shell not found')
return sh
def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
"""Arguments are used for pexpect calls."""
self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
None else read_timeout)
self.terminate_timeout = (ProcessHandler.terminate_timeout if
terminate_timeout is None else
terminate_timeout)
self.logfile = sys.stdout if logfile is None else logfile
def getoutput(self, cmd):
"""Run a command and return its stdout/stderr as a string.
Parameters
----------
cmd : str
A command to be executed in the system shell.
Returns
-------
output : str
A string containing the combination of stdout and stderr from the
subprocess, in whatever order the subprocess originally wrote to its
file descriptors (so the order of the information in this string is the
correct order as would be seen if running the command in a terminal).
"""
try:
MinRK
fix arguments for commands in _process_posix...
r5296 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 except KeyboardInterrupt:
print('^C', file=sys.stderr, end='')
Fernando Perez
Fix bugs in x=!cmd; we can't use pexpect at all....
r3002 def getoutput_pexpect(self, cmd):
"""Run a command and return its stdout/stderr as a string.
Parameters
----------
cmd : str
A command to be executed in the system shell.
Returns
-------
output : str
A string containing the combination of stdout and stderr from the
subprocess, in whatever order the subprocess originally wrote to its
file descriptors (so the order of the information in this string is the
correct order as would be seen if running the command in a terminal).
"""
try:
MinRK
fix arguments for commands in _process_posix...
r5296 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
Fernando Perez
Fix bugs in x=!cmd; we can't use pexpect at all....
r3002 except KeyboardInterrupt:
print('^C', file=sys.stderr, end='')
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 def system(self, cmd):
"""Execute a command in a subshell.
Parameters
----------
cmd : str
A command to be executed in the system shell.
Returns
-------
MinRK
store exit code in user_ns['_exit_code']...
r3910 int : child's exitstatus
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 """
Thomas Kluyver
Decode output from unix subprocesses using platform default encoding.
r4836 # Get likely encoding for the output.
Brandon Parsons
saner default encoding mechanism
r6716 enc = DEFAULT_ENCODING
Thomas Kluyver
Decode output from unix subprocesses using platform default encoding.
r4836
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 # Patterns to match on the output, for pexpect. We read input and
# allow either a short timeout or EOF
patterns = [pexpect.TIMEOUT, pexpect.EOF]
# the index of the EOF pattern in the list.
MinRK
fix arguments for commands in _process_posix...
r5296 # even though we know it's 1, this call means we don't have to worry if
# we change the above list, and forget to change this value:
EOF_index = patterns.index(pexpect.EOF)
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 # The size of the output stored so far in the process output buffer.
# Since pexpect only appends to this buffer, each time we print we
# record how far we've printed, so that next time we only print *new*
# content from the buffer.
out_size = 0
try:
# Since we're not really searching the buffer for text patterns, we
# can set pexpect's search window to be tiny and it won't matter.
# We only search for the 'patterns' timeout or EOF, which aren't in
# the text itself.
Thomas Kluyver
Allow pexpect piped processes to work with either pexpect-u or vanilla pexpect.
r5433 #child = pexpect.spawn(pcmd, searchwindowsize=1)
Thomas Kluyver
Handle subprocesses more consistently between pexpect and pexpect-u.
r5434 if hasattr(pexpect, 'spawnb'):
child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
else:
child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 flush = sys.stdout.flush
while True:
# res is the index of the pattern that caused the match, so we
# know whether we've finished (if we matched EOF) or not
res_idx = child.expect_list(patterns, self.read_timeout)
Thomas Kluyver
Handle subprocesses more consistently between pexpect and pexpect-u.
r5434 print(child.before[out_size:].decode(enc, 'replace'), end='')
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 flush()
if res_idx==EOF_index:
break
Fernando Perez
Minor robustness/speed improvements to process handling
r3075 # Update the pointer to what we've already printed
out_size = len(child.before)
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 except KeyboardInterrupt:
# We need to send ^C to the process. The ascii code for '^C' is 3
# (the character is known as ETX for 'End of Text', see
# curses.ascii.ETX).
child.sendline(chr(3))
# Read and print any more output the program might produce on its
# way out.
try:
out_size = len(child.before)
child.expect_list(patterns, self.terminate_timeout)
Thomas Kluyver
Handle subprocesses more consistently between pexpect and pexpect-u.
r5434 print(child.before[out_size:].decode(enc, 'replace'), end='')
Fernando Perez
Minor robustness/speed improvements to process handling
r3075 sys.stdout.flush()
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908 except KeyboardInterrupt:
# Impatient users tend to type it multiple times
pass
finally:
# Ensure the subprocess really is terminated
child.terminate(force=True)
MinRK
fix arguments for commands in _process_posix...
r5296 # add isalive check, to ensure exitstatus is set:
child.isalive()
MinRK
store exit code in user_ns['_exit_code']...
r3910 return child.exitstatus
Fernando Perez
Fully refactored subprocess handling on all platforms....
r2908
Fernando Perez
Fix bugs in x=!cmd; we can't use pexpect at all....
r3002 # Make system() with a functional interface for outside use. Note that we use
# getoutput() from the _common utils, which is built on top of popen(). Using
# pexpect to get subprocess output produces difficult to parse output, since
# programs think they are talking to a tty and produce highly formatted output
# (ls is a good example) that makes them hard.
system = ProcessHandler().system
Jörgen Stenarson
Moved arg_split to _process_win32.py and _process_posix.py.
r5517