diff --git a/dvc/cli/__init__.py b/dvc/cli/__init__.py index 590f956ef..e206befd6 100644 --- a/dvc/cli/__init__.py +++ b/dvc/cli/__init__.py @@ -189,6 +189,15 @@ def main(argv=None): # noqa: C901 except KeyboardInterrupt: logger.exception("interrupted by the user") ret = 252 + except BrokenPipeError: + import os + + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown + # See: https://docs.python.org/3/library/signal.html#note-on-sigpipe + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + ret = 141 # 128 + 13 (SIGPIPE) except NotDvcRepoError: logger.exception("") ret = 253 diff --git a/dvc/logger.py b/dvc/logger.py index d44ca0835..cf3cce2a1 100644 --- a/dvc/logger.py +++ b/dvc/logger.py @@ -163,7 +163,7 @@ class LoggerHandler(logging.StreamHandler): msg, file=self.stream, end=getattr(self, "terminator", "\n") ) self.flush() - except RecursionError: + except (BrokenPipeError, RecursionError): raise except Exception: # noqa, pylint: disable=broad-except self.handleError(record)