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