Use colorama instead of wconio.

This commit is contained in:
Bastian Kleineidam 2012-08-10 22:24:00 +02:00
parent c74690a79a
commit d9acc97f9f
3 changed files with 214 additions and 54 deletions

View file

@ -32,9 +32,6 @@ installation is recommended.
Visual C++ 2008 runtime from
http://www.microsoft.com/downloads/details.aspx?FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en
- *Optional on Windows, for console color support:*
Wconio from http://newcenturycomputers.net/projects/wconio.html
- *Optional, for HTML/CSS syntax checks:*
HTML tidy from http://utidylib.berlios.de/
cssutils from http://cthedot.de/cssutils/

View file

@ -15,8 +15,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
ANSI Color definitions and functions. For Windows systems, WConio is
required.
ANSI Color definitions and functions. For Windows systems, the colorama module
uses ctypes and Windows DLLs to generate colored output.
From Term::ANSIColor, applies also to this module:
@ -54,16 +54,14 @@ ISO 6429 is available from ISO for a charge; the author of this module does
not own a copy of it. Since the source material for ISO 6429 was ECMA-048
and the latter is available for free, there seems little reason to obtain
the ISO standard.
WConio module: http://newcenturycomputers.net/projects/wconio.html
"""
import os
import logging
import types
from .fileutil import has_module, is_tty
from . import colorama
has_wconio = has_module("WConio")
has_curses = has_module("curses")
# Color constants
@ -114,8 +112,9 @@ Purple = 'Purple'
Cyan = 'Cyna'
White = 'White'
InverseColors = (Black, Red, Green, Yellow, Blue, Purple, Cyan, White)
# Color numbers; capitalized colors are inverse
# Ansi color numbers; capitalized colors are inverse
AnsiColor = {
None: '0',
default: '0',
@ -137,6 +136,28 @@ AnsiColor = {
White: '47',
}
# Windows color numbers; capitalized colors are used as background
WinColor = {
None: None,
default: colorama.GREY,
black: colorama.BLACK,
red: colorama.RED,
green: colorama.GREEN,
yellow: colorama.YELLOW,
blue: colorama.BLUE,
purple: colorama.MAGENTA,
cyan: colorama.CYAN,
white: colorama.WHITE,
Black: colorama.BLACK,
Red: colorama.RED,
Green: colorama.GREEN,
Yellow: colorama.YELLOW,
Blue: colorama.BLUE,
Purple: colorama.MAGENTA,
Cyan: colorama.CYAN,
White: colorama.WHITE,
}
# pc speaker beep escape code
Beep = "\007"
@ -153,6 +174,22 @@ def esc_ansicolor (color):
AnsiReset = esc_ansicolor(default)
def get_win_color(color):
"""Convert a named color definition to Windows console color foreground,
background and style numbers."""
foreground = background = style = None
control = ''
if ";" in color:
control, color = color.split(";", 1)
if control == bold:
style = colorama.BRIGHT
if color in InverseColors:
background = WinColor[color]
else:
foreground = WinColor.get(color)
return foreground, background, style
def has_colors (fp):
"""Test if given file is an ANSI color enabled tty."""
# The isatty() function ensures that we do not colorize
@ -160,11 +197,7 @@ def has_colors (fp):
if not is_tty(fp):
return False
if os.name == 'nt':
# On Win9x system, ANSI.SYS would also work. But this
# requires manually adding it to config.sys, which is
# unlikely someone will do just to run this software on
# an old system.
return has_wconio
return True
elif has_curses:
import curses
try:
@ -182,15 +215,8 @@ def get_columns (fp):
"""Return number of columns for given file."""
if not is_tty(fp):
return 80
if has_wconio:
# gettextinfo() returns a tuple
# - left, top, right, bottom: window coordinates
# - textattr, normattr: current attributes
# - videomode: current video mode
# - height, width: screen size
# - curx, cury: current cursor position
# return the width:
return WConio.gettextinfo()[8]
if os.name == 'nt':
return colorama.get_console_size().X
if has_curses:
import curses
try:
@ -201,15 +227,12 @@ def get_columns (fp):
return 80
def _write_color_nt (fp, text, color):
"""Assumes WConio has been imported at module level."""
oldcolor = WConio.gettextinfo()[4]
oldtextcolor = oldcolor & 0x000F
if ";" in color:
color = color.split(";", 1)[1]
WConio.textcolor(WConioColor.get(color, oldtextcolor))
def _write_color_colorama (fp, text, color):
foreground, background, style = get_win_color(color)
colorama.set_console(foreground=foreground, background=background,
style=style)
fp.write(text)
WConio.textattr(oldcolor)
colorama.reset_console()
def _write_color_ansi (fp, text, color):
@ -219,29 +242,8 @@ def _write_color_ansi (fp, text, color):
fp.write(AnsiReset)
if os.name == 'nt' and has_wconio:
import WConio
WConioColor = {
None: WConio.LIGHTGREY,
default: WConio.LIGHTGREY,
black: WConio.BLACK,
red: WConio.RED,
green: WConio.GREEN,
yellow: WConio.YELLOW,
blue: WConio.BLUE,
purple: WConio.MAGENTA,
cyan: WConio.CYAN,
white: WConio.WHITE,
Black: WConio.BLACK,
Red: WConio.RED,
Green: WConio.GREEN,
Yellow: WConio.YELLOW,
Blue: WConio.BLUE,
Purple: WConio.MAGENTA,
Cyan: WConio.CYAN,
White: WConio.WHITE,
}
write_color = _write_color_nt
if os.name == 'nt':
write_color = _write_color_colorama
else:
write_color = _write_color_ansi

161
linkcheck/colorama.py Normal file
View file

@ -0,0 +1,161 @@
# These functions are part of the python-colorama module
# They have been adjusted slightly for LinkChecker
#
# Copyright: (C) 2010 Jonathan Hartley <tartley@tartley.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name(s) of the copyright holders nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# from winbase.h
STDOUT = -11
STDERR = -12
from ctypes import (windll, byref, Structure, c_char, c_short, c_uint32,
c_ushort)
handles = {
STDOUT: windll.kernel32.GetStdHandle(STDOUT),
STDERR: windll.kernel32.GetStdHandle(STDERR),
}
SHORT = c_short
WORD = c_ushort
DWORD = c_uint32
TCHAR = c_char
class COORD(Structure):
"""struct in wincon.h"""
_fields_ = [
('X', SHORT),
('Y', SHORT),
]
class SMALL_RECT(Structure):
"""struct in wincon.h."""
_fields_ = [
("Left", SHORT),
("Top", SHORT),
("Right", SHORT),
("Bottom", SHORT),
]
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
"""struct in wincon.h."""
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", WORD),
("srWindow", SMALL_RECT),
("dwMaximumWindowSize", COORD),
]
def __str__(self):
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
self.dwSize.Y, self.dwSize.X
, self.dwCursorPosition.Y, self.dwCursorPosition.X
, self.wAttributes
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
)
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
handle = handles[stream_id]
csbi = CONSOLE_SCREEN_BUFFER_INFO()
success = windll.kernel32.GetConsoleScreenBufferInfo(
handle, byref(csbi))
return csbi
def SetConsoleTextAttribute(stream_id, attrs):
handle = handles[stream_id]
return windll.kernel32.SetConsoleTextAttribute(handle, attrs)
def FillConsoleOutputCharacter(stream_id, char, length, start):
handle = handles[stream_id]
char = TCHAR(char)
length = DWORD(length)
num_written = DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
success = windll.kernel32.FillConsoleOutputCharacterA(
handle, char, length, start, byref(num_written))
return num_written.value
def FillConsoleOutputAttribute(stream_id, attr, length, start):
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
handle = handles[stream_id]
attribute = WORD(attr)
length = DWORD(length)
num_written = DWORD(0)
# Note that this is hard-coded for ANSI (vs wide) bytes.
return windll.kernel32.FillConsoleOutputAttribute(
handle, attribute, length, start, byref(num_written))
# from wincon.h
BLACK = 0
BLUE = 1
GREEN = 2
CYAN = 3
RED = 4
MAGENTA = 5
YELLOW = 6
GREY = 7
# from wincon.h
NORMAL = 0x00 # dim text, dim background
BRIGHT = 0x08 # bright text, dim background
_default_foreground = None
_default_background = None
_default_style = None
def init():
global _default_foreground, _default_background, _default_style
attrs = GetConsoleScreenBufferInfo(STDOUT).wAttributes
_default_foreground = attrs & 7
_default_background = (attrs >> 4) & 7
_default_style = attrs & BRIGHT
def get_attrs(foreground, background, style):
return foreground + (background << 4) + style
def set_console(stream=STDOUT, foreground=None, background=None, style=None):
if foreground is None:
foreground = _default_foreground
if background is None:
background = _default_background
if style is None:
style = _default_style
attrs = get_attrs(foreground, background, style)
SetConsoleTextAttribute(stream, attrs)
def reset_console(stream=STDOUT):
set_console(stream=stream)
def get_console_size():
return GetConsoleScreenBufferInfo(STDOUT).dwSize