Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 19 additions & 39 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,6 @@

### 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.
# Based on the description of the PHP's version_compare():
# http://php.net/manual/en/function.version-compare.php
Expand Down Expand Up @@ -288,16 +275,15 @@ def _syscmd_ver(system='', release='', version='',
return system, release, version

# Try some common cmd strings
import subprocess
for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
try:
pipe = os.popen(cmd)
info = pipe.read()
if pipe.close():
raise OSError('command failed')
# XXX How can I suppress shell errors from being written
# to stderr ?
except OSError as why:
#print 'Command %s failed: %s' % (cmd, why)
info = subprocess.check_output(cmd,
stderr=subprocess.DEVNULL,
text=True,
shell=True)
except (OSError, subprocess.CalledProcessError) as why:
#print('Command %s failed: %s' % (cmd, why))
continue
else:
break
Expand Down Expand Up @@ -602,16 +588,15 @@ def _syscmd_uname(option, default=''):
if sys.platform in ('dos', 'win32', 'win16'):
# XXX Others too ?
return default

import subprocess
try:
f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
except (AttributeError, OSError):
return default
output = f.read().strip()
rc = f.close()
if not output or rc:
output = subprocess.check_output(('uname', option),
stderr=subprocess.DEVNULL,
text=True)
except (OSError, subprocess.CalledProcessError):
return default
else:
return output
return (output.strip() or default)

def _syscmd_file(target, default=''):

Expand All @@ -629,17 +614,12 @@ def _syscmd_file(target, default=''):
import subprocess
target = _follow_symlinks(target)
try:
proc = subprocess.Popen(['file', target],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
except (AttributeError, OSError):
output = subprocess.check_output(['file', target],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code contradicts the docstring. This can lead to returning an incorrect result if the executable path contains some key strings like "'32-bit'" or "PE". This is a separate issue, but it could be better to fix it before merging this PR. Merging this PR will make backporting harder.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has been changed by commit 685fffa, https://bugs.python.org/issue16112 The docstring seems to be outdated.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can lead to returning an incorrect result if the executable path contains some key strings like "'32-bit'" or "PE".

I would prefer to keep this PR simple, and so don't try to fix this bug nor update the docstring.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stderr=subprocess.DEVNULL,
encoding='latin-1')
except (OSError, subprocess.CalledProcessError):
return default
output = proc.communicate()[0].decode('latin-1')
rc = proc.wait()
if not output or rc:
return default
else:
return output
return (output or default)

### Information about the used architecture

Expand Down
18 changes: 9 additions & 9 deletions Lib/test/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,16 @@ def test_mac_ver(self):
res = platform.mac_ver()

if platform.uname().system == 'Darwin':
# We're on a MacOSX system, check that
# the right version information is returned
fd = os.popen('sw_vers', 'r')
real_ver = None
for ln in fd:
if ln.startswith('ProductVersion:'):
real_ver = ln.strip().split()[-1]
# We are on a macOS system, check that the right version
# information is returned
output = subprocess.check_output(['sw_vers'], text=True)
for line in output.splitlines():
if line.startswith('ProductVersion:'):
real_ver = line.strip().split()[-1]
break
fd.close()
self.assertFalse(real_ver is None)
else:
self.fail(f"failed to parse sw_vers output: {output!r}")

result_list = res[0].split('.')
expect_list = real_ver.split('.')
len_diff = len(result_list) - len(expect_list)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:func:`platform.uname` now redirects ``stderr`` to :data:`os.devnull` when
running external programs like ``cmd /c ver``.