Coverage for sphinxlint/sphinxlint.py: 85%
52 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-24 18:46 +0100
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-24 18:46 +0100
1from collections import Counter
2from dataclasses import dataclass
3from os.path import splitext
4from pathlib import Path
5from typing import Optional
7from sphinxlint.utils import PER_FILE_CACHES, hide_non_rst_blocks, po2rst
10@dataclass(frozen=True)
11class LintError:
12 """A linting error found by one of the checkers"""
14 filename: str
15 line_no: int
16 msg: str
17 checker_name: str
19 def __str__(self):
20 return f"{self.filename}:{self.line_no}: {self.msg} ({self.checker_name})"
23class CheckersOptions:
24 """Configuration options for checkers."""
26 max_line_length = 80
28 @classmethod
29 def from_argparse(cls, namespace):
30 options = cls()
31 options.max_line_length = namespace.max_line_length
32 return options
35def check_text(filename, text, checkers, options=None):
36 if options is None:
37 options = CheckersOptions()
38 errors = []
39 ext = splitext(filename)[1]
40 checkers = {checker for checker in checkers if ext in checker.suffixes}
41 lines = tuple(text.splitlines(keepends=True))
42 if any(checker.rst_only for checker in checkers):
43 lines_with_rst_only = hide_non_rst_blocks(lines)
44 for check in checkers:
45 if ext not in check.suffixes:
46 continue
47 for lno, msg in check(
48 filename, lines_with_rst_only if check.rst_only else lines, options
49 ):
50 errors.append(LintError(filename, lno, msg, check.name))
51 return errors
54def check_file(filename, checkers, options: Optional[CheckersOptions] = None):
55 try:
56 ext = splitext(filename)[1]
57 if not any(ext in checker.suffixes for checker in checkers):
58 return Counter()
59 try:
60 text = Path(filename).read_text(encoding="UTF-8")
61 if filename.endswith(".po"):
62 text = po2rst(text)
63 except OSError as err:
64 return [f"{filename}: cannot open: {err}"]
65 except UnicodeDecodeError as err:
66 return [f"{filename}: cannot decode as UTF-8: {err}"]
67 return check_text(filename, text, checkers, options)
68 finally:
69 for memoized_function in PER_FILE_CACHES:
70 memoized_function.cache_clear()