Skip to content

Commit

Permalink
Prevent error messages/exit code 120 after exiting on EPIPE
Browse files Browse the repository at this point in the history
  • Loading branch information
frankier committed Sep 5, 2018
1 parent 123dd71 commit e96d7a3
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
5 changes: 4 additions & 1 deletion click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from functools import update_wrapper

from .types import convert_type, IntRange, BOOL
from .utils import make_str, make_default_short_help, echo, get_os_args
from .utils import PacifyFlushWrapper, make_str, make_default_short_help, \
echo, get_os_args
from .exceptions import ClickException, UsageError, BadParameter, Abort, \
MissingParameter, Exit
from .termui import prompt, confirm, style
Expand Down Expand Up @@ -732,6 +733,8 @@ def main(self, args=None, prog_name=None, complete_var=None,
sys.exit(e.exit_code)
except IOError as e:
if e.errno == errno.EPIPE:
sys.stdout = PacifyFlushWrapper(sys.stdout)
sys.stderr = PacifyFlushWrapper(sys.stderr)
sys.exit(1)
else:
raise
Expand Down
22 changes: 22 additions & 0 deletions click/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,25 @@ def get_app_dir(app_name, roaming=True, force_posix=False):
return os.path.join(
os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
_posixify(app_name))


class PacifyFlushWrapper(object):
"""This wrapper is used to catch and supress BrokenPipeErrors resulting
from ``.flush()`` being called on broken pipe during the shutdown/final-GC
of the Python interpreter. Notably ``.flush()`` is always called on
``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any
other cleanup code, and the case where the underlying file is not a broken
pipe, all calls and attributes are proxied.
"""

def __init__(self, wrapped):
self.wrapped = wrapped

def flush(self):
try:
self.wrapped.flush()
except BrokenPipeError:
pass

def __getattr__(self, attr):
return getattr(self.wrapped, attr)

0 comments on commit e96d7a3

Please sign in to comment.