| from __future__ import absolute_import |
| |
| import contextlib |
| import logging |
| import logging.handlers |
| import os |
| |
| try: |
| import threading |
| except ImportError: |
| import dummy_threading as threading |
| |
| from pip.compat import WINDOWS |
| from pip.utils import ensure_dir |
| |
| try: |
| from pip._vendor import colorama |
| # Lots of different errors can come from this, including SystemError and |
| # ImportError. |
| except Exception: |
| colorama = None |
| |
| |
| _log_state = threading.local() |
| _log_state.indentation = 0 |
| |
| |
| @contextlib.contextmanager |
| def indent_log(num=2): |
| """ |
| A context manager which will cause the log output to be indented for any |
| log messages emitted inside it. |
| """ |
| _log_state.indentation += num |
| try: |
| yield |
| finally: |
| _log_state.indentation -= num |
| |
| |
| def get_indentation(): |
| return getattr(_log_state, 'indentation', 0) |
| |
| |
| class IndentingFormatter(logging.Formatter): |
| |
| def format(self, record): |
| """ |
| Calls the standard formatter, but will indent all of the log messages |
| by our current indentation level. |
| """ |
| formatted = logging.Formatter.format(self, record) |
| formatted = "".join([ |
| (" " * get_indentation()) + line |
| for line in formatted.splitlines(True) |
| ]) |
| return formatted |
| |
| |
| def _color_wrap(*colors): |
| def wrapped(inp): |
| return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) |
| return wrapped |
| |
| |
| class ColorizedStreamHandler(logging.StreamHandler): |
| |
| # Don't build up a list of colors if we don't have colorama |
| if colorama: |
| COLORS = [ |
| # This needs to be in order from highest logging level to lowest. |
| (logging.ERROR, _color_wrap(colorama.Fore.RED)), |
| (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)), |
| ] |
| else: |
| COLORS = [] |
| |
| def __init__(self, stream=None): |
| logging.StreamHandler.__init__(self, stream) |
| |
| if WINDOWS and colorama: |
| self.stream = colorama.AnsiToWin32(self.stream) |
| |
| def should_color(self): |
| # Don't colorize things if we do not have colorama |
| if not colorama: |
| return False |
| |
| real_stream = ( |
| self.stream if not isinstance(self.stream, colorama.AnsiToWin32) |
| else self.stream.wrapped |
| ) |
| |
| # If the stream is a tty we should color it |
| if hasattr(real_stream, "isatty") and real_stream.isatty(): |
| return True |
| |
| # If we have an ASNI term we should color it |
| if os.environ.get("TERM") == "ANSI": |
| return True |
| |
| # If anything else we should not color it |
| return False |
| |
| def format(self, record): |
| msg = logging.StreamHandler.format(self, record) |
| |
| if self.should_color(): |
| for level, color in self.COLORS: |
| if record.levelno >= level: |
| msg = color(msg) |
| break |
| |
| return msg |
| |
| |
| class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): |
| |
| def _open(self): |
| ensure_dir(os.path.dirname(self.baseFilename)) |
| return logging.handlers.RotatingFileHandler._open(self) |
| |
| |
| class MaxLevelFilter(logging.Filter): |
| |
| def __init__(self, level): |
| self.level = level |
| |
| def filter(self, record): |
| return record.levelno < self.level |