Skip to content

Commit 74db402

Browse files
hugovkAlexWaygood
andauthored
Lint on GitHub Actions via pre-commit (#104)
* Format with Black via pre-commit * Lint with Ruff * Add some handy pre-commit hooks * Apply common format to pyproject.toml and validate * Format tox.ini * autoupdate_schedule: quarterly * Ignore UP038: it makes code slower and more verbose Co-authored-by: Alex Waygood <[email protected]> --------- Co-authored-by: Alex Waygood <[email protected]>
1 parent f5ee878 commit 74db402

14 files changed

+158
-40
lines changed

.github/workflows/lint.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Lint
2+
3+
on: [push, pull_request, workflow_dispatch]
4+
5+
env:
6+
FORCE_COLOR: 1
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
lint:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-python@v4
18+
with:
19+
python-version: "3.x"
20+
- uses: pre-commit/[email protected]

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
# when adding new versions, update the one used to test
16+
# when adding new versions, update the one used to test
1717
# friend projects below to the latest one
1818
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
1919
os: [ubuntu-latest, macos-latest, windows-latest]

.pre-commit-config.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
repos:
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
rev: v0.1.6
4+
hooks:
5+
- id: ruff
6+
args: [--fix, --exit-non-zero-on-fix]
7+
8+
- repo: https://github.com/psf/black-pre-commit-mirror
9+
rev: 23.11.0
10+
hooks:
11+
- id: black
12+
13+
- repo: https://github.com/pre-commit/pre-commit-hooks
14+
rev: v4.5.0
15+
hooks:
16+
- id: check-case-conflict
17+
- id: check-merge-conflict
18+
- id: check-toml
19+
- id: check-yaml
20+
- id: debug-statements
21+
- id: end-of-file-fixer
22+
exclude: tests/fixtures/xfail/missing-newline-at-end-of-file.rst
23+
- id: trailing-whitespace
24+
exclude: tests/fixtures/xfail/trailing-whitespaces.rst
25+
26+
- repo: https://github.com/tox-dev/pyproject-fmt
27+
rev: 1.5.1
28+
hooks:
29+
- id: pyproject-fmt
30+
additional_dependencies: [tox]
31+
32+
- repo: https://github.com/abravalheri/validate-pyproject
33+
rev: v0.15
34+
hooks:
35+
- id: validate-pyproject
36+
37+
- repo: https://github.com/tox-dev/tox-ini-fmt
38+
rev: 1.3.1
39+
hooks:
40+
- id: tox-ini-fmt
41+
42+
- repo: meta
43+
hooks:
44+
- id: check-hooks-apply
45+
- id: check-useless-excludes
46+
47+
ci:
48+
autoupdate_schedule: quarterly

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ $ docutils --writer=pseudoxml tests/fixtures/xpass/role-in-code-sample.rst
102102

103103
1. Make sure that the [CI tests pass](https://github.com/sphinx-contrib/sphinx-lint/actions)
104104
and optionally double-check locally with "friends projects" by running:
105-
105+
106106
sh download-more-tests.sh
107107
python -m pytest
108108
2. Go on the [Releases page](https://github.com/sphinx-contrib/sphinx-lint/releases)

pyproject.toml

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,36 @@ authors = [
1414
{name = "Georg Brandl", email = "[email protected]"},
1515
{name = "Julien Palard", email = "[email protected]"},
1616
]
17+
requires-python = ">= 3.8"
1718
classifiers = [
18-
"Development Status :: 5 - Production/Stable",
19-
"Topic :: Documentation :: Sphinx",
20-
"Intended Audience :: Developers",
21-
"License :: OSI Approved :: Python Software Foundation License",
22-
"Natural Language :: English",
23-
"Programming Language :: Python :: 3",
19+
"Development Status :: 5 - Production/Stable",
20+
"Intended Audience :: Developers",
21+
"License :: OSI Approved :: Python Software Foundation License",
22+
"Natural Language :: English",
23+
"Programming Language :: Python :: 3 :: Only",
24+
"Programming Language :: Python :: 3.8",
25+
"Programming Language :: Python :: 3.9",
26+
"Programming Language :: Python :: 3.10",
27+
"Programming Language :: Python :: 3.11",
28+
"Programming Language :: Python :: 3.12",
29+
"Programming Language :: Python :: 3.13",
30+
"Topic :: Documentation :: Sphinx",
31+
]
32+
dynamic = [
33+
"version",
2434
]
25-
requires-python = ">= 3.8"
2635
dependencies = [
27-
"regex",
28-
"polib",
36+
"polib",
37+
"regex",
2938
]
30-
dynamic = ["version"]
31-
32-
3339
[project.optional-dependencies]
3440
tests = [
3541
"pytest",
3642
"pytest-cov",
3743
]
3844
[project.urls]
39-
Repository = "https://github.com/sphinx-contrib/sphinx-lint"
4045
Changelog = "https://github.com/sphinx-contrib/sphinx-lint/releases"
41-
46+
Repository = "https://github.com/sphinx-contrib/sphinx-lint"
4247
[project.scripts]
4348
sphinx-lint = "sphinxlint.cli:main"
4449

@@ -50,5 +55,25 @@ local_scheme = "no-local-version"
5055

5156
[tool.black]
5257

58+
[tool.ruff]
59+
select = [
60+
"E", # pycodestyle errors
61+
"F", # pyflakes errors
62+
"I", # isort
63+
"ISC", # flake8-implicit-str-concat
64+
"PGH", # pygrep-hooks
65+
"RUF100", # unused noqa (yesqa)
66+
"UP", # pyupgrade
67+
"W", # pycodestyle warnings
68+
"YTT", # flake8-2020
69+
]
70+
extend-ignore = [
71+
"E203", # Whitespace before ':'
72+
"E221", # Multiple spaces before operator
73+
"E226", # Missing whitespace around arithmetic operator
74+
"E241", # Multiple spaces after ','
75+
"UP038", # makes code slower and more verbose
76+
]
77+
5378
[tool.pylint.variables]
5479
callbacks = ["check_"]

sphinxlint/checkers.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
paragraphs,
1313
)
1414

15-
1615
all_checkers = {}
1716

1817

@@ -60,7 +59,10 @@ def check_missing_backtick_after_role(file, lines, options=None):
6059
error = rst.ROLE_MISSING_CLOSING_BACKTICK_RE.search(paragraph)
6160
if error:
6261
error_offset = paragraph[: error.start()].count("\n")
63-
yield paragraph_lno + error_offset, f"role missing closing backtick: {error.group(0)!r}"
62+
yield (
63+
paragraph_lno + error_offset,
64+
f"role missing closing backtick: {error.group(0)!r}",
65+
)
6466

6567

6668
_RST_ROLE_RE = re.compile("``.+?``(?!`).", flags=re.DOTALL)
@@ -129,8 +131,12 @@ def check_default_role(file, lines, options=None):
129131
before_match = line[: match.start()]
130132
after_match = line[match.end() :]
131133
stripped_line = line.strip()
132-
if (stripped_line.startswith("|") and stripped_line.endswith("|") and
133-
stripped_line.count("|") >= 4 and "|" in match.group(0)):
134+
if (
135+
stripped_line.startswith("|")
136+
and stripped_line.endswith("|")
137+
and stripped_line.count("|") >= 4
138+
and "|" in match.group(0)
139+
):
134140
return # we don't handle tables yet.
135141
if _ends_with_role_tag(before_match):
136142
# It's not a default role: it ends with a tag.
@@ -141,7 +147,10 @@ def check_default_role(file, lines, options=None):
141147
if match.group(0).startswith("``") and match.group(0).endswith("``"):
142148
# It's not a default role: it's an inline literal.
143149
continue
144-
yield lno, "default role used (hint: for inline literals, use double backticks)"
150+
yield (
151+
lno,
152+
"default role used (hint: for inline literals, use double backticks)",
153+
)
145154

146155

147156
@checker(".rst", ".po")
@@ -287,7 +296,10 @@ def check_role_with_double_backticks(file, lines, options=None):
287296
before = paragraph[: inline_literal.start()]
288297
if _ends_with_role_tag(before):
289298
error_offset = paragraph[: inline_literal.start()].count("\n")
290-
yield paragraph_lno + error_offset, "role use a single backtick, double backtick found."
299+
yield (
300+
paragraph_lno + error_offset,
301+
"role use a single backtick, double backtick found.",
302+
)
291303
paragraph = (
292304
paragraph[: inline_literal.start()] + paragraph[inline_literal.end() :]
293305
)
@@ -308,9 +320,15 @@ def check_missing_space_before_role(file, lines, options=None):
308320
if match:
309321
error_offset = paragraph[: match.start()].count("\n")
310322
if looks_like_glued(match):
311-
yield paragraph_lno + error_offset, f"missing space before role ({match.group(0)})."
323+
yield (
324+
paragraph_lno + error_offset,
325+
f"missing space before role ({match.group(0)}).",
326+
)
312327
else:
313-
yield paragraph_lno + error_offset, f"role missing opening tag colon ({match.group(0)})."
328+
yield (
329+
paragraph_lno + error_offset,
330+
f"role missing opening tag colon ({match.group(0)}).",
331+
)
314332

315333

316334
@checker(".rst", ".po")
@@ -494,4 +512,4 @@ def check_dangling_hyphen(file, lines, options):
494512
for lno, line in enumerate(lines):
495513
stripped_line = line.rstrip("\n")
496514
if _has_dangling_hyphen(stripped_line):
497-
yield lno + 1, f"Line ends with dangling hyphen"
515+
yield lno + 1, "Line ends with dangling hyphen"

sphinxlint/cli.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def __call__(self, parser, namespace, values, option_string=None):
5454
sort_fields.append(SortField[field_name.upper()])
5555
except KeyError:
5656
raise ValueError(
57-
f"Unsupported sort field: {field_name}, supported values are {SortField.as_supported_options()}"
57+
f"Unsupported sort field: {field_name}, "
58+
f"supported values are {SortField.as_supported_options()}"
5859
) from None
5960
setattr(namespace, self.dest, sort_fields)
6061

@@ -85,7 +86,8 @@ def job_count(values):
8586
"-d",
8687
"--disable",
8788
action=DisableAction,
88-
help='comma-separated list of checks to disable. Give "all" to disable them all. '
89+
help="comma-separated list of checks to disable. "
90+
'Give "all" to disable them all. '
8991
"Can be used in conjunction with --enable (it's evaluated left-to-right). "
9092
'"--disable all --enable trailing-whitespace" can be used to enable a '
9193
"single check.",

sphinxlint/utils.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from sphinxlint import rst
88

9-
109
PER_FILE_CACHES = []
1110

1211

@@ -187,10 +186,7 @@ def hide_non_rst_blocks(lines, hidden_block_cb=None):
187186
in_literal = len(_ZERO_OR_MORE_SPACES_RE.match(line)[0])
188187
block_line_start = lineno
189188
assert not excluded_lines
190-
if (
191-
type_of_explicit_markup(line) == "comment"
192-
and _COMMENT_RE.search(line)
193-
):
189+
if type_of_explicit_markup(line) == "comment" and _COMMENT_RE.search(line):
194190
line = "\n"
195191
output.append(line)
196192
if excluded_lines and hidden_block_cb:

tests/test_default_role_re.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ def test_shall_not_pass():
1212
assert not rst.INTERPRETED_TEXT_RE.search("``")
1313
assert not rst.INTERPRETED_TEXT_RE.search("2 * x a ** b (* BOM32_* ` `` _ __ |")
1414
assert not rst.INTERPRETED_TEXT_RE.search(
15-
""""`" '|' (`) [`] {`} <`> ‘`’ ‚`‘ ‘`‚ ’`’ ‚`’ “`” „`“ “`„ ”`” „`” »`« ›`‹ «`» »`» ›`›"""
15+
""""`" '|' (`) [`] {`} <`> ‘`’ ‚`‘ ‘`‚ ’`’ ‚`’ “`” „`“ “`„ ”`” „`” »`« ›`‹ «`» »`» ›`›""" # noqa: E501
1616
)

tests/test_enable_disable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from random import choice
21
import re
2+
from random import choice
33

44
from sphinxlint.cli import main
55

0 commit comments

Comments
 (0)