Skip to content

Commit b973542

Browse files
authored
bpo-42238: Check Misc/NEWS.d/next/ for reStructuredText issues. (GH-23802)
1 parent 886b2e5 commit b973542

7 files changed

+89
-13
lines changed

Doc/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ dist:
202202

203203
check:
204204
$(PYTHON) tools/rstlint.py -i tools -i $(VENVDIR) -i README.rst
205+
$(PYTHON) tools/rstlint.py ../Misc/NEWS.d/next/
205206

206207
serve:
207208
$(PYTHON) ../Tools/scripts/serve.py build/html

Doc/tools/rstlint.py

+76
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import re
1414
import sys
1515
import getopt
16+
from string import ascii_letters
1617
from os.path import join, splitext, abspath, exists
1718
from collections import defaultdict
1819

@@ -128,6 +129,81 @@ def check_leaked_markup(fn, lines):
128129
yield lno+1, 'possibly leaked markup: %r' % line
129130

130131

132+
def hide_literal_blocks(lines):
133+
"""Tool to remove literal blocks from given lines.
134+
135+
It yields empty lines in place of blocks, so line numbers are
136+
still meaningful.
137+
"""
138+
in_block = False
139+
for line in lines:
140+
if line.endswith("::\n"):
141+
in_block = True
142+
elif in_block:
143+
if line == "\n" or line.startswith(" "):
144+
line = "\n"
145+
else:
146+
in_block = False
147+
yield line
148+
149+
150+
def type_of_explicit_markup(line):
151+
if re.match(fr'\.\. {all_directives}::', line):
152+
return 'directive'
153+
if re.match(r'\.\. \[[0-9]+\] ', line):
154+
return 'footnote'
155+
if re.match(r'\.\. \[[^\]]+\] ', line):
156+
return 'citation'
157+
if re.match(r'\.\. _.*[^_]: ', line):
158+
return 'target'
159+
if re.match(r'\.\. \|[^\|]*\| ', line):
160+
return 'substitution_definition'
161+
return 'comment'
162+
163+
164+
def hide_comments(lines):
165+
"""Tool to remove comments from given lines.
166+
167+
It yields empty lines in place of comments, so line numbers are
168+
still meaningfull.
169+
"""
170+
in_multiline_comment = False
171+
for line in lines:
172+
if line == "..\n":
173+
in_multiline_comment = True
174+
elif in_multiline_comment:
175+
if line == "\n" or line.startswith(" "):
176+
line = "\n"
177+
else:
178+
in_multiline_comment = False
179+
if line.startswith(".. ") and type_of_explicit_markup(line) == 'comment':
180+
line = "\n"
181+
yield line
182+
183+
184+
185+
@checker(".rst", severity=2)
186+
def check_missing_surrogate_space_on_plural(fn, lines):
187+
r"""Check for missing 'backslash-space' between a code sample a letter.
188+
189+
Good: ``Point``\ s
190+
Bad: ``Point``s
191+
"""
192+
in_code_sample = False
193+
check_next_one = False
194+
for lno, line in enumerate(hide_comments(hide_literal_blocks(lines))):
195+
tokens = line.split("``")
196+
for token_no, token in enumerate(tokens):
197+
if check_next_one:
198+
if token[0] in ascii_letters:
199+
yield lno + 1, f"Missing backslash-space between code sample and {token!r}."
200+
check_next_one = False
201+
if token_no == len(tokens) - 1:
202+
continue
203+
if in_code_sample:
204+
check_next_one = True
205+
in_code_sample = not in_code_sample
206+
131207
def main(argv):
132208
usage = '''\
133209
Usage: %s [-v] [-f] [-s sev] [-i path]* [path]
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
The ``__args__`` of the parameterized generics for :data:`typing.Callable`
2-
and :class:`collections.abc.Callable` are now consistent. The ``__args__``
3-
for :class:`collections.abc.Callable` are now flattened while
4-
:data:`typing.Callable`'s have not changed. To allow this change,
5-
:class:`types.GenericAlias` can now be subclassed and
2+
and :class:`collections.abc.Callable` are now consistent. The ``__args__``
3+
for :class:`collections.abc.Callable` are now flattened while
4+
:data:`typing.Callable`'s have not changed. To allow this change,
5+
:class:`types.GenericAlias` can now be subclassed and
66
``collections.abc.Callable``'s ``__class_getitem__`` will now return a subclass
7-
of ``types.GenericAlias``. Tests for typing were also updated to not subclass
7+
of ``types.GenericAlias``. Tests for typing were also updated to not subclass
88
things like ``Callable[..., T]`` as that is not a valid base class. Finally,
9-
both ``Callable``\ s no longer validate their ``argtypes``, in
10-
``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`. Patch by Ken Jin.
11-
9+
both ``Callable``\ s no longer validate their ``argtypes``, in
10+
``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`. Patch by Ken Jin.
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
fix `format()` behavior for `IntFlag`
1+
fix ``format()`` behavior for ``IntFlag``
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
`Enum`: call `__init_subclass__` after members have been added
1+
``Enum``: call ``__init_subclass__`` after members have been added
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[tarfile] update nested exception raising to use `from None` or `from e`
1+
[tarfile] update nested exception raising to use ``from None`` or ``from e``
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
`logging.disable` will now validate the types and value of its parameter. It
2-
also now accepts strings representing the levels (as does `loging.setLevel`)
1+
``logging.disable`` will now validate the types and value of its parameter. It
2+
also now accepts strings representing the levels (as does ``loging.setLevel``)
33
instead of only the numerical values.

0 commit comments

Comments
 (0)