From 5ff553f6f337f2ddcb6173bd80af138cdbd298ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 10 Nov 2018 19:42:59 +0100 Subject: [PATCH 1/3] Add tests verifying graceful handling on reST errors. Currently all fail. --- pelican/tests/parse_error/parse_error.rst | 4 ++++ pelican/tests/test_pelican.py | 15 +++++++++++++++ pelican/tests/test_readers.py | 6 ++++++ 3 files changed, 25 insertions(+) create mode 100644 pelican/tests/parse_error/parse_error.rst diff --git a/pelican/tests/parse_error/parse_error.rst b/pelican/tests/parse_error/parse_error.rst new file mode 100644 index 00000000..7aee68e1 --- /dev/null +++ b/pelican/tests/parse_error/parse_error.rst @@ -0,0 +1,4 @@ +Page with a parse error +############# + +The underline is too short. diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py index 273fc430..adc07072 100644 --- a/pelican/tests/test_pelican.py +++ b/pelican/tests/test_pelican.py @@ -225,3 +225,18 @@ class TestPelican(LoggedTestCase): count=1, msg="MD_EXTENSIONS is deprecated use MARKDOWN instead.", level=logging.WARNING) + + def test_parse_errors(self): + # Verify that just an error is printed and the application doesn't + # abort, exit or something. + settings = read_settings(path=None, override={ + 'PATH': os.path.abspath(os.path.join(CURRENT_DIR, 'parse_error')), + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + self.assertLogCountEqual( + count=1, + msg="Could not process .*parse_error.rst", + level=logging.ERROR) diff --git a/pelican/tests/test_readers.py b/pelican/tests/test_readers.py index 4db4938e..81a7d92d 100644 --- a/pelican/tests/test_readers.py +++ b/pelican/tests/test_readers.py @@ -410,6 +410,12 @@ class RstReaderTest(ReaderTest): self.assertEqual(tuple_date.metadata['date'], string_date.metadata['date']) + def test_parse_error(self): + # Verify that it raises an Exception, not nothing and not SystemExit or + # some such + with six.assertRaisesRegex(self, Exception, "underline too short"): + self.read_file(path='../parse_error/parse_error.rst') + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") class MdReaderTest(ReaderTest): From 015eefe7de51eada383073711b99da23efa94285 Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Sat, 10 Nov 2018 13:31:08 +0100 Subject: [PATCH 2/3] Let's handle reST errors in a simple and nice way, finally. --- pelican/readers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pelican/readers.py b/pelican/readers.py index 842602aa..b4bc9e91 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -12,6 +12,7 @@ import docutils.io from docutils.writers.html4css1 import HTMLTranslator, Writer import six +from six import StringIO from six.moves.html_parser import HTMLParser from pelican import rstdirectives # NOQA @@ -256,7 +257,9 @@ class RstReader(BaseReader): 'syntax_highlight': 'short', 'input_encoding': 'utf-8', 'language_code': self.settings.get('DEFAULT_LANG'), - 'exit_status_level': 2, + 'halt_level': 2, + 'traceback': True, + 'warning_stream': StringIO(), 'embed_stylesheet': False} user_params = self.settings.get('DOCUTILS_SETTINGS') if user_params: @@ -269,7 +272,7 @@ class RstReader(BaseReader): pub.set_components('standalone', 'restructuredtext', 'html') pub.process_programmatic_settings(None, extra_params, None) pub.set_source(source_path=source_path) - pub.publish(enable_exit_status=True) + pub.publish() return pub def read(self, source_path): From dd76c7158f7e05b0d203818d3fe18bea26e48c3f Mon Sep 17 00:00:00 2001 From: Deniz Turgut Date: Sat, 10 Nov 2018 13:57:27 +0100 Subject: [PATCH 3/3] Improve the looks of reST parser error output. --- pelican/log.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pelican/log.py b/pelican/log.py index 345f79d0..e7a6f317 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -24,6 +24,9 @@ class BaseFormatter(logging.Formatter): record.__dict__['customlevelname'] = customlevel # format multiline messages 'nicely' to make it clear they are together record.msg = record.msg.replace('\n', '\n | ') + record.args = tuple(arg.replace('\n', '\n | ') if + isinstance(arg, six.string_types) else + arg for arg in record.args) return super(BaseFormatter, self).format(record) def formatException(self, ei):