Skip to content

Commit 193b7a1

Browse files
authored
Merge branch 'master' into rm-3.4
2 parents 036faef + 8f2829d commit 193b7a1

File tree

4 files changed

+86
-30
lines changed

4 files changed

+86
-30
lines changed

CHANGELOG.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,31 @@ to `semantic versioning`_.
1111
.. _Keep a Changelog: http://keepachangelog.com/
1212
.. _semantic versioning: http://semver.org/
1313

14+
`Release 11.2`_ (2020-02-15)
15+
----------------------------
16+
17+
Merge pull request `#79`_ which adds support for Python 3.8.
18+
19+
.. _Release 11.2: https://github.com/xolox/python-coloredlogs/compare/11.1...11.2
20+
.. _#79: https://github.com/xolox/python-coloredlogs/pull/79
21+
22+
`Release 11.1`_ (2020-02-15)
23+
----------------------------
24+
25+
Starting with the previous release I've resolved to try and tackle the large
26+
number of open issues after an unplanned hiatus from the development and
27+
maintenance of my open source projects, so here are some more bug fixes:
28+
29+
- Fix support for custom log record factories and add a test to avoid
30+
regressions (`#47`_, `#59`_).
31+
32+
- Change ``make screenshots`` to be Python 3 compatible and document
33+
additional requirements (`#65`_).
34+
35+
.. _Release 11.1: https://github.com/xolox/python-coloredlogs/compare/11.0...11.1
36+
.. _#59: https://github.com/xolox/python-coloredlogs/issues/59
37+
.. _#65: https://github.com/xolox/python-coloredlogs/issues/65
38+
1439
`Release 11.0`_ (2020-02-14)
1540
----------------------------
1641

README.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ The `coloredlogs` package enables colored terminal output for Python's logging_
1111
module. The ColoredFormatter_ class inherits from `logging.Formatter`_ and uses
1212
`ANSI escape sequences`_ to render your logging messages in color. It uses only
1313
standard colors so it should work on any UNIX terminal. It's currently tested
14-
on Python 2.7, 3.5+ and PyPy. On Windows `coloredlogs`
15-
automatically pulls in Colorama_ as a dependency and enables ANSI escape
16-
sequence translation using Colorama. Here is a screen shot of the demo that is
17-
printed when the command ``coloredlogs --demo`` is executed:
14+
on Python 2.7, 3.5+ and PyPy. On Windows `coloredlogs` automatically pulls in
15+
Colorama_ as a dependency and enables ANSI escape sequence translation using
16+
Colorama. Here is a screen shot of the demo that is printed when the command
17+
``coloredlogs --demo`` is executed:
1818

1919
.. image:: https://coloredlogs.readthedocs.io/en/latest/_images/defaults.png
2020

coloredlogs/__init__.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Colored terminal output for Python's logging module.
22
#
33
# Author: Peter Odding <peter@peterodding.com>
4-
# Last Change: February 14, 2020
4+
# Last Change: February 15, 2020
55
# URL: https://coloredlogs.readthedocs.io
66

77
"""
@@ -213,7 +213,7 @@
213213
NEED_COLORAMA = WINDOWS
214214

215215
# Semi-standard module versioning.
216-
__version__ = '11.0'
216+
__version__ = '11.2'
217217

218218
DEFAULT_LOG_LEVEL = logging.INFO
219219
"""The default log level for :mod:`coloredlogs` (:data:`logging.INFO`)."""
@@ -981,10 +981,6 @@ def __init__(self, fmt=None, datefmt=None, level_styles=None, field_styles=None,
981981
initializer of the base class.
982982
"""
983983
self.nn = NameNormalizer()
984-
# The use of the logging.getLogRecordFactory() is preferable over
985-
# logging.LogRecord in Python 3, but this function isn't available in
986-
# Python 2. We'll check the existence of the function just once now.
987-
self.log_record_factory = getattr(logging, 'getLogRecordFactory', None)
988984
# The default values of the following arguments are defined here so
989985
# that Sphinx doesn't embed the default values in the generated
990986
# documentation (because the result is awkward to read).
@@ -1102,11 +1098,7 @@ def format(self, record):
11021098
# For more details refer to issue 29 on GitHub:
11031099
# https://github.com/xolox/python-coloredlogs/issues/29
11041100
copy = Empty()
1105-
copy.__class__ = (
1106-
self.log_record_factory()
1107-
if self.log_record_factory is not None
1108-
else logging.LogRecord
1109-
)
1101+
copy.__class__ = record.__class__
11101102
copy.__dict__.update(record.__dict__)
11111103
copy.msg = ansi_wrap(coerce_string(record.msg), **style)
11121104
record = copy

coloredlogs/tests.py

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Automated tests for the `coloredlogs' package.
22
#
33
# Author: Peter Odding <peter@peterodding.com>
4-
# Last Change: February 14, 2020
4+
# Last Change: February 15, 2020
55
# URL: https://coloredlogs.readthedocs.io
66

77
"""Automated tests for the `coloredlogs` package."""
@@ -20,7 +20,7 @@
2020
# External dependencies.
2121
from humanfriendly.compat import StringIO
2222
from humanfriendly.terminal import ANSI_COLOR_CODES, ansi_style, ansi_wrap
23-
from humanfriendly.testing import PatchedItem, TestCase, retry
23+
from humanfriendly.testing import PatchedAttribute, PatchedItem, TestCase, retry
2424
from humanfriendly.text import format, random_string
2525
from mock import MagicMock
2626

@@ -46,6 +46,7 @@
4646
set_level,
4747
walk_propagation_tree,
4848
)
49+
from coloredlogs.demo import demonstrate_colored_logging
4950
from coloredlogs.syslog import SystemLogging, match_syslog_handler
5051
from coloredlogs.converter import (
5152
ColoredCronMailer,
@@ -415,42 +416,42 @@ def test_html_conversion(self):
415416
'<code>plain text followed by <span style="color:{css}">{name}</span> text</code>',
416417
css=EIGHT_COLOR_PALETTE[ansi_code], name=color_name,
417418
)
418-
self.assertEquals(expected_html, convert(ansi_encoded_text))
419+
self.assertEqual(expected_html, convert(ansi_encoded_text))
419420
# Check conversion of bright colored text.
420421
expected_html = '<code><span style="color:#FF0">bright yellow</span></code>'
421-
self.assertEquals(expected_html, convert(ansi_wrap('bright yellow', color='yellow', bright=True)))
422+
self.assertEqual(expected_html, convert(ansi_wrap('bright yellow', color='yellow', bright=True)))
422423
# Check conversion of text with a background color.
423424
expected_html = '<code><span style="background-color:#DE382B">red background</span></code>'
424-
self.assertEquals(expected_html, convert(ansi_wrap('red background', background='red')))
425+
self.assertEqual(expected_html, convert(ansi_wrap('red background', background='red')))
425426
# Check conversion of text with a bright background color.
426427
expected_html = '<code><span style="background-color:#F00">bright red background</span></code>'
427-
self.assertEquals(expected_html, convert(ansi_wrap('bright red background', background='red', bright=True)))
428+
self.assertEqual(expected_html, convert(ansi_wrap('bright red background', background='red', bright=True)))
428429
# Check conversion of text that uses the 256 color mode palette as a foreground color.
429430
expected_html = '<code><span style="color:#FFAF00">256 color mode foreground</span></code>'
430-
self.assertEquals(expected_html, convert(ansi_wrap('256 color mode foreground', color=214)))
431+
self.assertEqual(expected_html, convert(ansi_wrap('256 color mode foreground', color=214)))
431432
# Check conversion of text that uses the 256 color mode palette as a background color.
432433
expected_html = '<code><span style="background-color:#AF0000">256 color mode background</span></code>'
433-
self.assertEquals(expected_html, convert(ansi_wrap('256 color mode background', background=124)))
434+
self.assertEqual(expected_html, convert(ansi_wrap('256 color mode background', background=124)))
434435
# Check that invalid 256 color mode indexes don't raise exceptions.
435436
expected_html = '<code>plain text expected</code>'
436-
self.assertEquals(expected_html, convert('\x1b[38;5;256mplain text expected\x1b[0m'))
437+
self.assertEqual(expected_html, convert('\x1b[38;5;256mplain text expected\x1b[0m'))
437438
# Check conversion of bold text.
438439
expected_html = '<code><span style="font-weight:bold">bold text</span></code>'
439-
self.assertEquals(expected_html, convert(ansi_wrap('bold text', bold=True)))
440+
self.assertEqual(expected_html, convert(ansi_wrap('bold text', bold=True)))
440441
# Check conversion of underlined text.
441442
expected_html = '<code><span style="text-decoration:underline">underlined text</span></code>'
442-
self.assertEquals(expected_html, convert(ansi_wrap('underlined text', underline=True)))
443+
self.assertEqual(expected_html, convert(ansi_wrap('underlined text', underline=True)))
443444
# Check conversion of strike-through text.
444445
expected_html = '<code><span style="text-decoration:line-through">strike-through text</span></code>'
445-
self.assertEquals(expected_html, convert(ansi_wrap('strike-through text', strike_through=True)))
446+
self.assertEqual(expected_html, convert(ansi_wrap('strike-through text', strike_through=True)))
446447
# Check conversion of inverse text.
447448
expected_html = '<code><span style="background-color:#FFC706;color:#000">inverse</span></code>'
448-
self.assertEquals(expected_html, convert(ansi_wrap('inverse', color='yellow', inverse=True)))
449+
self.assertEqual(expected_html, convert(ansi_wrap('inverse', color='yellow', inverse=True)))
449450
# Check conversion of URLs.
450451
for sample_text in 'www.python.org', 'http://coloredlogs.rtfd.org', 'https://coloredlogs.rtfd.org':
451452
sample_url = sample_text if '://' in sample_text else ('http://' + sample_text)
452453
expected_html = '<code><a href="%s" style="color:inherit">%s</a></code>' % (sample_url, sample_text)
453-
self.assertEquals(expected_html, convert(sample_text))
454+
self.assertEqual(expected_html, convert(sample_text))
454455
# Check that the capture pattern for URLs doesn't match ANSI escape
455456
# sequences and also check that the short hand for the 0 reset code is
456457
# supported. These are tests for regressions of bugs found in
@@ -464,7 +465,7 @@ def test_html_conversion(self):
464465
'https://coloredlogs.readthedocs.io'
465466
'</a></span>&gt;</code>'
466467
)
467-
self.assertEquals(expected_html, convert(ansi_encoded_text))
468+
self.assertEqual(expected_html, convert(ansi_encoded_text))
468469

469470
def test_output_interception(self):
470471
"""Test capturing of output from external commands."""
@@ -538,6 +539,44 @@ def test_explicit_usage_message(self):
538539
"""Test that the usage message is shown when ``--help`` is given."""
539540
assert 'Usage:' in main('coloredlogs', '--help', capture=True)
540541

542+
def test_custom_record_factory(self):
543+
"""
544+
Test that custom LogRecord factories are supported.
545+
546+
This test is a bit convoluted because the logging module suppresses
547+
exceptions. We monkey patch the method suspected of encountering
548+
exceptions so that we can tell after it was called whether any
549+
exceptions occurred (despite the exceptions not propagating).
550+
"""
551+
if not hasattr(logging, 'getLogRecordFactory'):
552+
return self.skipTest("this test requires Python >= 3.2")
553+
554+
exceptions = []
555+
original_method = ColoredFormatter.format
556+
original_factory = logging.getLogRecordFactory()
557+
558+
def custom_factory(*args, **kwargs):
559+
record = original_factory(*args, **kwargs)
560+
record.custom_attribute = 0xdecafbad
561+
return record
562+
563+
def custom_method(*args, **kw):
564+
try:
565+
return original_method(*args, **kw)
566+
except Exception as e:
567+
exceptions.append(e)
568+
raise
569+
570+
with PatchedAttribute(ColoredFormatter, 'format', custom_method):
571+
logging.setLogRecordFactory(custom_factory)
572+
try:
573+
demonstrate_colored_logging()
574+
finally:
575+
logging.setLogRecordFactory(original_factory)
576+
577+
# Ensure that no exceptions were triggered.
578+
assert not exceptions
579+
541580

542581
def check_contents(filename, contents, match):
543582
"""Check if a line in a file contains an expected string."""

0 commit comments

Comments
 (0)