bpo-35346, platform: replace os.popen() with subprocess (GH-10786)
Replace os.popen() with subprocess.check_output() in the platform module: * platform.uname() (its _syscmd_ver() helper function) now redirects stderr to DEVNULL. * Remove platform.DEV_NULL. * _syscmd_uname() and _syscmd_file() no longer catch AttributeError. The "except AttributeError:" was only needed in Python 2, when os.popen() was not always available. In Python 3, subprocess.check_output() is always available.
This commit is contained in:
parent
9ebe8794f0
commit
3a521f0b61
|
@ -119,19 +119,6 @@ import sys
|
||||||
|
|
||||||
### Globals & Constants
|
### Globals & Constants
|
||||||
|
|
||||||
# Determine the platform's /dev/null device
|
|
||||||
try:
|
|
||||||
DEV_NULL = os.devnull
|
|
||||||
except AttributeError:
|
|
||||||
# os.devnull was added in Python 2.4, so emulate it for earlier
|
|
||||||
# Python versions
|
|
||||||
if sys.platform in ('dos', 'win32', 'win16'):
|
|
||||||
# Use the old CP/M NUL as device name
|
|
||||||
DEV_NULL = 'NUL'
|
|
||||||
else:
|
|
||||||
# Standard Unix uses /dev/null
|
|
||||||
DEV_NULL = '/dev/null'
|
|
||||||
|
|
||||||
# Helper for comparing two version number strings.
|
# Helper for comparing two version number strings.
|
||||||
# Based on the description of the PHP's version_compare():
|
# Based on the description of the PHP's version_compare():
|
||||||
# http://php.net/manual/en/function.version-compare.php
|
# http://php.net/manual/en/function.version-compare.php
|
||||||
|
@ -288,16 +275,15 @@ def _syscmd_ver(system='', release='', version='',
|
||||||
return system, release, version
|
return system, release, version
|
||||||
|
|
||||||
# Try some common cmd strings
|
# Try some common cmd strings
|
||||||
|
import subprocess
|
||||||
for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
|
for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
|
||||||
try:
|
try:
|
||||||
pipe = os.popen(cmd)
|
info = subprocess.check_output(cmd,
|
||||||
info = pipe.read()
|
stderr=subprocess.DEVNULL,
|
||||||
if pipe.close():
|
text=True,
|
||||||
raise OSError('command failed')
|
shell=True)
|
||||||
# XXX How can I suppress shell errors from being written
|
except (OSError, subprocess.CalledProcessError) as why:
|
||||||
# to stderr ?
|
#print('Command %s failed: %s' % (cmd, why))
|
||||||
except OSError as why:
|
|
||||||
#print 'Command %s failed: %s' % (cmd, why)
|
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
@ -602,16 +588,15 @@ def _syscmd_uname(option, default=''):
|
||||||
if sys.platform in ('dos', 'win32', 'win16'):
|
if sys.platform in ('dos', 'win32', 'win16'):
|
||||||
# XXX Others too ?
|
# XXX Others too ?
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
import subprocess
|
||||||
try:
|
try:
|
||||||
f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
|
output = subprocess.check_output(('uname', option),
|
||||||
except (AttributeError, OSError):
|
stderr=subprocess.DEVNULL,
|
||||||
|
text=True)
|
||||||
|
except (OSError, subprocess.CalledProcessError):
|
||||||
return default
|
return default
|
||||||
output = f.read().strip()
|
return (output.strip() or default)
|
||||||
rc = f.close()
|
|
||||||
if not output or rc:
|
|
||||||
return default
|
|
||||||
else:
|
|
||||||
return output
|
|
||||||
|
|
||||||
def _syscmd_file(target, default=''):
|
def _syscmd_file(target, default=''):
|
||||||
|
|
||||||
|
@ -629,17 +614,12 @@ def _syscmd_file(target, default=''):
|
||||||
import subprocess
|
import subprocess
|
||||||
target = _follow_symlinks(target)
|
target = _follow_symlinks(target)
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(['file', target],
|
output = subprocess.check_output(['file', target],
|
||||||
stdout=subprocess.PIPE,
|
stderr=subprocess.DEVNULL,
|
||||||
stderr=subprocess.STDOUT)
|
encoding='latin-1')
|
||||||
except (AttributeError, OSError):
|
except (OSError, subprocess.CalledProcessError):
|
||||||
return default
|
return default
|
||||||
output = proc.communicate()[0].decode('latin-1')
|
return (output or default)
|
||||||
rc = proc.wait()
|
|
||||||
if not output or rc:
|
|
||||||
return default
|
|
||||||
else:
|
|
||||||
return output
|
|
||||||
|
|
||||||
### Information about the used architecture
|
### Information about the used architecture
|
||||||
|
|
||||||
|
|
|
@ -222,16 +222,16 @@ class PlatformTest(unittest.TestCase):
|
||||||
res = platform.mac_ver()
|
res = platform.mac_ver()
|
||||||
|
|
||||||
if platform.uname().system == 'Darwin':
|
if platform.uname().system == 'Darwin':
|
||||||
# We're on a MacOSX system, check that
|
# We are on a macOS system, check that the right version
|
||||||
# the right version information is returned
|
# information is returned
|
||||||
fd = os.popen('sw_vers', 'r')
|
output = subprocess.check_output(['sw_vers'], text=True)
|
||||||
real_ver = None
|
for line in output.splitlines():
|
||||||
for ln in fd:
|
if line.startswith('ProductVersion:'):
|
||||||
if ln.startswith('ProductVersion:'):
|
real_ver = line.strip().split()[-1]
|
||||||
real_ver = ln.strip().split()[-1]
|
|
||||||
break
|
break
|
||||||
fd.close()
|
else:
|
||||||
self.assertFalse(real_ver is None)
|
self.fail(f"failed to parse sw_vers output: {output!r}")
|
||||||
|
|
||||||
result_list = res[0].split('.')
|
result_list = res[0].split('.')
|
||||||
expect_list = real_ver.split('.')
|
expect_list = real_ver.split('.')
|
||||||
len_diff = len(result_list) - len(expect_list)
|
len_diff = len(result_list) - len(expect_list)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
:func:`platform.uname` now redirects ``stderr`` to :data:`os.devnull` when
|
||||||
|
running external programs like ``cmd /c ver``.
|
Loading…
Reference in New Issue