Mercurial > repos > guerler > hhblits
comparison lib/python3.8/site-packages/pip/_internal/utils/logging.py @ 1:64071f2a4cf0 draft default tip
Deleted selected files
| author | guerler | 
|---|---|
| date | Mon, 27 Jul 2020 03:55:49 -0400 | 
| parents | 9e54283cc701 | 
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 0:9e54283cc701 | 1:64071f2a4cf0 | 
|---|---|
| 1 # The following comment should be removed at some point in the future. | |
| 2 # mypy: disallow-untyped-defs=False | |
| 3 | |
| 4 from __future__ import absolute_import | |
| 5 | |
| 6 import contextlib | |
| 7 import errno | |
| 8 import logging | |
| 9 import logging.handlers | |
| 10 import os | |
| 11 import sys | |
| 12 from logging import Filter, getLogger | |
| 13 | |
| 14 from pip._vendor.six import PY2 | |
| 15 | |
| 16 from pip._internal.utils.compat import WINDOWS | |
| 17 from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX | |
| 18 from pip._internal.utils.misc import ensure_dir | |
| 19 | |
| 20 try: | |
| 21 import threading | |
| 22 except ImportError: | |
| 23 import dummy_threading as threading # type: ignore | |
| 24 | |
| 25 | |
| 26 try: | |
| 27 # Use "import as" and set colorama in the else clause to avoid mypy | |
| 28 # errors and get the following correct revealed type for colorama: | |
| 29 # `Union[_importlib_modulespec.ModuleType, None]` | |
| 30 # Otherwise, we get an error like the following in the except block: | |
| 31 # > Incompatible types in assignment (expression has type "None", | |
| 32 # variable has type Module) | |
| 33 # TODO: eliminate the need to use "import as" once mypy addresses some | |
| 34 # of its issues with conditional imports. Here is an umbrella issue: | |
| 35 # https://github.com/python/mypy/issues/1297 | |
| 36 from pip._vendor import colorama as _colorama | |
| 37 # Lots of different errors can come from this, including SystemError and | |
| 38 # ImportError. | |
| 39 except Exception: | |
| 40 colorama = None | |
| 41 else: | |
| 42 # Import Fore explicitly rather than accessing below as colorama.Fore | |
| 43 # to avoid the following error running mypy: | |
| 44 # > Module has no attribute "Fore" | |
| 45 # TODO: eliminate the need to import Fore once mypy addresses some of its | |
| 46 # issues with conditional imports. This particular case could be an | |
| 47 # instance of the following issue (but also see the umbrella issue above): | |
| 48 # https://github.com/python/mypy/issues/3500 | |
| 49 from pip._vendor.colorama import Fore | |
| 50 | |
| 51 colorama = _colorama | |
| 52 | |
| 53 | |
| 54 _log_state = threading.local() | |
| 55 _log_state.indentation = 0 | |
| 56 subprocess_logger = getLogger('pip.subprocessor') | |
| 57 | |
| 58 | |
| 59 class BrokenStdoutLoggingError(Exception): | |
| 60 """ | |
| 61 Raised if BrokenPipeError occurs for the stdout stream while logging. | |
| 62 """ | |
| 63 pass | |
| 64 | |
| 65 | |
| 66 # BrokenPipeError does not exist in Python 2 and, in addition, manifests | |
| 67 # differently in Windows and non-Windows. | |
| 68 if WINDOWS: | |
| 69 # In Windows, a broken pipe can show up as EINVAL rather than EPIPE: | |
| 70 # https://bugs.python.org/issue19612 | |
| 71 # https://bugs.python.org/issue30418 | |
| 72 if PY2: | |
| 73 def _is_broken_pipe_error(exc_class, exc): | |
| 74 """See the docstring for non-Windows Python 3 below.""" | |
| 75 return (exc_class is IOError and | |
| 76 exc.errno in (errno.EINVAL, errno.EPIPE)) | |
| 77 else: | |
| 78 # In Windows, a broken pipe IOError became OSError in Python 3. | |
| 79 def _is_broken_pipe_error(exc_class, exc): | |
| 80 """See the docstring for non-Windows Python 3 below.""" | |
| 81 return ((exc_class is BrokenPipeError) or # noqa: F821 | |
| 82 (exc_class is OSError and | |
| 83 exc.errno in (errno.EINVAL, errno.EPIPE))) | |
| 84 elif PY2: | |
| 85 def _is_broken_pipe_error(exc_class, exc): | |
| 86 """See the docstring for non-Windows Python 3 below.""" | |
| 87 return (exc_class is IOError and exc.errno == errno.EPIPE) | |
| 88 else: | |
| 89 # Then we are in the non-Windows Python 3 case. | |
| 90 def _is_broken_pipe_error(exc_class, exc): | |
| 91 """ | |
| 92 Return whether an exception is a broken pipe error. | |
| 93 | |
| 94 Args: | |
| 95 exc_class: an exception class. | |
| 96 exc: an exception instance. | |
| 97 """ | |
| 98 return (exc_class is BrokenPipeError) # noqa: F821 | |
| 99 | |
| 100 | |
| 101 @contextlib.contextmanager | |
| 102 def indent_log(num=2): | |
| 103 """ | |
| 104 A context manager which will cause the log output to be indented for any | |
| 105 log messages emitted inside it. | |
| 106 """ | |
| 107 _log_state.indentation += num | |
| 108 try: | |
| 109 yield | |
| 110 finally: | |
| 111 _log_state.indentation -= num | |
| 112 | |
| 113 | |
| 114 def get_indentation(): | |
| 115 return getattr(_log_state, 'indentation', 0) | |
| 116 | |
| 117 | |
| 118 class IndentingFormatter(logging.Formatter): | |
| 119 | |
| 120 def __init__(self, *args, **kwargs): | |
| 121 """ | |
| 122 A logging.Formatter that obeys the indent_log() context manager. | |
| 123 | |
| 124 :param add_timestamp: A bool indicating output lines should be prefixed | |
| 125 with their record's timestamp. | |
| 126 """ | |
| 127 self.add_timestamp = kwargs.pop("add_timestamp", False) | |
| 128 super(IndentingFormatter, self).__init__(*args, **kwargs) | |
| 129 | |
| 130 def get_message_start(self, formatted, levelno): | |
| 131 """ | |
| 132 Return the start of the formatted log message (not counting the | |
| 133 prefix to add to each line). | |
| 134 """ | |
| 135 if levelno < logging.WARNING: | |
| 136 return '' | |
| 137 if formatted.startswith(DEPRECATION_MSG_PREFIX): | |
| 138 # Then the message already has a prefix. We don't want it to | |
| 139 # look like "WARNING: DEPRECATION: ...." | |
| 140 return '' | |
| 141 if levelno < logging.ERROR: | |
| 142 return 'WARNING: ' | |
| 143 | |
| 144 return 'ERROR: ' | |
| 145 | |
| 146 def format(self, record): | |
| 147 """ | |
| 148 Calls the standard formatter, but will indent all of the log message | |
| 149 lines by our current indentation level. | |
| 150 """ | |
| 151 formatted = super(IndentingFormatter, self).format(record) | |
| 152 message_start = self.get_message_start(formatted, record.levelno) | |
| 153 formatted = message_start + formatted | |
| 154 | |
| 155 prefix = '' | |
| 156 if self.add_timestamp: | |
| 157 # TODO: Use Formatter.default_time_format after dropping PY2. | |
| 158 t = self.formatTime(record, "%Y-%m-%dT%H:%M:%S") | |
| 159 prefix = '%s,%03d ' % (t, record.msecs) | |
| 160 prefix += " " * get_indentation() | |
| 161 formatted = "".join([ | |
| 162 prefix + line | |
| 163 for line in formatted.splitlines(True) | |
| 164 ]) | |
| 165 return formatted | |
| 166 | |
| 167 | |
| 168 def _color_wrap(*colors): | |
| 169 def wrapped(inp): | |
| 170 return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) | |
| 171 return wrapped | |
| 172 | |
| 173 | |
| 174 class ColorizedStreamHandler(logging.StreamHandler): | |
| 175 | |
| 176 # Don't build up a list of colors if we don't have colorama | |
| 177 if colorama: | |
| 178 COLORS = [ | |
| 179 # This needs to be in order from highest logging level to lowest. | |
| 180 (logging.ERROR, _color_wrap(Fore.RED)), | |
| 181 (logging.WARNING, _color_wrap(Fore.YELLOW)), | |
| 182 ] | |
| 183 else: | |
| 184 COLORS = [] | |
| 185 | |
| 186 def __init__(self, stream=None, no_color=None): | |
| 187 logging.StreamHandler.__init__(self, stream) | |
| 188 self._no_color = no_color | |
| 189 | |
| 190 if WINDOWS and colorama: | |
| 191 self.stream = colorama.AnsiToWin32(self.stream) | |
| 192 | |
| 193 def _using_stdout(self): | |
| 194 """ | |
| 195 Return whether the handler is using sys.stdout. | |
| 196 """ | |
| 197 if WINDOWS and colorama: | |
| 198 # Then self.stream is an AnsiToWin32 object. | |
| 199 return self.stream.wrapped is sys.stdout | |
| 200 | |
| 201 return self.stream is sys.stdout | |
| 202 | |
| 203 def should_color(self): | |
| 204 # Don't colorize things if we do not have colorama or if told not to | |
| 205 if not colorama or self._no_color: | |
| 206 return False | |
| 207 | |
| 208 real_stream = ( | |
| 209 self.stream if not isinstance(self.stream, colorama.AnsiToWin32) | |
| 210 else self.stream.wrapped | |
| 211 ) | |
| 212 | |
| 213 # If the stream is a tty we should color it | |
| 214 if hasattr(real_stream, "isatty") and real_stream.isatty(): | |
| 215 return True | |
| 216 | |
| 217 # If we have an ANSI term we should color it | |
| 218 if os.environ.get("TERM") == "ANSI": | |
| 219 return True | |
| 220 | |
| 221 # If anything else we should not color it | |
| 222 return False | |
| 223 | |
| 224 def format(self, record): | |
| 225 msg = logging.StreamHandler.format(self, record) | |
| 226 | |
| 227 if self.should_color(): | |
| 228 for level, color in self.COLORS: | |
| 229 if record.levelno >= level: | |
| 230 msg = color(msg) | |
| 231 break | |
| 232 | |
| 233 return msg | |
| 234 | |
| 235 # The logging module says handleError() can be customized. | |
| 236 def handleError(self, record): | |
| 237 exc_class, exc = sys.exc_info()[:2] | |
| 238 # If a broken pipe occurred while calling write() or flush() on the | |
| 239 # stdout stream in logging's Handler.emit(), then raise our special | |
| 240 # exception so we can handle it in main() instead of logging the | |
| 241 # broken pipe error and continuing. | |
| 242 if (exc_class and self._using_stdout() and | |
| 243 _is_broken_pipe_error(exc_class, exc)): | |
| 244 raise BrokenStdoutLoggingError() | |
| 245 | |
| 246 return super(ColorizedStreamHandler, self).handleError(record) | |
| 247 | |
| 248 | |
| 249 class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): | |
| 250 | |
| 251 def _open(self): | |
| 252 ensure_dir(os.path.dirname(self.baseFilename)) | |
| 253 return logging.handlers.RotatingFileHandler._open(self) | |
| 254 | |
| 255 | |
| 256 class MaxLevelFilter(Filter): | |
| 257 | |
| 258 def __init__(self, level): | |
| 259 self.level = level | |
| 260 | |
| 261 def filter(self, record): | |
| 262 return record.levelno < self.level | |
| 263 | |
| 264 | |
| 265 class ExcludeLoggerFilter(Filter): | |
| 266 | |
| 267 """ | |
| 268 A logging Filter that excludes records from a logger (or its children). | |
| 269 """ | |
| 270 | |
| 271 def filter(self, record): | |
| 272 # The base Filter class allows only records from a logger (or its | |
| 273 # children). | |
| 274 return not super(ExcludeLoggerFilter, self).filter(record) | |
| 275 | |
| 276 | |
| 277 def setup_logging(verbosity, no_color, user_log_file): | |
| 278 """Configures and sets up all of the logging | |
| 279 | |
| 280 Returns the requested logging level, as its integer value. | |
| 281 """ | |
| 282 | |
| 283 # Determine the level to be logging at. | |
| 284 if verbosity >= 1: | |
| 285 level = "DEBUG" | |
| 286 elif verbosity == -1: | |
| 287 level = "WARNING" | |
| 288 elif verbosity == -2: | |
| 289 level = "ERROR" | |
| 290 elif verbosity <= -3: | |
| 291 level = "CRITICAL" | |
| 292 else: | |
| 293 level = "INFO" | |
| 294 | |
| 295 level_number = getattr(logging, level) | |
| 296 | |
| 297 # The "root" logger should match the "console" level *unless* we also need | |
| 298 # to log to a user log file. | |
| 299 include_user_log = user_log_file is not None | |
| 300 if include_user_log: | |
| 301 additional_log_file = user_log_file | |
| 302 root_level = "DEBUG" | |
| 303 else: | |
| 304 additional_log_file = "/dev/null" | |
| 305 root_level = level | |
| 306 | |
| 307 # Disable any logging besides WARNING unless we have DEBUG level logging | |
| 308 # enabled for vendored libraries. | |
| 309 vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" | |
| 310 | |
| 311 # Shorthands for clarity | |
| 312 log_streams = { | |
| 313 "stdout": "ext://sys.stdout", | |
| 314 "stderr": "ext://sys.stderr", | |
| 315 } | |
| 316 handler_classes = { | |
| 317 "stream": "pip._internal.utils.logging.ColorizedStreamHandler", | |
| 318 "file": "pip._internal.utils.logging.BetterRotatingFileHandler", | |
| 319 } | |
| 320 handlers = ["console", "console_errors", "console_subprocess"] + ( | |
| 321 ["user_log"] if include_user_log else [] | |
| 322 ) | |
| 323 | |
| 324 logging.config.dictConfig({ | |
| 325 "version": 1, | |
| 326 "disable_existing_loggers": False, | |
| 327 "filters": { | |
| 328 "exclude_warnings": { | |
| 329 "()": "pip._internal.utils.logging.MaxLevelFilter", | |
| 330 "level": logging.WARNING, | |
| 331 }, | |
| 332 "restrict_to_subprocess": { | |
| 333 "()": "logging.Filter", | |
| 334 "name": subprocess_logger.name, | |
| 335 }, | |
| 336 "exclude_subprocess": { | |
| 337 "()": "pip._internal.utils.logging.ExcludeLoggerFilter", | |
| 338 "name": subprocess_logger.name, | |
| 339 }, | |
| 340 }, | |
| 341 "formatters": { | |
| 342 "indent": { | |
| 343 "()": IndentingFormatter, | |
| 344 "format": "%(message)s", | |
| 345 }, | |
| 346 "indent_with_timestamp": { | |
| 347 "()": IndentingFormatter, | |
| 348 "format": "%(message)s", | |
| 349 "add_timestamp": True, | |
| 350 }, | |
| 351 }, | |
| 352 "handlers": { | |
| 353 "console": { | |
| 354 "level": level, | |
| 355 "class": handler_classes["stream"], | |
| 356 "no_color": no_color, | |
| 357 "stream": log_streams["stdout"], | |
| 358 "filters": ["exclude_subprocess", "exclude_warnings"], | |
| 359 "formatter": "indent", | |
| 360 }, | |
| 361 "console_errors": { | |
| 362 "level": "WARNING", | |
| 363 "class": handler_classes["stream"], | |
| 364 "no_color": no_color, | |
| 365 "stream": log_streams["stderr"], | |
| 366 "filters": ["exclude_subprocess"], | |
| 367 "formatter": "indent", | |
| 368 }, | |
| 369 # A handler responsible for logging to the console messages | |
| 370 # from the "subprocessor" logger. | |
| 371 "console_subprocess": { | |
| 372 "level": level, | |
| 373 "class": handler_classes["stream"], | |
| 374 "no_color": no_color, | |
| 375 "stream": log_streams["stderr"], | |
| 376 "filters": ["restrict_to_subprocess"], | |
| 377 "formatter": "indent", | |
| 378 }, | |
| 379 "user_log": { | |
| 380 "level": "DEBUG", | |
| 381 "class": handler_classes["file"], | |
| 382 "filename": additional_log_file, | |
| 383 "delay": True, | |
| 384 "formatter": "indent_with_timestamp", | |
| 385 }, | |
| 386 }, | |
| 387 "root": { | |
| 388 "level": root_level, | |
| 389 "handlers": handlers, | |
| 390 }, | |
| 391 "loggers": { | |
| 392 "pip._vendor": { | |
| 393 "level": vendored_log_level | |
| 394 } | |
| 395 }, | |
| 396 }) | |
| 397 | |
| 398 return level_number | 
