aboutsummaryrefslogtreecommitdiffstats
path: root/pylog/onaplogging/colorFormatter.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylog/onaplogging/colorFormatter.py')
-rw-r--r--pylog/onaplogging/colorFormatter.py274
1 files changed, 176 insertions, 98 deletions
diff --git a/pylog/onaplogging/colorFormatter.py b/pylog/onaplogging/colorFormatter.py
index 64e220a..5de0d60 100644
--- a/pylog/onaplogging/colorFormatter.py
+++ b/pylog/onaplogging/colorFormatter.py
@@ -13,129 +13,207 @@
# limitations under the License.
import os
-import sys
-import logging
-from logging import Formatter
+from logging import Formatter, LogRecord
+from deprecated import deprecated
+from warnings import warn
+from typing import Optional, Union, Dict
-ATTRIBUTES = {
- 'normal': 0,
- 'bold': 1,
- 'underline': 4,
- 'blink': 5,
- 'invert': 7,
- 'hide': 8,
+from onaplogging.utils.system import is_above_python_2_7, is_above_python_3_2
+from onaplogging.utils.styles import (
+ ATTRIBUTES,
+ HIGHLIGHTS,
+ COLORS,
-}
+ ATTRIBUTE_TAG,
+ HIGHLIGHT_TAG,
+ COLOR_TAG,
+ RESET,
+ FMT_STR
+)
-HIGHLIGHTS = {
- 'black': 40,
- 'red': 41,
- 'green': 42,
- 'yellow': 43,
- 'blue': 44,
- 'purple': 45,
- 'cyan': 46,
- 'white': 47,
-}
-
-COLORS = {
-
- 'black': 30,
- 'red': 31,
- 'green': 32,
- 'yellow': 33,
- 'blue': 34,
- 'purple': 35,
- 'cyan': 36,
- 'white': 37,
-}
-
-COLOR_TAG = "color"
-HIGHLIGHT_TAG = "highlight"
-ATTRIBUTE_TAG = "attribute"
+class BaseColorFormatter(Formatter):
+ """Text color formatter class.
+
+ Wraps the logging. Uses Git shell coloring codes. Doesn't support Windows
+ CMD yet. If `fmt` is not suppied, the `style` is used. Eventually converts
+ a LogRecord object to "colored" text.
+
+ TODO:
+ Support for Windows CMD.
+ Extends:
+ logging.Formatter
+ Properties:
+ style : '%', '{' or '$' formatting.
+ datefrmt : ISO8601-like (or RFC 3339-like) format.
+ Args:
+ fmt : human-readable format. Defaults to None.
+ datefmt : ISO8601-like (or RFC 3339-like) format. Defaults to None.
+ colorfmt : Color schemas for logging levels. Defaults to None.
+ style : '%', '{' or '$' formatting. Defaults to '%'.
+ Methods:
+ format : formats a LogRecord record.
+ _parseColor : selects colors based on a logging levels.
+ """
+
+ @property
+ def style(self):
+ # type: () -> str
+ return self.__style # name mangling with __ to avoid accidents
+
+ @property
+ def colorfmt(self):
+ # type: () -> str
+ return self.__colorfmt
+
+ @style.setter
+ def style(self, value):
+ # type: (str) -> None
+ """Assign new style."""
+ self.__style = value
+
+ @colorfmt.setter
+ def colorfmt(self, value):
+ # type: (str) -> None
+ """Assign new color format."""
+ self.__colorfmt = value
+
+ def __init__(self,
+ fmt=None, # type: Optional[str]
+ datefmt=None, # type: Optional[str]
+ colorfmt=None, # type: Optional[Dict]
+ style="%"): # type: Optional[str]
+
+ if is_above_python_3_2():
+ super(BaseColorFormatter, self). \
+ __init__(fmt=fmt, # noqa: E122
+ datefmt=datefmt,
+ style=style)
+
+ elif is_above_python_2_7():
+ super(BaseColorFormatter, self). \
+ __init__(fmt, datefmt) # noqa: E122
-RESET = '\033[0m'
+ else:
+ Formatter. \
+ __init__(self, fmt, datefmt) # noqa: E122
+ self.style = style
+ self.colorfmt = colorfmt
+ def format(self, record):
+ """Text formatter.
-def colored(text, color=None, on_color=None, attrs=None):
- # It can't support windows system cmd right now!
- # TODO: colered output on windows system cmd
- if os.name in ('nt', 'ce'):
- return text
+ Connects 2 methods. First it extract a level and a colors
+ assigned to this level in the BaseColorFormatter class.
+ Second it applied the colors to the text.
- if isinstance(attrs, str):
- attrs = [attrs]
+ Args:
+ record : an instance of a logged event.
+ Returns:
+ str : "colored" text (formatted text).
+ """
- if os.getenv('ANSI_COLORS_DISABLED', None) is None:
- fmt_str = '\033[%dm%s'
- if color is not None and isinstance(color, str):
- text = fmt_str % (COLORS.get(color, 0), text)
+ if is_above_python_2_7():
+ s = super(BaseColorFormatter, self). \
+ format(record)
- if on_color is not None and isinstance(on_color, str):
- text = fmt_str % (HIGHLIGHTS.get(on_color, 0), text)
+ else:
+ s = Formatter. \
+ format(self, record)
- if attrs is not None:
- for attr in attrs:
- text = fmt_str % (ATTRIBUTES.get(attr, 0), text)
+ color, highlight, attribute = self._parse_color(record)
- # keep origin color for tail spaces
- text += RESET
- return text
+ return apply_color(s, color, highlight, attrs=attribute)
+ def _parse_color(self, record):
+ # type: (LogRecord) -> (Optional[str], Optional[str], Optional[str])
+ """Color formatter based on the logging level.
-class BaseColorFormatter(Formatter):
+ This method formats the record according to its level
+ and a color format set for that level. If the level is
+ not found, then this method will eventually return None.
- def __init__(self, fmt=None, datefmt=None, colorfmt=None, style="%"):
- if sys.version_info > (3, 2):
- super(BaseColorFormatter, self).__init__(
- fmt=fmt, datefmt=datefmt, style=style)
- elif sys.version_info > (2, 7):
- super(BaseColorFormatter, self).__init__(fmt, datefmt)
- else:
- Formatter.__init__(self, fmt, datefmt)
+ Args:
+ record : an instance of a logged event.
+ Returns:
+ str : Colors.
+ str : Hightlight tag.
+ str : Attribute tag.
+ """
+ if self.colorfmt and \
+ isinstance(self.colorfmt, dict):
- self.style = style
- if sys.version_info > (3, 2):
- if self.style not in logging._STYLES:
- raise ValueError('Style must be one of: %s' % ','.join(
- logging._STYLES.keys()))
+ level = record.levelname
+ colors = self.colorfmt.get(level, None)
- self.colorfmt = colorfmt
+ if colors is not None and \
+ isinstance(colors, dict):
+ return (colors.get(COLOR_TAG, None), # noqa: E201
+ colors.get(HIGHLIGHT_TAG, None),
+ colors.get(ATTRIBUTE_TAG, None)) # noqa: E202
+ return None, None, None
+ @deprecated(reason="Will be removed. Use _parse_color(record) instead.")
def _parseColor(self, record):
"""
- color formatter for instance:
- {
- "logging-levelname":
- {
- "color":"<COLORS>",
- "highlight":"<HIGHLIGHTS>",
- "attribute":"<ATTRIBUTES>",
- }
- }
- :param record:
- :return: text color, background color, text attribute
+ Color based on logging level.
+ See method _parse_color(record).
"""
- if self.colorfmt and isinstance(self.colorfmt, dict):
+ return self._parse_color(record)
+
+
+def apply_color(text, # type: str
+ color=None, # type: Optional[str]
+ on_color=None, # type: Optional[str]
+ attrs=None): # type: Optional[Union[str, list]]
+ # type: (...) -> str
+ """Applies color codes to the text.
+
+ Args:
+ text : text to be "colored" (formatted).
+ color : Color in human-readable format. Defaults to None.
+ highlight : Hightlight color in human-readable format.
+ Previously called "on_color". Defaults to None.
+ attrs : Colors for attribute(s). Defaults to None.
+ Returns:
+ str : "colored" text (formatted text).
+ """
+ warn("`on_color` will be replaced with `highlight`.", DeprecationWarning)
+ highlight = on_color # replace the parameter and remove
- level = record.levelname
- colors = self.colorfmt.get(level, None)
+ if os.name in ('nt', 'ce'):
+ return text
- if colors is not None and isinstance(colors, dict):
- return colors.get(COLOR_TAG, None), \
- colors.get(HIGHLIGHT_TAG, None), \
- colors.get(ATTRIBUTE_TAG, None)
+ if isinstance(attrs, str):
+ attrs = [attrs]
- return None, None, None
+ ansi_disabled = os.getenv('ANSI_COLORS_DISABLED', None)
- def format(self, record):
+ if ansi_disabled is None:
- if sys.version_info > (2, 7):
- s = super(BaseColorFormatter, self).format(record)
- else:
- s = Formatter.format(self, record)
- color, on_color, attribute = self._parseColor(record)
- return colored(s, color, on_color, attrs=attribute)
+ if color is not None and \
+ isinstance(color, str):
+ text = FMT_STR % (COLORS.get(color, 0), text)
+
+ if highlight is not None and \
+ isinstance(highlight, str):
+ text = FMT_STR % (HIGHLIGHTS.get(highlight, 0), text)
+
+ if attrs is not None:
+ for attr in attrs:
+ text = FMT_STR % (ATTRIBUTES.get(attr, 0), text)
+
+ text += RESET # keep origin color for tail spaces
+
+ return text
+
+
+@deprecated(reason="Will be removed. Call apply_color(...) instead.")
+def colored(text, color=None, on_color=None, attrs=None):
+ """
+ Format text with color codes.
+ See method apply_color(text, color, on_color, attrs).
+ """
+ return apply_color(text, color, on_color, attrs)