bpo-35346, platform: replace os.popen() with subprocess#10786
bpo-35346, platform: replace os.popen() with subprocess#10786vstinner merged 1 commit intopython:masterfrom vstinner:platform_popen
Conversation
serhiy-storchaka
left a comment
There was a problem hiding this comment.
Can subprocess.check_output() be used here?
This function is documented in the "Older high-level API" section of the subprocess documentation. It seems like subprocess.run() is now preferred. subprocess.run() kills the process on exception, IMHO it's a nice enhancement (to not leak a process on error). I modified my PR to use subprocess.run(). |
|
Should not |
|
+1 on using .check_output() instead. It's a special purpose API for exactly this use case and also available in Python 2.7. |
I don't plan to backport this change to other branches.
I chose to keep the code checking manually the returncode. I don't see the point of a raising an exception, since the exception is ignored anyway. |
|
I think the code would be simpler, and therefore more readable, if use |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
Visible effect: suppressed the output to stderr. I think it is worth a news entry. And it can be worth backporting.
done
done
My PR only changes _syscmd_ver() when os.uname() doesn't exist, so only impacts Windows. I don't recall that I ever saw any spurious error when using platform on Windows. I would prefer to minimize changes in stable branches. So if someone considers that it's worth it (I don't think so), I suggest to add " 2> %s" % DEV_NULL to _syscmd_ver() command, rather than using check_output(). |
|
Hum, my PR didn't work as expected on Windows. Currently, _syscmd_ver() tries to run "ver" (as a string) with os.open() which uses a shell. My PR avoids shell=True. _syscmd_ver() still worked thanks to "cmd /c ver"... but that's basically like calling "ver" with shell=True, since subprocess uses cmd.exe as the shell: subprocess may not use cmd.exe if COMSPEC is set, but cmd.exe should always be available on Windows, no? |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
It has been changed by commit 685fffa, https://bugs.python.org/issue16112 The docstring seems to be outdated.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
|
@malemburg, @serhiy-storchaka: Does my PR look better with check_output()? |
There was a problem hiding this comment.
Why an AttributeError is caught here?
There was a problem hiding this comment.
AttributeError is to catch... missing os.popen() function (I guess) :-) AttributeError is as old as the module itself: commit 246d847. Do you think that we should remove it?
There was a problem hiding this comment.
I think it is better to remove it.
There was a problem hiding this comment.
Guys, please remember that these modules are used by other Python implementations as well. The AttributeError most likely came from this: having e.g. IronPython or Jython not having the needed os API available.
There was a problem hiding this comment.
Other Python implementations are supposed the implement the same stdlib. Why would IronPython or Jython not have subprocess.check_output()? For example, if IronPython implements "Python 3.5", they should copy platform.py from CPython 3.5.
If they decide to not implement subprocess.check_output(), well, we can have a talk :-) In the meanwhile, PyPy does patch the stdlib, but they don't propose these patches upstream :-(
There was a problem hiding this comment.
This used to be different... could be that we didn't listen to them.
In any case, see here for when the AttributeErrors were added: https://github.com/python/cpython/blob/2b665dbb53d02be09947116c1fe2ac002375d348/Lib/platform.py#L64
In Python 2 the module was meant to work across many different Python versions and platforms. It would be good to keep this feature in place, since it needs to be updated more frequently than the whole Python version stack (i.e. applications should be able to copy a more recent from from 3.7 to 3.5 and still have it work).
There was a problem hiding this comment.
Well, subprocess and and os.popen() are now available available on all platforms. The situation became better in Python 3 ;-)
There was a problem hiding this comment.
Note: PyPy3 has os.popen() and subprocess, and Jython and IronPython are both stuck at Python 2.7 ;-)
There was a problem hiding this comment.
os.popen() is optional in Python 2, but always available in Python 3. If other implementation have enough different stdlib without os.popen() and subprocess.check_output(), it can have different platform module as well.
I believe it is safe to remove AttributeError in all Python 3 versions.
There was a problem hiding this comment.
Ok. I removed the AttributeError. Anyway, if someone comes with an usecase where catching AttributeError makes sense, I have no problem to reintroduce it ;-) We can even revert this whole commit later if it causes any issue ;-)
|
Thank you, it looks better. But please defer merging it until issues with |
There was a problem hiding this comment.
Why not use just ['ver'] with shell=True?
There was a problem hiding this comment.
Why not use just ['ver'] with shell=True?
I wanted to avoid shell=True whenever possible, but ok, let's use shell=True here.
serhiy-storchaka
left a comment
There was a problem hiding this comment.
LGTM if it LGT @malemburg.
|
Marc Andre Lemburg:
@malemburg: My PR now uses check_output() as you requested. Would you mind to review it and make sure that you agree with the change? Note: It hasn't been mentioned explicitely previously, but my change removes platform.DEV_NULL. This constant is not documented. Since Python 3 has os.devnull and subprocess.DEVNULL, I don't think that it's worth it to keep platform.DEV_NULL for backward compatibility. |
|
@malemburg: I plan to merge this PR at the end of the week. |
Replace os.popen() with subprocess.check_output() in the platform module: * platform.uname() (_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.
|
I squashed the 7 commits into a single commit to update the commit message, I rebased my PR and I also replaced os.open() with subprocess.check_output() in test_platform. |
|
I removed the comments of the buildbot failures because they were false positives due to bad git checkouts. I am investigating why this PR that we made to fix that problem did not work. |
Replace os.popen() with subprocess.Popen in the platform module:
https://bugs.python.org/issue35346