Sinto-me na obrigação de salientar que o método que utiliza
signal(SIGPIPE, SIG_DFL)
é realmente perigoso (como já sugerido por David Bennet nos comentários) e, no meu caso, levou a negócios engraçados dependentes da plataforma quando combinado commultiprocessing.Manager
(porque a biblioteca padrão depende de BrokenPipeError sendo criado em vários lugares). Para encurtar uma longa e dolorosa história, é assim que eu consertei:
Primeiro, você precisa capturar o IOError
(Python 2) ou BrokenPipeError
(Python 3). Dependendo do seu programa, você pode tentar sair mais cedo nesse ponto ou simplesmente ignorar a exceção:
from errno import EPIPE
try:
broken_pipe_exception = BrokenPipeError
except NameError:
broken_pipe_exception = IOError
try:
YOUR CODE GOES HERE
except broken_pipe_exception as exc:
if broken_pipe_exception == IOError:
if exc.errno != EPIPE:
raise
No entanto, isso não é suficiente. O Python 3 ainda pode imprimir uma mensagem como esta:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
Infelizmente, livrar-se dessa mensagem não é simples, mas finalmente encontrei http://bugs.python.org/issue11380 onde Robert Collins sugere esta solução alternativa que transformei em um decorador com a qual você pode embrulhar sua função principal (sim, isso é uma loucura recuo):
from functools import wraps
from sys import exit, stderr, stdout
from traceback import print_exc
def suppress_broken_pipe_msg(f):
@wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except SystemExit:
raise
except:
print_exc()
exit(1)
finally:
try:
stdout.flush()
finally:
try:
stdout.close()
finally:
try:
stderr.flush()
finally:
stderr.close()
return wrapper
@suppress_broken_pipe_msg
def main():
YOUR CODE GOES HERE
print(f1.readlines())