Raise our own SubprocessError rather than a RuntimeError in when dealing with

odd rare errors coming from the subprocess module.
This commit is contained in:
Gregory P. Smith 2012-11-10 23:53:47 -08:00
parent 82fdadeba1
commit 8d07c264e4
4 changed files with 13 additions and 10 deletions

View file

@ -1042,9 +1042,9 @@ class Popen(object):
w9xpopen = os.path.join(os.path.dirname(sys.base_exec_prefix), w9xpopen = os.path.join(os.path.dirname(sys.base_exec_prefix),
"w9xpopen.exe") "w9xpopen.exe")
if not os.path.exists(w9xpopen): if not os.path.exists(w9xpopen):
raise RuntimeError("Cannot locate w9xpopen.exe, which is " raise SubprocessError(
"needed for Popen to work with your " "Cannot locate w9xpopen.exe, which is needed for "
"shell or platform.") "Popen to work with your shell or platform.")
return w9xpopen return w9xpopen
@ -1414,12 +1414,12 @@ class Popen(object):
except ValueError: except ValueError:
warnings.warn(RuntimeWarning( warnings.warn(RuntimeWarning(
'Bad exception data: %r' % errpipe_data)) 'Bad exception data: %r' % errpipe_data))
exception_name = b'RuntimeError' exception_name = b'SubprocessError'
hex_errno = b'0' hex_errno = b'0'
err_msg = b'Unknown' err_msg = b'Unknown'
child_exception_type = getattr( child_exception_type = getattr(
builtins, exception_name.decode('ascii'), builtins, exception_name.decode('ascii'),
RuntimeError) SubprocessError)
for fd in (p2cwrite, c2pread, errread): for fd in (p2cwrite, c2pread, errread):
if fd != -1: if fd != -1:
os.close(fd) os.close(fd)
@ -1452,7 +1452,7 @@ class Popen(object):
self.returncode = _WEXITSTATUS(sts) self.returncode = _WEXITSTATUS(sts)
else: else:
# Should never happen # Should never happen
raise RuntimeError("Unknown child exit status!") raise SubprocessError("Unknown child exit status!")
def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid, def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,

View file

@ -1179,7 +1179,7 @@ class POSIXProcessTestCase(BaseTestCase):
try: try:
p = subprocess.Popen([sys.executable, "-c", ""], p = subprocess.Popen([sys.executable, "-c", ""],
preexec_fn=raise_it) preexec_fn=raise_it)
except RuntimeError as e: except subprocess.SubprocessError as e:
self.assertTrue( self.assertTrue(
subprocess._posixsubprocess, subprocess._posixsubprocess,
"Expected a ValueError from the preexec_fn") "Expected a ValueError from the preexec_fn")
@ -1544,12 +1544,12 @@ class POSIXProcessTestCase(BaseTestCase):
# Pure Python implementations keeps the message # Pure Python implementations keeps the message
self.assertIsNone(subprocess._posixsubprocess) self.assertIsNone(subprocess._posixsubprocess)
self.assertEqual(str(err), "surrogate:\uDCff") self.assertEqual(str(err), "surrogate:\uDCff")
except RuntimeError as err: except subprocess.SubprocessError as err:
# _posixsubprocess uses a default message # _posixsubprocess uses a default message
self.assertIsNotNone(subprocess._posixsubprocess) self.assertIsNotNone(subprocess._posixsubprocess)
self.assertEqual(str(err), "Exception occurred in preexec_fn.") self.assertEqual(str(err), "Exception occurred in preexec_fn.")
else: else:
self.fail("Expected ValueError or RuntimeError") self.fail("Expected ValueError or subprocess.SubprocessError")
def test_undecodable_env(self): def test_undecodable_env(self):
for key, value in (('test', 'abc\uDCFF'), ('test\uDCFF', '42')): for key, value in (('test', 'abc\uDCFF'), ('test\uDCFF', '42')):

View file

@ -116,6 +116,9 @@ Core and Builtins
Library Library
------- -------
- The subprocess module now raises its own SubprocessError instead of a
RuntimeError in various error situations which should not normally happen.
- Issue #16327: The subprocess module no longer leaks file descriptors - Issue #16327: The subprocess module no longer leaks file descriptors
used for stdin/stdout/stderr pipes to the child when fork() fails. used for stdin/stdout/stderr pipes to the child when fork() fails.

View file

@ -497,7 +497,7 @@ error:
/* We can't call strerror(saved_errno). It is not async signal safe. /* We can't call strerror(saved_errno). It is not async signal safe.
* The parent process will look the error message up. */ * The parent process will look the error message up. */
} else { } else {
unused = write(errpipe_write, "RuntimeError:0:", 15); unused = write(errpipe_write, "SubprocessError:0:", 18);
unused = write(errpipe_write, err_msg, strlen(err_msg)); unused = write(errpipe_write, err_msg, strlen(err_msg));
} }
if (unused) return; /* silly? yes! avoids gcc compiler warning. */ if (unused) return; /* silly? yes! avoids gcc compiler warning. */