##// END OF EJS Templates
Merge pull request #4260 from takluyver/system-raw-subprocess...
Min RK -
r12824:6590fa5c merge
parent child Browse files
Show More
@@ -29,6 +29,7 b' import runpy'
29 import sys
29 import sys
30 import tempfile
30 import tempfile
31 import types
31 import types
32 import subprocess
32 from io import open as io_open
33 from io import open as io_open
33
34
34 from IPython.config.configurable import SingletonConfigurable
35 from IPython.config.configurable import SingletonConfigurable
@@ -2232,7 +2233,8 b' class InteractiveShell(SingletonConfigurable):'
2232 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2233 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2233
2234
2234 def system_raw(self, cmd):
2235 def system_raw(self, cmd):
2235 """Call the given cmd in a subprocess using os.system
2236 """Call the given cmd in a subprocess using os.system on Windows or
2237 subprocess.call using the system shell on other platforms.
2236
2238
2237 Parameters
2239 Parameters
2238 ----------
2240 ----------
@@ -2250,11 +2252,10 b' class InteractiveShell(SingletonConfigurable):'
2250 ec = os.system(cmd)
2252 ec = os.system(cmd)
2251 else:
2253 else:
2252 cmd = py3compat.unicode_to_str(cmd)
2254 cmd = py3compat.unicode_to_str(cmd)
2253 ec = os.system(cmd)
2255 # Call the cmd using the OS shell, instead of the default /bin/sh, if set.
2254 # The high byte is the exit code, the low byte is a signal number
2256 ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None))
2255 # that we discard for now. See the docs for os.wait()
2257 # exit code is positive for program failure, or negative for
2256 if ec > 255:
2258 # terminating signal number.
2257 ec >>= 8
2258
2259
2259 # We explicitly do NOT return the subprocess status code, because
2260 # We explicitly do NOT return the subprocess status code, because
2260 # a non-None value would trigger :func:`sys.displayhook` calls.
2261 # a non-None value would trigger :func:`sys.displayhook` calls.
@@ -22,6 +22,7 b' Authors'
22 # stdlib
22 # stdlib
23 import ast
23 import ast
24 import os
24 import os
25 import signal
25 import shutil
26 import shutil
26 import sys
27 import sys
27 import tempfile
28 import tempfile
@@ -33,7 +34,7 b' from StringIO import StringIO'
33 import nose.tools as nt
34 import nose.tools as nt
34
35
35 # Our own
36 # Our own
36 from IPython.testing.decorators import skipif, onlyif_unicode_paths
37 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
37 from IPython.testing import tools as tt
38 from IPython.testing import tools as tt
38 from IPython.utils import io
39 from IPython.utils import io
39
40
@@ -414,19 +415,48 b' class TestSafeExecfileNonAsciiPath(unittest.TestCase):'
414 """
415 """
415 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
416 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
416
417
418 class ExitCodeChecks(tt.TempFileMixin):
419 def test_exit_code_ok(self):
420 self.system('exit 0')
421 self.assertEqual(ip.user_ns['_exit_code'], 0)
422
423 def test_exit_code_error(self):
424 self.system('exit 1')
425 self.assertEqual(ip.user_ns['_exit_code'], 1)
426
427 @skipif(not hasattr(signal, 'SIGALRM'))
428 def test_exit_code_signal(self):
429 self.mktmp("import signal, time\n"
430 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
431 "time.sleep(1)\n")
432 self.system("%s %s" % (sys.executable, self.fname))
433 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
434
435 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
436 system = ip.system_raw
417
437
418 class TestSystemRaw(unittest.TestCase):
419 @onlyif_unicode_paths
438 @onlyif_unicode_paths
420 def test_1(self):
439 def test_1(self):
421 """Test system_raw with non-ascii cmd
440 """Test system_raw with non-ascii cmd
422 """
441 """
423 cmd = ur'''python -c "'åäö'" '''
442 cmd = u'''python -c "'åäö'" '''
424 ip.system_raw(cmd)
443 ip.system_raw(cmd)
425
444
426 def test_exit_code(self):
445 # TODO: Exit codes are currently ignored on Windows.
427 """Test that the exit code is parsed correctly."""
446 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
428 ip.system_raw('exit 1')
447 system = ip.system_piped
429 self.assertEqual(ip.user_ns['_exit_code'], 1)
448
449 @skip_win32
450 def test_exit_code_ok(self):
451 ExitCodeChecks.test_exit_code_ok(self)
452
453 @skip_win32
454 def test_exit_code_error(self):
455 ExitCodeChecks.test_exit_code_error(self)
456
457 @skip_win32
458 def test_exit_code_signal(self):
459 ExitCodeChecks.test_exit_code_signal(self)
430
460
431 class TestModules(unittest.TestCase, tt.TempFileMixin):
461 class TestModules(unittest.TestCase, tt.TempFileMixin):
432 def test_extraneous_loads(self):
462 def test_extraneous_loads(self):
@@ -184,6 +184,12 b' class ProcessHandler(object):'
184 child.terminate(force=True)
184 child.terminate(force=True)
185 # add isalive check, to ensure exitstatus is set:
185 # add isalive check, to ensure exitstatus is set:
186 child.isalive()
186 child.isalive()
187
188 # We follow the subprocess pattern, returning either the exit status
189 # as a positive number, or the terminating signal as a negative
190 # number. sh returns 128+n for signals
191 if child.exitstatus > 128:
192 return -(child.exitstatus - 128)
187 return child.exitstatus
193 return child.exitstatus
188
194
189
195
General Comments 0
You need to be logged in to leave comments. Login now