Source code for sphinx_no_pragma

"""
https://github.com/barseghyanartur/sphinx-no-pragma/
"""

import re
from copy import deepcopy

from docutils import nodes
from sphinx.directives.code import LiteralInclude

__title__ = "sphinx-no-pragma"
__version__ = "0.1.3"
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2023-2025 Artur Barseghyan"
__license__ = "MIT"
__all__ = (
    "DEFAULT_IGNORE_COMMENTS_ENDINGS",
    "NoPragmaLiteralInclude",
    "setup",
)

DEFAULT_IGNORE_COMMENTS_ENDINGS = [
    "# type: ignore",
    "# noqa",
    "# pragma: no cover",
    "# pragma: no branch",
    "# fmt: off",
    "# fmt: on",
    "# fmt: skip",
    "# yapf: disable",
    "# yapf: enable",
    "# pylint: disable",
    "# pylint: enable",
    "# flake8: noqa",
    "# noinspection",
    "# pragma: allowlist secret",
    "# pragma: NOSONAR",
]


[docs] class NoPragmaLiteralInclude(LiteralInclude):
[docs] def run(self): # Retrieve the global configuration set in conf.py config = self.state.document.settings.env.config # Default ignore endings ignore_endings = deepcopy(config.ignore_comments_endings) if not isinstance(ignore_endings, list): ignore_endings = [ignore_endings] # Additional user-defined ignore endings user_ignore_endings = deepcopy(config.user_ignore_comments_endings) if not isinstance(user_ignore_endings, list): user_ignore_endings = [user_ignore_endings] # Merge the two ignore_endings.extend(user_ignore_endings) # Get the original content generated by LiteralInclude original_content = super().run() new_content = [] for node in original_content: if isinstance(node, nodes.literal_block): # Modify lines by removing specified endings lines = node.rawsource.splitlines() filtered_lines = [ self.remove_endings(line, ignore_endings) for line in lines ] # Update the node content node.rawsource = "\n".join(filtered_lines) node[:] = [nodes.Text("\n".join(filtered_lines))] new_content.append(node) return new_content
[docs] def remove_endings(self, line, endings): """Remove from the line any trailing ignore markers. For each ending provided, this function uses a regex pattern to match the literal ending, optionally followed by a colon and error codes, and any extra whitespace until the end of the line. It repeatedly removes the matched pattern for each ending. """ for ending in endings: # Build a regex pattern: escape the given ending and allow an # optional colon and error codes, plus trailing whitespace until # the end of the line. pattern = re.escape(ending) + r"(?:\s*[:=]\s*\S+|\s+\S+)?\s*$" # Keep removing the marker until no match is found. while re.search(pattern, line): line = re.sub(pattern, "", line).rstrip() return line
[docs] def setup(app): app.add_directive("literalinclude", NoPragmaLiteralInclude, override=True) app.add_config_value( "ignore_comments_endings", DEFAULT_IGNORE_COMMENTS_ENDINGS, "env", ) app.add_config_value("user_ignore_comments_endings", [], "env") return { "version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True, }