Commit 5f8e0b8842692eeb83879771df36384ce7d2d10d

Authored by decalage2
1 parent f3d51f29

updated colorclass to v2.2.0, updated tablestream

oletools/thirdparty/colorclass/__init__.py
  1 +"""Colorful worry-free console applications for Linux, Mac OS X, and Windows.
  2 +
  3 +Supported natively on Linux and Mac OSX (Just Works), and on Windows it works the same if Windows.enable() is called.
  4 +
  5 +Gives you expected and sane results from methods like len() and .capitalize().
  6 +
  7 +https://github.com/Robpol86/colorclass
  8 +https://pypi.python.org/pypi/colorclass
  9 +"""
  10 +
  11 +from colorclass.codes import list_tags # noqa
  12 +from colorclass.color import Color # noqa
  13 +from colorclass.toggles import disable_all_colors # noqa
  14 +from colorclass.toggles import disable_if_no_tty # noqa
  15 +from colorclass.toggles import enable_all_colors # noqa
  16 +from colorclass.toggles import is_enabled # noqa
  17 +from colorclass.toggles import is_light # noqa
  18 +from colorclass.toggles import set_dark_background # noqa
  19 +from colorclass.toggles import set_light_background # noqa
  20 +from colorclass.windows import Windows # noqa
  21 +
  22 +
  23 +__all__ = (
  24 + 'Color',
  25 + 'disable_all_colors',
  26 + 'enable_all_colors',
  27 + 'is_enabled',
  28 + 'is_light',
  29 + 'list_tags',
  30 + 'set_dark_background',
  31 + 'set_light_background',
  32 + 'Windows',
  33 +)
  34 +
  35 +
  36 +__author__ = '@Robpol86'
  37 +__license__ = 'MIT'
  38 +__version__ = '2.2.0'
... ...
oletools/thirdparty/colorclass/__main__.py 0 → 100644
  1 +"""Called by "python -m". Allows package to be used as a script.
  2 +
  3 +Example usage:
  4 +echo "{red}Red{/red}" |python -m colorclass
  5 +"""
  6 +
  7 +from __future__ import print_function
  8 +
  9 +import fileinput
  10 +import os
  11 +
  12 +from colorclass.color import Color
  13 +from colorclass.toggles import disable_all_colors
  14 +from colorclass.toggles import enable_all_colors
  15 +from colorclass.toggles import set_dark_background
  16 +from colorclass.toggles import set_light_background
  17 +from colorclass.windows import Windows
  18 +
  19 +TRUTHY = ('true', '1', 'yes', 'on')
  20 +
  21 +
  22 +if __name__ == '__main__':
  23 + if os.environ.get('COLOR_ENABLE', '').lower() in TRUTHY:
  24 + enable_all_colors()
  25 + elif os.environ.get('COLOR_DISABLE', '').lower() in TRUTHY:
  26 + disable_all_colors()
  27 + if os.environ.get('COLOR_LIGHT', '').lower() in TRUTHY:
  28 + set_light_background()
  29 + elif os.environ.get('COLOR_DARK', '').lower() in TRUTHY:
  30 + set_dark_background()
  31 + Windows.enable()
  32 + for LINE in fileinput.input():
  33 + print(Color(LINE))
... ...
oletools/thirdparty/colorclass/codes.py 0 → 100644
  1 +"""Handles mapping between color names and ANSI codes and determining auto color codes."""
  2 +
  3 +import sys
  4 +from collections import Mapping
  5 +
  6 +BASE_CODES = {
  7 + '/all': 0, 'b': 1, 'f': 2, 'i': 3, 'u': 4, 'flash': 5, 'outline': 6, 'negative': 7, 'invis': 8, 'strike': 9,
  8 + '/b': 22, '/f': 22, '/i': 23, '/u': 24, '/flash': 25, '/outline': 26, '/negative': 27, '/invis': 28,
  9 + '/strike': 29, '/fg': 39, '/bg': 49,
  10 +
  11 + 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37,
  12 +
  13 + 'bgblack': 40, 'bgred': 41, 'bggreen': 42, 'bgyellow': 43, 'bgblue': 44, 'bgmagenta': 45, 'bgcyan': 46,
  14 + 'bgwhite': 47,
  15 +
  16 + 'hiblack': 90, 'hired': 91, 'higreen': 92, 'hiyellow': 93, 'hiblue': 94, 'himagenta': 95, 'hicyan': 96,
  17 + 'hiwhite': 97,
  18 +
  19 + 'hibgblack': 100, 'hibgred': 101, 'hibggreen': 102, 'hibgyellow': 103, 'hibgblue': 104, 'hibgmagenta': 105,
  20 + 'hibgcyan': 106, 'hibgwhite': 107,
  21 +
  22 + 'autored': None, 'autoblack': None, 'automagenta': None, 'autowhite': None, 'autoblue': None, 'autoyellow': None,
  23 + 'autogreen': None, 'autocyan': None,
  24 +
  25 + 'autobgred': None, 'autobgblack': None, 'autobgmagenta': None, 'autobgwhite': None, 'autobgblue': None,
  26 + 'autobgyellow': None, 'autobggreen': None, 'autobgcyan': None,
  27 +
  28 + '/black': 39, '/red': 39, '/green': 39, '/yellow': 39, '/blue': 39, '/magenta': 39, '/cyan': 39, '/white': 39,
  29 + '/hiblack': 39, '/hired': 39, '/higreen': 39, '/hiyellow': 39, '/hiblue': 39, '/himagenta': 39, '/hicyan': 39,
  30 + '/hiwhite': 39,
  31 +
  32 + '/bgblack': 49, '/bgred': 49, '/bggreen': 49, '/bgyellow': 49, '/bgblue': 49, '/bgmagenta': 49, '/bgcyan': 49,
  33 + '/bgwhite': 49, '/hibgblack': 49, '/hibgred': 49, '/hibggreen': 49, '/hibgyellow': 49, '/hibgblue': 49,
  34 + '/hibgmagenta': 49, '/hibgcyan': 49, '/hibgwhite': 49,
  35 +
  36 + '/autored': 39, '/autoblack': 39, '/automagenta': 39, '/autowhite': 39, '/autoblue': 39, '/autoyellow': 39,
  37 + '/autogreen': 39, '/autocyan': 39,
  38 +
  39 + '/autobgred': 49, '/autobgblack': 49, '/autobgmagenta': 49, '/autobgwhite': 49, '/autobgblue': 49,
  40 + '/autobgyellow': 49, '/autobggreen': 49, '/autobgcyan': 49,
  41 +}
  42 +
  43 +
  44 +class ANSICodeMapping(Mapping):
  45 + """Read-only dictionary, resolves closing tags and automatic colors. Iterates only used color tags.
  46 +
  47 + :cvar bool DISABLE_COLORS: Disable colors (strip color codes).
  48 + :cvar bool LIGHT_BACKGROUND: Use low intensity color codes.
  49 + """
  50 +
  51 + DISABLE_COLORS = False
  52 + LIGHT_BACKGROUND = False
  53 +
  54 + def __init__(self, value_markup):
  55 + """Constructor.
  56 +
  57 + :param str value_markup: String with {color} tags.
  58 + """
  59 + self.whitelist = [k for k in BASE_CODES if '{' + k + '}' in value_markup]
  60 +
  61 + def __getitem__(self, item):
  62 + """Return value for key or None if colors are disabled.
  63 +
  64 + :param str item: Key.
  65 +
  66 + :return: Color code integer.
  67 + :rtype: int
  68 + """
  69 + if item not in self.whitelist:
  70 + raise KeyError(item)
  71 + if self.DISABLE_COLORS:
  72 + return None
  73 + return getattr(self, item, BASE_CODES[item])
  74 +
  75 + def __iter__(self):
  76 + """Iterate dictionary."""
  77 + return iter(self.whitelist)
  78 +
  79 + def __len__(self):
  80 + """Dictionary length."""
  81 + return len(self.whitelist)
  82 +
  83 + @classmethod
  84 + def disable_all_colors(cls):
  85 + """Disable all colors. Strips any color tags or codes."""
  86 + cls.DISABLE_COLORS = True
  87 +
  88 + @classmethod
  89 + def enable_all_colors(cls):
  90 + """Enable all colors. Strips any color tags or codes."""
  91 + cls.DISABLE_COLORS = False
  92 +
  93 + @classmethod
  94 + def disable_if_no_tty(cls):
  95 + """Disable all colors only if there is no TTY available.
  96 +
  97 + :return: True if colors are disabled, False if stderr or stdout is a TTY.
  98 + :rtype: bool
  99 + """
  100 + if sys.stdout.isatty() or sys.stderr.isatty():
  101 + return False
  102 + cls.disable_all_colors()
  103 + return True
  104 +
  105 + @classmethod
  106 + def set_dark_background(cls):
  107 + """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
  108 + cls.LIGHT_BACKGROUND = False
  109 +
  110 + @classmethod
  111 + def set_light_background(cls):
  112 + """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
  113 + cls.LIGHT_BACKGROUND = True
  114 +
  115 + @property
  116 + def autoblack(self):
  117 + """Return automatic black foreground color depending on background color."""
  118 + return BASE_CODES['black' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiblack']
  119 +
  120 + @property
  121 + def autored(self):
  122 + """Return automatic red foreground color depending on background color."""
  123 + return BASE_CODES['red' if ANSICodeMapping.LIGHT_BACKGROUND else 'hired']
  124 +
  125 + @property
  126 + def autogreen(self):
  127 + """Return automatic green foreground color depending on background color."""
  128 + return BASE_CODES['green' if ANSICodeMapping.LIGHT_BACKGROUND else 'higreen']
  129 +
  130 + @property
  131 + def autoyellow(self):
  132 + """Return automatic yellow foreground color depending on background color."""
  133 + return BASE_CODES['yellow' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiyellow']
  134 +
  135 + @property
  136 + def autoblue(self):
  137 + """Return automatic blue foreground color depending on background color."""
  138 + return BASE_CODES['blue' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiblue']
  139 +
  140 + @property
  141 + def automagenta(self):
  142 + """Return automatic magenta foreground color depending on background color."""
  143 + return BASE_CODES['magenta' if ANSICodeMapping.LIGHT_BACKGROUND else 'himagenta']
  144 +
  145 + @property
  146 + def autocyan(self):
  147 + """Return automatic cyan foreground color depending on background color."""
  148 + return BASE_CODES['cyan' if ANSICodeMapping.LIGHT_BACKGROUND else 'hicyan']
  149 +
  150 + @property
  151 + def autowhite(self):
  152 + """Return automatic white foreground color depending on background color."""
  153 + return BASE_CODES['white' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiwhite']
  154 +
  155 + @property
  156 + def autobgblack(self):
  157 + """Return automatic black background color depending on background color."""
  158 + return BASE_CODES['bgblack' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgblack']
  159 +
  160 + @property
  161 + def autobgred(self):
  162 + """Return automatic red background color depending on background color."""
  163 + return BASE_CODES['bgred' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgred']
  164 +
  165 + @property
  166 + def autobggreen(self):
  167 + """Return automatic green background color depending on background color."""
  168 + return BASE_CODES['bggreen' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibggreen']
  169 +
  170 + @property
  171 + def autobgyellow(self):
  172 + """Return automatic yellow background color depending on background color."""
  173 + return BASE_CODES['bgyellow' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgyellow']
  174 +
  175 + @property
  176 + def autobgblue(self):
  177 + """Return automatic blue background color depending on background color."""
  178 + return BASE_CODES['bgblue' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgblue']
  179 +
  180 + @property
  181 + def autobgmagenta(self):
  182 + """Return automatic magenta background color depending on background color."""
  183 + return BASE_CODES['bgmagenta' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgmagenta']
  184 +
  185 + @property
  186 + def autobgcyan(self):
  187 + """Return automatic cyan background color depending on background color."""
  188 + return BASE_CODES['bgcyan' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgcyan']
  189 +
  190 + @property
  191 + def autobgwhite(self):
  192 + """Return automatic white background color depending on background color."""
  193 + return BASE_CODES['bgwhite' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgwhite']
  194 +
  195 +
  196 +def list_tags():
  197 + """List the available tags.
  198 +
  199 + :return: List of 4-item tuples: opening tag, closing tag, main ansi value, closing ansi value.
  200 + :rtype: list
  201 + """
  202 + # Build reverse dictionary. Keys are closing tags, values are [closing ansi, opening tag, opening ansi].
  203 + reverse_dict = dict()
  204 + for tag, ansi in sorted(BASE_CODES.items()):
  205 + if tag.startswith('/'):
  206 + reverse_dict[tag] = [ansi, None, None]
  207 + else:
  208 + reverse_dict['/' + tag][1:] = [tag, ansi]
  209 +
  210 + # Collapse
  211 + four_item_tuples = [(v[1], k, v[2], v[0]) for k, v in reverse_dict.items()]
  212 +
  213 + # Sort.
  214 + def sorter(four_item):
  215 + """Sort /all /fg /bg first, then b i u flash, then auto colors, then dark colors, finally light colors.
  216 +
  217 + :param iter four_item: [opening tag, closing tag, main ansi value, closing ansi value]
  218 +
  219 + :return Sorting weight.
  220 + :rtype: int
  221 + """
  222 + if not four_item[2]: # /all /fg /bg
  223 + return four_item[3] - 200
  224 + if four_item[2] < 10 or four_item[0].startswith('auto'): # b f i u or auto colors
  225 + return four_item[2] - 100
  226 + return four_item[2]
  227 + four_item_tuples.sort(key=sorter)
  228 +
  229 + return four_item_tuples
... ...
oletools/thirdparty/colorclass/color.py 0 → 100644
  1 +"""Color class used by library users."""
  2 +
  3 +from colorclass.core import ColorStr
  4 +
  5 +
  6 +class Color(ColorStr):
  7 + """Unicode (str in Python3) subclass with ANSI terminal text color support.
  8 +
  9 + Example syntax: Color('{red}Sample Text{/red}')
  10 +
  11 + Example without parsing logic: Color('{red}Sample Text{/red}', keep_tags=True)
  12 +
  13 + For a list of codes, call: colorclass.list_tags()
  14 + """
  15 +
  16 + @classmethod
  17 + def colorize(cls, color, string, auto=False):
  18 + """Color-code entire string using specified color.
  19 +
  20 + :param str color: Color of string.
  21 + :param str string: String to colorize.
  22 + :param bool auto: Enable auto-color (dark/light terminal).
  23 +
  24 + :return: Class instance for colorized string.
  25 + :rtype: Color
  26 + """
  27 + tag = '{0}{1}'.format('auto' if auto else '', color)
  28 + return cls('{%s}%s{/%s}' % (tag, string, tag))
  29 +
  30 + @classmethod
  31 + def black(cls, string, auto=False):
  32 + """Color-code entire string.
  33 +
  34 + :param str string: String to colorize.
  35 + :param bool auto: Enable auto-color (dark/light terminal).
  36 +
  37 + :return: Class instance for colorized string.
  38 + :rtype: Color
  39 + """
  40 + return cls.colorize('black', string, auto=auto)
  41 +
  42 + @classmethod
  43 + def bgblack(cls, string, auto=False):
  44 + """Color-code entire string.
  45 +
  46 + :param str string: String to colorize.
  47 + :param bool auto: Enable auto-color (dark/light terminal).
  48 +
  49 + :return: Class instance for colorized string.
  50 + :rtype: Color
  51 + """
  52 + return cls.colorize('bgblack', string, auto=auto)
  53 +
  54 + @classmethod
  55 + def red(cls, string, auto=False):
  56 + """Color-code entire string.
  57 +
  58 + :param str string: String to colorize.
  59 + :param bool auto: Enable auto-color (dark/light terminal).
  60 +
  61 + :return: Class instance for colorized string.
  62 + :rtype: Color
  63 + """
  64 + return cls.colorize('red', string, auto=auto)
  65 +
  66 + @classmethod
  67 + def bgred(cls, string, auto=False):
  68 + """Color-code entire string.
  69 +
  70 + :param str string: String to colorize.
  71 + :param bool auto: Enable auto-color (dark/light terminal).
  72 +
  73 + :return: Class instance for colorized string.
  74 + :rtype: Color
  75 + """
  76 + return cls.colorize('bgred', string, auto=auto)
  77 +
  78 + @classmethod
  79 + def green(cls, string, auto=False):
  80 + """Color-code entire string.
  81 +
  82 + :param str string: String to colorize.
  83 + :param bool auto: Enable auto-color (dark/light terminal).
  84 +
  85 + :return: Class instance for colorized string.
  86 + :rtype: Color
  87 + """
  88 + return cls.colorize('green', string, auto=auto)
  89 +
  90 + @classmethod
  91 + def bggreen(cls, string, auto=False):
  92 + """Color-code entire string.
  93 +
  94 + :param str string: String to colorize.
  95 + :param bool auto: Enable auto-color (dark/light terminal).
  96 +
  97 + :return: Class instance for colorized string.
  98 + :rtype: Color
  99 + """
  100 + return cls.colorize('bggreen', string, auto=auto)
  101 +
  102 + @classmethod
  103 + def yellow(cls, string, auto=False):
  104 + """Color-code entire string.
  105 +
  106 + :param str string: String to colorize.
  107 + :param bool auto: Enable auto-color (dark/light terminal).
  108 +
  109 + :return: Class instance for colorized string.
  110 + :rtype: Color
  111 + """
  112 + return cls.colorize('yellow', string, auto=auto)
  113 +
  114 + @classmethod
  115 + def bgyellow(cls, string, auto=False):
  116 + """Color-code entire string.
  117 +
  118 + :param str string: String to colorize.
  119 + :param bool auto: Enable auto-color (dark/light terminal).
  120 +
  121 + :return: Class instance for colorized string.
  122 + :rtype: Color
  123 + """
  124 + return cls.colorize('bgyellow', string, auto=auto)
  125 +
  126 + @classmethod
  127 + def blue(cls, string, auto=False):
  128 + """Color-code entire string.
  129 +
  130 + :param str string: String to colorize.
  131 + :param bool auto: Enable auto-color (dark/light terminal).
  132 +
  133 + :return: Class instance for colorized string.
  134 + :rtype: Color
  135 + """
  136 + return cls.colorize('blue', string, auto=auto)
  137 +
  138 + @classmethod
  139 + def bgblue(cls, string, auto=False):
  140 + """Color-code entire string.
  141 +
  142 + :param str string: String to colorize.
  143 + :param bool auto: Enable auto-color (dark/light terminal).
  144 +
  145 + :return: Class instance for colorized string.
  146 + :rtype: Color
  147 + """
  148 + return cls.colorize('bgblue', string, auto=auto)
  149 +
  150 + @classmethod
  151 + def magenta(cls, string, auto=False):
  152 + """Color-code entire string.
  153 +
  154 + :param str string: String to colorize.
  155 + :param bool auto: Enable auto-color (dark/light terminal).
  156 +
  157 + :return: Class instance for colorized string.
  158 + :rtype: Color
  159 + """
  160 + return cls.colorize('magenta', string, auto=auto)
  161 +
  162 + @classmethod
  163 + def bgmagenta(cls, string, auto=False):
  164 + """Color-code entire string.
  165 +
  166 + :param str string: String to colorize.
  167 + :param bool auto: Enable auto-color (dark/light terminal).
  168 +
  169 + :return: Class instance for colorized string.
  170 + :rtype: Color
  171 + """
  172 + return cls.colorize('bgmagenta', string, auto=auto)
  173 +
  174 + @classmethod
  175 + def cyan(cls, string, auto=False):
  176 + """Color-code entire string.
  177 +
  178 + :param str string: String to colorize.
  179 + :param bool auto: Enable auto-color (dark/light terminal).
  180 +
  181 + :return: Class instance for colorized string.
  182 + :rtype: Color
  183 + """
  184 + return cls.colorize('cyan', string, auto=auto)
  185 +
  186 + @classmethod
  187 + def bgcyan(cls, string, auto=False):
  188 + """Color-code entire string.
  189 +
  190 + :param str string: String to colorize.
  191 + :param bool auto: Enable auto-color (dark/light terminal).
  192 +
  193 + :return: Class instance for colorized string.
  194 + :rtype: Color
  195 + """
  196 + return cls.colorize('bgcyan', string, auto=auto)
  197 +
  198 + @classmethod
  199 + def white(cls, string, auto=False):
  200 + """Color-code entire string.
  201 +
  202 + :param str string: String to colorize.
  203 + :param bool auto: Enable auto-color (dark/light terminal).
  204 +
  205 + :return: Class instance for colorized string.
  206 + :rtype: Color
  207 + """
  208 + return cls.colorize('white', string, auto=auto)
  209 +
  210 + @classmethod
  211 + def bgwhite(cls, string, auto=False):
  212 + """Color-code entire string.
  213 +
  214 + :param str string: String to colorize.
  215 + :param bool auto: Enable auto-color (dark/light terminal).
  216 +
  217 + :return: Class instance for colorized string.
  218 + :rtype: Color
  219 + """
  220 + return cls.colorize('bgwhite', string, auto=auto)
... ...
oletools/thirdparty/colorclass/colorclass.py deleted
1   -"""Colorful worry-free console applications for Linux, Mac OS X, and Windows.
2   -
3   -Supported natively on Linux and Mac OSX (Just Works), and on Windows it works the same if Windows.enable() is called.
4   -
5   -Gives you expected and sane results from methods like len() and .capitalize().
6   -
7   -https://github.com/Robpol86/colorclass
8   -https://pypi.python.org/pypi/colorclass
9   -"""
10   -
11   -import atexit
12   -from collections import Mapping
13   -import ctypes
14   -import os
15   -import re
16   -import sys
17   -
18   -if os.name == 'nt':
19   - import ctypes.wintypes
20   -
21   -__author__ = '@Robpol86'
22   -__license__ = 'MIT'
23   -__version__ = '1.2.0'
24   -_BASE_CODES = {
25   - '/all': 0, 'b': 1, 'f': 2, 'i': 3, 'u': 4, 'flash': 5, 'outline': 6, 'negative': 7, 'invis': 8, 'strike': 9,
26   - '/b': 22, '/f': 22, '/i': 23, '/u': 24, '/flash': 25, '/outline': 26, '/negative': 27, '/invis': 28,
27   - '/strike': 29, '/fg': 39, '/bg': 49,
28   -
29   - 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37,
30   -
31   - 'bgblack': 40, 'bgred': 41, 'bggreen': 42, 'bgyellow': 43, 'bgblue': 44, 'bgmagenta': 45, 'bgcyan': 46,
32   - 'bgwhite': 47,
33   -
34   - 'hiblack': 90, 'hired': 91, 'higreen': 92, 'hiyellow': 93, 'hiblue': 94, 'himagenta': 95, 'hicyan': 96,
35   - 'hiwhite': 97,
36   -
37   - 'hibgblack': 100, 'hibgred': 101, 'hibggreen': 102, 'hibgyellow': 103, 'hibgblue': 104, 'hibgmagenta': 105,
38   - 'hibgcyan': 106, 'hibgwhite': 107,
39   -
40   - 'autored': None, 'autoblack': None, 'automagenta': None, 'autowhite': None, 'autoblue': None, 'autoyellow': None,
41   - 'autogreen': None, 'autocyan': None,
42   -
43   - 'autobgred': None, 'autobgblack': None, 'autobgmagenta': None, 'autobgwhite': None, 'autobgblue': None,
44   - 'autobgyellow': None, 'autobggreen': None, 'autobgcyan': None,
45   -
46   - '/black': 39, '/red': 39, '/green': 39, '/yellow': 39, '/blue': 39, '/magenta': 39, '/cyan': 39, '/white': 39,
47   - '/hiblack': 39, '/hired': 39, '/higreen': 39, '/hiyellow': 39, '/hiblue': 39, '/himagenta': 39, '/hicyan': 39,
48   - '/hiwhite': 39,
49   -
50   - '/bgblack': 49, '/bgred': 49, '/bggreen': 49, '/bgyellow': 49, '/bgblue': 49, '/bgmagenta': 49, '/bgcyan': 49,
51   - '/bgwhite': 49, '/hibgblack': 49, '/hibgred': 49, '/hibggreen': 49, '/hibgyellow': 49, '/hibgblue': 49,
52   - '/hibgmagenta': 49, '/hibgcyan': 49, '/hibgwhite': 49,
53   -
54   - '/autored': 39, '/autoblack': 39, '/automagenta': 39, '/autowhite': 39, '/autoblue': 39, '/autoyellow': 39,
55   - '/autogreen': 39, '/autocyan': 39,
56   -
57   - '/autobgred': 49, '/autobgblack': 49, '/autobgmagenta': 49, '/autobgwhite': 49, '/autobgblue': 49,
58   - '/autobgyellow': 49, '/autobggreen': 49, '/autobgcyan': 49,
59   -}
60   -_WINDOWS_CODES = {
61   - '/all': -33, '/fg': -39, '/bg': -49,
62   -
63   - 'black': 0, 'red': 4, 'green': 2, 'yellow': 6, 'blue': 1, 'magenta': 5, 'cyan': 3, 'white': 7,
64   -
65   - 'bgblack': -8, 'bgred': 64, 'bggreen': 32, 'bgyellow': 96, 'bgblue': 16, 'bgmagenta': 80, 'bgcyan': 48,
66   - 'bgwhite': 112,
67   -
68   - 'hiblack': 8, 'hired': 12, 'higreen': 10, 'hiyellow': 14, 'hiblue': 9, 'himagenta': 13, 'hicyan': 11, 'hiwhite': 15,
69   -
70   - 'hibgblack': 128, 'hibgred': 192, 'hibggreen': 160, 'hibgyellow': 224, 'hibgblue': 144, 'hibgmagenta': 208,
71   - 'hibgcyan': 176, 'hibgwhite': 240,
72   -
73   - '/black': -39, '/red': -39, '/green': -39, '/yellow': -39, '/blue': -39, '/magenta': -39, '/cyan': -39,
74   - '/white': -39, '/hiblack': -39, '/hired': -39, '/higreen': -39, '/hiyellow': -39, '/hiblue': -39, '/himagenta': -39,
75   - '/hicyan': -39, '/hiwhite': -39,
76   -
77   - '/bgblack': -49, '/bgred': -49, '/bggreen': -49, '/bgyellow': -49, '/bgblue': -49, '/bgmagenta': -49,
78   - '/bgcyan': -49, '/bgwhite': -49, '/hibgblack': -49, '/hibgred': -49, '/hibggreen': -49, '/hibgyellow': -49,
79   - '/hibgblue': -49, '/hibgmagenta': -49, '/hibgcyan': -49, '/hibgwhite': -49,
80   -}
81   -_RE_GROUP_SEARCH = re.compile(r'(?:\033\[[\d;]+m)+')
82   -_RE_NUMBER_SEARCH = re.compile(r'\033\[([\d;]+)m')
83   -_RE_SPLIT = re.compile(r'(\033\[[\d;]+m)')
84   -PARENT_CLASS = type(u'')
85   -
86   -
87   -class _AutoCodes(Mapping):
88   - """Read-only subclass of dict, resolves closing tags (based on colorclass.CODES) and automatic colors."""
89   - DISABLE_COLORS = False
90   - LIGHT_BACKGROUND = False
91   -
92   - def __init__(self):
93   - self.__dict = _BASE_CODES.copy()
94   -
95   - def __getitem__(self, item):
96   - if item == 'autoblack':
97   - answer = self.autoblack
98   - elif item == 'autored':
99   - answer = self.autored
100   - elif item == 'autogreen':
101   - answer = self.autogreen
102   - elif item == 'autoyellow':
103   - answer = self.autoyellow
104   - elif item == 'autoblue':
105   - answer = self.autoblue
106   - elif item == 'automagenta':
107   - answer = self.automagenta
108   - elif item == 'autocyan':
109   - answer = self.autocyan
110   - elif item == 'autowhite':
111   - answer = self.autowhite
112   - elif item == 'autobgblack':
113   - answer = self.autobgblack
114   - elif item == 'autobgred':
115   - answer = self.autobgred
116   - elif item == 'autobggreen':
117   - answer = self.autobggreen
118   - elif item == 'autobgyellow':
119   - answer = self.autobgyellow
120   - elif item == 'autobgblue':
121   - answer = self.autobgblue
122   - elif item == 'autobgmagenta':
123   - answer = self.autobgmagenta
124   - elif item == 'autobgcyan':
125   - answer = self.autobgcyan
126   - elif item == 'autobgwhite':
127   - answer = self.autobgwhite
128   - else:
129   - answer = self.__dict[item]
130   - return answer
131   -
132   - def __iter__(self):
133   - return iter(self.__dict)
134   -
135   - def __len__(self):
136   - return len(self.__dict)
137   -
138   - @property
139   - def autoblack(self):
140   - """Returns automatic black foreground color depending on background color."""
141   - return self.__dict['black' if _AutoCodes.LIGHT_BACKGROUND else 'hiblack']
142   -
143   - @property
144   - def autored(self):
145   - """Returns automatic red foreground color depending on background color."""
146   - return self.__dict['red' if _AutoCodes.LIGHT_BACKGROUND else 'hired']
147   -
148   - @property
149   - def autogreen(self):
150   - """Returns automatic green foreground color depending on background color."""
151   - return self.__dict['green' if _AutoCodes.LIGHT_BACKGROUND else 'higreen']
152   -
153   - @property
154   - def autoyellow(self):
155   - """Returns automatic yellow foreground color depending on background color."""
156   - return self.__dict['yellow' if _AutoCodes.LIGHT_BACKGROUND else 'hiyellow']
157   -
158   - @property
159   - def autoblue(self):
160   - """Returns automatic blue foreground color depending on background color."""
161   - return self.__dict['blue' if _AutoCodes.LIGHT_BACKGROUND else 'hiblue']
162   -
163   - @property
164   - def automagenta(self):
165   - """Returns automatic magenta foreground color depending on background color."""
166   - return self.__dict['magenta' if _AutoCodes.LIGHT_BACKGROUND else 'himagenta']
167   -
168   - @property
169   - def autocyan(self):
170   - """Returns automatic cyan foreground color depending on background color."""
171   - return self.__dict['cyan' if _AutoCodes.LIGHT_BACKGROUND else 'hicyan']
172   -
173   - @property
174   - def autowhite(self):
175   - """Returns automatic white foreground color depending on background color."""
176   - return self.__dict['white' if _AutoCodes.LIGHT_BACKGROUND else 'hiwhite']
177   -
178   - @property
179   - def autobgblack(self):
180   - """Returns automatic black background color depending on background color."""
181   - return self.__dict['bgblack' if _AutoCodes.LIGHT_BACKGROUND else 'hibgblack']
182   -
183   - @property
184   - def autobgred(self):
185   - """Returns automatic red background color depending on background color."""
186   - return self.__dict['bgred' if _AutoCodes.LIGHT_BACKGROUND else 'hibgred']
187   -
188   - @property
189   - def autobggreen(self):
190   - """Returns automatic green background color depending on background color."""
191   - return self.__dict['bggreen' if _AutoCodes.LIGHT_BACKGROUND else 'hibggreen']
192   -
193   - @property
194   - def autobgyellow(self):
195   - """Returns automatic yellow background color depending on background color."""
196   - return self.__dict['bgyellow' if _AutoCodes.LIGHT_BACKGROUND else 'hibgyellow']
197   -
198   - @property
199   - def autobgblue(self):
200   - """Returns automatic blue background color depending on background color."""
201   - return self.__dict['bgblue' if _AutoCodes.LIGHT_BACKGROUND else 'hibgblue']
202   -
203   - @property
204   - def autobgmagenta(self):
205   - """Returns automatic magenta background color depending on background color."""
206   - return self.__dict['bgmagenta' if _AutoCodes.LIGHT_BACKGROUND else 'hibgmagenta']
207   -
208   - @property
209   - def autobgcyan(self):
210   - """Returns automatic cyan background color depending on background color."""
211   - return self.__dict['bgcyan' if _AutoCodes.LIGHT_BACKGROUND else 'hibgcyan']
212   -
213   - @property
214   - def autobgwhite(self):
215   - """Returns automatic white background color depending on background color."""
216   - return self.__dict['bgwhite' if _AutoCodes.LIGHT_BACKGROUND else 'hibgwhite']
217   -
218   -
219   -def _pad_input(incoming):
220   - """Avoid IndexError and KeyError by ignoring un-related fields.
221   -
222   - Example: '{0}{autored}' becomes '{{0}}{autored}'.
223   -
224   - Positional arguments:
225   - incoming -- the input unicode value.
226   -
227   - Returns:
228   - Padded unicode value.
229   - """
230   - incoming_expanded = incoming.replace('{', '{{').replace('}', '}}')
231   - for key in _BASE_CODES:
232   - before, after = '{{%s}}' % key, '{%s}' % key
233   - if before in incoming_expanded:
234   - incoming_expanded = incoming_expanded.replace(before, after)
235   - return incoming_expanded
236   -
237   -
238   -def _parse_input(incoming):
239   - """Performs the actual conversion of tags to ANSI escaped codes.
240   -
241   - Provides a version of the input without any colors for len() and other methods.
242   -
243   - Positional arguments:
244   - incoming -- the input unicode value.
245   -
246   - Returns:
247   - 2-item tuple. First item is the parsed output. Second item is a version of the input without any colors.
248   - """
249   - codes = dict((k, v) for k, v in _AutoCodes().items() if '{%s}' % k in incoming)
250   - color_codes = dict((k, '' if _AutoCodes.DISABLE_COLORS else '\033[{0}m'.format(v)) for k, v in codes.items())
251   - incoming_padded = _pad_input(incoming)
252   - output_colors = incoming_padded.format(**color_codes)
253   -
254   - # Simplify: '{b}{red}' -> '\033[1m\033[31m' -> '\033[1;31m'
255   - groups = sorted(set(_RE_GROUP_SEARCH.findall(output_colors)), key=len, reverse=True) # Get codes, grouped adjacent.
256   - groups_simplified = [[x for n in _RE_NUMBER_SEARCH.findall(i) for x in n.split(';')] for i in groups]
257   - groups_compiled = ['\033[{0}m'.format(';'.join(g)) for g in groups_simplified] # Final codes.
258   - assert len(groups_compiled) == len(groups) # For testing.
259   - output_colors_simplified = output_colors
260   - for i in range(len(groups)):
261   - output_colors_simplified = output_colors_simplified.replace(groups[i], groups_compiled[i])
262   - output_no_colors = _RE_SPLIT.sub('', output_colors_simplified)
263   -
264   - # Strip any remaining color codes.
265   - if _AutoCodes.DISABLE_COLORS:
266   - output_colors_simplified = _RE_NUMBER_SEARCH.sub('', output_colors_simplified)
267   -
268   - return output_colors_simplified, output_no_colors
269   -
270   -
271   -def disable_all_colors():
272   - """Disable all colors. Strips any color tags or codes."""
273   - _AutoCodes.DISABLE_COLORS = True
274   -
275   -
276   -def set_light_background():
277   - """Chooses dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
278   - _AutoCodes.DISABLE_COLORS = False
279   - _AutoCodes.LIGHT_BACKGROUND = True
280   -
281   -
282   -def set_dark_background():
283   - """Chooses dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
284   - _AutoCodes.DISABLE_COLORS = False
285   - _AutoCodes.LIGHT_BACKGROUND = False
286   -
287   -
288   -def list_tags():
289   - """Lists the available tags.
290   -
291   - Returns:
292   - Tuple of tuples. Child tuples are four items: ('opening tag', 'closing tag', main ansi value, closing ansi value).
293   - """
294   - codes = _AutoCodes()
295   - grouped = set([(k, '/{0}'.format(k), codes[k], codes['/{0}'.format(k)]) for k in codes if not k.startswith('/')])
296   -
297   - # Add half-tags like /all.
298   - found = [c for r in grouped for c in r[:2]]
299   - missing = set([('', r[0], None, r[1]) if r[0].startswith('/') else (r[0], '', r[1], None)
300   - for r in _AutoCodes().items() if r[0] not in found])
301   - grouped |= missing
302   -
303   - # Sort.
304   - payload = sorted([i for i in grouped if i[2] is None], key=lambda x: x[3]) # /all /fg /bg
305   - grouped -= set(payload)
306   - payload.extend(sorted([i for i in grouped if i[2] < 10], key=lambda x: x[2])) # b i u flash
307   - grouped -= set(payload)
308   - payload.extend(sorted([i for i in grouped if i[0].startswith('auto')], key=lambda x: x[2])) # auto colors
309   - grouped -= set(payload)
310   - payload.extend(sorted([i for i in grouped if not i[0].startswith('hi')], key=lambda x: x[2])) # dark colors
311   - grouped -= set(payload)
312   - payload.extend(sorted(grouped, key=lambda x: x[2])) # light colors
313   - return tuple(payload)
314   -
315   -
316   -class ColorBytes(bytes):
317   - """Str (bytes in Python3) subclass, .decode() overridden to return Color() instance."""
318   -
319   - def decode(*args, **kwargs):
320   - return Color(super(ColorBytes, args[0]).decode(*args[1:], **kwargs))
321   -
322   -
323   -class Color(PARENT_CLASS):
324   - """Unicode (str in Python3) subclass with ANSI terminal text color support.
325   -
326   - Example syntax: Color('{red}Sample Text{/red}')
327   -
328   - For a list of codes, call: colorclass.list_tags()
329   - """
330   -
331   - @classmethod
332   - def red(cls, s, auto=False):
333   - return cls.colorize('red', s, auto=auto)
334   -
335   - @classmethod
336   - def bgred(cls, s, auto=False):
337   - return cls.colorize('bgred', s, auto=auto)
338   -
339   - @classmethod
340   - def green(cls, s, auto=False):
341   - return cls.colorize('green', s, auto=auto)
342   -
343   - @classmethod
344   - def bggreen(cls, s, auto=False):
345   - return cls.colorize('bggreen', s, auto=auto)
346   -
347   - @classmethod
348   - def blue(cls, s, auto=False):
349   - return cls.colorize('blue', s, auto=auto)
350   -
351   - @classmethod
352   - def bgblue(cls, s, auto=False):
353   - return cls.colorize('bgblue', s, auto=auto)
354   -
355   - @classmethod
356   - def yellow(cls, s, auto=False):
357   - return cls.colorize('yellow', s, auto=auto)
358   -
359   - @classmethod
360   - def bgyellow(cls, s, auto=False):
361   - return cls.colorize('bgyellow', s, auto=auto)
362   -
363   - @classmethod
364   - def cyan(cls, s, auto=False):
365   - return cls.colorize('cyan', s, auto=auto)
366   -
367   - @classmethod
368   - def bgcyan(cls, s, auto=False):
369   - return cls.colorize('bgcyan', s, auto=auto)
370   -
371   - @classmethod
372   - def magenta(cls, s, auto=False):
373   - return cls.colorize('magenta', s, auto=auto)
374   -
375   - @classmethod
376   - def bgmagenta(cls, s, auto=False):
377   - return cls.colorize('bgmagenta', s, auto=auto)
378   -
379   - @classmethod
380   - def colorize(cls, color, s, auto=False):
381   - tag = '{0}{1}'.format('auto' if auto else '', color)
382   - return cls('{%s}%s{/%s}' % (tag, s, tag))
383   -
384   - def __new__(cls, *args, **kwargs):
385   - parent_class = cls.__bases__[0]
386   - value_markup = args[0] if args else parent_class()
387   - value_colors, value_no_colors = _parse_input(value_markup)
388   - if args:
389   - args = [value_colors] + list(args[1:])
390   -
391   - obj = parent_class.__new__(cls, *args, **kwargs)
392   - obj.value_colors, obj.value_no_colors = value_colors, value_no_colors
393   - obj.has_colors = bool(_RE_NUMBER_SEARCH.match(value_colors))
394   - return obj
395   -
396   - def __len__(self):
397   - return self.value_no_colors.__len__()
398   -
399   - def capitalize(self):
400   - split = _RE_SPLIT.split(self.value_colors)
401   - for i in range(len(split)):
402   - if _RE_SPLIT.match(split[i]):
403   - continue
404   - split[i] = PARENT_CLASS(split[i]).capitalize()
405   - return Color().join(split)
406   -
407   - def center(self, width, fillchar=None):
408   - if fillchar is not None:
409   - result = PARENT_CLASS(self.value_no_colors).center(width, fillchar)
410   - else:
411   - result = PARENT_CLASS(self.value_no_colors).center(width)
412   - return result.replace(self.value_no_colors, self.value_colors)
413   -
414   - def count(self, *args, **kwargs):
415   - return PARENT_CLASS(self.value_no_colors).count(*args, **kwargs)
416   -
417   - def endswith(self, *args, **kwargs):
418   - return PARENT_CLASS(self.value_no_colors).endswith(*args, **kwargs)
419   -
420   - def encode(*args, **kwargs):
421   - return ColorBytes(super(Color, args[0]).encode(*args[1:], **kwargs))
422   -
423   - def decode(*args, **kwargs):
424   - return Color(super(Color, args[0]).decode(*args[1:], **kwargs))
425   -
426   - def find(self, *args, **kwargs):
427   - return PARENT_CLASS(self.value_no_colors).find(*args, **kwargs)
428   -
429   - def format(*args, **kwargs):
430   - return Color(super(Color, args[0]).format(*args[1:], **kwargs))
431   -
432   - def index(self, *args, **kwargs):
433   - return PARENT_CLASS(self.value_no_colors).index(*args, **kwargs)
434   -
435   - def isalnum(self):
436   - return PARENT_CLASS(self.value_no_colors).isalnum()
437   -
438   - def isalpha(self):
439   - return PARENT_CLASS(self.value_no_colors).isalpha()
440   -
441   - def isdecimal(self):
442   - return PARENT_CLASS(self.value_no_colors).isdecimal()
443   -
444   - def isdigit(self):
445   - return PARENT_CLASS(self.value_no_colors).isdigit()
446   -
447   - def isnumeric(self):
448   - return PARENT_CLASS(self.value_no_colors).isnumeric()
449   -
450   - def isspace(self):
451   - return PARENT_CLASS(self.value_no_colors).isspace()
452   -
453   - def istitle(self):
454   - return PARENT_CLASS(self.value_no_colors).istitle()
455   -
456   - def isupper(self):
457   - return PARENT_CLASS(self.value_no_colors).isupper()
458   -
459   - def ljust(self, width, fillchar=None):
460   - if fillchar is not None:
461   - result = PARENT_CLASS(self.value_no_colors).ljust(width, fillchar)
462   - else:
463   - result = PARENT_CLASS(self.value_no_colors).ljust(width)
464   - return result.replace(self.value_no_colors, self.value_colors)
465   -
466   - def rfind(self, *args, **kwargs):
467   - return PARENT_CLASS(self.value_no_colors).rfind(*args, **kwargs)
468   -
469   - def rindex(self, *args, **kwargs):
470   - return PARENT_CLASS(self.value_no_colors).rindex(*args, **kwargs)
471   -
472   - def rjust(self, width, fillchar=None):
473   - if fillchar is not None:
474   - result = PARENT_CLASS(self.value_no_colors).rjust(width, fillchar)
475   - else:
476   - result = PARENT_CLASS(self.value_no_colors).rjust(width)
477   - return result.replace(self.value_no_colors, self.value_colors)
478   -
479   - def splitlines(self):
480   - return [Color(l) for l in PARENT_CLASS(self.value_colors).splitlines()]
481   -
482   - def startswith(self, *args, **kwargs):
483   - return PARENT_CLASS(self.value_no_colors).startswith(*args, **kwargs)
484   -
485   - def swapcase(self):
486   - split = _RE_SPLIT.split(self.value_colors)
487   - for i in range(len(split)):
488   - if _RE_SPLIT.match(split[i]):
489   - continue
490   - split[i] = PARENT_CLASS(split[i]).swapcase()
491   - return Color().join(split)
492   -
493   - def title(self):
494   - split = _RE_SPLIT.split(self.value_colors)
495   - for i in range(len(split)):
496   - if _RE_SPLIT.match(split[i]):
497   - continue
498   - split[i] = PARENT_CLASS(split[i]).title()
499   - return Color().join(split)
500   -
501   - def translate(self, table):
502   - split = _RE_SPLIT.split(self.value_colors)
503   - for i in range(len(split)):
504   - if _RE_SPLIT.match(split[i]):
505   - continue
506   - split[i] = PARENT_CLASS(split[i]).translate(table)
507   - return Color().join(split)
508   -
509   - def upper(self):
510   - split = _RE_SPLIT.split(self.value_colors)
511   - for i in range(len(split)):
512   - if _RE_SPLIT.match(split[i]):
513   - continue
514   - split[i] = PARENT_CLASS(split[i]).upper()
515   - return Color().join(split)
516   -
517   - def zfill(self, width):
518   - if not self.value_no_colors:
519   - return PARENT_CLASS().zfill(width)
520   -
521   - split = _RE_SPLIT.split(self.value_colors)
522   - filled = PARENT_CLASS(self.value_no_colors).zfill(width)
523   - if len(split) == 1:
524   - return filled
525   -
526   - padding = filled.replace(self.value_no_colors, '')
527   - if not split[0]:
528   - split[2] = padding + split[2]
529   - else:
530   - split[0] = padding + split[0]
531   -
532   - return Color().join(split)
533   -
534   -
535   -class Windows(object):
536   - """Enable and disable Windows support for ANSI color character codes.
537   -
538   - Call static method Windows.enable() to enable color support for the remainder of the process' lifetime.
539   -
540   - This class is also a context manager. You can do this:
541   - with Windows():
542   - print(Color('{autored}Test{/autored}'))
543   -
544   - Or this:
545   - with Windows(auto_colors=True):
546   - print(Color('{autored}Test{/autored}'))
547   - """
548   -
549   - @staticmethod
550   - def disable():
551   - """Restore sys.stderr and sys.stdout to their original objects. Resets colors to their original values."""
552   - if os.name != 'nt' or not Windows.is_enabled():
553   - return False
554   -
555   - getattr(sys.stderr, '_reset_colors', lambda: False)()
556   - getattr(sys.stdout, '_reset_colors', lambda: False)()
557   -
558   - if hasattr(sys.stderr, 'ORIGINAL_STREAM'):
559   - sys.stderr = getattr(sys.stderr, 'ORIGINAL_STREAM')
560   - if hasattr(sys.stdout, 'ORIGINAL_STREAM'):
561   - sys.stdout = getattr(sys.stdout, 'ORIGINAL_STREAM')
562   -
563   - return True
564   -
565   - @staticmethod
566   - def is_enabled():
567   - """Returns True if either stderr or stdout has colors enabled."""
568   - return hasattr(sys.stderr, 'ORIGINAL_STREAM') or hasattr(sys.stdout, 'ORIGINAL_STREAM')
569   -
570   - @staticmethod
571   - def enable(auto_colors=False, reset_atexit=False):
572   - """Enables color text with print() or sys.stdout.write() (stderr too).
573   -
574   - Keyword arguments:
575   - auto_colors -- automatically selects dark or light colors based on current terminal's background color. Only
576   - works with {autored} and related tags.
577   - reset_atexit -- resets original colors upon Python exit (in case you forget to reset it yourself with a closing
578   - tag).
579   - """
580   - if os.name != 'nt':
581   - return False
582   -
583   - # Overwrite stream references.
584   - if not hasattr(sys.stderr, 'ORIGINAL_STREAM'):
585   - sys.stderr.flush()
586   - sys.stderr = _WindowsStreamStdErr()
587   - if not hasattr(sys.stdout, 'ORIGINAL_STREAM'):
588   - sys.stdout.flush()
589   - sys.stdout = _WindowsStreamStdOut()
590   - if not hasattr(sys.stderr, 'ORIGINAL_STREAM') and not hasattr(sys.stdout, 'ORIGINAL_STREAM'):
591   - return False
592   -
593   - # Automatically select which colors to display.
594   - bg_color = getattr(sys.stdout, 'default_bg', getattr(sys.stderr, 'default_bg', None))
595   - if auto_colors and bg_color is not None:
596   - set_light_background() if bg_color in (112, 96, 240, 176, 224, 208, 160) else set_dark_background()
597   -
598   - # Reset on exit if requested.
599   - if reset_atexit:
600   - atexit.register(lambda: Windows.disable())
601   -
602   - return True
603   -
604   - def __init__(self, auto_colors=False):
605   - self.auto_colors = auto_colors
606   -
607   - def __enter__(self):
608   - Windows.enable(auto_colors=self.auto_colors)
609   -
610   - def __exit__(self, *_):
611   - Windows.disable()
612   -
613   -
614   -class _WindowsCSBI(object):
615   - """Interfaces with Windows CONSOLE_SCREEN_BUFFER_INFO API/DLL calls. Gets info for stderr and stdout.
616   -
617   - References:
618   - http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231
619   - https://code.google.com/p/colorama/issues/detail?id=47.
620   - pytest's py project: py/_io/terminalwriter.py.
621   -
622   - Class variables:
623   - CSBI -- ConsoleScreenBufferInfo class/struct (not instance, the class definition itself) defined in _define_csbi().
624   - HANDLE_STDERR -- GetStdHandle() return integer for stderr.
625   - HANDLE_STDOUT -- GetStdHandle() return integer for stdout.
626   - WINDLL -- my own loaded instance of ctypes.WinDLL.
627   - """
628   -
629   - CSBI = None
630   - HANDLE_STDERR = None
631   - HANDLE_STDOUT = None
632   - WINDLL = ctypes.LibraryLoader(getattr(ctypes, 'WinDLL', None))
633   -
634   - @staticmethod
635   - def _define_csbi():
636   - """Defines structs and populates _WindowsCSBI.CSBI."""
637   - if _WindowsCSBI.CSBI is not None:
638   - return
639   -
640   - class COORD(ctypes.Structure):
641   - """Windows COORD structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119"""
642   - _fields_ = [('X', ctypes.c_short), ('Y', ctypes.c_short)]
643   -
644   - class SmallRECT(ctypes.Structure):
645   - """Windows SMALL_RECT structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311"""
646   - _fields_ = [('Left', ctypes.c_short), ('Top', ctypes.c_short), ('Right', ctypes.c_short),
647   - ('Bottom', ctypes.c_short)]
648   -
649   - class ConsoleScreenBufferInfo(ctypes.Structure):
650   - """Windows CONSOLE_SCREEN_BUFFER_INFO structure.
651   - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093
652   - """
653   - _fields_ = [
654   - ('dwSize', COORD),
655   - ('dwCursorPosition', COORD),
656   - ('wAttributes', ctypes.wintypes.WORD),
657   - ('srWindow', SmallRECT),
658   - ('dwMaximumWindowSize', COORD)
659   - ]
660   -
661   - _WindowsCSBI.CSBI = ConsoleScreenBufferInfo
662   -
663   - @staticmethod
664   - def initialize():
665   - """Initializes the WINDLL resource and populated the CSBI class variable."""
666   - _WindowsCSBI._define_csbi()
667   - _WindowsCSBI.HANDLE_STDERR = _WindowsCSBI.HANDLE_STDERR or _WindowsCSBI.WINDLL.kernel32.GetStdHandle(-12)
668   - _WindowsCSBI.HANDLE_STDOUT = _WindowsCSBI.HANDLE_STDOUT or _WindowsCSBI.WINDLL.kernel32.GetStdHandle(-11)
669   - if _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.argtypes:
670   - return
671   -
672   - _WindowsCSBI.WINDLL.kernel32.GetStdHandle.argtypes = [ctypes.wintypes.DWORD]
673   - _WindowsCSBI.WINDLL.kernel32.GetStdHandle.restype = ctypes.wintypes.HANDLE
674   - _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.restype = ctypes.wintypes.BOOL
675   - _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.argtypes = [
676   - ctypes.wintypes.HANDLE, ctypes.POINTER(_WindowsCSBI.CSBI)
677   - ]
678   -
679   - @staticmethod
680   - def get_info(handle):
681   - """Get information about this current console window (for Microsoft Windows only).
682   -
683   - Raises IOError if attempt to get information fails (if there is no console window).
684   -
685   - Don't forget to call _WindowsCSBI.initialize() once in your application before calling this method.
686   -
687   - Positional arguments:
688   - handle -- either _WindowsCSBI.HANDLE_STDERR or _WindowsCSBI.HANDLE_STDOUT.
689   -
690   - Returns:
691   - Dictionary with different integer values. Keys are:
692   - buffer_width -- width of the buffer (Screen Buffer Size in cmd.exe layout tab).
693   - buffer_height -- height of the buffer (Screen Buffer Size in cmd.exe layout tab).
694   - terminal_width -- width of the terminal window.
695   - terminal_height -- height of the terminal window.
696   - bg_color -- current background color (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088).
697   - fg_color -- current text color code.
698   - """
699   - # Query Win32 API.
700   - csbi = _WindowsCSBI.CSBI()
701   - try:
702   - if not _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo(handle, ctypes.byref(csbi)):
703   - raise IOError('Unable to get console screen buffer info from win32 API.')
704   - except ctypes.ArgumentError:
705   - raise IOError('Unable to get console screen buffer info from win32 API.')
706   -
707   - # Parse data.
708   - result = dict(
709   - buffer_width=int(csbi.dwSize.X - 1),
710   - buffer_height=int(csbi.dwSize.Y),
711   - terminal_width=int(csbi.srWindow.Right - csbi.srWindow.Left),
712   - terminal_height=int(csbi.srWindow.Bottom - csbi.srWindow.Top),
713   - bg_color=int(csbi.wAttributes & 240),
714   - fg_color=int(csbi.wAttributes % 16),
715   - )
716   - return result
717   -
718   -
719   -class _WindowsStreamStdOut(object):
720   - """Replacement stream which overrides sys.stdout. When writing or printing, ANSI codes are converted.
721   -
722   - ANSI (Linux/Unix) color codes are converted into win32 system calls, changing the next character's color before
723   - printing it. Resources referenced:
724   - https://github.com/tartley/colorama
725   - http://www.cplusplus.com/articles/2ywTURfi/
726   - http://thomasfischer.biz/python-and-windows-terminal-colors/
727   - http://stackoverflow.com/questions/17125440/c-win32-console-color
728   - http://www.tysos.org/svn/trunk/mono/corlib/System/WindowsConsoleDriver.cs
729   - http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python
730   - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088#_win32_character_attributes
731   -
732   - Class variables:
733   - ALL_BG_CODES -- list of background Windows codes. Used to determine if requested color is foreground or background.
734   - COMPILED_CODES -- 'translation' dictionary. Keys are ANSI codes (values of _BASE_CODES), values are Windows codes.
735   - ORIGINAL_STREAM -- the original stream to write non-code text to.
736   - WIN32_STREAM_HANDLE -- handle to the Windows stdout device. Used by other Windows functions.
737   -
738   - Instance variables:
739   - default_fg -- the foreground Windows color code at the time of instantiation.
740   - default_bg -- the background Windows color code at the time of instantiation.
741   - """
742   -
743   - ALL_BG_CODES = [v for k, v in _WINDOWS_CODES.items() if k.startswith('bg') or k.startswith('hibg')]
744   - COMPILED_CODES = dict((v, _WINDOWS_CODES[k]) for k, v in _BASE_CODES.items() if k in _WINDOWS_CODES)
745   - ORIGINAL_STREAM = sys.stdout
746   - WIN32_STREAM_HANDLE = _WindowsCSBI.HANDLE_STDOUT
747   -
748   - def __init__(self):
749   - _WindowsCSBI.initialize()
750   - self.default_fg, self.default_bg = self._get_colors()
751   - for attr in dir(self.ORIGINAL_STREAM):
752   - if hasattr(self, attr):
753   - continue
754   - setattr(self, attr, getattr(self.ORIGINAL_STREAM, attr))
755   -
756   - def __getattr__(self, item):
757   - """If an attribute/function/etc is not defined in this function, retrieve the one from the original stream.
758   -
759   - Fixes ipython arrow key presses.
760   - """
761   - return getattr(self.ORIGINAL_STREAM, item)
762   -
763   - def _get_colors(self):
764   - """Returns a tuple of two integers representing current colors: (foreground, background)."""
765   - try:
766   - csbi = _WindowsCSBI.get_info(self.WIN32_STREAM_HANDLE)
767   - return csbi['fg_color'], csbi['bg_color']
768   - except IOError:
769   - return 7, 0
770   -
771   - def _reset_colors(self):
772   - """Sets the foreground and background colors to their original values (when class was instantiated)."""
773   - self._set_color(-33)
774   -
775   - def _set_color(self, color_code):
776   - """Changes the foreground and background colors for subsequently printed characters.
777   -
778   - Since setting a color requires including both foreground and background codes (merged), setting just the
779   - foreground color resets the background color to black, and vice versa.
780   -
781   - This function first gets the current background and foreground colors, merges in the requested color code, and
782   - sets the result.
783   -
784   - However if we need to remove just the foreground color but leave the background color the same (or vice versa)
785   - such as when {/red} is used, we must merge the default foreground color with the current background color. This
786   - is the reason for those negative values.
787   -
788   - Positional arguments:
789   - color_code -- integer color code from _WINDOWS_CODES.
790   - """
791   - # Get current color code.
792   - current_fg, current_bg = self._get_colors()
793   -
794   - # Handle special negative codes. Also determine the final color code.
795   - if color_code == -39:
796   - final_color_code = self.default_fg | current_bg # Reset the foreground only.
797   - elif color_code == -49:
798   - final_color_code = current_fg | self.default_bg # Reset the background only.
799   - elif color_code == -33:
800   - final_color_code = self.default_fg | self.default_bg # Reset both.
801   - elif color_code == -8:
802   - final_color_code = current_fg # Black background.
803   - else:
804   - new_is_bg = color_code in self.ALL_BG_CODES
805   - final_color_code = color_code | (current_fg if new_is_bg else current_bg)
806   -
807   - # Set new code.
808   - _WindowsCSBI.WINDLL.kernel32.SetConsoleTextAttribute(self.WIN32_STREAM_HANDLE, final_color_code)
809   -
810   - def write(self, p_str):
811   - for segment in _RE_SPLIT.split(p_str):
812   - if not segment:
813   - # Empty string. p_str probably starts with colors so the first item is always ''.
814   - continue
815   - if not _RE_SPLIT.match(segment):
816   - # No color codes, print regular text.
817   - self.ORIGINAL_STREAM.write(segment)
818   - self.ORIGINAL_STREAM.flush()
819   - continue
820   - for color_code in (int(c) for c in _RE_NUMBER_SEARCH.findall(segment)[0].split(';')):
821   - if color_code in self.COMPILED_CODES:
822   - self._set_color(self.COMPILED_CODES[color_code])
823   -
824   -
825   -class _WindowsStreamStdErr(_WindowsStreamStdOut):
826   - """Replacement stream which overrides sys.stderr. Subclasses _WindowsStreamStdOut."""
827   -
828   - ORIGINAL_STREAM = sys.stderr
829   - WIN32_STREAM_HANDLE = _WindowsCSBI.HANDLE_STDERR
oletools/thirdparty/colorclass/core.py 0 → 100644
  1 +"""String subclass that handles ANSI color codes."""
  2 +
  3 +from colorclass.codes import ANSICodeMapping
  4 +from colorclass.parse import parse_input, RE_SPLIT
  5 +from colorclass.search import build_color_index, find_char_color
  6 +
  7 +PARENT_CLASS = type(u'')
  8 +
  9 +
  10 +def apply_text(incoming, func):
  11 + """Call `func` on text portions of incoming color string.
  12 +
  13 + :param iter incoming: Incoming string/ColorStr/string-like object to iterate.
  14 + :param func: Function to call with string portion as first and only parameter.
  15 +
  16 + :return: Modified string, same class type as incoming string.
  17 + """
  18 + split = RE_SPLIT.split(incoming)
  19 + for i, item in enumerate(split):
  20 + if not item or RE_SPLIT.match(item):
  21 + continue
  22 + split[i] = func(item)
  23 + return incoming.__class__().join(split)
  24 +
  25 +
  26 +class ColorBytes(bytes):
  27 + """Str (bytes in Python3) subclass, .decode() overridden to return unicode (str in Python3) subclass instance."""
  28 +
  29 + def __new__(cls, *args, **kwargs):
  30 + """Save original class so decode() returns an instance of it."""
  31 + original_class = kwargs.pop('original_class')
  32 + combined_args = [cls] + list(args)
  33 + instance = bytes.__new__(*combined_args, **kwargs)
  34 + instance.original_class = original_class
  35 + return instance
  36 +
  37 + def decode(self, encoding='utf-8', errors='strict'):
  38 + """Decode using the codec registered for encoding. Default encoding is 'utf-8'.
  39 +
  40 + errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors
  41 + raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name
  42 + registered with codecs.register_error that is able to handle UnicodeDecodeErrors.
  43 +
  44 + :param str encoding: Codec.
  45 + :param str errors: Error handling scheme.
  46 + """
  47 + original_class = getattr(self, 'original_class')
  48 + return original_class(super(ColorBytes, self).decode(encoding, errors))
  49 +
  50 +
  51 +class ColorStr(PARENT_CLASS):
  52 + """Core color class."""
  53 +
  54 + def __new__(cls, *args, **kwargs):
  55 + """Parse color markup and instantiate."""
  56 + keep_tags = kwargs.pop('keep_tags', False)
  57 +
  58 + # Parse string.
  59 + value_markup = args[0] if args else PARENT_CLASS() # e.g. '{red}test{/red}'
  60 + value_colors, value_no_colors = parse_input(value_markup, ANSICodeMapping.DISABLE_COLORS, keep_tags)
  61 + color_index = build_color_index(value_colors)
  62 +
  63 + # Instantiate.
  64 + color_args = [cls, value_colors] + list(args[1:])
  65 + instance = PARENT_CLASS.__new__(*color_args, **kwargs)
  66 +
  67 + # Add additional attributes and return.
  68 + instance.value_colors = value_colors
  69 + instance.value_no_colors = value_no_colors
  70 + instance.has_colors = value_colors != value_no_colors
  71 + instance.color_index = color_index
  72 + return instance
  73 +
  74 + def __add__(self, other):
  75 + """Concatenate."""
  76 + return self.__class__(self.value_colors + other, keep_tags=True)
  77 +
  78 + def __getitem__(self, item):
  79 + """Retrieve character."""
  80 + try:
  81 + color_pos = self.color_index[int(item)]
  82 + except TypeError: # slice
  83 + return super(ColorStr, self).__getitem__(item)
  84 + return self.__class__(find_char_color(self.value_colors, color_pos), keep_tags=True)
  85 +
  86 + def __iter__(self):
  87 + """Yield one color-coded character at a time."""
  88 + for color_pos in self.color_index:
  89 + yield self.__class__(find_char_color(self.value_colors, color_pos))
  90 +
  91 + def __len__(self):
  92 + """Length of string without color codes (what users expect)."""
  93 + return self.value_no_colors.__len__()
  94 +
  95 + def __mod__(self, other):
  96 + """String substitution (like printf)."""
  97 + return self.__class__(self.value_colors % other, keep_tags=True)
  98 +
  99 + def __mul__(self, other):
  100 + """Multiply string."""
  101 + return self.__class__(self.value_colors * other, keep_tags=True)
  102 +
  103 + def __repr__(self):
  104 + """Representation of a class instance (like datetime.datetime.now())."""
  105 + return '{name}({value})'.format(name=self.__class__.__name__, value=repr(self.value_colors))
  106 +
  107 + def capitalize(self):
  108 + """Return a copy of the string with only its first character capitalized."""
  109 + return apply_text(self, lambda s: s.capitalize())
  110 +
  111 + def center(self, width, fillchar=None):
  112 + """Return centered in a string of length width. Padding is done using the specified fill character or space.
  113 +
  114 + :param int width: Length of output string.
  115 + :param str fillchar: Use this character instead of spaces.
  116 + """
  117 + if fillchar is not None:
  118 + result = self.value_no_colors.center(width, fillchar)
  119 + else:
  120 + result = self.value_no_colors.center(width)
  121 + return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True)
  122 +
  123 + def count(self, sub, start=0, end=-1):
  124 + """Return the number of non-overlapping occurrences of substring sub in string[start:end].
  125 +
  126 + Optional arguments start and end are interpreted as in slice notation.
  127 +
  128 + :param str sub: Substring to search.
  129 + :param int start: Beginning position.
  130 + :param int end: Stop comparison at this position.
  131 + """
  132 + return self.value_no_colors.count(sub, start, end)
  133 +
  134 + def endswith(self, suffix, start=0, end=None):
  135 + """Return True if ends with the specified suffix, False otherwise.
  136 +
  137 + With optional start, test beginning at that position. With optional end, stop comparing at that position.
  138 + suffix can also be a tuple of strings to try.
  139 +
  140 + :param str suffix: Suffix to search.
  141 + :param int start: Beginning position.
  142 + :param int end: Stop comparison at this position.
  143 + """
  144 + args = [suffix, start] + ([] if end is None else [end])
  145 + return self.value_no_colors.endswith(*args)
  146 +
  147 + def encode(self, encoding=None, errors='strict'):
  148 + """Encode using the codec registered for encoding. encoding defaults to the default encoding.
  149 +
  150 + errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors
  151 + raise a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and 'xmlcharrefreplace' as well as any
  152 + other name registered with codecs.register_error that is able to handle UnicodeEncodeErrors.
  153 +
  154 + :param str encoding: Codec.
  155 + :param str errors: Error handling scheme.
  156 + """
  157 + return ColorBytes(super(ColorStr, self).encode(encoding, errors), original_class=self.__class__)
  158 +
  159 + def decode(self, encoding=None, errors='strict'):
  160 + """Decode using the codec registered for encoding. encoding defaults to the default encoding.
  161 +
  162 + errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors
  163 + raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name
  164 + registered with codecs.register_error that is able to handle UnicodeDecodeErrors.
  165 +
  166 + :param str encoding: Codec.
  167 + :param str errors: Error handling scheme.
  168 + """
  169 + return self.__class__(super(ColorStr, self).decode(encoding, errors), keep_tags=True)
  170 +
  171 + def find(self, sub, start=None, end=None):
  172 + """Return the lowest index where substring sub is found, such that sub is contained within string[start:end].
  173 +
  174 + Optional arguments start and end are interpreted as in slice notation.
  175 +
  176 + :param str sub: Substring to search.
  177 + :param int start: Beginning position.
  178 + :param int end: Stop comparison at this position.
  179 + """
  180 + return self.value_no_colors.find(sub, start, end)
  181 +
  182 + def format(self, *args, **kwargs):
  183 + """Return a formatted version, using substitutions from args and kwargs.
  184 +
  185 + The substitutions are identified by braces ('{' and '}').
  186 + """
  187 + return self.__class__(super(ColorStr, self).format(*args, **kwargs), keep_tags=True)
  188 +
  189 + def index(self, sub, start=None, end=None):
  190 + """Like S.find() but raise ValueError when the substring is not found.
  191 +
  192 + :param str sub: Substring to search.
  193 + :param int start: Beginning position.
  194 + :param int end: Stop comparison at this position.
  195 + """
  196 + return self.value_no_colors.index(sub, start, end)
  197 +
  198 + def isalnum(self):
  199 + """Return True if all characters in string are alphanumeric and there is at least one character in it."""
  200 + return self.value_no_colors.isalnum()
  201 +
  202 + def isalpha(self):
  203 + """Return True if all characters in string are alphabetic and there is at least one character in it."""
  204 + return self.value_no_colors.isalpha()
  205 +
  206 + def isdecimal(self):
  207 + """Return True if there are only decimal characters in string, False otherwise."""
  208 + return self.value_no_colors.isdecimal()
  209 +
  210 + def isdigit(self):
  211 + """Return True if all characters in string are digits and there is at least one character in it."""
  212 + return self.value_no_colors.isdigit()
  213 +
  214 + def isnumeric(self):
  215 + """Return True if there are only numeric characters in string, False otherwise."""
  216 + return self.value_no_colors.isnumeric()
  217 +
  218 + def isspace(self):
  219 + """Return True if all characters in string are whitespace and there is at least one character in it."""
  220 + return self.value_no_colors.isspace()
  221 +
  222 + def istitle(self):
  223 + """Return True if string is a titlecased string and there is at least one character in it.
  224 +
  225 + That is uppercase characters may only follow uncased characters and lowercase characters only cased ones. Return
  226 + False otherwise.
  227 + """
  228 + return self.value_no_colors.istitle()
  229 +
  230 + def isupper(self):
  231 + """Return True if all cased characters are uppercase and there is at least one cased character in it."""
  232 + return self.value_no_colors.isupper()
  233 +
  234 + def join(self, iterable):
  235 + """Return a string which is the concatenation of the strings in the iterable.
  236 +
  237 + :param iterable: Join items in this iterable.
  238 + """
  239 + return self.__class__(super(ColorStr, self).join(iterable), keep_tags=True)
  240 +
  241 + def ljust(self, width, fillchar=None):
  242 + """Return left-justified string of length width. Padding is done using the specified fill character or space.
  243 +
  244 + :param int width: Length of output string.
  245 + :param str fillchar: Use this character instead of spaces.
  246 + """
  247 + if fillchar is not None:
  248 + result = self.value_no_colors.ljust(width, fillchar)
  249 + else:
  250 + result = self.value_no_colors.ljust(width)
  251 + return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True)
  252 +
  253 + def rfind(self, sub, start=None, end=None):
  254 + """Return the highest index where substring sub is found, such that sub is contained within string[start:end].
  255 +
  256 + Optional arguments start and end are interpreted as in slice notation.
  257 +
  258 + :param str sub: Substring to search.
  259 + :param int start: Beginning position.
  260 + :param int end: Stop comparison at this position.
  261 + """
  262 + return self.value_no_colors.rfind(sub, start, end)
  263 +
  264 + def rindex(self, sub, start=None, end=None):
  265 + """Like .rfind() but raise ValueError when the substring is not found.
  266 +
  267 + :param str sub: Substring to search.
  268 + :param int start: Beginning position.
  269 + :param int end: Stop comparison at this position.
  270 + """
  271 + return self.value_no_colors.rindex(sub, start, end)
  272 +
  273 + def rjust(self, width, fillchar=None):
  274 + """Return right-justified string of length width. Padding is done using the specified fill character or space.
  275 +
  276 + :param int width: Length of output string.
  277 + :param str fillchar: Use this character instead of spaces.
  278 + """
  279 + if fillchar is not None:
  280 + result = self.value_no_colors.rjust(width, fillchar)
  281 + else:
  282 + result = self.value_no_colors.rjust(width)
  283 + return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True)
  284 +
  285 + def splitlines(self, keepends=False):
  286 + """Return a list of the lines in the string, breaking at line boundaries.
  287 +
  288 + Line breaks are not included in the resulting list unless keepends is given and True.
  289 +
  290 + :param bool keepends: Include linebreaks.
  291 + """
  292 + return [self.__class__(l) for l in self.value_colors.splitlines(keepends)]
  293 +
  294 + def startswith(self, prefix, start=0, end=-1):
  295 + """Return True if string starts with the specified prefix, False otherwise.
  296 +
  297 + With optional start, test beginning at that position. With optional end, stop comparing at that position. prefix
  298 + can also be a tuple of strings to try.
  299 +
  300 + :param str prefix: Prefix to search.
  301 + :param int start: Beginning position.
  302 + :param int end: Stop comparison at this position.
  303 + """
  304 + return self.value_no_colors.startswith(prefix, start, end)
  305 +
  306 + def swapcase(self):
  307 + """Return a copy of the string with uppercase characters converted to lowercase and vice versa."""
  308 + return apply_text(self, lambda s: s.swapcase())
  309 +
  310 + def title(self):
  311 + """Return a titlecased version of the string.
  312 +
  313 + That is words start with uppercase characters, all remaining cased characters have lowercase.
  314 + """
  315 + return apply_text(self, lambda s: s.title())
  316 +
  317 + def translate(self, table):
  318 + """Return a copy of the string, where all characters have been mapped through the given translation table.
  319 +
  320 + Table must be a mapping of Unicode ordinals to Unicode ordinals, strings, or None. Unmapped characters are left
  321 + untouched. Characters mapped to None are deleted.
  322 +
  323 + :param table: Translation table.
  324 + """
  325 + return apply_text(self, lambda s: s.translate(table))
  326 +
  327 + def upper(self):
  328 + """Return a copy of the string converted to uppercase."""
  329 + return apply_text(self, lambda s: s.upper())
  330 +
  331 + def zfill(self, width):
  332 + """Pad a numeric string with zeros on the left, to fill a field of the specified width.
  333 +
  334 + The string is never truncated.
  335 +
  336 + :param int width: Length of output string.
  337 + """
  338 + if not self.value_no_colors:
  339 + result = self.value_no_colors.zfill(width)
  340 + else:
  341 + result = self.value_colors.replace(self.value_no_colors, self.value_no_colors.zfill(width))
  342 + return self.__class__(result, keep_tags=True)
... ...
oletools/thirdparty/colorclass/parse.py 0 → 100644
  1 +"""Parse color markup tags into ANSI escape sequences."""
  2 +
  3 +import re
  4 +
  5 +from colorclass.codes import ANSICodeMapping, BASE_CODES
  6 +
  7 +CODE_GROUPS = (
  8 + tuple(set(str(i) for i in BASE_CODES.values() if i and (40 <= i <= 49 or 100 <= i <= 109))), # bg colors
  9 + tuple(set(str(i) for i in BASE_CODES.values() if i and (30 <= i <= 39 or 90 <= i <= 99))), # fg colors
  10 + ('1', '22'), ('2', '22'), ('3', '23'), ('4', '24'), ('5', '25'), ('6', '26'), ('7', '27'), ('8', '28'), ('9', '29'),
  11 +)
  12 +RE_ANSI = re.compile(r'(\033\[([\d;]+)m)')
  13 +RE_COMBINE = re.compile(r'\033\[([\d;]+)m\033\[([\d;]+)m')
  14 +RE_SPLIT = re.compile(r'(\033\[[\d;]+m)')
  15 +
  16 +
  17 +def prune_overridden(ansi_string):
  18 + """Remove color codes that are rendered ineffective by subsequent codes in one escape sequence then sort codes.
  19 +
  20 + :param str ansi_string: Incoming ansi_string with ANSI color codes.
  21 +
  22 + :return: Color string with pruned color sequences.
  23 + :rtype: str
  24 + """
  25 + multi_seqs = set(p for p in RE_ANSI.findall(ansi_string) if ';' in p[1]) # Sequences with multiple color codes.
  26 +
  27 + for escape, codes in multi_seqs:
  28 + r_codes = list(reversed(codes.split(';')))
  29 +
  30 + # Nuke everything before {/all}.
  31 + try:
  32 + r_codes = r_codes[:r_codes.index('0') + 1]
  33 + except ValueError:
  34 + pass
  35 +
  36 + # Thin out groups.
  37 + for group in CODE_GROUPS:
  38 + for pos in reversed([i for i, n in enumerate(r_codes) if n in group][1:]):
  39 + r_codes.pop(pos)
  40 +
  41 + # Done.
  42 + reduced_codes = ';'.join(sorted(r_codes, key=int))
  43 + if codes != reduced_codes:
  44 + ansi_string = ansi_string.replace(escape, '\033[' + reduced_codes + 'm')
  45 +
  46 + return ansi_string
  47 +
  48 +
  49 +def parse_input(tagged_string, disable_colors, keep_tags):
  50 + """Perform the actual conversion of tags to ANSI escaped codes.
  51 +
  52 + Provides a version of the input without any colors for len() and other methods.
  53 +
  54 + :param str tagged_string: The input unicode value.
  55 + :param bool disable_colors: Strip all colors in both outputs.
  56 + :param bool keep_tags: Skip parsing curly bracket tags into ANSI escape sequences.
  57 +
  58 + :return: 2-item tuple. First item is the parsed output. Second item is a version of the input without any colors.
  59 + :rtype: tuple
  60 + """
  61 + codes = ANSICodeMapping(tagged_string)
  62 + output_colors = getattr(tagged_string, 'value_colors', tagged_string)
  63 +
  64 + # Convert: '{b}{red}' -> '\033[1m\033[31m'
  65 + if not keep_tags:
  66 + for tag, replacement in (('{' + k + '}', '' if v is None else '\033[%dm' % v) for k, v in codes.items()):
  67 + output_colors = output_colors.replace(tag, replacement)
  68 +
  69 + # Strip colors.
  70 + output_no_colors = RE_ANSI.sub('', output_colors)
  71 + if disable_colors:
  72 + return output_no_colors, output_no_colors
  73 +
  74 + # Combine: '\033[1m\033[31m' -> '\033[1;31m'
  75 + while True:
  76 + simplified = RE_COMBINE.sub(r'\033[\1;\2m', output_colors)
  77 + if simplified == output_colors:
  78 + break
  79 + output_colors = simplified
  80 +
  81 + # Prune: '\033[31;32;33;34;35m' -> '\033[35m'
  82 + output_colors = prune_overridden(output_colors)
  83 +
  84 + # Deduplicate: '\033[1;mT\033[1;mE\033[1;mS\033[1;mT' -> '\033[1;mTEST'
  85 + previous_escape = None
  86 + segments = list()
  87 + for item in (i for i in RE_SPLIT.split(output_colors) if i):
  88 + if RE_SPLIT.match(item):
  89 + if item != previous_escape:
  90 + segments.append(item)
  91 + previous_escape = item
  92 + else:
  93 + segments.append(item)
  94 + output_colors = ''.join(segments)
  95 +
  96 + return output_colors, output_no_colors
... ...
oletools/thirdparty/colorclass/search.py 0 → 100644
  1 +"""Determine color of characters that may or may not be adjacent to ANSI escape sequences."""
  2 +
  3 +from colorclass.parse import RE_SPLIT
  4 +
  5 +
  6 +def build_color_index(ansi_string):
  7 + """Build an index between visible characters and a string with invisible color codes.
  8 +
  9 + :param str ansi_string: String with color codes (ANSI escape sequences).
  10 +
  11 + :return: Position of visible characters in color string (indexes match non-color string).
  12 + :rtype: tuple
  13 + """
  14 + mapping = list()
  15 + color_offset = 0
  16 + for item in (i for i in RE_SPLIT.split(ansi_string) if i):
  17 + if RE_SPLIT.match(item):
  18 + color_offset += len(item)
  19 + else:
  20 + for _ in range(len(item)):
  21 + mapping.append(color_offset)
  22 + color_offset += 1
  23 + return tuple(mapping)
  24 +
  25 +
  26 +def find_char_color(ansi_string, pos):
  27 + """Determine what color a character is in the string.
  28 +
  29 + :param str ansi_string: String with color codes (ANSI escape sequences).
  30 + :param int pos: Position of the character in the ansi_string.
  31 +
  32 + :return: Character along with all surrounding color codes.
  33 + :rtype: str
  34 + """
  35 + result = list()
  36 + position = 0 # Set to None when character is found.
  37 + for item in (i for i in RE_SPLIT.split(ansi_string) if i):
  38 + if RE_SPLIT.match(item):
  39 + result.append(item)
  40 + if position is not None:
  41 + position += len(item)
  42 + elif position is not None:
  43 + for char in item:
  44 + if position == pos:
  45 + result.append(char)
  46 + position = None
  47 + break
  48 + position += 1
  49 + return ''.join(result)
... ...
oletools/thirdparty/colorclass/toggles.py 0 → 100644
  1 +"""Convenience functions to enable/disable features."""
  2 +
  3 +from colorclass.codes import ANSICodeMapping
  4 +
  5 +
  6 +def disable_all_colors():
  7 + """Disable all colors. Strip any color tags or codes."""
  8 + ANSICodeMapping.disable_all_colors()
  9 +
  10 +
  11 +def enable_all_colors():
  12 + """Enable colors."""
  13 + ANSICodeMapping.enable_all_colors()
  14 +
  15 +
  16 +def disable_if_no_tty():
  17 + """Disable all colors if there is no TTY available.
  18 +
  19 + :return: True if colors are disabled, False if stderr or stdout is a TTY.
  20 + :rtype: bool
  21 + """
  22 + return ANSICodeMapping.disable_if_no_tty()
  23 +
  24 +
  25 +def is_enabled():
  26 + """Are colors enabled."""
  27 + return not ANSICodeMapping.DISABLE_COLORS
  28 +
  29 +
  30 +def set_light_background():
  31 + """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
  32 + ANSICodeMapping.set_light_background()
  33 +
  34 +
  35 +def set_dark_background():
  36 + """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""
  37 + ANSICodeMapping.set_dark_background()
  38 +
  39 +
  40 +def is_light():
  41 + """Are background colors for light backgrounds."""
  42 + return ANSICodeMapping.LIGHT_BACKGROUND
... ...
oletools/thirdparty/colorclass/windows.py 0 → 100644
  1 +"""Windows console screen buffer handlers."""
  2 +
  3 +from __future__ import print_function
  4 +
  5 +import atexit
  6 +import ctypes
  7 +import re
  8 +import sys
  9 +
  10 +from colorclass.codes import ANSICodeMapping, BASE_CODES
  11 +from colorclass.core import RE_SPLIT
  12 +
  13 +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
  14 +INVALID_HANDLE_VALUE = -1
  15 +IS_WINDOWS = sys.platform == 'win32'
  16 +RE_NUMBER_SEARCH = re.compile(r'\033\[([\d;]+)m')
  17 +STD_ERROR_HANDLE = -12
  18 +STD_OUTPUT_HANDLE = -11
  19 +WINDOWS_CODES = {
  20 + '/all': -33, '/fg': -39, '/bg': -49,
  21 +
  22 + 'black': 0, 'red': 4, 'green': 2, 'yellow': 6, 'blue': 1, 'magenta': 5, 'cyan': 3, 'white': 7,
  23 +
  24 + 'bgblack': -8, 'bgred': 64, 'bggreen': 32, 'bgyellow': 96, 'bgblue': 16, 'bgmagenta': 80, 'bgcyan': 48,
  25 + 'bgwhite': 112,
  26 +
  27 + 'hiblack': 8, 'hired': 12, 'higreen': 10, 'hiyellow': 14, 'hiblue': 9, 'himagenta': 13, 'hicyan': 11, 'hiwhite': 15,
  28 +
  29 + 'hibgblack': 128, 'hibgred': 192, 'hibggreen': 160, 'hibgyellow': 224, 'hibgblue': 144, 'hibgmagenta': 208,
  30 + 'hibgcyan': 176, 'hibgwhite': 240,
  31 +
  32 + '/black': -39, '/red': -39, '/green': -39, '/yellow': -39, '/blue': -39, '/magenta': -39, '/cyan': -39,
  33 + '/white': -39, '/hiblack': -39, '/hired': -39, '/higreen': -39, '/hiyellow': -39, '/hiblue': -39, '/himagenta': -39,
  34 + '/hicyan': -39, '/hiwhite': -39,
  35 +
  36 + '/bgblack': -49, '/bgred': -49, '/bggreen': -49, '/bgyellow': -49, '/bgblue': -49, '/bgmagenta': -49,
  37 + '/bgcyan': -49, '/bgwhite': -49, '/hibgblack': -49, '/hibgred': -49, '/hibggreen': -49, '/hibgyellow': -49,
  38 + '/hibgblue': -49, '/hibgmagenta': -49, '/hibgcyan': -49, '/hibgwhite': -49,
  39 +}
  40 +
  41 +
  42 +class COORD(ctypes.Structure):
  43 + """COORD structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119."""
  44 +
  45 + _fields_ = [
  46 + ('X', ctypes.c_short),
  47 + ('Y', ctypes.c_short),
  48 + ]
  49 +
  50 +
  51 +class SmallRECT(ctypes.Structure):
  52 + """SMALL_RECT structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311."""
  53 +
  54 + _fields_ = [
  55 + ('Left', ctypes.c_short),
  56 + ('Top', ctypes.c_short),
  57 + ('Right', ctypes.c_short),
  58 + ('Bottom', ctypes.c_short),
  59 + ]
  60 +
  61 +
  62 +class ConsoleScreenBufferInfo(ctypes.Structure):
  63 + """CONSOLE_SCREEN_BUFFER_INFO structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093."""
  64 +
  65 + _fields_ = [
  66 + ('dwSize', COORD),
  67 + ('dwCursorPosition', COORD),
  68 + ('wAttributes', ctypes.c_ushort),
  69 + ('srWindow', SmallRECT),
  70 + ('dwMaximumWindowSize', COORD)
  71 + ]
  72 +
  73 +
  74 +def init_kernel32(kernel32=None):
  75 + """Load a unique instance of WinDLL into memory, set arg/return types, and get stdout/err handles.
  76 +
  77 + 1. Since we are setting DLL function argument types and return types, we need to maintain our own instance of
  78 + kernel32 to prevent overriding (or being overwritten by) user's own changes to ctypes.windll.kernel32.
  79 + 2. While we're doing all this we might as well get the handles to STDOUT and STDERR streams.
  80 + 3. If either stream has already been replaced set return value to INVALID_HANDLE_VALUE to indicate it shouldn't be
  81 + replaced.
  82 +
  83 + :raise AttributeError: When called on a non-Windows platform.
  84 +
  85 + :param kernel32: Optional mock kernel32 object. For testing.
  86 +
  87 + :return: Loaded kernel32 instance, stderr handle (int), stdout handle (int).
  88 + :rtype: tuple
  89 + """
  90 + if not kernel32:
  91 + kernel32 = ctypes.LibraryLoader(ctypes.WinDLL).kernel32 # Load our own instance. Unique memory address.
  92 + kernel32.GetStdHandle.argtypes = [ctypes.c_ulong]
  93 + kernel32.GetStdHandle.restype = ctypes.c_void_p
  94 + kernel32.GetConsoleScreenBufferInfo.argtypes = [
  95 + ctypes.c_void_p,
  96 + ctypes.POINTER(ConsoleScreenBufferInfo),
  97 + ]
  98 + kernel32.GetConsoleScreenBufferInfo.restype = ctypes.c_long
  99 +
  100 + # Get handles.
  101 + if hasattr(sys.stderr, '_original_stream'):
  102 + stderr = INVALID_HANDLE_VALUE
  103 + else:
  104 + stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE)
  105 + if hasattr(sys.stdout, '_original_stream'):
  106 + stdout = INVALID_HANDLE_VALUE
  107 + else:
  108 + stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  109 +
  110 + return kernel32, stderr, stdout
  111 +
  112 +
  113 +def get_console_info(kernel32, handle):
  114 + """Get information about this current console window.
  115 +
  116 + http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231
  117 + https://code.google.com/p/colorama/issues/detail?id=47
  118 + https://bitbucket.org/pytest-dev/py/src/4617fe46/py/_io/terminalwriter.py
  119 +
  120 + Windows 10 Insider since around February 2016 finally introduced support for ANSI colors. No need to replace stdout
  121 + and stderr streams to intercept colors and issue multiple SetConsoleTextAttribute() calls for these consoles.
  122 +
  123 + :raise OSError: When GetConsoleScreenBufferInfo or GetConsoleMode API calls fail.
  124 +
  125 + :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance.
  126 + :param int handle: stderr or stdout handle.
  127 +
  128 + :return: Foreground and background colors (integers) as well as native ANSI support (bool).
  129 + :rtype: tuple
  130 + """
  131 + # Query Win32 API.
  132 + csbi = ConsoleScreenBufferInfo() # Populated by GetConsoleScreenBufferInfo.
  133 + lpcsbi = ctypes.byref(csbi)
  134 + dword = ctypes.c_ulong() # Populated by GetConsoleMode.
  135 + lpdword = ctypes.byref(dword)
  136 + if not kernel32.GetConsoleScreenBufferInfo(handle, lpcsbi) or not kernel32.GetConsoleMode(handle, lpdword):
  137 + raise ctypes.WinError()
  138 +
  139 + # Parse data.
  140 + # buffer_width = int(csbi.dwSize.X - 1)
  141 + # buffer_height = int(csbi.dwSize.Y)
  142 + # terminal_width = int(csbi.srWindow.Right - csbi.srWindow.Left)
  143 + # terminal_height = int(csbi.srWindow.Bottom - csbi.srWindow.Top)
  144 + fg_color = csbi.wAttributes % 16
  145 + bg_color = csbi.wAttributes & 240
  146 + native_ansi = bool(dword.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
  147 +
  148 + return fg_color, bg_color, native_ansi
  149 +
  150 +
  151 +def bg_color_native_ansi(kernel32, stderr, stdout):
  152 + """Get background color and if console supports ANSI colors natively for both streams.
  153 +
  154 + :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance.
  155 + :param int stderr: stderr handle.
  156 + :param int stdout: stdout handle.
  157 +
  158 + :return: Background color (int) and native ANSI support (bool).
  159 + :rtype: tuple
  160 + """
  161 + try:
  162 + if stderr == INVALID_HANDLE_VALUE:
  163 + raise OSError
  164 + bg_color, native_ansi = get_console_info(kernel32, stderr)[1:]
  165 + except OSError:
  166 + try:
  167 + if stdout == INVALID_HANDLE_VALUE:
  168 + raise OSError
  169 + bg_color, native_ansi = get_console_info(kernel32, stdout)[1:]
  170 + except OSError:
  171 + bg_color, native_ansi = WINDOWS_CODES['black'], False
  172 + return bg_color, native_ansi
  173 +
  174 +
  175 +class WindowsStream(object):
  176 + """Replacement stream which overrides sys.stdout or sys.stderr. When writing or printing, ANSI codes are converted.
  177 +
  178 + ANSI (Linux/Unix) color codes are converted into win32 system calls, changing the next character's color before
  179 + printing it. Resources referenced:
  180 + https://github.com/tartley/colorama
  181 + http://www.cplusplus.com/articles/2ywTURfi/
  182 + http://thomasfischer.biz/python-and-windows-terminal-colors/
  183 + http://stackoverflow.com/questions/17125440/c-win32-console-color
  184 + http://www.tysos.org/svn/trunk/mono/corlib/System/WindowsConsoleDriver.cs
  185 + http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python
  186 + http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088#_win32_character_attributes
  187 +
  188 + :cvar list ALL_BG_CODES: List of bg Windows codes. Used to determine if requested color is foreground or background.
  189 + :cvar dict COMPILED_CODES: Translation dict. Keys are ANSI codes (values of BASE_CODES), values are Windows codes.
  190 + :ivar int default_fg: Foreground Windows color code at the time of instantiation.
  191 + :ivar int default_bg: Background Windows color code at the time of instantiation.
  192 + """
  193 +
  194 + ALL_BG_CODES = [v for k, v in WINDOWS_CODES.items() if k.startswith('bg') or k.startswith('hibg')]
  195 + COMPILED_CODES = dict((v, WINDOWS_CODES[k]) for k, v in BASE_CODES.items() if k in WINDOWS_CODES)
  196 +
  197 + def __init__(self, kernel32, stream_handle, original_stream):
  198 + """Constructor.
  199 +
  200 + :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance.
  201 + :param int stream_handle: stderr or stdout handle.
  202 + :param original_stream: sys.stderr or sys.stdout before being overridden by this class' instance.
  203 + """
  204 + self._kernel32 = kernel32
  205 + self._stream_handle = stream_handle
  206 + self._original_stream = original_stream
  207 + self.default_fg, self.default_bg = self.colors
  208 +
  209 + def __getattr__(self, item):
  210 + """If an attribute/function/etc is not defined in this function, retrieve the one from the original stream.
  211 +
  212 + Fixes ipython arrow key presses.
  213 + """
  214 + return getattr(self._original_stream, item)
  215 +
  216 + @property
  217 + def colors(self):
  218 + """Return the current foreground and background colors."""
  219 + try:
  220 + return get_console_info(self._kernel32, self._stream_handle)[:2]
  221 + except OSError:
  222 + return WINDOWS_CODES['white'], WINDOWS_CODES['black']
  223 +
  224 + @colors.setter
  225 + def colors(self, color_code):
  226 + """Change the foreground and background colors for subsequently printed characters.
  227 +
  228 + None resets colors to their original values (when class was instantiated).
  229 +
  230 + Since setting a color requires including both foreground and background codes (merged), setting just the
  231 + foreground color resets the background color to black, and vice versa.
  232 +
  233 + This function first gets the current background and foreground colors, merges in the requested color code, and
  234 + sets the result.
  235 +
  236 + However if we need to remove just the foreground color but leave the background color the same (or vice versa)
  237 + such as when {/red} is used, we must merge the default foreground color with the current background color. This
  238 + is the reason for those negative values.
  239 +
  240 + :param int color_code: Color code from WINDOWS_CODES.
  241 + """
  242 + if color_code is None:
  243 + color_code = WINDOWS_CODES['/all']
  244 +
  245 + # Get current color code.
  246 + current_fg, current_bg = self.colors
  247 +
  248 + # Handle special negative codes. Also determine the final color code.
  249 + if color_code == WINDOWS_CODES['/fg']:
  250 + final_color_code = self.default_fg | current_bg # Reset the foreground only.
  251 + elif color_code == WINDOWS_CODES['/bg']:
  252 + final_color_code = current_fg | self.default_bg # Reset the background only.
  253 + elif color_code == WINDOWS_CODES['/all']:
  254 + final_color_code = self.default_fg | self.default_bg # Reset both.
  255 + elif color_code == WINDOWS_CODES['bgblack']:
  256 + final_color_code = current_fg # Black background.
  257 + else:
  258 + new_is_bg = color_code in self.ALL_BG_CODES
  259 + final_color_code = color_code | (current_fg if new_is_bg else current_bg)
  260 +
  261 + # Set new code.
  262 + self._kernel32.SetConsoleTextAttribute(self._stream_handle, final_color_code)
  263 +
  264 + def write(self, p_str):
  265 + """Write to stream.
  266 +
  267 + :param str p_str: string to print.
  268 + """
  269 + for segment in RE_SPLIT.split(p_str):
  270 + if not segment:
  271 + # Empty string. p_str probably starts with colors so the first item is always ''.
  272 + continue
  273 + if not RE_SPLIT.match(segment):
  274 + # No color codes, print regular text.
  275 + print(segment, file=self._original_stream, end='')
  276 + self._original_stream.flush()
  277 + continue
  278 + for color_code in (int(c) for c in RE_NUMBER_SEARCH.findall(segment)[0].split(';')):
  279 + if color_code in self.COMPILED_CODES:
  280 + self.colors = self.COMPILED_CODES[color_code]
  281 +
  282 +
  283 +class Windows(object):
  284 + """Enable and disable Windows support for ANSI color character codes.
  285 +
  286 + Call static method Windows.enable() to enable color support for the remainder of the process' lifetime.
  287 +
  288 + This class is also a context manager. You can do this:
  289 + with Windows():
  290 + print(Color('{autored}Test{/autored}'))
  291 +
  292 + Or this:
  293 + with Windows(auto_colors=True):
  294 + print(Color('{autored}Test{/autored}'))
  295 + """
  296 +
  297 + @classmethod
  298 + def disable(cls):
  299 + """Restore sys.stderr and sys.stdout to their original objects. Resets colors to their original values.
  300 +
  301 + :return: If streams restored successfully.
  302 + :rtype: bool
  303 + """
  304 + # Skip if not on Windows.
  305 + if not IS_WINDOWS:
  306 + return False
  307 +
  308 + # Restore default colors.
  309 + if hasattr(sys.stderr, '_original_stream'):
  310 + getattr(sys, 'stderr').color = None
  311 + if hasattr(sys.stdout, '_original_stream'):
  312 + getattr(sys, 'stdout').color = None
  313 +
  314 + # Restore original streams.
  315 + changed = False
  316 + if hasattr(sys.stderr, '_original_stream'):
  317 + changed = True
  318 + sys.stderr = getattr(sys.stderr, '_original_stream')
  319 + if hasattr(sys.stdout, '_original_stream'):
  320 + changed = True
  321 + sys.stdout = getattr(sys.stdout, '_original_stream')
  322 +
  323 + return changed
  324 +
  325 + @staticmethod
  326 + def is_enabled():
  327 + """Return True if either stderr or stdout has colors enabled."""
  328 + return hasattr(sys.stderr, '_original_stream') or hasattr(sys.stdout, '_original_stream')
  329 +
  330 + @classmethod
  331 + def enable(cls, auto_colors=False, reset_atexit=False):
  332 + """Enable color text with print() or sys.stdout.write() (stderr too).
  333 +
  334 + :param bool auto_colors: Automatically selects dark or light colors based on current terminal's background
  335 + color. Only works with {autored} and related tags.
  336 + :param bool reset_atexit: Resets original colors upon Python exit (in case you forget to reset it yourself with
  337 + a closing tag). Does nothing on native ANSI consoles.
  338 +
  339 + :return: If streams replaced successfully.
  340 + :rtype: bool
  341 + """
  342 + if not IS_WINDOWS:
  343 + return False # Windows only.
  344 +
  345 + # Get values from init_kernel32().
  346 + kernel32, stderr, stdout = init_kernel32()
  347 + if stderr == INVALID_HANDLE_VALUE and stdout == INVALID_HANDLE_VALUE:
  348 + return False # No valid handles, nothing to do.
  349 +
  350 + # Get console info.
  351 + bg_color, native_ansi = bg_color_native_ansi(kernel32, stderr, stdout)
  352 +
  353 + # Set auto colors:
  354 + if auto_colors:
  355 + if bg_color in (112, 96, 240, 176, 224, 208, 160):
  356 + ANSICodeMapping.set_light_background()
  357 + else:
  358 + ANSICodeMapping.set_dark_background()
  359 +
  360 + # Don't replace streams if ANSI codes are natively supported.
  361 + if native_ansi:
  362 + return False
  363 +
  364 + # Reset on exit if requested.
  365 + if reset_atexit:
  366 + atexit.register(cls.disable)
  367 +
  368 + # Overwrite stream references.
  369 + if stderr != INVALID_HANDLE_VALUE:
  370 + sys.stderr.flush()
  371 + sys.stderr = WindowsStream(kernel32, stderr, sys.stderr)
  372 + if stdout != INVALID_HANDLE_VALUE:
  373 + sys.stdout.flush()
  374 + sys.stdout = WindowsStream(kernel32, stdout, sys.stdout)
  375 +
  376 + return True
  377 +
  378 + def __init__(self, auto_colors=False):
  379 + """Constructor."""
  380 + self.auto_colors = auto_colors
  381 +
  382 + def __enter__(self):
  383 + """Context manager, enables colors on Windows."""
  384 + self.enable(auto_colors=self.auto_colors)
  385 +
  386 + def __exit__(self, *_):
  387 + """Context manager, disabled colors on Windows."""
  388 + self.disable()
... ...
oletools/thirdparty/tablestream/tablestream.py
... ... @@ -48,8 +48,9 @@ License: BSD, see source code or documentation
48 48 # 2015-11-01 v0.01 PL: - first version
49 49 # 2016-01-01 v0.02 PL: - added styles, color support
50 50 # 2016-04-19 v0.03 PL: - enable colorclass on Windows, fixed issue #39
  51 +# 2016-05-25 v0.04 PL: - updated for colorclass 2.2.0 (now a package)
51 52  
52   -__version__ = '0.03'
  53 +__version__ = '0.04'
53 54  
54 55 #------------------------------------------------------------------------------
55 56 # TODO:
... ... @@ -64,7 +65,7 @@ __version__ = &#39;0.03&#39;
64 65 import textwrap
65 66 import sys, os
66 67  
67   -from thirdparty.colorclass import colorclass
  68 +from thirdparty import colorclass
68 69  
69 70 # On Windows, colorclass needs to be enabled:
70 71 if os.name == 'nt':
... ...