diff --git a/RELEASE.md b/RELEASE.md index f52fafd2..38a5a2b6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -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. \ No newline at end of file diff --git a/docs/settings.rst b/docs/settings.rst index 1d5e1b7f..c66c42a3 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -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 diff --git a/pelican/log.py b/pelican/log.py index 325ac3ea..6210ea5a 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -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 diff --git a/pelican/readers.py b/pelican/readers.py index b8cf44e2..15d09908 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -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) diff --git a/pelican/settings.py b/pelican/settings.py index 9dd3da35..393bee3a 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -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 diff --git a/pelican/tests/content/article_with_images.html b/pelican/tests/content/article_with_images.html deleted file mode 100644 index 4e2af9e7..00000000 --- a/pelican/tests/content/article_with_images.html +++ /dev/null @@ -1,9 +0,0 @@ - -
- - - Images -
-
-
-
diff --git a/pelican/tests/test_cache.py b/pelican/tests/test_cache.py
index 76e228c2..564f1d31 100644
--- a/pelican/tests/test_cache.py
+++ b/pelican/tests/test_cache.py
@@ -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"""
diff --git a/pelican/tests/test_log.py b/pelican/tests/test_log.py
index 3f9d7250..53d83d29 100644
--- a/pelican/tests/test_log.py
+++ b/pelican/tests/test_log.py
@@ -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()
diff --git a/pelican/tests/test_readers.py b/pelican/tests/test_readers.py
index 51af582c..ea5f3bdd 100644
--- a/pelican/tests/test_readers.py
+++ b/pelican/tests/test_readers.py
@@ -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):