8000 Do not remove body of directives known to contain reStructuredText · sphinx-contrib/sphinx-lint@a419948 · GitHub
[go: up one dir, main page]

Skip to content

Commit a419948

Browse files
committed
Do not remove body of directives known to contain reStructuredText
1 parent d24fdad commit a419948

File tree

5 files changed

+120
-15
lines changed

5 files changed

+120
-15
lines changed

download-more-tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
# https://github.com/sympy/sympy doc
3131
# https://github.com/sphinx-doc/sphinx doc --enable line-too-long --max-line-length 85
3232

33+
# This one could be enabled soon:
34+
## https://github.com/python/python-docs-fr . --enable all --disable line-too-long
35+
3336
grep '^# https://' "$0" |
3437
while read -r _ repo directory flags
3538
do

sphinxlint.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
"""Sphinx rst linter."""
1212

13-
__version__ = "0.6.6"
13+
__version__ = "0.6.7"
1414

1515
import argparse
1616
import io
@@ -77,34 +77,50 @@
7777
)
7878

7979
# fmt: off
80-
DIRECTIVES = [
80+
DIRECTIVES_CONTAINING_RST = [
8181
# standard docutils ones
8282
'admonition', 'attention', 'caution', 'class', 'compound', 'container',
83-
'contents', 'csv-table', 'danger', 'date', 'default-role', 'epigraph',
84-
'error', 'figure', 'footer', 'header', 'highlights', 'hint', 'image',
85-
'important', 'include', 'line-block', 'list-table', 'meta', 'note',
86-
'parsed-literal', 'pull-quote', 'raw', 'replace',
87-
'restructuredtext-test-directive', 'role', 'rubric', 'sectnum', 'sidebar',
88-
'table', 'target-notes', 'tip', 'title', 'topic', 'unicode', 'warning',
83+
'danger', 'epigraph', 'error', 'figure', 'footer', 'header', 'highlights',
84+
'hint', 'image', 'important', 'include', 'line-block', 'list-table', 'meta',
85+
'note', 'parsed-literal', 'pull-quote', 'replace', 'sidebar', 'tip', 'topic',
86+
'warning',
8987
# Sphinx and Python docs custom ones
9088
'acks', 'attribute', 'autoattribute', 'autoclass', 'autodata',
9189
'autoexception', 'autofunction', 'automethod', 'automodule',
9290
'availability', 'centered', 'cfunction', 'class', 'classmethod', 'cmacro',
93-
'cmdoption', 'cmember', 'code-block', 'confval', 'cssclass', 'ctype',
91+
'cmdoption', 'cmember', 'confval', 'cssclass', 'ctype',
9492
'currentmodule', 'cvar', 'data', 'decorator', 'decoratormethod',
9593
'deprecated-removed', 'deprecated(?!-removed)', 'describe', 'directive',
9694
'doctest', 'envvar', 'event', 'exception', 'function', 'glossary',
9795
'highlight', 'highlightlang', 'impl-detail', 'index', 'literalinclude',
9896
'method', 'miscnews', 'module', 'moduleauthor', 'opcode', 'pdbcommand',
99-
'productionlist', 'program', 'role', 'sectionauthor', 'seealso',
97+
'program', 'role', 'sectionauthor', 'seealso',
10098
'sourcecode', 'staticmethod', 'tabularcolumns', 'testcode', 'testoutput',
10199
'testsetup', 'toctree', 'todo', 'todolist', 'versionadded',
102100
'versionchanged', 'c:function', 'coroutinefunction'
103101
]
102+
103+
DIRECTIVES_CONTAINING_ARBITRARY_CONTENT = [
104+
# standard docutils ones
105+
'contents', 'csv-table', 'date', 'default-role', 'include', 'raw',
106+
'restructuredtext-test-directive','role', 'rubric', 'sectnum', 'table',
107+
'target-notes', 'title', 'unicode',
108+
# Sphinx and Python docs custom ones
109+
'productionlist', 'code-block',
110+
]
111+
104112
# fmt: on
105113

106114

107-
ALL_DIRECTIVES = "(" + "|".join(DIRECTIVES) + ")"
115+
DIRECTIVES_CONTAINING_ARBITRARY_CONTENT_RE = (
116+
"(" + "|".join(DIRECTIVES_CONTAINING_ARBITRARY_CONTENT) + ")"
117+
)
118+
DIRECTIVES_CONTAINING_RST_RE = "(" + "|".join(DIRECTIVES_CONTAINING_RST) + ")"
119+
ALL_DIRECTIVES = (
120+
"("
121+
+ "|".join(DIRECTIVES_CONTAINING_RST + DIRECTIVES_CONTAINING_ARBITRARY_CONTENT)
122+
+ ")"
123+
)
108124
BEFORE_ROLE = r"(^|(?<=[\s(/'{\[*-]))"
109125
SIMPLENAME = r"(?:(?!_)\w)+(?:[-._+:](?:(?!_)\w)+)*"
110126
ROLE_TAG = rf":{SIMPLENAME}:"
@@ -780,16 +796,18 @@ def check_leaked_markup(file, lines, options=None):
780796

781797
def is_multiline_non_rst_block(line):
782798
"""Returns True if the next lines are an indented literal block."""
783-
if line.endswith("..\n"):
784-
return True
785-
if line.endswith("::\n"):
799+
if re.match(r"^\s*\.\.$", line): # it's the start of a comment block.
786800
return True
787-
if re.match(r"^ *\.\. code-block::", line):
801+
if re.match(rf"^ *\.\. {DIRECTIVES_CONTAINING_RST_RE}::", line):
802+
return False
803+
if re.match(rf"^ *\.\. {DIRECTIVES_CONTAINING_ARBITRARY_CONTENT_RE}::", line):
788804
return True
789805
if re.match(r"^ *.. productionlist::", line):
790806
return True
791807
if re.match(r"^ *\.\. ", line) and type_of_explicit_markup(line) == "comment&q 1E0A uot;:
792808
return True
809+
if line.endswith("::\n"): # It's a literal block
810+
return True
793811
return False
794812

795813

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.. expect: default role used
2+
3+
.. note::
4+
This is a note, but it's still parsed as rst, so errors should be spotted.
5+
Like using a `default role`.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
``_PyUnicode_Name_CAPI`` de l'API PyCapsule ``unicodedata.ucnhash_CAPI``
2+
a été déplacée dans l'API C interne. Contribution par Victor Stinner.

tests/test_filter_out_literal.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,80 @@ def test_consecutive_production_list():
294294
for line in hide_non_rst_blocks(CONSECUTIVE_PRODUCTION_LIST.splitlines(True)):
295295
out.append(line)
296296
assert "".join(out) == CONSECUTIVE_PRODUCTION_LIST_EXPECTED
297+
298+
299+
ATTENTION = """
300+
This is a test for an attention admonition.
301+
302+
.. attention::
303+
An admonition can contain RST so it should **NOT** be dropped.
304+
305+
and that's it.
306+
"""
307+
308+
309+
def test_filter_out_attention():
310+
out = []
311+
excluded = []
312+
for line in hide_non_rst_blocks(
313+
ATTENTION.splitlines(True),
314+
hidden_block_cb=lambda lineno, block: excluded.append((lineno, block)),
315+
):
316+
out.append(line)
317+
assert "".join(out) == ATTENTION
318+
assert not excluded
319+
320+
321+
NOTE = """
322+
This is a note, it contains rst, so it should **not** be dropped:
323+
324+
.. note::
325+
326+
hello I am a not **I can** contain rst.
327+
328+
End of it.
329+
"""
330+
331+
332+
def test_filter_out_note():
333+
out = []
334+
excluded = []
335+
for line in hide_non_rst_blocks(
336+
NOTE.splitlines(True),
337+
hidden_block_cb=lambda lineno, block: excluded.append((lineno, block)),
338+
):
339+
out.append(line)
340+
assert "".join(out) == NOTE
341+
assert not excluded
342+
343+
344+
UNKNOWN = """
345+
This is an unknown directive, to avoid false positives, just drop its content.
346+
347+
.. this_is_not_a_known_directive::
348+
349+
So this can contain rst, or arbitary text.
350+
351+
In the face of ambiguity, refuse the temptation to guess.
352+
"""
353+
354+
UNKNOWN_EXPECTED = """
355+
This is an unknown directive, to avoid false positives, just drop its content.
356+
357+
358+
359+
360+
361+
In the face of ambiguity, refuse the temptation to guess.
362+
"""
363+
364+
365+
def test_filter_out_unknown():
366+
out = []
367+
excluded = []
368+
for line in hide_non_rst_blocks(
369+
UNKNOWN.splitlines(True),
370+
hidden_block_cb=lambda lineno, block: excluded.append((lineno, block)),
371+
):
372+
out.append(line)
373+
assert "".join(out) == UNKNOWN_EXPECTED

0 commit comments

Comments
 (0)
0