summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-04-13 10:21:32 +0200
committerGravatar Walter Purcaro <vuolter@users.noreply.github.com> 2015-04-13 10:21:32 +0200
commiteca20b701c411046e7ededb0462b310124ce3c18 (patch)
treec5eb36261cfc935f001b816f28f15d1f5afbf7e0 /lib
parentMerge branch 'stable' into 0.4.10 (diff)
downloadpyload-eca20b701c411046e7ededb0462b310124ce3c18.tar.xz
Cleanup + fixup + new lib
Diffstat (limited to 'lib')
-rw-r--r--lib/colorama/__init__.py7
-rw-r--r--lib/colorama/ansi.py99
-rw-r--r--lib/colorama/ansitowin32.py228
-rw-r--r--lib/colorama/initialise.py66
-rw-r--r--lib/colorama/win32.py146
-rw-r--r--lib/colorama/winterm.py151
-rw-r--r--lib/colorlog/__init__.py14
-rw-r--r--lib/colorlog/colorlog.py137
-rw-r--r--lib/colorlog/escape_codes.py57
-rw-r--r--lib/colorlog/logging.py44
10 files changed, 949 insertions, 0 deletions
diff --git a/lib/colorama/__init__.py b/lib/colorama/__init__.py
new file mode 100644
index 000000000..4af0c1e11
--- /dev/null
+++ b/lib/colorama/__init__.py
@@ -0,0 +1,7 @@
+# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
+from .initialise import init, deinit, reinit
+from .ansi import Fore, Back, Style, Cursor
+from .ansitowin32 import AnsiToWin32
+
+__version__ = '0.3.3'
+
diff --git a/lib/colorama/ansi.py b/lib/colorama/ansi.py
new file mode 100644
index 000000000..1cc722500
--- /dev/null
+++ b/lib/colorama/ansi.py
@@ -0,0 +1,99 @@
+# 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
+'''
+
+CSI = '\033['
+OSC = '\033]'
+BEL = '\007'
+
+
+def code_to_chars(code):
+ return CSI + str(code) + 'm'
+
+
+class AnsiCodes(object):
+ def __init__(self, codes):
+ for name in dir(codes):
+ if not name.startswith('_'):
+ value = getattr(codes, 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"
+
+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 AnsiFore:
+ 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:
+ 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:
+ BRIGHT = 1
+ DIM = 2
+ NORMAL = 22
+ RESET_ALL = 0
+
+Fore = AnsiCodes( AnsiFore )
+Back = AnsiCodes( AnsiBack )
+Style = AnsiCodes( AnsiStyle )
+Cursor = AnsiCursor()
diff --git a/lib/colorama/ansitowin32.py b/lib/colorama/ansitowin32.py
new file mode 100644
index 000000000..62e770c86
--- /dev/null
+++ b/lib/colorama/ansitowin32.py
@@ -0,0 +1,228 @@
+# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
+import re
+import sys
+import os
+
+from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style
+from .winterm import WinTerm, WinColor, WinStyle
+from .win32 import windll
+
+
+winterm = None
+if windll is not None:
+ winterm = WinTerm()
+
+
+def is_a_tty(stream):
+ return hasattr(stream, 'isatty') and stream.isatty()
+
+
+class StreamWrapper(object):
+ '''
+ Wraps a stream (such as stdout), acting as a transparent proxy for all
+ attribute access apart from method 'write()', which is delegated to our
+ Converter instance.
+ '''
+ def __init__(self, wrapped, converter):
+ # double-underscore everything to prevent clashes with names of
+ # attributes on the wrapped stream object.
+ self.__wrapped = wrapped
+ self.__convertor = converter
+
+ def __getattr__(self, name):
+ return getattr(self.__wrapped, name)
+
+ def write(self, text):
+ self.__convertor.write(text)
+
+
+class AnsiToWin32(object):
+ '''
+ Implements a 'write()' method which, on Windows, will strip ANSI character
+ sequences from the text, and if outputting to a tty, will convert them into
+ win32 function calls.
+ '''
+ ANSI_CSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') # Control Sequence Introducer
+ ANSI_OSC_RE = re.compile('\033\]((?:.|;)*?)(\x07)') # Operating System Command
+
+ def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
+ # The wrapped stream (normally sys.stdout or sys.stderr)
+ self.wrapped = wrapped
+
+ # should we reset colors to defaults after every .write()
+ self.autoreset = autoreset
+
+ # create the proxy wrapping our output stream
+ self.stream = StreamWrapper(wrapped, self)
+
+ on_windows = os.name == 'nt'
+ on_emulated_windows = on_windows and 'TERM' in os.environ
+
+ # should we strip ANSI sequences from our output?
+ if strip is None:
+ strip = on_windows and not on_emulated_windows
+ self.strip = strip
+
+ # should we should convert ANSI sequences into win32 calls?
+ if convert is None:
+ convert = on_windows and not wrapped.closed and not on_emulated_windows and is_a_tty(wrapped)
+ self.convert = convert
+
+ # dict of ansi codes to win32 functions and parameters
+ self.win32_calls = self.get_win32_calls()
+
+ # are we wrapping stderr?
+ self.on_stderr = self.wrapped is sys.stderr
+
+ def should_wrap(self):
+ '''
+ True if this class is actually needed. If false, then the output
+ stream will not be affected, nor will win32 calls be issued, so
+ wrapping stdout is not actually required. This will generally be
+ False on non-Windows platforms, unless optional functionality like
+ autoreset has been requested using kwargs to init()
+ '''
+ return self.convert or self.strip or self.autoreset
+
+ def get_win32_calls(self):
+ if self.convert and winterm:
+ return {
+ AnsiStyle.RESET_ALL: (winterm.reset_all, ),
+ AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
+ AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
+ AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
+ AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
+ AnsiFore.RED: (winterm.fore, WinColor.RED),
+ AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
+ AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
+ AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
+ AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
+ AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
+ AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
+ AnsiFore.RESET: (winterm.fore, ),
+ AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True),
+ AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True),
+ AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True),
+ AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True),
+ AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True),
+ AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True),
+ AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True),
+ AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True),
+ AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
+ AnsiBack.RED: (winterm.back, WinColor.RED),
+ AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
+ AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
+ AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
+ AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
+ AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
+ AnsiBack.WHITE: (winterm.back, WinColor.GREY),
+ AnsiBack.RESET: (winterm.back, ),
+ AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True),
+ AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True),
+ AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True),
+ AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True),
+ AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True),
+ AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True),
+ AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True),
+ AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True),
+ }
+ return dict()
+
+ def write(self, text):
+ if self.strip or self.convert:
+ self.write_and_convert(text)
+ else:
+ self.wrapped.write(text)
+ self.wrapped.flush()
+ if self.autoreset:
+ self.reset_all()
+
+
+ def reset_all(self):
+ if self.convert:
+ self.call_win32('m', (0,))
+ elif not self.wrapped.closed and is_a_tty(self.wrapped):
+ self.wrapped.write(Style.RESET_ALL)
+
+
+ def write_and_convert(self, text):
+ '''
+ Write the given text to our wrapped stream, stripping any ANSI
+ sequences from the text, and optionally converting them into win32
+ calls.
+ '''
+ cursor = 0
+ text = self.convert_osc(text)
+ for match in self.ANSI_CSI_RE.finditer(text):
+ start, end = match.span()
+ self.write_plain_text(text, cursor, start)
+ self.convert_ansi(*match.groups())
+ cursor = end
+ self.write_plain_text(text, cursor, len(text))
+
+
+ def write_plain_text(self, text, start, end):
+ if start < end:
+ self.wrapped.write(text[start:end])
+ self.wrapped.flush()
+
+
+ def convert_ansi(self, paramstring, command):
+ if self.convert:
+ params = self.extract_params(command, paramstring)
+ self.call_win32(command, params)
+
+
+ def extract_params(self, command, paramstring):
+ if command in 'Hf':
+ params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';'))
+ while len(params) < 2:
+ # defaults:
+ params = params + (1,)
+ else:
+ params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0)
+ if len(params) == 0:
+ # defaults:
+ if command in 'JKm':
+ params = (0,)
+ elif command in 'ABCD':
+ params = (1,)
+
+ return params
+
+
+ def call_win32(self, command, params):
+ if command == 'm':
+ for param in params:
+ if param in self.win32_calls:
+ func_args = self.win32_calls[param]
+ func = func_args[0]
+ args = func_args[1:]
+ kwargs = dict(on_stderr=self.on_stderr)
+ func(*args, **kwargs)
+ elif command in 'J':
+ winterm.erase_screen(params[0], on_stderr=self.on_stderr)
+ elif command in 'K':
+ winterm.erase_line(params[0], on_stderr=self.on_stderr)
+ elif command in 'Hf': # cursor position - absolute
+ winterm.set_cursor_position(params, on_stderr=self.on_stderr)
+ elif command in 'ABCD': # cursor position - relative
+ n = params[0]
+ # A - up, B - down, C - forward, D - back
+ x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command]
+ winterm.cursor_adjust(x, y, on_stderr=self.on_stderr)
+
+
+ def convert_osc(self, text):
+ for match in self.ANSI_OSC_RE.finditer(text):
+ start, end = match.span()
+ text = text[:start] + text[end:]
+ paramstring, command = match.groups()
+ if command in '\x07': # \x07 = BEL
+ params = paramstring.split(";")
+ # 0 - change title and icon (we will only change title)
+ # 1 - change icon (we don't support this)
+ # 2 - change title
+ if params[0] in '02':
+ winterm.set_title(params[1])
+ return text
diff --git a/lib/colorama/initialise.py b/lib/colorama/initialise.py
new file mode 100644
index 000000000..7e27f84f8
--- /dev/null
+++ b/lib/colorama/initialise.py
@@ -0,0 +1,66 @@
+# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
+import atexit
+import sys
+
+from .ansitowin32 import AnsiToWin32
+
+
+orig_stdout = sys.stdout
+orig_stderr = sys.stderr
+
+wrapped_stdout = sys.stdout
+wrapped_stderr = sys.stderr
+
+atexit_done = False
+
+
+def reset_all():
+ AnsiToWin32(orig_stdout).reset_all()
+
+
+def init(autoreset=False, convert=None, strip=None, wrap=True):
+
+ if not wrap and any([autoreset, convert, strip]):
+ raise ValueError('wrap=False conflicts with any other arg=True')
+
+ global wrapped_stdout, wrapped_stderr
+ if sys.stdout is None:
+ wrapped_stdout = None
+ else:
+ sys.stdout = wrapped_stdout = \
+ wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
+ if sys.stderr is None:
+ wrapped_stderr = None
+ else:
+ sys.stderr = wrapped_stderr = \
+ wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
+
+ global atexit_done
+ if not atexit_done:
+ atexit.register(reset_all)
+ atexit_done = True
+
+
+def deinit():
+ if orig_stdout is not None:
+ sys.stdout = orig_stdout
+ if orig_stderr is not None:
+ sys.stderr = orig_stderr
+
+
+def reinit():
+ if wrapped_stdout is not None:
+ sys.stdout = wrapped_stdout
+ if wrapped_stderr is not None:
+ sys.stderr = wrapped_stderr
+
+
+def wrap_stream(stream, convert, strip, autoreset, wrap):
+ if wrap:
+ wrapper = AnsiToWin32(stream,
+ convert=convert, strip=strip, autoreset=autoreset)
+ if wrapper.should_wrap():
+ stream = wrapper.stream
+ return stream
+
+
diff --git a/lib/colorama/win32.py b/lib/colorama/win32.py
new file mode 100644
index 000000000..c604f3721
--- /dev/null
+++ b/lib/colorama/win32.py
@@ -0,0 +1,146 @@
+# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
+
+# from winbase.h
+STDOUT = -11
+STDERR = -12
+
+try:
+ import ctypes
+ from ctypes import LibraryLoader
+ windll = LibraryLoader(ctypes.WinDLL)
+ from ctypes import wintypes
+except (AttributeError, ImportError):
+ windll = None
+ SetConsoleTextAttribute = lambda *_: None
+else:
+ from ctypes import byref, Structure, c_char, POINTER
+
+ COORD = wintypes._COORD
+
+ class CONSOLE_SCREEN_BUFFER_INFO(Structure):
+ """struct in wincon.h."""
+ _fields_ = [
+ ("dwSize", COORD),
+ ("dwCursorPosition", COORD),
+ ("wAttributes", wintypes.WORD),
+ ("srWindow", wintypes.SMALL_RECT),
+ ("dwMaximumWindowSize", COORD),
+ ]
+ def __str__(self):
+ return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
+ self.dwSize.Y, self.dwSize.X
+ , self.dwCursorPosition.Y, self.dwCursorPosition.X
+ , self.wAttributes
+ , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
+ , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
+ )
+
+ _GetStdHandle = windll.kernel32.GetStdHandle
+ _GetStdHandle.argtypes = [
+ wintypes.DWORD,
+ ]
+ _GetStdHandle.restype = wintypes.HANDLE
+
+ _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
+ _GetConsoleScreenBufferInfo.argtypes = [
+ wintypes.HANDLE,
+ POINTER(CONSOLE_SCREEN_BUFFER_INFO),
+ ]
+ _GetConsoleScreenBufferInfo.restype = wintypes.BOOL
+
+ _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
+ _SetConsoleTextAttribute.argtypes = [
+ wintypes.HANDLE,
+ wintypes.WORD,
+ ]
+ _SetConsoleTextAttribute.restype = wintypes.BOOL
+
+ _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
+ _SetConsoleCursorPosition.argtypes = [
+ wintypes.HANDLE,
+ COORD,
+ ]
+ _SetConsoleCursorPosition.restype = wintypes.BOOL
+
+ _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
+ _FillConsoleOutputCharacterA.argtypes = [
+ wintypes.HANDLE,
+ c_char,
+ wintypes.DWORD,
+ COORD,
+ POINTER(wintypes.DWORD),
+ ]
+ _FillConsoleOutputCharacterA.restype = wintypes.BOOL
+
+ _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
+ _FillConsoleOutputAttribute.argtypes = [
+ wintypes.HANDLE,
+ wintypes.WORD,
+ wintypes.DWORD,
+ COORD,
+ POINTER(wintypes.DWORD),
+ ]
+ _FillConsoleOutputAttribute.restype = wintypes.BOOL
+
+ _SetConsoleTitleW = windll.kernel32.SetConsoleTitleA
+ _SetConsoleTitleW.argtypes = [
+ wintypes.LPCSTR
+ ]
+ _SetConsoleTitleW.restype = wintypes.BOOL
+
+ handles = {
+ STDOUT: _GetStdHandle(STDOUT),
+ STDERR: _GetStdHandle(STDERR),
+ }
+
+ def GetConsoleScreenBufferInfo(stream_id=STDOUT):
+ handle = handles[stream_id]
+ csbi = CONSOLE_SCREEN_BUFFER_INFO()
+ success = _GetConsoleScreenBufferInfo(
+ handle, byref(csbi))
+ return csbi
+
+ def SetConsoleTextAttribute(stream_id, attrs):
+ handle = handles[stream_id]
+ return _SetConsoleTextAttribute(handle, attrs)
+
+ def SetConsoleCursorPosition(stream_id, position, adjust=True):
+ position = COORD(*position)
+ # If the position is out of range, do nothing.
+ if position.Y <= 0 or position.X <= 0:
+ return
+ # Adjust for Windows' SetConsoleCursorPosition:
+ # 1. being 0-based, while ANSI is 1-based.
+ # 2. expecting (x,y), while ANSI uses (y,x).
+ adjusted_position = COORD(position.Y - 1, position.X - 1)
+ if adjust:
+ # Adjust for viewport's scroll position
+ sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
+ adjusted_position.Y += sr.Top
+ adjusted_position.X += sr.Left
+ # Resume normal processing
+ handle = handles[stream_id]
+ return _SetConsoleCursorPosition(handle, adjusted_position)
+
+ def FillConsoleOutputCharacter(stream_id, char, length, start):
+ handle = handles[stream_id]
+ char = c_char(char.encode())
+ length = wintypes.DWORD(length)
+ num_written = wintypes.DWORD(0)
+ # Note that this is hard-coded for ANSI (vs wide) bytes.
+ success = _FillConsoleOutputCharacterA(
+ handle, char, length, start, byref(num_written))
+ return num_written.value
+
+ def FillConsoleOutputAttribute(stream_id, attr, length, start):
+ ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
+ handle = handles[stream_id]
+ attribute = wintypes.WORD(attr)
+ length = wintypes.DWORD(length)
+ num_written = wintypes.DWORD(0)
+ # Note that this is hard-coded for ANSI (vs wide) bytes.
+ return _FillConsoleOutputAttribute(
+ handle, attribute, length, start, byref(num_written))
+
+ def SetConsoleTitle(title):
+ return _SetConsoleTitleW(title)
diff --git a/lib/colorama/winterm.py b/lib/colorama/winterm.py
new file mode 100644
index 000000000..fcc774ffa
--- /dev/null
+++ b/lib/colorama/winterm.py
@@ -0,0 +1,151 @@
+# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
+from . import win32
+
+
+# from wincon.h
+class WinColor(object):
+ BLACK = 0
+ BLUE = 1
+ GREEN = 2
+ CYAN = 3
+ RED = 4
+ MAGENTA = 5
+ YELLOW = 6
+ GREY = 7
+
+# from wincon.h
+class WinStyle(object):
+ NORMAL = 0x00 # dim text, dim background
+ BRIGHT = 0x08 # bright text, dim background
+ BRIGHT_BACKGROUND = 0x80 # dim text, bright background
+
+class WinTerm(object):
+
+ def __init__(self):
+ self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes
+ self.set_attrs(self._default)
+ self._default_fore = self._fore
+ self._default_back = self._back
+ self._default_style = self._style
+
+ def get_attrs(self):
+ return self._fore + self._back * 16 + self._style
+
+ def set_attrs(self, value):
+ self._fore = value & 7
+ self._back = (value >> 4) & 7
+ self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND)
+
+ def reset_all(self, on_stderr=None):
+ self.set_attrs(self._default)
+ self.set_console(attrs=self._default)
+
+ def fore(self, fore=None, light=False, on_stderr=False):
+ if fore is None:
+ fore = self._default_fore
+ self._fore = fore
+ if light:
+ self._style |= WinStyle.BRIGHT
+ self.set_console(on_stderr=on_stderr)
+
+ def back(self, back=None, light=False, on_stderr=False):
+ if back is None:
+ back = self._default_back
+ self._back = back
+ if light:
+ self._style |= WinStyle.BRIGHT_BACKGROUND
+ self.set_console(on_stderr=on_stderr)
+
+ def style(self, style=None, on_stderr=False):
+ if style is None:
+ style = self._default_style
+ self._style = style
+ self.set_console(on_stderr=on_stderr)
+
+ def set_console(self, attrs=None, on_stderr=False):
+ if attrs is None:
+ attrs = self.get_attrs()
+ handle = win32.STDOUT
+ if on_stderr:
+ handle = win32.STDERR
+ win32.SetConsoleTextAttribute(handle, attrs)
+
+ def get_position(self, handle):
+ position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition
+ # Because Windows coordinates are 0-based,
+ # and win32.SetConsoleCursorPosition expects 1-based.
+ position.X += 1
+ position.Y += 1
+ return position
+
+ def set_cursor_position(self, position=None, on_stderr=False):
+ if position is None:
+ #I'm not currently tracking the position, so there is no default.
+ #position = self.get_position()
+ return
+ handle = win32.STDOUT
+ if on_stderr:
+ handle = win32.STDERR
+ win32.SetConsoleCursorPosition(handle, position)
+
+ def cursor_adjust(self, x, y, on_stderr=False):
+ handle = win32.STDOUT
+ if on_stderr:
+ handle = win32.STDERR
+ position = self.get_position(handle)
+ adjusted_position = (position.Y + y, position.X + x)
+ win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False)
+
+ def erase_screen(self, mode=0, on_stderr=False):
+ # 0 should clear from the cursor to the end of the screen.
+ # 1 should clear from the cursor to the beginning of the screen.
+ # 2 should clear the entire screen, and move cursor to (1,1)
+ handle = win32.STDOUT
+ if on_stderr:
+ handle = win32.STDERR
+ csbi = win32.GetConsoleScreenBufferInfo(handle)
+ # get the number of character cells in the current buffer
+ cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y
+ # get number of character cells before current cursor position
+ cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X
+ if mode == 0:
+ from_coord = csbi.dwCursorPosition
+ cells_to_erase = cells_in_screen - cells_before_cursor
+ if mode == 1:
+ from_coord = win32.COORD(0, 0)
+ cells_to_erase = cells_before_cursor
+ elif mode == 2:
+ from_coord = win32.COORD(0, 0)
+ cells_to_erase = cells_in_screen
+ # fill the entire screen with blanks
+ win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
+ # now set the buffer's attributes accordingly
+ win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
+ if mode == 2:
+ # put the cursor where needed
+ win32.SetConsoleCursorPosition(handle, (1, 1))
+
+ def erase_line(self, mode=0, on_stderr=False):
+ # 0 should clear from the cursor to the end of the line.
+ # 1 should clear from the cursor to the beginning of the line.
+ # 2 should clear the entire line.
+ handle = win32.STDOUT
+ if on_stderr:
+ handle = win32.STDERR
+ csbi = win32.GetConsoleScreenBufferInfo(handle)
+ if mode == 0:
+ from_coord = csbi.dwCursorPosition
+ cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X
+ if mode == 1:
+ from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
+ cells_to_erase = csbi.dwCursorPosition.X
+ elif mode == 2:
+ from_coord = win32.COORD(0, csbi.dwCursorPosition.Y)
+ cells_to_erase = csbi.dwSize.X
+ # fill the entire screen with blanks
+ win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord)
+ # now set the buffer's attributes accordingly
+ win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord)
+
+ def set_title(self, title):
+ win32.SetConsoleTitle(title)
diff --git a/lib/colorlog/__init__.py b/lib/colorlog/__init__.py
new file mode 100644
index 000000000..1d57f586d
--- /dev/null
+++ b/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/colorlog/colorlog.py b/lib/colorlog/colorlog.py
new file mode 100644
index 000000000..49860dd50
--- /dev/null
+++ b/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/colorlog/escape_codes.py b/lib/colorlog/escape_codes.py
new file mode 100644
index 000000000..848eb6489
--- /dev/null
+++ b/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/colorlog/logging.py b/lib/colorlog/logging.py
new file mode 100644
index 000000000..13f0c4ffb
--- /dev/null
+++ b/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)