From c82d3f7bd1371a15c68d4ad44cba68dab218f85f Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sun, 13 Jul 2025 11:33:10 +0200 Subject: [PATCH 1/2] Forgot changelog fragment. --- changelogs/fragments/14-docutils.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelogs/fragments/14-docutils.yml b/changelogs/fragments/14-docutils.yml index 07e5fb1..da25ae3 100644 --- a/changelogs/fragments/14-docutils.yml +++ b/changelogs/fragments/14-docutils.yml @@ -1,3 +1,6 @@ +bugfixes: + - "Make sure that all code blocks without language are found + (https://github.com/ansible-community/antsibull-docutils/pull/14)." minor_changes: - "Add functionality to parse documents, and to search for code blocks in parsed documents. This allows to perform other operations on the parsed document, instead of having to parse From 40c188b303f239d8faa45953c4b8640575c87336 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sun, 13 Jul 2025 12:23:45 +0200 Subject: [PATCH 2/2] Allow to find all literal blocks without language. --- changelogs/fragments/14-docutils.yml | 3 -- changelogs/fragments/15-code-blocks.yml | 3 ++ src/antsibull_docutils/rst_code_finder.py | 36 ++++++++++++++++++++--- tests/test_rst_code_finder.py | 28 ++++++++++++++++-- 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/15-code-blocks.yml diff --git a/changelogs/fragments/14-docutils.yml b/changelogs/fragments/14-docutils.yml index da25ae3..07e5fb1 100644 --- a/changelogs/fragments/14-docutils.yml +++ b/changelogs/fragments/14-docutils.yml @@ -1,6 +1,3 @@ -bugfixes: - - "Make sure that all code blocks without language are found - (https://github.com/ansible-community/antsibull-docutils/pull/14)." minor_changes: - "Add functionality to parse documents, and to search for code blocks in parsed documents. This allows to perform other operations on the parsed document, instead of having to parse diff --git a/changelogs/fragments/15-code-blocks.yml b/changelogs/fragments/15-code-blocks.yml new file mode 100644 index 0000000..50be1b4 --- /dev/null +++ b/changelogs/fragments/15-code-blocks.yml @@ -0,0 +1,3 @@ +minor_changes: + - "Allow to find all literal blocks without language + (https://github.com/ansible-community/antsibull-docutils/pull/15)." diff --git a/src/antsibull_docutils/rst_code_finder.py b/src/antsibull_docutils/rst_code_finder.py index 056b0d0..faf51cf 100644 --- a/src/antsibull_docutils/rst_code_finder.py +++ b/src/antsibull_docutils/rst_code_finder.py @@ -191,7 +191,9 @@ def __init__( callback: t.Callable[ [str, int, int, bool, bool, str, nodes.literal_block], None ], - warn_unknown_block: t.Callable[[int | str, int, nodes.literal_block], None], + warn_unknown_block: t.Callable[ + [int | str, int, nodes.literal_block, bool], None + ], ): super().__init__(document) self.__content_lines = content.splitlines() @@ -216,7 +218,9 @@ def visit_literal_block(self, node: nodes.literal_block) -> None: """ if "antsibull-code-block" not in node.attributes: # This could be a `::` block, or something else (unknown) - self.__warn_unknown_block(node.line or "unknown", 0, node) + self.__warn_unknown_block( + node.line or "unknown", 0, node, bool(node.attributes["classes"]) + ) raise nodes.SkipNode language = node.attributes["antsibull-code-language"] @@ -316,6 +320,9 @@ def find_code_blocks_in_document( document: nodes.document, content: str, warn_unknown_block: t.Callable[[int | str, int, str], None] | None = None, + warn_unknown_block_w_unknown_info: ( + t.Callable[[int | str, int, str, bool], None] | None + ) = None, ) -> t.Generator[CodeBlockInfo]: """ Given a parsed RST document, finds all code blocks. @@ -323,6 +330,12 @@ def find_code_blocks_in_document( All code blocks must be parsed with special directives (see ``get_code_block_directives()``) that have appropriate metadata registered with ``mark_antsibull_code_block()``. + + You can provide callbacks: + * ``warn_unknown_block()`` will be called for every literal block + that's of unknown origin. + * ``warn_unknown_block_w_unknown_info()`` will be called for every + literal block that's of known or unknown origin. """ # If someone can figure out how to yield from a sub-function, we can avoid # using this ugly list @@ -357,9 +370,14 @@ def warn_unknown_block_cb( line: int | str, col: int, node: nodes.literal_block, + unknown_directive: bool, ) -> None: - if warn_unknown_block: + if warn_unknown_block and unknown_directive: warn_unknown_block(line, col, node.rawsource) + if warn_unknown_block_w_unknown_info: + warn_unknown_block_w_unknown_info( + line, col, node.rawsource, unknown_directive + ) # Process the document try: @@ -371,13 +389,16 @@ def warn_unknown_block_cb( yield from results -def find_code_blocks( +def find_code_blocks( # pylint: disable=too-many-arguments content: str, *, path: str | os.PathLike[str] | None = None, root_prefix: str | os.PathLike[str] | None = None, extra_directives: Mapping[str, t.Type[Directive]] | None = None, warn_unknown_block: t.Callable[[int | str, int, str], None] | None = None, + warn_unknown_block_w_unknown_info: ( + t.Callable[[int | str, int, str, bool], None] | None + ) = None, ) -> t.Generator[CodeBlockInfo]: """ Given a RST document, finds all code blocks. @@ -385,6 +406,12 @@ def find_code_blocks( To add support for own types of code blocks, you can pass these as ``extra_directives``. Use ``mark_antsibull_code_block()`` to mark them to be found by ``find_code_blocks()``. + + You can provide callbacks: + * ``warn_unknown_block()`` will be called for every literal block + that's of unknown origin. + * ``warn_unknown_block_w_unknown_info()`` will be called for every + literal block that's of known or unknown origin. """ directives = get_code_block_directives(extra_directives=extra_directives) @@ -400,6 +427,7 @@ def find_code_blocks( document=doc, content=content, warn_unknown_block=warn_unknown_block, + warn_unknown_block_w_unknown_info=warn_unknown_block_w_unknown_info, ) diff --git a/tests/test_rst_code_finder.py b/tests/test_rst_code_finder.py index b82174b..9b0cc69 100644 --- a/tests/test_rst_code_finder.py +++ b/tests/test_rst_code_finder.py @@ -284,17 +284,37 @@ def test_find_code_blocks_ext(): foobar Some invalid `markup + +.. highlight:: python + +:: + + def foo(): + pass + +.. literalinclude:: nox.py + +| a +| b + c """ found_warnings = [] + found_warnings_2 = [] def add_warning(line: int | str, col: int, message: str) -> None: found_warnings.append((line, col, message)) + def add_warning_2( + line: int | str, col: int, message: str, unknown_origin: bool + ) -> None: + found_warnings_2.append((line, col, message, unknown_origin)) + found_code_block_infos = list( find_code_blocks( source, extra_directives={"foo": CodeBlockTest}, warn_unknown_block=add_warning, + warn_unknown_block_w_unknown_info=add_warning_2, ) ) assert found_code_block_infos == [ @@ -317,9 +337,11 @@ def add_warning(line: int | str, col: int, message: str) -> None: attributes={}, ), ] - assert found_warnings == [ - (6, 0, "bar"), - (12, 0, "bazbam"), + assert found_warnings == [] + assert found_warnings_2 == [ + (6, 0, "bar", False), + (12, 0, "bazbam", False), + (24, 0, "def foo():\n pass", False), ]