Skip to content

Commit dc0514d

Browse files
authored
Merge pull request #79 from AlexWaygood/caches
2 parents 1e84162 + aad06d0 commit dc0514d

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

sphinxlint/sphinxlint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def check_text(filename, text, checkers, options=None):
3636
errors = []
3737
ext = splitext(filename)[1]
3838
checkers = {checker for checker in checkers if ext in checker.suffixes}
39-
lines = text.splitlines(keepends=True)
39+
lines = tuple(text.splitlines(keepends=True))
4040
if any(checker.rst_only for checker in checkers):
4141
lines_with_rst_only = hide_non_rst_blocks(lines)
4242
for check in checkers:

sphinxlint/utils.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""Just a bunch of utility functions for sphinxlint."""
2+
from functools import lru_cache
3+
24
import regex as re
35
from polib import pofile
46

@@ -27,6 +29,7 @@ def _clean_heuristic(paragraph, regex):
2729
paragraph = paragraph[: candidate.start()] + paragraph[candidate.end() :]
2830

2931

32+
@lru_cache()
3033
def clean_paragraph(paragraph):
3134
"""Removes all good constructs, so detectors can focus on bad ones.
3235
@@ -42,6 +45,7 @@ def clean_paragraph(paragraph):
4245
return paragraph.replace("\x00", "\\")
4346

4447

48+
@lru_cache()
4549
def escape2null(text):
4650
r"""Return a string with escape-backslashes converted to nulls.
4751
@@ -75,10 +79,12 @@ def escape2null(text):
7579
start = found + 2 # skip character after escape
7680

7781

82+
@lru_cache()
7883
def paragraphs(lines):
7984
"""Yield (paragraph_line_no, paragraph_text) pairs describing
8085
paragraphs of the given lines.
8186
"""
87+
output = []
8288
paragraph = []
8389
paragraph_lno = 1
8490
for lno, line in enumerate(lines, start=1):
@@ -88,10 +94,11 @@ def paragraphs(lines):
8894
paragraph_lno = lno
8995
paragraph.append(line)
9096
elif paragraph:
91-
yield paragraph_lno, "".join(paragraph)
97+
output.append((paragraph_lno, "".join(paragraph)))
9298
paragraph = []
9399
if paragraph:
94-
yield paragraph_lno, "".join(paragraph)
100+
output.append((paragraph_lno, "".join(paragraph)))
101+
return tuple(output)
95102

96103

97104
def looks_like_glued(match):
@@ -143,12 +150,22 @@ def is_multiline_non_rst_block(line):
143150
return False
144151

145152

153+
_NON_RST_BLOCKS_CACHE = {}
154+
155+
146156
def hide_non_rst_blocks(lines, hidden_block_cb=None):
147157
"""Filters out literal, comments, code blocks, ...
148158
149159
The filter actually replace "removed" lines by empty lines, so the
150160
line numbering still make sense.
161+
162+
This function is quite hot, so we cache the returned value where possible.
163+
The function is only "pure" when hidden_block_cb is None, however,
164+
so we can only safely cache the output when hidden_block_cb=None.
151165
"""
166+
lines = tuple(lines)
167+
if hidden_block_cb is None and lines in _NON_RST_BLOCKS_CACHE:
168+
return _NON_RST_BLOCKS_CACHE[lines]
152169
in_literal = None
153170
excluded_lines = []
154171
block_line_start = None
@@ -176,9 +193,13 @@ def hide_non_rst_blocks(lines, hidden_block_cb=None):
176193
output.append(line)
177194
if excluded_lines and hidden_block_cb:
178195
hidden_block_cb(block_line_start, "".join(excluded_lines))
196+
output = tuple(output)
197+
if hidden_block_cb is None:
198+
_NON_RST_BLOCKS_CACHE[lines] = output
179199
return output
180200

181201

202+
@lru_cache()
182203
def type_of_explicit_markup(line):
183204
"""Tell apart various explicit markup blocks."""
184205
line = line.lstrip()

tests/test_sphinxlint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_sphinxlint_shall_not_pass(file, expected_errors, capsys):
7070
@pytest.mark.parametrize("file", [str(FIXTURE_DIR / "paragraphs.rst")])
7171
def test_paragraphs(file):
7272
with open(file) as f:
73-
lines = f.readlines()
73+
lines = tuple(f.readlines())
7474
actual = paragraphs(lines)
7575
for lno, para in actual:
7676
firstpline = para.splitlines(keepends=True)[0]

0 commit comments

Comments
 (0)