summaryrefslogtreecommitdiffstats
path: root/lib/Python/Lib/colorlog
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Python/Lib/colorlog')
-rw-r--r--lib/Python/Lib/colorlog/__init__.py14
-rw-r--r--lib/Python/Lib/colorlog/colorlog.py137
-rw-r--r--lib/Python/Lib/colorlog/escape_codes.py57
-rw-r--r--lib/Python/Lib/colorlog/logging.py44
4 files changed, 252 insertions, 0 deletions
diff --git a/lib/Python/Lib/colorlog/__init__.py b/lib/Python/Lib/colorlog/__init__.py
new file mode 100644
index 000000000..1d57f586d
--- /dev/null
+++ b/lib/Python/Lib/colorlog/__init__.py
@@ -0,0 +1,14 @@
+"""A logging formatter for colored output."""
+
+from __future__ import absolute_import
+
+from colorlog.colorlog import (
+ ColoredFormatter, escape_codes, default_log_colors)
+
+from colorlog.logging import (
+ basicConfig, root, getLogger, log,
+ debug, info, warning, error, exception, critical)
+
+__all__ = ('ColoredFormatter', 'default_log_colors', 'escape_codes',
+ 'basicConfig', 'root', 'getLogger', 'debug', 'info', 'warning',
+ 'error', 'exception', 'critical', 'log', 'exception')
diff --git a/lib/Python/Lib/colorlog/colorlog.py b/lib/Python/Lib/colorlog/colorlog.py
new file mode 100644
index 000000000..49860dd50
--- /dev/null
+++ b/lib/Python/Lib/colorlog/colorlog.py
@@ -0,0 +1,137 @@
+"""The ColoredFormatter class."""
+
+from __future__ import absolute_import
+
+import logging
+import collections
+import sys
+
+from colorlog.escape_codes import escape_codes, parse_colors
+
+__all__ = ('escape_codes', 'default_log_colors', 'ColoredFormatter')
+
+# The default colors to use for the debug levels
+default_log_colors = {
+ 'DEBUG': 'white',
+ 'INFO': 'green',
+ 'WARNING': 'yellow',
+ 'ERROR': 'red',
+ 'CRITICAL': 'bold_red',
+}
+
+# The default format to use for each style
+default_formats = {
+ '%': '%(log_color)s%(levelname)s:%(name)s:%(message)s',
+ '{': '{log_color}{levelname}:{name}:{message}',
+ '$': '${log_color}${levelname}:${name}:${message}'
+}
+
+
+class ColoredRecord(object):
+ """
+ Wraps a LogRecord and attempts to parse missing keys as escape codes.
+
+ When the record is formatted, the logging library uses ``record.__dict__``
+ directly - so this class replaced the dict with a ``defaultdict`` that
+ checks if a missing key is an escape code.
+ """
+
+ class __dict(collections.defaultdict):
+ def __missing__(self, name):
+ try:
+ return parse_colors(name)
+ except Exception:
+ raise KeyError("{} is not a valid record attribute "
+ "or color sequence".format(name))
+
+ def __init__(self, record):
+ # Replace the internal dict with one that can handle missing keys
+ self.__dict__ = self.__dict()
+ self.__dict__.update(record.__dict__)
+
+ # Keep a refrence to the original refrence so ``__getattr__`` can
+ # access functions that are not in ``__dict__``
+ self.__record = record
+
+ def __getattr__(self, name):
+ return getattr(self.__record, name)
+
+
+class ColoredFormatter(logging.Formatter):
+ """
+ A formatter that allows colors to be placed in the format string.
+
+ Intended to help in creating more readable logging output.
+ """
+
+ def __init__(self, fmt=None, datefmt=None,
+ log_colors=None, reset=True, style='%',
+ secondary_log_colors=None):
+ """
+ Set the format and colors the ColoredFormatter will use.
+
+ The ``fmt``, ``datefmt`` and ``style`` args are passed on to the
+ ``logging.Formatter`` constructor.
+
+ The ``secondary_log_colors`` argument can be used to create additional
+ ``log_color`` attributes. Each key in the dictionary will set
+ ``log_color_{key}``, using the value to select from a different
+ ``log_colors`` set.
+
+ :Parameters:
+ - fmt (str): The format string to use
+ - datefmt (str): A format string for the date
+ - log_colors (dict):
+ A mapping of log level names to color names
+ - reset (bool):
+ Implictly append a color reset to all records unless False
+ - style ('%' or '{' or '$'):
+ The format style to use. (*No meaning prior to Python 3.2.*)
+ - secondary_log_colors (dict):
+ Map secondary ``log_color`` attributes. (*New in version 2.6.*)
+ """
+ if fmt is None:
+ if sys.version_info > (3, 2):
+ fmt = default_formats[style]
+ else:
+ fmt = default_formats['%']
+
+ if sys.version_info > (3, 2):
+ super(ColoredFormatter, self).__init__(fmt, datefmt, style)
+ elif sys.version_info > (2, 7):
+ super(ColoredFormatter, self).__init__(fmt, datefmt)
+ else:
+ logging.Formatter.__init__(self, fmt, datefmt)
+
+ self.log_colors = (
+ log_colors if log_colors is not None else default_log_colors)
+ self.secondary_log_colors = secondary_log_colors
+ self.reset = reset
+
+ def color(self, log_colors, name):
+ """Return escape codes from a ``log_colors`` dict."""
+ return parse_colors(log_colors.get(name, ""))
+
+ def format(self, record):
+ """Format a message from a record object."""
+ record = ColoredRecord(record)
+ record.log_color = self.color(self.log_colors, record.levelname)
+
+ # Set secondary log colors
+ if self.secondary_log_colors:
+ for name, log_colors in self.secondary_log_colors.items():
+ color = self.color(log_colors, record.levelname)
+ setattr(record, name + '_log_color', color)
+
+ # Format the message
+ if sys.version_info > (2, 7):
+ message = super(ColoredFormatter, self).format(record)
+ else:
+ message = logging.Formatter.format(self, record)
+
+ # Add a reset code to the end of the message
+ # (if it wasn't explicitly added in format str)
+ if self.reset and not message.endswith(escape_codes['reset']):
+ message += escape_codes['reset']
+
+ return message
diff --git a/lib/Python/Lib/colorlog/escape_codes.py b/lib/Python/Lib/colorlog/escape_codes.py
new file mode 100644
index 000000000..848eb6489
--- /dev/null
+++ b/lib/Python/Lib/colorlog/escape_codes.py
@@ -0,0 +1,57 @@
+"""
+Generates a dictionary of ANSI escape codes.
+
+http://en.wikipedia.org/wiki/ANSI_escape_code
+
+Uses colorama as an optional dependancy to support color on Windows
+"""
+
+try:
+ import colorama
+except ImportError:
+ pass
+else:
+ colorama.init()
+
+__all__ = ('escape_codes', 'parse_colors')
+
+# Returns escape codes from format codes
+esc = lambda *x: '\033[' + ';'.join(x) + 'm'
+
+# The initial list of escape codes
+escape_codes = {
+ 'reset': esc('0'),
+ 'bold': esc('01'),
+}
+
+# The color names
+COLORS = [
+ 'black',
+ 'red',
+ 'green',
+ 'yellow',
+ 'blue',
+ 'purple',
+ 'cyan',
+ 'white'
+]
+
+PREFIXES = [
+ # Foreground without prefix
+ ('3', ''), ('01;3', 'bold_'),
+
+ # Foreground with fg_ prefix
+ ('3', 'fg_'), ('01;3', 'fg_bold_'),
+
+ # Background with bg_ prefix - bold/light works differently
+ ('4', 'bg_'), ('10', 'bg_bold_'),
+]
+
+for prefix, prefix_name in PREFIXES:
+ for code, name in enumerate(COLORS):
+ escape_codes[prefix_name + name] = esc(prefix + str(code))
+
+
+def parse_colors(sequence):
+ """Return escape codes from a color sequence."""
+ return ''.join(escape_codes[n] for n in sequence.split(',') if n)
diff --git a/lib/Python/Lib/colorlog/logging.py b/lib/Python/Lib/colorlog/logging.py
new file mode 100644
index 000000000..13f0c4ffb
--- /dev/null
+++ b/lib/Python/Lib/colorlog/logging.py
@@ -0,0 +1,44 @@
+"""Wrappers around the logging module."""
+
+from __future__ import absolute_import
+
+import functools
+import logging
+
+from colorlog.colorlog import ColoredFormatter
+
+BASIC_FORMAT = "%(log_color)s%(levelname)s%(reset)s:%(name)s:%(message)s"
+
+
+def basicConfig(**kwargs):
+ """Call ``logging.basicConfig`` and override the formatter it creates."""
+ logging.basicConfig(**kwargs)
+ logging._acquireLock()
+ try:
+ stream = logging.root.handlers[0]
+ stream.setFormatter(
+ ColoredFormatter(
+ fmt=kwargs.get('format', BASIC_FORMAT),
+ datefmt=kwargs.get('datefmt', None)))
+ finally:
+ logging._releaseLock()
+
+
+def ensure_configured(func):
+ """Modify a function to call ``basicConfig`` first if no handlers exist."""
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ if len(logging.root.handlers) == 0:
+ basicConfig()
+ return func(*args, **kwargs)
+ return wrapper
+
+root = logging.root
+getLogger = logging.getLogger
+debug = ensure_configured(logging.debug)
+info = ensure_configured(logging.info)
+warning = ensure_configured(logging.warning)
+error = ensure_configured(logging.error)
+critical = ensure_configured(logging.critical)
+log = ensure_configured(logging.log)
+exception = ensure_configured(logging.exception)