Skip to content

Commit 7133721

Browse files
committed
Adding a copy of the colorama library.
1 parent c748c6c commit 7133721

File tree

6 files changed

+433
-0
lines changed

6 files changed

+433
-0
lines changed

pyzen/_colorama/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from .initialise import init
2+
from .ansi import Fore, Back, Style
3+
from .ansitowin32 import AnsiToWin32
4+
5+
VERSION = '0.1.18'
6+

pyzen/_colorama/ansi.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'''
2+
This module generates ANSI character codes to printing colors to terminals.
3+
See: http://en.wikipedia.org/wiki/ANSI_escape_code
4+
'''
5+
6+
CSI = '\033['
7+
8+
def code_to_chars(code):
9+
return CSI + str(code) + 'm'
10+
11+
class AnsiCodes(object):
12+
def __init__(self, codes):
13+
for name in dir(codes):
14+
if not name.startswith('_'):
15+
value = getattr(codes, name)
16+
setattr(self, name, code_to_chars(value))
17+
18+
class AnsiFore:
19+
BLACK = 30
20+
RED = 31
21+
GREEN = 32
22+
YELLOW = 33
23+
BLUE = 34
24+
MAGENTA = 35
25+
CYAN = 36
26+
WHITE = 37
27+
RESET = 39
28+
29+
class AnsiBack:
30+
BLACK = 40
31+
RED = 41
32+
GREEN = 42
33+
YELLOW = 43
34+
BLUE = 44
35+
MAGENTA = 45
36+
CYAN = 46
37+
WHITE = 47
38+
RESET = 49
39+
40+
class AnsiStyle:
41+
BRIGHT = 1
42+
DIM = 2
43+
NORMAL = 22
44+
RESET_ALL = 0
45+
46+
Fore = AnsiCodes( AnsiFore )
47+
Back = AnsiCodes( AnsiBack )
48+
Style = AnsiCodes( AnsiStyle )
49+

pyzen/_colorama/ansitowin32.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
2+
import re
3+
import sys
4+
5+
from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style
6+
from .winterm import WinTerm, WinColor, WinStyle
7+
from .win32 import windll
8+
9+
10+
if windll is not None:
11+
winterm = WinTerm()
12+
13+
14+
def is_a_tty(stream):
15+
return hasattr(stream, 'isatty') and stream.isatty()
16+
17+
18+
class StreamWrapper(object):
19+
'''
20+
Wraps a stream (such as stdout), acting as a transparent proxy for all
21+
attribute access apart from method 'write()', which is delegated to our
22+
Converter instance.
23+
'''
24+
def __init__(self, wrapped, converter):
25+
# double-underscore everything to prevent clashes with names of
26+
# attributes on the wrapped stream object.
27+
self.__wrapped = wrapped
28+
self.__convertor = converter
29+
30+
def __getattr__(self, name):
31+
return getattr(self.__wrapped, name)
32+
33+
def write(self, text):
34+
self.__convertor.write(text)
35+
36+
37+
class AnsiToWin32(object):
38+
'''
39+
Implements a 'write()' method which, on Windows, will strip ANSI character
40+
sequences from the text, and if outputting to a tty, will convert them into
41+
win32 function calls.
42+
'''
43+
ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])')
44+
45+
def __init__(self, wrapped, convert=None, strip=None, autoreset=False):
46+
# The wrapped stream (normally sys.stdout or sys.stderr)
47+
self.wrapped = wrapped
48+
49+
# should we reset colors to defaults after every .write()
50+
self.autoreset = autoreset
51+
52+
# create the proxy wrapping our output stream
53+
self.stream = StreamWrapper(wrapped, self)
54+
55+
on_windows = sys.platform.startswith('win')
56+
57+
# should we strip ANSI sequences from our output?
58+
if strip is None:
59+
strip = on_windows
60+
self.strip = strip
61+
62+
# should we should convert ANSI sequences into win32 calls?
63+
if convert is None:
64+
convert = on_windows and is_a_tty(wrapped)
65+
self.convert = convert
66+
67+
# dict of ansi codes to win32 functions and parameters
68+
self.win32_calls = self.get_win32_calls()
69+
70+
# are we wrapping stderr?
71+
self.on_stderr = self.wrapped is sys.stderr
72+
73+
74+
def should_wrap(self):
75+
'''
76+
True if this class is actually needed. If false, then the output
77+
stream will not be affected, nor will win32 calls be issued, so
78+
wrapping stdout is not actually required. This will generally be
79+
False on non-Windows platforms, unless optional functionality like
80+
autoreset has been requested using kwargs to init()
81+
'''
82+
return self.convert or self.strip or self.autoreset
83+
84+
85+
def get_win32_calls(self):
86+
if self.convert and winterm:
87+
return {
88+
AnsiStyle.RESET_ALL: (winterm.reset_all, ),
89+
AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT),
90+
AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL),
91+
AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL),
92+
AnsiFore.BLACK: (winterm.fore, WinColor.BLACK),
93+
AnsiFore.RED: (winterm.fore, WinColor.RED),
94+
AnsiFore.GREEN: (winterm.fore, WinColor.GREEN),
95+
AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW),
96+
AnsiFore.BLUE: (winterm.fore, WinColor.BLUE),
97+
AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA),
98+
AnsiFore.CYAN: (winterm.fore, WinColor.CYAN),
99+
AnsiFore.WHITE: (winterm.fore, WinColor.GREY),
100+
AnsiFore.RESET: (winterm.fore, ),
101+
AnsiBack.BLACK: (winterm.back, WinColor.BLACK),
102+
AnsiBack.RED: (winterm.back, WinColor.RED),
103+
AnsiBack.GREEN: (winterm.back, WinColor.GREEN),
104+
AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW),
105+
AnsiBack.BLUE: (winterm.back, WinColor.BLUE),
106+
AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA),
107+
AnsiBack.CYAN: (winterm.back, WinColor.CYAN),
108+
AnsiBack.WHITE: (winterm.back, WinColor.GREY),
109+
AnsiBack.RESET: (winterm.back, ),
110+
}
111+
112+
113+
def write(self, text):
114+
if self.strip or self.convert:
115+
self.write_and_convert(text)
116+
else:
117+
self.wrapped.write(text)
118+
self.wrapped.flush()
119+
if self.autoreset:
120+
self.reset_all()
121+
122+
123+
def reset_all(self):
124+
if self.convert:
125+
self.call_win32('m', (0,))
126+
else:
127+
self.wrapped.write(Style.RESET_ALL)
128+
129+
130+
def write_and_convert(self, text):
131+
'''
132+
Write the given text to our wrapped stream, stripping any ANSI
133+
sequences from the text, and optionally converting them into win32
134+
calls.
135+
'''
136+
cursor = 0
137+
for match in self.ANSI_RE.finditer(text):
138+
start, end = match.span()
139+
self.write_plain_text(text, cursor, start)
140+
self.convert_ansi(*match.groups())
141+
cursor = end
142+
self.write_plain_text(text, cursor, len(text))
143+
144+
145+
def write_plain_text(self, text, start, end):
146+
if start < end:
147+
self.wrapped.write(text[start:end])
148+
self.wrapped.flush()
149+
150+
151+
def convert_ansi(self, paramstring, command):
152+
if self.convert:
153+
params = self.extract_params(paramstring)
154+
self.call_win32(command, params)
155+
156+
157+
def extract_params(self, paramstring):
158+
def split(paramstring):
159+
for p in paramstring.split(';'):
160+
if p != '':
161+
yield int(p)
162+
return tuple(split(paramstring))
163+
164+
165+
def call_win32(self, command, params):
166+
if params == []:
167+
params = [0]
168+
if command == 'm':
169+
for param in params:
170+
if param in self.win32_calls:
171+
func_args = self.win32_calls[param]
172+
func = func_args[0]
173+
args = func_args[1:]
174+
kwargs = dict(on_stderr=self.on_stderr)
175+
func(*args, **kwargs)
176+

pyzen/_colorama/initialise.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import atexit
2+
import sys
3+
4+
from .ansitowin32 import AnsiToWin32
5+
6+
7+
orig_stdout = sys.stdout
8+
orig_stderr = sys.stderr
9+
10+
atexit_done = False
11+
12+
13+
def reset_all():
14+
AnsiToWin32(orig_stdout).reset_all()
15+
16+
17+
def init(autoreset=False, convert=None, strip=None, wrap=True):
18+
19+
if wrap==False and (autoreset==True or convert==True or strip==True):
20+
raise ValueError('wrap=False conflicts with any other arg=True')
21+
22+
sys.stdout = wrap_stream(orig_stdout, convert, strip, autoreset, wrap)
23+
sys.stderr = wrap_stream(orig_stderr, convert, strip, autoreset, wrap)
24+
25+
global atexit_done
26+
if not atexit_done:
27+
atexit.register(reset_all)
28+
atexit_done = True
29+
30+
31+
def wrap_stream(stream, convert, strip, autoreset, wrap):
32+
if wrap:
33+
wrapper = AnsiToWin32(stream,
34+
convert=convert, strip=strip, autoreset=autoreset)
35+
if wrapper.should_wrap():
36+
stream = wrapper.stream
37+
return stream
38+

pyzen/_colorama/win32.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
2+
# from winbase.h
3+
STDOUT = -11
4+
STDERR = -12
5+
6+
try:
7+
from ctypes import windll
8+
except ImportError:
9+
windll = None
10+
SetConsoleTextAttribute = lambda *_: None
11+
else:
12+
from ctypes import (
13+
byref, Structure, c_char, c_short, c_uint32, c_ushort
14+
)
15+
16+
handles = {
17+
STDOUT: windll.kernel32.GetStdHandle(STDOUT),
18+
STDERR: windll.kernel32.GetStdHandle(STDERR),
19+
}
20+
21+
SHORT = c_short
22+
WORD = c_ushort
23+
DWORD = c_uint32
24+
TCHAR = c_char
25+
26+
class COORD(Structure):
27+
"""struct in wincon.h"""
28+
_fields_ = [
29+
('X', SHORT),
30+
('Y', SHORT),
31+
]
32+
33+
class SMALL_RECT(Structure):
34+
"""struct in wincon.h."""
35+
_fields_ = [
36+
("Left", SHORT),
37+
("Top", SHORT),
38+
("Right", SHORT),
39+
("Bottom", SHORT),
40+
]
41+
42+
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
43+
"""struct in wincon.h."""
44+
_fields_ = [
45+
("dwSize", COORD),
46+
("dwCursorPosition", COORD),
47+
("wAttributes", WORD),
48+
("srWindow", SMALL_RECT),
49+
("dwMaximumWindowSize", COORD),
50+
]
51+
52+
def GetConsoleScreenBufferInfo(stream_id):
53+
handle = handles[stream_id]
54+
csbi = CONSOLE_SCREEN_BUFFER_INFO()
55+
success = windll.kernel32.GetConsoleScreenBufferInfo(
56+
handle, byref(csbi))
57+
# This fails when imported via setup.py when installing using 'pip'
58+
# presumably the fix is that running setup.py should not trigger all
59+
# this activity.
60+
# assert success
61+
return csbi
62+
63+
def SetConsoleTextAttribute(stream_id, attrs):
64+
handle = handles[stream_id]
65+
success = windll.kernel32.SetConsoleTextAttribute(handle, attrs)
66+
assert success
67+
68+
def SetConsoleCursorPosition(stream_id, position):
69+
handle = handles[stream_id]
70+
position = COORD(*position)
71+
success = windll.kernel32.SetConsoleCursorPosition(handle, position)
72+
assert success
73+
74+
def FillConsoleOutputCharacter(stream_id, char, length, start):
75+
handle = handles[stream_id]
76+
char = TCHAR(char)
77+
length = DWORD(length)
78+
start = COORD(*start)
79+
num_written = DWORD(0)
80+
# AttributeError: function 'FillConsoleOutputCharacter' not found
81+
# could it just be that my types are wrong?
82+
success = windll.kernel32.FillConsoleOutputCharacter(
83+
handle, char, length, start, byref(num_written))
84+
assert success
85+
return num_written.value
86+
87+
88+
if __name__=='__main__':
89+
x = GetConsoleScreenBufferInfo(STDOUT)
90+
print(x.dwSize)
91+
print(x.dwCursorPosition)
92+
print(x.wAttributes)
93+
print(x.srWindow)
94+
print(x.dwMaximumWindowSize)
95+

0 commit comments

Comments
 (0)