1import logging 2import sys 3 4 5VERBOSITY = 3 6 7 8# The root logger for the whole top-level package: 9_logger = logging.getLogger(__name__.rpartition('.')[0]) 10 11 12def configure_logger(logger, verbosity=VERBOSITY, *, 13 logfile=None, 14 maxlevel=logging.CRITICAL, 15 ): 16 level = max(1, # 0 disables it, so we use the next lowest. 17 min(maxlevel, 18 maxlevel - verbosity * 10)) 19 logger.setLevel(level) 20 #logger.propagate = False 21 22 if not logger.handlers: 23 if logfile: 24 handler = logging.FileHandler(logfile) 25 else: 26 handler = logging.StreamHandler(sys.stdout) 27 handler.setLevel(level) 28 #handler.setFormatter(logging.Formatter()) 29 logger.addHandler(handler) 30 31 # In case the provided logger is in a sub-package... 32 if logger is not _logger: 33 configure_logger( 34 _logger, 35 verbosity, 36 logfile=logfile, 37 maxlevel=maxlevel, 38 ) 39 40 41def hide_emit_errors(): 42 """Ignore errors while emitting log entries. 43 44 Rather than printing a message describing the error, we show nothing. 45 """ 46 # For now we simply ignore all exceptions. If we wanted to ignore 47 # specific ones (e.g. BrokenPipeError) then we would need to use 48 # a Handler subclass with a custom handleError() method. 49 orig = logging.raiseExceptions 50 logging.raiseExceptions = False 51 def restore(): 52 logging.raiseExceptions = orig 53 return restore 54 55 56class Printer: 57 def __init__(self, verbosity=VERBOSITY): 58 self.verbosity = verbosity 59 60 def info(self, *args, **kwargs): 61 if self.verbosity < 3: 62 return 63 print(*args, **kwargs) 64