diff --git a/Lib/subprocess.py b/Lib/subprocess.py index c0bda96cbc0339..f5ccf42c4768f5 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1300,6 +1300,13 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, self.pid = pid _winapi.CloseHandle(ht) + + def _set_returncode(self, exitcode): + self.returncode = exitcode + self._handle.Close() + self._handle = None + + def _internal_poll(self, _deadstate=None, _WaitForSingleObject=_winapi.WaitForSingleObject, _WAIT_OBJECT_0=_winapi.WAIT_OBJECT_0, @@ -1313,7 +1320,8 @@ def _internal_poll(self, _deadstate=None, """ if self.returncode is None: if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0: - self.returncode = _GetExitCodeProcess(self._handle) + exitcode = _GetExitCodeProcess(self._handle) + self._set_returncode(exitcode) return self.returncode @@ -1329,7 +1337,8 @@ def _wait(self, timeout): timeout_millis) if result == _winapi.WAIT_TIMEOUT: raise TimeoutExpired(self.args, timeout) - self.returncode = _winapi.GetExitCodeProcess(self._handle) + exitcode = _winapi.GetExitCodeProcess(self._handle) + self._set_returncode(exitcode) return self.returncode @@ -1417,7 +1426,7 @@ def terminate(self): rc = _winapi.GetExitCodeProcess(self._handle) if rc == _winapi.STILL_ACTIVE: raise - self.returncode = rc + self._set_returncode(rc) kill = terminate @@ -1638,7 +1647,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, try: pid, sts = os.waitpid(self.pid, 0) if pid == self.pid: - self._handle_exitstatus(sts) + self._set_returncode(sts) else: self.returncode = sys.maxsize except ChildProcessError: @@ -1674,7 +1683,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, raise child_exception_type(err_msg) - def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED, + def _set_returncode(self, sts, _WIFSIGNALED=os.WIFSIGNALED, _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED, _WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED, _WSTOPSIG=os.WSTOPSIG): @@ -1711,7 +1720,7 @@ def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid, return self.returncode # Another thread waited. pid, sts = _waitpid(self.pid, _WNOHANG) if pid == self.pid: - self._handle_exitstatus(sts) + self._set_returncode(sts) except OSError as e: if _deadstate is not None: self.returncode = _deadstate @@ -1758,7 +1767,7 @@ def _wait(self, timeout): (pid, sts) = self._try_wait(os.WNOHANG) assert pid == self.pid or pid == 0 if pid == self.pid: - self._handle_exitstatus(sts) + self._set_returncode(sts) break finally: self._waitpid_lock.release() @@ -1777,7 +1786,7 @@ def _wait(self, timeout): # return 0 even without WNOHANG in odd situations. # http://bugs.python.org/issue14396. if pid == self.pid: - self._handle_exitstatus(sts) + self._set_returncode(sts) return self.returncode diff --git a/Misc/NEWS.d/next/Library/2019-06-26-13-54-40.bpo-37410.H2R9oS.rst b/Misc/NEWS.d/next/Library/2019-06-26-13-54-40.bpo-37410.H2R9oS.rst new file mode 100644 index 00000000000000..ff8282ede163d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-06-26-13-54-40.bpo-37410.H2R9oS.rst @@ -0,0 +1,3 @@ +On Windows, :class:`subprocess.Popen` now closes the process handle when the +process completes. Previously, it was only closed when the Popen object was +destroyed.