Je me sens obligé de souligner que la méthode qui utilise
signal(SIGPIPE, SIG_DFL)
est en effet dangereux (comme l'a déjà suggéré David Bennet dans les commentaires) et, dans mon cas, a conduit à des affaires bizarres dépendantes de la plate-forme lorsqu'il est combiné avec multiprocessing.Manager
(parce que la bibliothèque standard repose sur le fait que BrokenPipeError est levé à plusieurs endroits). Pour résumer une histoire longue et pénible, voici comment je l'ai réparée :
D'abord, vous devez attraper le IOError
(Python 2) ou BrokenPipeError
(Python 3). En fonction de votre programme, vous pouvez essayer de sortir prématurément à ce moment-là ou simplement ignorer l'exception :
from errno import EPIPE
try:
broken_pipe_exception = BrokenPipeError
except NameError: # Python 2
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
Toutefois, cela ne suffit pas. Python 3 peut toujours imprimer un message comme celui-ci :
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
Malheureusement, se débarrasser de ce message n'est pas simple, mais j'ai finalement trouvé http://bugs.python.org/issue11380 où Robert Collins suggère cette solution de contournement que j'ai transformée en un décorateur avec lequel vous pouvez envelopper votre fonction principale (oui, c'est une indentation folle) :
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