sphinx-contrib / sphinx-lint

Check for stylistic and formal issues in .rst and .py files included in the documentation
https://pypi.org/project/sphinx-lint/
Other
75 stars 20 forks source link

Default role not found in indented block #108

Open hugovk opened 10 months ago

hugovk commented 10 months ago

Given this (based on https://github.com/python/cpython/blob/9f088336b268dfe9011a7cb550f4e488ccd7e8f5/Doc/library/code.rst?plain=1):

.. c:type:: int (*PyCode_WatchCallback)(PyCodeEvent event, PyCodeObject* co)

   Not detected:

   If *event* is ``PY_CODE_EVENT_CREATE``, then the callback is invoked
   after `co` has been fully initialized. Otherwise, the callback is invoked
   before the destruction of *co* takes place, so the prior state of *co*
   can be inspected.

Detected:

If *event* is ``PY_CODE_EVENT_CREATE``, then the callback is invoked
after `co` has been fully initialized. Otherwise, the callback is invoked
before the destruction of *co* takes place, so the prior state of *co*
can be inspected.

Sphinx Lint only finds the second `co`:

❯ sphinx-lint --enable=default-role 1.rst
1.rst:13: default role used (hint: for inline literals, use double backticks) (default-role)
hugovk commented 10 months ago

Another undetected `func` at https://github.com/python/cpython/blob/9f088336b268dfe9011a7cb550f4e488ccd7e8f5/Doc/c-api/function.rst?plain=1#L171:

.. c:type:: int (*PyFunction_WatchCallback)(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value)

   Type of a function watcher callback function.

   If *event* is ``PyFunction_EVENT_CREATE`` or ``PyFunction_EVENT_DESTROY``
   then *new_value* will be ``NULL``. Otherwise, *new_value* will hold a
   :term:`borrowed reference` to the new value that is about to be stored in
   *func* for the attribute that is being modified.

   The callback may inspect but must not modify *func*; doing so could have
   unpredictable effects, including infinite recursion.

   If *event* is ``PyFunction_EVENT_CREATE``, then the callback is invoked
   after `func` has been fully initialized. Otherwise, the callback is invoked
   before the modification to *func* takes place, so the prior state of *func*
   can be inspected. The runtime is permitted to optimize away the creation of
   function objects when possible. In such cases no event will be emitted.
   Although this creates the possibility of an observable difference of
   runtime behavior depending on optimization decisions, it does not change
   the semantics of the Python code being executed.

(https://github.com/pre-commit/pygrep-hooks's rst-backticks does find them, but also finds valid uses in productionlist directives.)

hugovk commented 10 months ago

I think this is because Sphinx Lint doesn't know about .. c:type:: (and the others at https://www.sphinx-doc.org/en/master/usage/domains/c.html#cross-referencing-c-constructs), so we we classify it as "comment":

@per_file_cache
def type_of_explicit_markup(line):
    """Tell apart various explicit markup blocks."""
    line = line.lstrip()
    if _starts_with_directive_marker(line):
        return "directive"
    if _starts_with_footnote_marker(line):
        return "footnote"
    if _starts_with_citation_marker(line):
        return "citation"
    if _starts_with_target(line):
        return "target"
    if _starts_with_substitution_definition(line):
        return "substitution_definition"
    return "comment"

And so these indented lines are hidden by hide_non_rst_blocks so don't get checked:

def check_text(filename, text, checkers, options=None):
    if options is None:
        options = CheckersOptions()
    errors = []
    ext = splitext(filename)[1]
    checkers = {checker for checker in checkers if ext in checker.suffixes}
    lines = tuple(text.splitlines(keepends=True))
    if any(checker.rst_only for checker in checkers):
        lines_with_rst_only = hide_non_rst_blocks(lines)
    for check in checkers:
...

Adding 'c:type' to DIRECTIVES_CONTAINING_RST enables detection of these blocks and finds the default roles:

Doc/c-api/code.rst:171: default role used (hint: for inline literals, use double backticks) (default-role)
Doc/c-api/code.rst:200: default role used (hint: for inline literals, use double backticks) (default-role)
Doc/c-api/function.rst:171: default role used (hint: for inline literals, use double backticks) (default-role)