Inconsistent `Popen.communicate()` behavior if stdin/stdout/stderr is closed `PIPE`
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Python
- Estrellas
- 77.2k
- Forks
- 36k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
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
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Reproduce primero los ejemplos de closed-PIPE y, después, inspecciona en Lib/subprocess.py la optimización de communicate() vinculada cerca de la línea 1194 y el manejo de stdin/stdout mostrado en el traceback. Decide y confirma el comportamiento coherente previsto para los streams cerrados; después, añade cobertura de regresión para las combinaciones afectadas y verifica las pruebas existentes de subprocess.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- python
- Área
- operating-systems
- Tipo de issue
- Error
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 42/100