diff --git a/kibot/ansi.py b/kibot/ansi.py new file mode 100644 index 00000000..e97ba2fa --- /dev/null +++ b/kibot/ansi.py @@ -0,0 +1,104 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' +import sys +import os + +CSI = '\033[' +OSC = '\033]' +BEL = '\a' +is_a_tty = sys.stderr.isatty() and os.name == 'posix' + +def code_to_chars(code): + return CSI + str(code) + 'm' if is_a_tty else '' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/kibot/log.py b/kibot/log.py index 17e5ef30..44d94511 100644 --- a/kibot/log.py +++ b/kibot/log.py @@ -12,7 +12,16 @@ Handles logging initialization and formating. import sys import logging from io import StringIO - +no_colorama = False +try: + from colorama import init as colorama_init, Fore, Back, Style +except ImportError: # pragma: no cover + no_colorama = True +# If colorama isn't installed use an ANSI basic replacement +if no_colorama: + from .ansi import Fore, Back, Style +else: + colorama_init() # Default domain, base name for the tool domain = 'kilog' filters = None @@ -105,17 +114,17 @@ class CustomFormatter(logging.Formatter): """Logging Formatter to add colors""" if sys.stderr.isatty(): - grey = "\x1b[38;21m" - yellow = "\x1b[93;1m" - red = "\x1b[91;1m" - bold_red = "\x1b[91;21m" - cyan = "\x1b[36;1m" - reset = "\x1b[0m" + white = Fore.WHITE + yellow = Fore.YELLOW + Style.BRIGHT + red = Fore.RED + Style.BRIGHT + red_alarm = Fore.RED + Back.WHITE + Style.BRIGHT + cyan = Fore.CYAN + Style.BRIGHT + reset = Style.RESET_ALL else: - grey = "" + white = "" yellow = "" red = "" - bold_red = "" + red_alarm = "" cyan = "" reset = "" # format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s " @@ -125,10 +134,10 @@ class CustomFormatter(logging.Formatter): FORMATS = { logging.DEBUG: cyan + format + reset, - logging.INFO: grey + format_simple + reset, + logging.INFO: white + format_simple + reset, logging.WARNING: yellow + format + reset, logging.ERROR: red + format + reset, - logging.CRITICAL: bold_red + format + reset + logging.CRITICAL: red_alarm + format + reset } def format(self, record): diff --git a/setup.py b/setup.py index 60a00979..70de3848 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ setup(name='kibot', # Packages are marked using __init__.py packages=find_packages(), scripts=['src/kibot', 'src/kiplot'], - install_requires=['kiauto', 'pyyaml', 'xlsxwriter'], + install_requires=['kiauto', 'pyyaml', 'xlsxwriter', 'colorama'], classifiers=['Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers',