Get rid of the colorlog dependency
colorlog was problematic for various reasons: - Not commonly packaged for Linux distributions - Calling colorama.init() automatically on import - Not supporting {foo} log formatting - Not supporting an easy way to turn colors off Instead we now do the log coloring by hand, which is simpler and means everyone will have colored logs.
This commit is contained in:
parent
a9a853baf0
commit
c64e5c9bd5
@ -46,6 +46,8 @@ Changed
|
||||
not be.
|
||||
- Show favicons as window icon with `tabs-are-windows` set.
|
||||
- `:bind <key>` without a command now shows the existing binding
|
||||
- The optional `colorlog` dependency got removed, as qutebrowser now displays
|
||||
colored logs without it.
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
@ -212,7 +212,6 @@ Documentation of used Python libraries:
|
||||
* http://pythonhosted.org/setuptools/[setuptools]
|
||||
* http://cx-freeze.readthedocs.org/en/latest/overview.html[cx_Freeze]
|
||||
* https://pypi.python.org/pypi/colorama[colorama]
|
||||
* https://pypi.python.org/pypi/colorlog[colorlog]
|
||||
|
||||
Related RFCs and standards:
|
||||
|
||||
|
@ -109,11 +109,8 @@ The following libraries are optional and provide a better user experience:
|
||||
To generate the documentation for the `:help` command, when using the git
|
||||
repository (rather than a release), http://asciidoc.org/[asciidoc] is needed.
|
||||
|
||||
The following libraries are optional and provide colored logging in the
|
||||
console:
|
||||
|
||||
* https://pypi.python.org/pypi/colorlog/[colorlog]
|
||||
* On Windows: https://pypi.python.org/pypi/colorama/[colorama]
|
||||
On Windows, https://pypi.python.org/pypi/colorama/[colorama] is needed to
|
||||
display colored log output.
|
||||
|
||||
See link:INSTALL.asciidoc[INSTALL] for directions on how to install qutebrowser
|
||||
and its dependencies.
|
||||
|
@ -35,33 +35,16 @@ try:
|
||||
import colorama
|
||||
except ImportError:
|
||||
colorama = None
|
||||
try:
|
||||
import colorlog
|
||||
except ImportError:
|
||||
colorlog = None
|
||||
else:
|
||||
# WORKAROUND
|
||||
# colorlog calls colorama.init() which we don't want, also it breaks our
|
||||
# sys.stdout/sys.stderr if they are None. Bugreports:
|
||||
# https://code.google.com/p/colorama/issues/detail?id=61
|
||||
# https://github.com/borntyping/python-colorlog/issues/13
|
||||
# This should be (partially) fixed in colorama 0.3.2.
|
||||
# (stream only gets wrapped if it's not None)
|
||||
if colorama is not None:
|
||||
colorama.deinit()
|
||||
|
||||
COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'purple', 'cyan', 'white']
|
||||
|
||||
# Log formats to use.
|
||||
SIMPLE_FMT = '{asctime:8} {levelname}: {message}'
|
||||
EXTENDED_FMT = ('{asctime:8} {levelname:8} {name:10} {module}:{funcName}:'
|
||||
'{lineno} {message}')
|
||||
SIMPLE_FMT_COLORED = ('%(green)s%(asctime)-8s%(reset)s '
|
||||
'%(log_color)s%(levelname)s%(reset)s: %(message)s')
|
||||
EXTENDED_FMT_COLORED = (
|
||||
'%(green)s%(asctime)-8s%(reset)s '
|
||||
'%(log_color)s%(levelname)-8s%(reset)s '
|
||||
'%(cyan)s%(name)-10s %(module)s:%(funcName)s:%(lineno)s%(reset)s '
|
||||
'%(log_color)s%(message)s%(reset)s'
|
||||
)
|
||||
SIMPLE_FMT = ('{green}{asctime:8}{reset} {log_color}{levelname}{reset}: '
|
||||
'{message}')
|
||||
EXTENDED_FMT = ('{green}{asctime:8}{reset} '
|
||||
'{log_color}{levelname:8}{reset} '
|
||||
'{cyan}{name:10} {module}:{funcName}:{lineno}{reset} '
|
||||
'{log_color}{message}{reset}')
|
||||
EXTENDED_FMT_HTML = (
|
||||
'<tr>'
|
||||
'<td><pre>%(green)s%(asctime)-8s%(reset)s</pre></td>'
|
||||
@ -223,12 +206,7 @@ def _init_formatters(level, color, force_color):
|
||||
console_formatter/ram_formatter: logging.Formatter instances.
|
||||
use_colorama: Whether to use colorama.
|
||||
"""
|
||||
if level <= logging.DEBUG:
|
||||
console_fmt = EXTENDED_FMT
|
||||
console_fmt_colored = EXTENDED_FMT_COLORED
|
||||
else:
|
||||
console_fmt = SIMPLE_FMT
|
||||
console_fmt_colored = SIMPLE_FMT_COLORED
|
||||
console_fmt = EXTENDED_FMT if level <= logging.DEBUG else SIMPLE_FMT
|
||||
ram_formatter = logging.Formatter(EXTENDED_FMT, DATEFMT, '{')
|
||||
html_formatter = HTMLFormatter(EXTENDED_FMT_HTML, DATEFMT,
|
||||
log_colors=LOG_COLORS)
|
||||
@ -236,14 +214,17 @@ def _init_formatters(level, color, force_color):
|
||||
return None, ram_formatter, html_formatter, False
|
||||
|
||||
use_colorama = False
|
||||
color_supported = colorlog is not None and (os.name == 'posix' or colorama)
|
||||
color_supported = os.name == 'posix' or colorama
|
||||
|
||||
if color_supported and (sys.stderr.isatty() or force_color) and color:
|
||||
console_formatter = colorlog.ColoredFormatter(
|
||||
console_fmt_colored, DATEFMT, log_colors=LOG_COLORS)
|
||||
use_colors = True
|
||||
if colorama and os.name != 'posix':
|
||||
use_colorama = True
|
||||
else:
|
||||
console_formatter = logging.Formatter(console_fmt, DATEFMT, '{')
|
||||
use_colors = False
|
||||
|
||||
console_formatter = ColoredFormatter(console_fmt, DATEFMT, '{',
|
||||
use_colors=use_colors)
|
||||
return console_formatter, ram_formatter, html_formatter, use_colorama
|
||||
|
||||
|
||||
@ -467,9 +448,43 @@ class RAMHandler(logging.Handler):
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
class ColoredFormatter(logging.Formatter):
|
||||
|
||||
"""Logging formatter to output colored logs.
|
||||
|
||||
Attributes:
|
||||
use_colors: Whether to do colored logging or not.
|
||||
|
||||
Class attributes:
|
||||
COLOR_ESCAPES: A dict mapping color names to escape sequences
|
||||
RESET_ESCAPE: The escape sequence using for resetting colors
|
||||
"""
|
||||
|
||||
COLOR_ESCAPES = {color: '\033[{}m'.format(i)
|
||||
for i, color in enumerate(COLORS, start=30)}
|
||||
RESET_ESCAPE = '\033[0m'
|
||||
|
||||
def __init__(self, fmt, datefmt, style, *, use_colors):
|
||||
super().__init__(fmt, datefmt, style)
|
||||
self._use_colors = use_colors
|
||||
|
||||
def format(self, record):
|
||||
if self._use_colors:
|
||||
color_dict = dict(self.COLOR_ESCAPES)
|
||||
color_dict['reset'] = self.RESET_ESCAPE
|
||||
log_color = LOG_COLORS[record.levelname]
|
||||
color_dict['log_color'] = self.COLOR_ESCAPES[log_color]
|
||||
else:
|
||||
color_dict = {color: '' for color in self.COLOR_ESCAPES}
|
||||
color_dict['reset'] = ''
|
||||
color_dict['log_color'] = ''
|
||||
record.__dict__.update(color_dict)
|
||||
return super().format(record)
|
||||
|
||||
|
||||
class HTMLFormatter(logging.Formatter):
|
||||
|
||||
"""Formatter for HTML-colored log messages, similar to colorlog.
|
||||
"""Formatter for HTML-colored log messages.
|
||||
|
||||
Attributes:
|
||||
_log_colors: The colors to use for logging levels.
|
||||
@ -489,8 +504,7 @@ class HTMLFormatter(logging.Formatter):
|
||||
self._colordict = {}
|
||||
# We could solve this nicer by using CSS, but for this simple case this
|
||||
# works.
|
||||
for color in ['black', 'red', 'green', 'yellow', 'blue', 'purple',
|
||||
'cyan', 'white']:
|
||||
for color in COLORS:
|
||||
self._colordict[color] = '<font color="{}">'.format(color)
|
||||
self._colordict['reset'] = '</font>'
|
||||
|
||||
|
@ -129,7 +129,6 @@ def _module_versions():
|
||||
lines = []
|
||||
modules = collections.OrderedDict([
|
||||
('sip', ['SIP_VERSION_STR']),
|
||||
('colorlog', []),
|
||||
('colorama', ['VERSION', '__version__']),
|
||||
('pypeg2', ['__version__']),
|
||||
('jinja2', ['__version__']),
|
||||
|
@ -4,5 +4,4 @@ Pygments==2.1.3
|
||||
pyPEG2==2.15.2
|
||||
PyYAML==3.11
|
||||
colorama==0.3.7
|
||||
colorlog==2.6.3
|
||||
cssutils==1.0.1
|
||||
|
@ -319,7 +319,6 @@ class ImportFake:
|
||||
def __init__(self):
|
||||
self.exists = {
|
||||
'sip': True,
|
||||
'colorlog': True,
|
||||
'colorama': True,
|
||||
'pypeg2': True,
|
||||
'jinja2': True,
|
||||
@ -383,15 +382,14 @@ class TestModuleVersions:
|
||||
@pytest.mark.usefixtures('import_fake')
|
||||
def test_all_present(self):
|
||||
"""Test with all modules present in version 1.2.3."""
|
||||
expected = ['sip: yes', 'colorlog: yes', 'colorama: 1.2.3',
|
||||
'pypeg2: 1.2.3', 'jinja2: 1.2.3', 'pygments: 1.2.3',
|
||||
'yaml: 1.2.3', 'cssutils: 1.2.3']
|
||||
expected = ['sip: yes', 'colorama: 1.2.3', 'pypeg2: 1.2.3',
|
||||
'jinja2: 1.2.3', 'pygments: 1.2.3', 'yaml: 1.2.3',
|
||||
'cssutils: 1.2.3']
|
||||
assert version._module_versions() == expected
|
||||
|
||||
@pytest.mark.parametrize('module, idx, expected', [
|
||||
('colorlog', 1, 'colorlog: no'),
|
||||
('colorama', 2, 'colorama: no'),
|
||||
('cssutils', 7, 'cssutils: no'),
|
||||
('colorama', 1, 'colorama: no'),
|
||||
('cssutils', 6, 'cssutils: no'),
|
||||
])
|
||||
def test_missing_module(self, module, idx, expected, import_fake):
|
||||
"""Test with a module missing.
|
||||
@ -405,15 +403,14 @@ class TestModuleVersions:
|
||||
assert version._module_versions()[idx] == expected
|
||||
|
||||
@pytest.mark.parametrize('value, expected', [
|
||||
('VERSION', ['sip: yes', 'colorlog: yes', 'colorama: 1.2.3',
|
||||
'pypeg2: yes', 'jinja2: yes', 'pygments: yes',
|
||||
'yaml: yes', 'cssutils: yes']),
|
||||
('SIP_VERSION_STR', ['sip: 1.2.3', 'colorlog: yes', 'colorama: yes',
|
||||
'pypeg2: yes', 'jinja2: yes', 'pygments: yes',
|
||||
'yaml: yes', 'cssutils: yes']),
|
||||
(None, ['sip: yes', 'colorlog: yes', 'colorama: yes', 'pypeg2: yes',
|
||||
'jinja2: yes', 'pygments: yes', 'yaml: yes',
|
||||
'cssutils: yes']),
|
||||
('VERSION', ['sip: yes', 'colorama: 1.2.3', 'pypeg2: yes',
|
||||
'jinja2: yes', 'pygments: yes', 'yaml: yes',
|
||||
'cssutils: yes']),
|
||||
('SIP_VERSION_STR', ['sip: 1.2.3', 'colorama: yes', 'pypeg2: yes',
|
||||
'jinja2: yes', 'pygments: yes', 'yaml: yes',
|
||||
'cssutils: yes']),
|
||||
(None, ['sip: yes', 'colorama: yes', 'pypeg2: yes', 'jinja2: yes',
|
||||
'pygments: yes', 'yaml: yes', 'cssutils: yes']),
|
||||
])
|
||||
def test_version_attribute(self, value, expected, import_fake):
|
||||
"""Test with a different version attribute.
|
||||
@ -429,7 +426,6 @@ class TestModuleVersions:
|
||||
assert version._module_versions() == expected
|
||||
|
||||
@pytest.mark.parametrize('name, has_version', [
|
||||
('colorlog', False),
|
||||
('sip', False),
|
||||
('colorama', True),
|
||||
('pypeg2', True),
|
||||
@ -442,7 +438,7 @@ class TestModuleVersions:
|
||||
"""Check if all dependencies have an expected __version__ attribute.
|
||||
|
||||
The aim of this test is to fail if modules suddenly don't have a
|
||||
__version__ attribute anymore in a newer version, or colorlog has one.
|
||||
__version__ attribute anymore in a newer version.
|
||||
|
||||
Args:
|
||||
name: The name of the module to check.
|
||||
|
Loading…
Reference in New Issue
Block a user