Fix --fatal to honor LOG_FILTER

This commit is contained in:
Eric Dunham 2021-03-03 12:32:08 -06:00
commit f5cec6f13e
9 changed files with 63 additions and 51 deletions

View file

@ -1,3 +1,3 @@
Release type: minor
Release type: patch
Add setting to allow for empty `alt` attributes in images; it defaults to `False`, which is the current behavior. Empty `alt` text can be indicative of an accessibility oversight, but can be intentional and desired, e.g. https://webaim.org/techniques/alttext/, https://www.w3.org/WAI/tutorials/images/decorative/.
Address an issue where `--fatal=warnings|errors` would not honor entries in the `LOG_FILTER` setting.

View file

@ -364,10 +364,6 @@ Basic settings
A list of metadata fields containing reST/Markdown content to be parsed and
translated to HTML.
.. data:: IMAGES_ALLOW_EMPTY_ALT_TEXT = False
If ``True``, warnings will not be emitted when empty ``alt`` attributes for images are found.
.. data:: PORT = 8000
The TCP port to serve content from the output folder via HTTP when pelican

View file

@ -149,24 +149,9 @@ class LimitLogger(logging.Logger):
self.addFilter(LimitLogger.limit_filter)
class FatalLogger(LimitLogger):
warnings_fatal = False
errors_fatal = False
def warning(self, *args, **kwargs):
super().warning(*args, **kwargs)
if FatalLogger.warnings_fatal:
raise RuntimeError('Warning encountered')
def error(self, *args, **kwargs):
super().error(*args, **kwargs)
if FatalLogger.errors_fatal:
raise RuntimeError('Error encountered')
logging.setLoggerClass(FatalLogger)
logging.setLoggerClass(LimitLogger)
# force root logger to be of our preferred class
logging.getLogger().__class__ = FatalLogger
logging.getLogger().__class__ = LimitLogger
def supports_color():
@ -194,11 +179,13 @@ def get_formatter():
return TextFormatter()
class FatalHandler(logging.Handler):
def emit(self, record):
sys.exit(1)
def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
logs_dedup_min_level=None):
FatalLogger.warnings_fatal = fatal.startswith('warning')
FatalLogger.errors_fatal = bool(fatal)
logger = logging.getLogger(name)
handler.setFormatter(get_formatter())
@ -209,6 +196,11 @@ def init(level=None, fatal='', handler=logging.StreamHandler(), name=None,
if logs_dedup_min_level:
LimitFilter.LOGS_DEDUP_MIN_LEVEL = logs_dedup_min_level
if fatal.startswith('warning'):
logger.addHandler(FatalHandler(level=logging.WARNING))
if fatal:
logger.addHandler(FatalHandler(level=logging.ERROR))
def log_warnings():
import warnings

View file

@ -574,7 +574,7 @@ class Readers(FileStampDataCacher):
self.cache_data(path, (content, reader_metadata))
metadata.update(_filter_discardable_metadata(reader_metadata))
if not self.settings['IMAGES_ALLOW_EMPTY_ALT_TEXT'] and content:
if content:
# find images with empty alt
find_empty_alt(content, path)

View file

@ -163,8 +163,7 @@ DEFAULT_CONFIG = {
'WRITE_SELECTED': [],
'FORMATTED_FIELDS': ['summary'],
'PORT': 8000,
'BIND': '127.0.0.1',
'IMAGES_ALLOW_EMPTY_ALT_TEXT': False
'BIND': '127.0.0.1'
}
PYGMENTS_RST_OPTIONS = None

View file

@ -1,9 +0,0 @@
<html>
<head>
</head>
<body>
Images
<img alt="" src="test-image.png" width="300px" />
<img src="test-image.png" width="300px" alt="" />
</body>
</html>

View file

@ -153,7 +153,7 @@ class TestCache(unittest.TestCase):
- empty.md
- empty_with_bom.md
"""
self.assertEqual(generator.readers.read_file.call_count, 7)
self.assertEqual(generator.readers.read_file.call_count, 6)
def test_article_reader_content_caching(self):
"""Test raw article content caching at the reader level"""

View file

@ -2,6 +2,7 @@ import logging
import unittest
from collections import defaultdict
from contextlib import contextmanager
from unittest import mock
from pelican import log
from pelican.tests.support import LogCountHandler
@ -130,3 +131,48 @@ class TestLog(unittest.TestCase):
self.assertEqual(
self.handler.count_logs('Another log \\d', logging.WARNING),
0)
@mock.patch.object(log, 'sys')
class TestLogInit(unittest.TestCase):
def init(self, fatal, name):
logger = logging.getLogger(name)
log.init(fatal=fatal, name=name)
return logger
def test_fatal_warnings(self, sys):
logger = self.init('warnings', 'test_fatal_warnings')
logger.warning('foo')
logger.error('bar')
sys.exit.assert_called_with(1)
def test_fatal_errors(self, sys):
logger = self.init('errors', 'test_fatal_errors')
logger.warning('foo')
logger.error('bar')
sys.exit.assert_called_with(1)
def test_no_fatal(self, sys):
logger = self.init('', 'test_no_fatal')
logger.warning('foo')
logger.error('bar')
sys.exit.assert_not_called()
def test_fatal_warnings_log_filter(self, sys):
limit_filter = log.LimitFilter()
limit_filter._ignore = {(logging.WARNING, 'foo')}
lf = mock.PropertyMock(return_value=limit_filter)
with mock.patch('pelican.log.LimitLogger.limit_filter', new=lf):
logger = self.init('warnings', 'test_fatal_warnings_log_filter')
logger.warning('foo')
sys.exit.assert_not_called()
def test_fatal_errors_log_filter(self, sys):
limit_filter = log.LimitFilter()
limit_filter.LOGS_DEDUP_MIN_LEVEL = logging.CRITICAL
limit_filter._ignore = {(logging.ERROR, 'bar')}
lf = mock.PropertyMock(return_value=limit_filter)
with mock.patch('pelican.log.LimitLogger.limit_filter', new=lf):
logger = self.init('errors', 'test_fatal_errors_log_filter')
logger.error('bar')
sys.exit.assert_not_called()

View file

@ -134,18 +134,6 @@ class DefaultReaderTest(ReaderTest):
'Other images have empty alt attributes'}
)
@patch('pelican.readers.logger')
def test_read_file_with_images_allow_empty_alt_text_false(self, log_mock):
test_file = 'article_with_images.html'
self.read_file(path=test_file, IMAGES_ALLOW_EMPTY_ALT_TEXT=False)
assert 2 == log_mock.warning.call_count
@patch('pelican.readers.logger')
def test_read_file_with_images_allow_empty_alt_text_true(self, log_mock):
test_file = 'article_with_images.html'
self.read_file(path=test_file, IMAGES_ALLOW_EMPTY_ALT_TEXT=True)
log_mock.warning.assert_not_called()
class RstReaderTest(ReaderTest):