pip icon indicating copy to clipboard operation
pip copied to clipboard

pip list |head raises BrokenPipeError

Open wimglenn opened this issue 2 years ago • 12 comments

Description

https://github.com/pypa/pip/issues/4170 is closed but the bug is still there not sure if it's a regression or the fix may have missed something in the first place (@cjerdonek?). I could not bisect it, because I also get the same issue on pip 19.0.0 which is when the fix went in according to the changelog. reproducible on both macOS and Linux.

Expected behavior

pip handles BrokenPipeError and exits gracefully

pip version

22.3.1

Python version

3.11.0

OS

macOS and/or Linux

How to Reproduce

$ pip --version
pip 22.3.1 from .../.venv/lib/python3.11/site-packages/pip (python 3.11)
$ head --version
head (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David MacKenzie and Jim Meyering.
$ pip list | head -1
Package                                Version     Editable project location
ERROR: Pipe to stdout was broken
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pipe

Interestingly, it doesn't happen for pip freeze

$ pip freeze | head -1
anytree==2.8.0

wimglenn avatar Nov 18 '22 21:11 wimglenn

❯ pip list | head -1 
Package            Version   Editable project location
ERROR: Pipe to stdout was broken
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pipe
❯ echo $?                                                 
0

What behaviour are you expecting to be different?

pradyunsg avatar Nov 18 '22 22:11 pradyunsg

The final three lines are basically providing a bunch of context, on the fact that the stdout pipe was broken (they're all at different levels within pip's logging and CLI infra).

pradyunsg avatar Nov 18 '22 22:11 pradyunsg

I'm not talking about the return code, I just think this should not cause any print output on stderr. It could be debug or info log events, if anything, so it's not shown by default (i.e. without increased verbosity -v flag).

head closing stdin is normal, isn't it? So that shouldn't be a ERROR event printed from pip, it's not really an error condition?

basically I'm expecting it to behave like pip 21.x does here on python 3.8:

$ pip list | head -1
Package    Version
WARNING: You are using pip version 21.3.1; however, version 22.3.1 is available.
You should consider upgrading via the '/Users/wim/opt/miniconda3/envs/pb/bin/python3 -m pip install --upgrade pip' command.
$ /tmp pip list --disable-pip-version-check | head -1
Package    Version
$ /tmp echo $?
0
$ pip install -U pip
Requirement already satisfied: pip in /Users/wim/opt/miniconda3/envs/pb/lib/python3.8/site-packages (21.3.1)
Collecting pip
  Using cached pip-22.3.1-py3-none-any.whl (2.1 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 21.3.1
    Uninstalling pip-21.3.1:
      Successfully uninstalled pip-21.3.1
Successfully installed pip-22.3.1
$ /tmp pip list | head -1
Package    Version
ERROR: Pipe to stdout was broken
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pipe

wimglenn avatar Nov 19 '22 03:11 wimglenn

head closing stdin is normal, isn't it?

It closed stdout in this case, which caused an error within pip's output stack. That error is suppressed (in terms of the exit code), but presented across three lines.

pradyunsg avatar Nov 19 '22 14:11 pradyunsg

Why is that an error condition for pip list, but not for pip freeze (or earlier releases of pip)?

wimglenn avatar Nov 19 '22 18:11 wimglenn

OS Name:            macOS
OS Version:         13.0.1
Chip:               Apple M1 Max
Memory:             64 GB
pip version:        22.3.1
Screenshot 2022-11-25 at 23 47 52

binbjz avatar Nov 25 '22 15:11 binbjz

It's intermittent in iterm2:

❯ pip list | head -n2
Package    Version
---------- -------
❯ pip list | head -n2
Package    Version
---------- -------
❯ pip list | head -n2
Package    Version
---------- -------
❯ pip list | head -n2
Package    Version
---------- -------
ERROR: Pipe to stdout was broken
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
BrokenPipeError: [Errno 32] Broken pipe
❯ pip --version
pip 23.1.2 from /Users/tekumara/.virtualenvs/tmp-c317f937f66cda0/lib/python3.9/site-packages/pip (python 3.9)

But I can reproduce it every time in a vscode terminal.

tekumara avatar May 14 '23 10:05 tekumara

BTW tail can be used to consume all output and cleanly exit, effectively handling any broken pipes,

eg: this won't error

❯ pip list |  tail -n +1 | head -n1
Package    Version

tekumara avatar May 14 '23 11:05 tekumara

I think the standard thing to do with SIGPIPE and EPIPE is to silently exit with a non zero status code. This is the default behavior under POSIX, but Python ignores the SIGPIPE and turns the EPIPE into the BrokenPipeError error.

I think just removing these lines would restore pip back to the default behavior on POSIX, and arguably what people expect to happen:

https://github.com/pypa/pip/blob/f25f8fffbbd16fdb13a4f8977946afe9a3248453/src/pip/_internal/cli/base_command.py#L198-L202

dstufft avatar May 14 '23 17:05 dstufft

Also note that $? on pip list | head -1 will be the return code for head, not for pip. To get the return code for pip you need ${PIPESTATUS[0]}

dstufft avatar May 14 '23 17:05 dstufft

Oh, and the error status should be 141 IIRC, convention is to return with 128 + the signal number.

dstufft avatar May 14 '23 18:05 dstufft

+1 for the solution proposed by @dstufft. It is unusual and annoying to get extra BrokenPipeError output when it isn't expected. Adding a flag to suppress this output would be helpful at the very least.

xintenseapple avatar Apr 26 '24 02:04 xintenseapple