Show More
@@ -2355,19 +2355,31 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2355 | 2355 | ec = os.system(cmd) |
|
2356 | 2356 | else: |
|
2357 | 2357 | cmd = py3compat.unicode_to_str(cmd) |
|
2358 | # Call the cmd using the OS shell, instead of the default /bin/sh, if set. | |
|
2359 | ec = subprocess.call(cmd, shell=True, executable=os.environ.get('SHELL', None)) | |
|
2360 | # exit code is positive for program failure, or negative for | |
|
2361 | # terminating signal number. | |
|
2362 | ||
|
2363 | # Interpret ec > 128 as signal | |
|
2364 | # Some shells (csh, fish) don't follow sh/bash conventions for exit codes | |
|
2358 | # For posix the result of the subprocess.call() below is an exit | |
|
2359 | # code, which by convention is zero for success, positive for | |
|
2360 | # program failure. Exit codes above 128 are reserved for signals, | |
|
2361 | # and the formula for converting a signal to an exit code is usually | |
|
2362 | # signal_number+128. To more easily differentiate between exit | |
|
2363 | # codes and signals, ipython uses negative numbers. For instance | |
|
2364 | # since control-c is signal 2 but exit code 130, ipython's | |
|
2365 | # _exit_code variable will read -2. Note that some shells like | |
|
2366 | # csh and fish don't follow sh/bash conventions for exit codes. | |
|
2367 | executable = os.environ.get('SHELL', None) | |
|
2368 | try: | |
|
2369 | # Use env shell instead of default /bin/sh | |
|
2370 | ec = subprocess.call(cmd, shell=True, executable=executable) | |
|
2371 | except KeyboardInterrupt: | |
|
2372 | # intercept control-C; a long traceback is not useful here | |
|
2373 | self.write_err("\nKeyboardInterrupt\n") | |
|
2374 | ec = 130 | |
|
2365 | 2375 | if ec > 128: |
|
2366 | 2376 | ec = -(ec - 128) |
|
2367 | 2377 | |
|
2368 | 2378 | # We explicitly do NOT return the subprocess status code, because |
|
2369 | 2379 | # a non-None value would trigger :func:`sys.displayhook` calls. |
|
2370 | # Instead, we store the exit_code in user_ns. | |
|
2380 | # Instead, we store the exit_code in user_ns. Note the semantics | |
|
2381 | # of _exit_code: for control-c, _exit_code == -signal.SIGNIT, | |
|
2382 | # but raising SystemExit(_exit_code) will give status 254! | |
|
2371 | 2383 | self.user_ns['_exit_code'] = ec |
|
2372 | 2384 | |
|
2373 | 2385 | # use piped system by default, because it is better behaved |
@@ -544,6 +544,16 b' class TestSystemRaw(unittest.TestCase, ExitCodeChecks):' | |||
|
544 | 544 | cmd = u'''python -c "'åäö'" ''' |
|
545 | 545 | ip.system_raw(cmd) |
|
546 | 546 | |
|
547 | @mock.patch('subprocess.call') | |
|
548 | def test_control_c(self, call_mock): | |
|
549 | call_mock.side_effect = KeyboardInterrupt() | |
|
550 | try: | |
|
551 | self.system("sleep 1 # wont happen") | |
|
552 | except KeyboardInterrupt: | |
|
553 | self.fail("system call should intercept " | |
|
554 | "keyboard interrupt from subprocess.call") | |
|
555 | self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT) | |
|
556 | ||
|
547 | 557 | # TODO: Exit codes are currently ignored on Windows. |
|
548 | 558 | class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks): |
|
549 | 559 | system = ip.system_piped |
General Comments 0
You need to be logged in to leave comments.
Login now