From 0889c5972d214fea81ffd60d76429835470d7498 Mon Sep 17 00:00:00 2001 From: Mike Fiedler Date: Sun, 13 Mar 2022 15:01:42 +0000 Subject: [PATCH 1/3] fix: emit a warning when no content is rendered Fixes #149 Signed-off-by: Mike Fiedler --- readme_renderer/rst.py | 1 + tests/test_rst.py | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/readme_renderer/rst.py b/readme_renderer/rst.py index f237f32..628ad03 100644 --- a/readme_renderer/rst.py +++ b/readme_renderer/rst.py @@ -129,4 +129,5 @@ def render( if rendered: return clean(rendered) else: + stream.write("no output rendered") return None diff --git a/tests/test_rst.py b/tests/test_rst.py index 64e552c..def5e70 100755 --- a/tests/test_rst.py +++ b/tests/test_rst.py @@ -53,3 +53,13 @@ def test_rst_raw(): """, stream=warnings) is None assert '"raw" directive disabled' in warnings.getvalue() + + +def test_rst_header_only(): + warnings = io.StringIO() + assert render(""" +Header +====== +""", stream=warnings) is None + + assert "no output rendered" in warnings.getvalue() From 8eb63dac16824df99ed9eafabc288bc7b97e3fcc Mon Sep 17 00:00:00 2001 From: Mike Fiedler Date: Sun, 20 Mar 2022 21:03:04 +0000 Subject: [PATCH 2/3] feat: emit empty warning only if no warnings exist This is a bit more gymnastics than I think is warranted, but wanted to play out the example. Needing to inspect the stream proved more complex than originally expected, as each version confroms to a slightly different interface. - Updated the outpout string to be clearer - Added test for empty RST file Signed-off-by: Mike Fiedler --- readme_renderer/rst.py | 22 +++++++++++++++++++--- tests/test_rst.py | 22 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/readme_renderer/rst.py b/readme_renderer/rst.py index 628ad03..10670d3 100644 --- a/readme_renderer/rst.py +++ b/readme_renderer/rst.py @@ -14,7 +14,7 @@ from __future__ import absolute_import, division, print_function import io -from typing import Any, Dict, IO, Optional, Union +from typing import Any, Dict, Optional, TextIO, Union, TYPE_CHECKING from docutils.core import publish_parts from docutils.nodes import colspec, image @@ -23,6 +23,10 @@ from .clean import clean +if TYPE_CHECKING: + # Prevent a circular import + from .integration.distutils import _WarningStream + class ReadMeHTMLTranslator(HTMLTranslator): # type: ignore[misc] # docutils is incomplete, returns `Any` python/typeshed#7256 # noqa E501 @@ -105,7 +109,7 @@ def emptytag( def render( raw: str, - stream: Optional[IO[str]] = None, + stream: Optional[Union[io.StringIO, TextIO, "_WarningStream"]] = None, **kwargs: Any ) -> Optional[str]: if stream is None: @@ -129,5 +133,17 @@ def render( if rendered: return clean(rendered) else: - stream.write("no output rendered") + # If the warnings stream is empty, docutils had none, so add ours. + + # We have to currently handle the legacy disutils integration check + # command, as it implements its own warnings stream structure. + # Once that code is removed, we can remove this conditional. + if hasattr(stream, "output"): + if not stream.output.getvalue(): # type: ignore[union-attr] + stream.write("No content rendered from RST source.") + elif isinstance(stream, io.StringIO) and not stream.getvalue(): + stream.write("No content rendered from RST source.") + elif isinstance(stream, TextIO) and not stream.readlines(): + # This is `sys.stderr` from using readme_renderer CLI + stream.write("No content rendered from RST source.") return None diff --git a/tests/test_rst.py b/tests/test_rst.py index def5e70..4e04c17 100755 --- a/tests/test_rst.py +++ b/tests/test_rst.py @@ -55,6 +55,13 @@ def test_rst_raw(): assert '"raw" directive disabled' in warnings.getvalue() +def test_rst_empty_file(): + warnings = io.StringIO() + assert render("", stream=warnings) is None + + assert "No content rendered from RST source." in warnings.getvalue() + + def test_rst_header_only(): warnings = io.StringIO() assert render(""" @@ -62,4 +69,17 @@ def test_rst_header_only(): ====== """, stream=warnings) is None - assert "no output rendered" in warnings.getvalue() + assert "No content rendered from RST source." in warnings.getvalue() + + +def test_header_and_malformed_emits_docutils_warning_only(): + warnings = io.StringIO() + assert render(""" +Header +====== + +====== +""", stream=warnings) is None + + assert len(warnings.getvalue().splitlines()) == 1 + assert "No content rendered from RST source." not in warnings.getvalue() From 9a9de1ba0eb425c7e9c1b601cfc62a6747587f3d Mon Sep 17 00:00:00 2001 From: Mike Fiedler Date: Wed, 23 Mar 2022 18:02:45 +0000 Subject: [PATCH 3/3] refactor: simplify now that distutils is gone Signed-off-by: Mike Fiedler --- readme_renderer/rst.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/readme_renderer/rst.py b/readme_renderer/rst.py index 10670d3..7bfaebc 100644 --- a/readme_renderer/rst.py +++ b/readme_renderer/rst.py @@ -14,7 +14,7 @@ from __future__ import absolute_import, division, print_function import io -from typing import Any, Dict, Optional, TextIO, Union, TYPE_CHECKING +from typing import Any, Dict, IO, Optional, Union from docutils.core import publish_parts from docutils.nodes import colspec, image @@ -23,10 +23,6 @@ from .clean import clean -if TYPE_CHECKING: - # Prevent a circular import - from .integration.distutils import _WarningStream - class ReadMeHTMLTranslator(HTMLTranslator): # type: ignore[misc] # docutils is incomplete, returns `Any` python/typeshed#7256 # noqa E501 @@ -109,7 +105,7 @@ def emptytag( def render( raw: str, - stream: Optional[Union[io.StringIO, TextIO, "_WarningStream"]] = None, + stream: Optional[IO[str]] = None, **kwargs: Any ) -> Optional[str]: if stream is None: @@ -134,16 +130,6 @@ def render( return clean(rendered) else: # If the warnings stream is empty, docutils had none, so add ours. - - # We have to currently handle the legacy disutils integration check - # command, as it implements its own warnings stream structure. - # Once that code is removed, we can remove this conditional. - if hasattr(stream, "output"): - if not stream.output.getvalue(): # type: ignore[union-attr] - stream.write("No content rendered from RST source.") - elif isinstance(stream, io.StringIO) and not stream.getvalue(): - stream.write("No content rendered from RST source.") - elif isinstance(stream, TextIO) and not stream.readlines(): - # This is `sys.stderr` from using readme_renderer CLI + if not stream.tell(): stream.write("No content rendered from RST source.") return None