Opened 5 years ago
#4184 defect new
reactor.spawnProcess() handles file-not-found differently on different platforms
|Reported by:||TimAllen||Owned by:|
In #3292, I wrote some RPM-building tests, and added some code to skip them if the rpmbuild command was not found:
def checkForRpmbuild(): def skipTestIfError(result): out, err, code = result if code != 0 or not out.startswith("RPM version"): raise SkipTest("rpmbuild must be present to test tap2rpm") d = utils.getProcessOutputAndValue("rpmbuild", ("--version",)) d.addCallback(skipTestIfError) return d
On my Fedora workstation, this code worked fine - it found the installed rpmbuild binary, and the tests passed. On the various Ubuntu and Debian buildbots, this code worked fine - rpmbuild was not found, the process' return code was non-zero, and the tests were properly skipped. On the various Win32 buildbots, it broke horribly, with this traceback:
Traceback (most recent call last): File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\scripts\test\test_tap2rpm.py", line 94, in setUp return self._checkForRpmbuild() File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\scripts\test\test_tap2rpm.py", line 106, in _checkForRpmbuild d = utils.getProcessOutputAndValue("rpmbuild", ("--version",)) File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\internet\utils.py", line 169, in getProcessOutputAndValue reactor) File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\internet\utils.py", line 25, in _callProtocolWithDeferred reactor.spawnProcess(p, executable, (executable,)+tuple(args), env, path) File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\internet\posixbase.py", line 234, in spawnProcess return Process(self, processProtocol, executable, args, env, path) File "c:\twistedbot2\WXP32-full2.5-scmikes-select\Twisted\twisted\internet\_dumbwin32proc.py", line 181, in __init__ raise OSError(pwte) exceptions.OSError: (2, 'CreateProcess', 'The system cannot find the file specified.')
It seems that on POSIX, calling spawnProcess() with a bogus command results in the callback being called; on Win32 it results in the errback being called, a behaviour likely to catch many people by surprise.
The spawnProcess() docs *do* say "OSError is raised errno EAGAIN or ENOMEM if there are insufficient system resources to create a new process." so anyone who calls spawnProcess() without handling OSError is technically in the wrong, but in that case the documentation still needs to be updated.
Exarkun has pointed out #3815 which doesn't mention a traceback, but does involve process-creation on Win32 being annoyingly non-POSIX. If someone with a Win32 machine determines this ticket is actually the same problem as that ticket, feel free to mark this as a duplicate.