Skip to content

Commit 880d42a

Browse files
authored
bpo-8110: Refactor platform detection in subprocess (GH-9053)
Check for functionality via imports rather than checking sys.platform specifically for Windows
1 parent 28ea4c2 commit 880d42a

File tree

2 files changed

+58
-55
lines changed

2 files changed

+58
-55
lines changed

Lib/subprocess.py

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,56 @@
4141
then returns a (exitcode, output) tuple
4242
"""
4343

44-
import sys
45-
_mswindows = (sys.platform == "win32")
46-
44+
import builtins
45+
import errno
4746
import io
4847
import os
4948
import time
5049
import signal
51-
import builtins
50+
import sys
51+
import threading
5252
import warnings
53-
import errno
5453
from time import monotonic as _time
5554

55+
56+
__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput",
57+
"getoutput", "check_output", "run", "CalledProcessError", "DEVNULL",
58+
"SubprocessError", "TimeoutExpired", "CompletedProcess"]
59+
# NOTE: We intentionally exclude list2cmdline as it is
60+
# considered an internal implementation detail. issue10838.
61+
62+
try:
63+
import msvcrt
64+
import _winapi
65+
_mswindows = True
66+
except ModuleNotFoundError:
67+
_mswindows = False
68+
import _posixsubprocess
69+
import select
70+
import selectors
71+
else:
72+
from _winapi import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP,
73+
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
74+
STD_ERROR_HANDLE, SW_HIDE,
75+
STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW,
76+
ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS,
77+
HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS,
78+
NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,
79+
CREATE_NO_WINDOW, DETACHED_PROCESS,
80+
CREATE_DEFAULT_ERROR_MODE, CREATE_BREAKAWAY_FROM_JOB)
81+
82+
__all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP",
83+
"STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE",
84+
"STD_ERROR_HANDLE", "SW_HIDE",
85+
"STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW",
86+
"STARTUPINFO",
87+
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
88+
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
89+
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
90+
"CREATE_NO_WINDOW", "DETACHED_PROCESS",
91+
"CREATE_DEFAULT_ERROR_MODE", "CREATE_BREAKAWAY_FROM_JOB"])
92+
93+
5694
# Exception classes used by this module.
5795
class SubprocessError(Exception): pass
5896

@@ -123,9 +161,6 @@ def stdout(self, value):
123161

124162

125163
if _mswindows:
126-
import threading
127-
import msvcrt
128-
import _winapi
129164
class STARTUPINFO:
130165
def __init__(self, *, dwFlags=0, hStdInput=None, hStdOutput=None,
131166
hStdError=None, wShowWindow=0, lpAttributeList=None):
@@ -148,53 +183,6 @@ def copy(self):
148183
wShowWindow=self.wShowWindow,
149184
lpAttributeList=attr_list)
150185

151-
else:
152-
import _posixsubprocess
153-
import select
154-
import selectors
155-
import threading
156-
157-
# When select or poll has indicated that the file is writable,
158-
# we can write up to _PIPE_BUF bytes without risk of blocking.
159-
# POSIX defines PIPE_BUF as >= 512.
160-
_PIPE_BUF = getattr(select, 'PIPE_BUF', 512)
161-
162-
# poll/select have the advantage of not requiring any extra file
163-
# descriptor, contrarily to epoll/kqueue (also, they require a single
164-
# syscall).
165-
if hasattr(selectors, 'PollSelector'):
166-
_PopenSelector = selectors.PollSelector
167-
else:
168-
_PopenSelector = selectors.SelectSelector
169-
170-
171-
__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput",
172-
"getoutput", "check_output", "run", "CalledProcessError", "DEVNULL",
173-
"SubprocessError", "TimeoutExpired", "CompletedProcess"]
174-
# NOTE: We intentionally exclude list2cmdline as it is
175-
# considered an internal implementation detail. issue10838.
176-
177-
if _mswindows:
178-
from _winapi import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP,
179-
STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
180-
STD_ERROR_HANDLE, SW_HIDE,
181-
STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW,
182-
ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS,
183-
HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS,
184-
NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,
185-
CREATE_NO_WINDOW, DETACHED_PROCESS,
186-
CREATE_DEFAULT_ERROR_MODE, CREATE_BREAKAWAY_FROM_JOB)
187-
188-
__all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP",
189-
"STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE",
190-
"STD_ERROR_HANDLE", "SW_HIDE",
191-
"STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW",
192-
"STARTUPINFO",
193-
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
194-
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
195-
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
196-
"CREATE_NO_WINDOW", "DETACHED_PROCESS",
197-
"CREATE_DEFAULT_ERROR_MODE", "CREATE_BREAKAWAY_FROM_JOB"])
198186

199187
class Handle(int):
200188
closed = False
@@ -215,6 +203,19 @@ def __repr__(self):
215203

216204
__del__ = Close
217205
__str__ = __repr__
206+
else:
207+
# When select or poll has indicated that the file is writable,
208+
# we can write up to _PIPE_BUF bytes without risk of blocking.
209+
# POSIX defines PIPE_BUF as >= 512.
210+
_PIPE_BUF = getattr(select, 'PIPE_BUF', 512)
211+
212+
# poll/select have the advantage of not requiring any extra file
213+
# descriptor, contrarily to epoll/kqueue (also, they require a single
214+
# syscall).
215+
if hasattr(selectors, 'PollSelector'):
216+
_PopenSelector = selectors.PollSelector
217+
else:
218+
_PopenSelector = selectors.SelectSelector
218219

219220

220221
# This lists holds Popen instances for which the underlying process had not
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Refactored :mod:`subprocess` to check for Windows-specific modules rather
2+
than ``sys.platform == 'win32'``.

0 commit comments

Comments
 (0)