Inconsistent `Popen.communicate()` behavior if stdin/stdout/stderr is closed `PIPE`
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 35.9k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Bug report
Bug description:
The behavior with Popen.communicate() if stdin/stdout/stderr are PIPEs and they are closed before calling communicate() is rather strange.
If both stdout and stderr are PIPEs and one (or both) is closed, communicate() succeeds. If only one of them is a PIPE and it is closed, the behavior changes and there's a ValueError instead:
>>> from subprocess import Popen, PIPE
>>>
>>> p = Popen(['python', '-V'], stdout=PIPE, stderr=PIPE)
>>> p.stdout.close()
>>> p.communicate()
(b'', b'')
>>>
>>> p = Popen(['python', '-V'], stdout=PIPE)
>>> p.stdout.close()
>>> p.communicate()
Traceback (most recent call last):
File "<python-input-7>", line 1, in <module>
p.communicate()
~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/subprocess.py", line 1207, in communicate
stdout = self.stdout.read()
ValueError: read of closed file
If stdin is a closed PIPE, the behavior is pretty much the opposite of the above. If other streams are not PIPEs, communicate() succeeds, but if the are other PIPEs, we get a ValueError:
>>> from subprocess import Popen, PIPE
>>>
>>> p = Popen(['python', '-c', 'pass'], stdin=PIPE)
>>> p.stdin.close()
>>> p.communicate()
(None, None)
>>>
>>> p = Popen(['python', '-c', 'pass'], stdin=PIPE, stdout=PIPE)
>>> p.stdin.close()
>>> p.communicate()
Traceback (most recent call last):
File "<python-input-14>", line 1, in <module>
p.communicate()
~~~~~~~~~~~~~^^
File "/usr/lib/python3.14/subprocess.py", line 1220, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 2081, in _communicate
self.stdin.flush()
~~~~~~~~~~~~~~~~^^
ValueError: flush of closed file
This inconsistency seems to be caused by an optimization that leads to two different code paths depending on the number of PIPEs. I needed to spend some time to understand why our tests behaved seemingly inconsistently after code was refactored.
It would be easy to fix problems by changing code like if self.stdout: to if self.stdout and not self.stdout.closed:. I guess it could be argued that raising a ValueError is the correct way to handle these situations, but in that case it should be raised always.
Tested with Python 3.14 alpha 5. Occurs also with earlier ones.
CPython versions tested on:
3.14
Operating systems tested on:
Linux
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Reproduziere zuerst die Beispiele für closed-PIPE und untersuche dann in Lib/subprocess.py die communicate()-Optimierung in der Nähe von Zeile 1194 sowie die in der traceback gezeigte stdin/stdout-Behandlung. Entscheide und bestätige das beabsichtigte konsistente Verhalten für geschlossene Streams, füge dann Regressionstests für die betroffenen Kombinationen hinzu und überprüfe die vorhandenen subprocess-Tests.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- operating-systems
- Issue-Typ
- Bug
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 42/100