Skip to content

Commit 11dce06

Browse files
committed
introduce ruff
1 parent 9717712 commit 11dce06

File tree

18 files changed

+292
-266
lines changed

18 files changed

+292
-266
lines changed

docs/src/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
plot_html_show_source_link = False
5858

5959

60-
def setup(app):
60+
def setup(app) -> None:
6161
app.add_object_type(
6262
"confval",
6363
"confval",

docs/src/lib.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
from typing import List
2-
3-
41
class Knight:
52
limbs: int = 4
6-
taunts: List[str] = [
3+
taunts: list[str] = [
74
"None shall pass!",
85
"'Tis but a scratch!",
96
"It's just a flesh wound... Chicken!",
@@ -26,6 +23,6 @@ class Shrubbery:
2623
looks_nice: bool
2724
too_expensive: bool
2825

29-
def __init__(self, looks_nice: bool, too_expensive: bool):
26+
def __init__(self, looks_nice: bool, too_expensive: bool) -> None:
3027
self.looks_nice = looks_nice
3128
self.too_expensive = too_expensive

pyproject.toml

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,38 @@ precision = 1
6060
show_missing = true
6161
skip_covered = true
6262

63-
[tool.pydocstyle]
64-
ignore = "D107,D203,D212,D413,D416"
63+
[tool.ruff.lint]
64+
select = ["ALL"]
65+
ignore = [
66+
"ANN", # annotations - too oppressive
67+
"TC", # type checking - too much hassle
68+
]
69+
extend-ignore = [
70+
"ARG001", # unused args needed in interfaces
71+
"ARG002", # unused args needed in interfaces
72+
"D107", # docstring missing is fine
73+
"D203", # recommended by ruff format
74+
"D212", # docstring format clash
75+
"D413", # empty docstring ending line
76+
"COM812", # recommended by ruff format
77+
"ISC001", # recommended by ruff format
78+
"PLR0913", # many arguments is fine
79+
]
80+
extend-unsafe-fixes = ["F401"]
81+
isort.split-on-trailing-comma = false
6582

66-
[tool.black]
67-
skip-magic-trailing-comma = true
83+
[tool.ruff.lint.extend-per-file-ignores]
84+
"src/*/__init__.py" = ["F401"]
85+
"src/sphinx_codeautolink/parse.py" = ["N802"]
86+
"docs/*" = ["ALL"]
87+
"tests/*" = [
88+
"D", # docstring
89+
"ANN", # annotations
90+
"S101", # assertions - necessary in tests
91+
"T201", # print - helpful in tests
92+
]
93+
# TODO: support future annotated hints properly
94+
"tests/extension/src/test_project/__init__.py" = ["FA100"]
6895

69-
[tool.isort]
70-
atomic = true
71-
profile = "black"
72-
line_length = 88
73-
skip_gitignore = true
96+
[tool.ruff.format]
97+
skip-magic-trailing-comma = true

requirements/dev

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,5 @@
55

66
tox>=4
77
doc8>=0.9
8-
flake8
9-
flake8-bugbear
10-
pydocstyle[toml]>=6.1
8+
ruff
119
pygments
12-
black
13-
isort

src/sphinx_codeautolink/__init__.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from sphinx.application import Sphinx
44

55
from .extension import SphinxCodeAutoLink, backref, directive
6-
from .extension.block import clean_ipython, clean_pycon # NOQA
6+
from .extension.block import clean_ipython, clean_pycon
77

88
__version__ = "0.15.2"
99

@@ -13,17 +13,35 @@ def setup(app: Sphinx):
1313
state = SphinxCodeAutoLink()
1414
app.setup_extension("sphinx.ext.autodoc")
1515
app.add_css_file("sphinx-codeautolink.css")
16-
app.add_config_value("codeautolink_autodoc_inject", False, "html", types=[bool])
17-
app.add_config_value("codeautolink_global_preface", "", "html", types=[str])
18-
app.add_config_value("codeautolink_custom_blocks", {}, "html", types=[dict])
19-
app.add_config_value("codeautolink_concat_default", False, "html", types=[bool])
20-
app.add_config_value("codeautolink_search_css_classes", [], "html", types=[list])
21-
app.add_config_value("codeautolink_inventory_map", {}, "html", types=[dict])
2216
app.add_config_value(
23-
"codeautolink_warn_on_missing_inventory", False, "html", types=[bool]
17+
"codeautolink_autodoc_inject", default=False, rebuild="html", types=[bool]
2418
)
2519
app.add_config_value(
26-
"codeautolink_warn_on_failed_resolve", False, "html", types=[bool]
20+
"codeautolink_global_preface", default="", rebuild="html", types=[str]
21+
)
22+
app.add_config_value(
23+
"codeautolink_custom_blocks", default={}, rebuild="html", types=[dict]
24+
)
25+
app.add_config_value(
26+
"codeautolink_concat_default", default=False, rebuild="html", types=[bool]
27+
)
28+
app.add_config_value(
29+
"codeautolink_search_css_classes", default=[], rebuild="html", types=[list]
30+
)
31+
app.add_config_value(
32+
"codeautolink_inventory_map", default={}, rebuild="html", types=[dict]
33+
)
34+
app.add_config_value(
35+
"codeautolink_warn_on_missing_inventory",
36+
default=False,
37+
rebuild="html",
38+
types=[bool],
39+
)
40+
app.add_config_value(
41+
"codeautolink_warn_on_failed_resolve",
42+
default=False,
43+
rebuild="html",
44+
types=[bool],
2745
)
2846

2947
app.add_directive("autolink-concat", directive.Concat)

src/sphinx_codeautolink/extension/__init__.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
"""Sphinx extension implementation."""
22

3+
from __future__ import annotations
4+
35
from dataclasses import dataclass
46
from functools import wraps
57
from pathlib import Path
68
from traceback import print_exc
7-
from typing import Dict, List, Optional, Set
89

910
from sphinx.ext.intersphinx import InventoryAdapter
1011
from sphinx.util import import_object
1112

12-
from ..parse import Name
13-
from ..warn import logger, warn_type
13+
from sphinx_codeautolink.parse import Name
14+
from sphinx_codeautolink.warn import logger, warn_type
15+
1416
from .backref import CodeExample, CodeRefsVisitor
1517
from .block import CodeBlockAnalyser, SourceTransform, link_html
1618
from .cache import DataCache
@@ -27,7 +29,7 @@ class DocumentedObject:
2729
return_type: str = None
2830

2931

30-
def print_exceptions(append_source: bool = False):
32+
def print_exceptions(*, append_source: bool = False):
3133
"""
3234
Print the traceback of uncaught and unexpected exceptions.
3335
@@ -62,27 +64,27 @@ def wrapper(*args, **kwargs):
6264
class SphinxCodeAutoLink:
6365
"""Provide functionality and manage state between events."""
6466

65-
def __init__(self):
67+
def __init__(self) -> None:
6668
# Configuration
6769
self.do_nothing = False
68-
self.global_preface: List[str] = []
70+
self.global_preface: list[str] = []
6971
self.custom_blocks = None
7072
self.concat_default = None
7173
self.search_css_classes = None
72-
self.inventory_map: Dict[str, str] = {}
74+
self.inventory_map: dict[str, str] = {}
7375
self.warn_missing_inventory = None
7476
self.warn_failed_resolve = None
7577

7678
# Populated once
77-
self.outdated_docs: Set[str] = set()
79+
self.outdated_docs: set[str] = set()
7880
self.inventory = {}
79-
self.code_refs: Dict[str, List[CodeExample]] = {}
81+
self.code_refs: dict[str, list[CodeExample]] = {}
8082

8183
# Changing state
82-
self.cache: Optional[DataCache] = None
84+
self.cache: DataCache | None = None
8385

8486
@print_exceptions()
85-
def build_inited(self, app):
87+
def build_inited(self, app) -> None:
8688
"""Handle initial setup."""
8789
if app.builder.name != "html":
8890
self.do_nothing = True
@@ -112,7 +114,7 @@ def build_inited(self, app):
112114
self.global_preface = preface.split("\n")
113115

114116
@print_exceptions()
115-
def autodoc_process_docstring(self, app, what, name, obj, options, lines):
117+
def autodoc_process_docstring(self, app, what, name, obj, options, lines) -> None:
116118
"""Handle autodoc-process-docstring event."""
117119
if self.do_nothing:
118120
return
@@ -123,7 +125,7 @@ def autodoc_process_docstring(self, app, what, name, obj, options, lines):
123125
lines.append(" :collapse:")
124126

125127
@print_exceptions(append_source=True)
126-
def parse_blocks(self, app, doctree):
128+
def parse_blocks(self, app, doctree) -> None:
127129
"""Parse code blocks for later link substitution."""
128130
if self.do_nothing:
129131
return
@@ -138,14 +140,14 @@ def parse_blocks(self, app, doctree):
138140
doctree.walkabout(visitor)
139141
self.cache.transforms[visitor.current_document] = visitor.source_transforms
140142

141-
def merge_environments(self, app, env, docnames, other):
143+
def merge_environments(self, app, env, docnames, other) -> None:
142144
"""Merge transform information."""
143145
if self.do_nothing:
144146
return
145147

146148
env.sphinx_codeautolink_transforms.update(other.sphinx_codeautolink_transforms)
147149

148-
def purge_doc_from_environment(self, app, env, docname):
150+
def purge_doc_from_environment(self, app, env, docname) -> None:
149151
"""Remove transforms from cache."""
150152
if self.cache:
151153
self.cache.transforms.pop(docname, None)
@@ -169,7 +171,7 @@ def make_inventory(app):
169171
return transposed
170172

171173
@print_exceptions()
172-
def create_references(self, app, env):
174+
def create_references(self, app, env) -> None:
173175
"""Clean source transforms and create code references."""
174176
if self.do_nothing:
175177
return
@@ -184,16 +186,16 @@ def create_references(self, app, env):
184186
transform.example
185187
)
186188
if skipped and self.warn_missing_inventory:
187-
tops = sorted(set(s.split(".")[0] for s in skipped))
189+
tops = sorted({s.split(".")[0] for s in skipped})
188190
msg = (
189191
f"Cannot locate modules: {str(tops)[1:-1]}"
190192
"\n because of missing intersphinx or documentation entries"
191193
)
192194
logger.warning(msg, type=warn_type, subtype="missing_inventory")
193195

194196
def filter_and_resolve(
195-
self, transforms: List[SourceTransform], skipped: Set[str], doc: str
196-
):
197+
self, transforms: list[SourceTransform], skipped: set[str], doc: str
198+
) -> None:
197199
"""Try to link name chains to objects."""
198200
for transform in transforms:
199201
filtered = []
@@ -207,7 +209,7 @@ def filter_and_resolve(
207209
path = ".".join(name.import_components).replace(".()", "()")
208210
msg = (
209211
f"Could not resolve {self._resolve_msg(name)}"
210-
f" using path `{path}`.\n{str(e)}"
212+
f" using path `{path}`.\n{e!s}"
211213
)
212214
logger.warning(
213215
msg,
@@ -238,7 +240,7 @@ def filter_and_resolve(
238240
transform.names = filtered
239241

240242
@staticmethod
241-
def _resolve_msg(name: Name):
243+
def _resolve_msg(name: Name) -> str:
242244
if name.lineno == name.end_lineno:
243245
line = f"line {name.lineno}"
244246
else:
@@ -255,9 +257,10 @@ def generate_backref_tables(self, app, doctree, docname):
255257

256258
visitor = CodeRefsVisitor(doctree, code_refs=self.code_refs)
257259
doctree.walk(visitor)
260+
return None
258261

259262
@print_exceptions()
260-
def apply_links(self, app, exception):
263+
def apply_links(self, app, exception) -> None:
261264
"""Apply links to HTML output and write refs file."""
262265
if self.do_nothing or exception is not None:
263266
return
@@ -277,7 +280,7 @@ def apply_links(self, app, exception):
277280
self.cache.write()
278281

279282

280-
def transpose_inventory(inv: dict, relative_to: str):
283+
def transpose_inventory(inv: dict, relative_to: str) -> dict[str, str]:
281284
"""
282285
Transpose Sphinx inventory from {type: {name: (..., location)}} to {name: location}.
283286

src/sphinx_codeautolink/extension/backref.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Backreference tables implementation."""
22

33
from dataclasses import dataclass
4-
from typing import Dict, List
54

65
from docutils import nodes
76

@@ -14,7 +13,7 @@ class CodeExample:
1413

1514
document: str
1615
ref_id: str
17-
headings: List[str]
16+
headings: list[str]
1817

1918

2019
class DetailsNode(nodes.Element):
@@ -25,12 +24,12 @@ def copy(self):
2524
return self.__class__()
2625

2726

28-
def visit_details(self, node: DetailsNode):
27+
def visit_details(self, node: DetailsNode) -> None:
2928
"""Insert a details tag."""
3029
self.body.append("<details>")
3130

3231

33-
def depart_details(self, node: DetailsNode):
32+
def depart_details(self, node: DetailsNode) -> None:
3433
"""Close a details tag."""
3534
self.body.append("</details>")
3635

@@ -43,27 +42,29 @@ def copy(self):
4342
return self.__class__()
4443

4544

46-
def visit_summary(self, node: SummaryNode):
45+
def visit_summary(self, node: SummaryNode) -> None:
4746
"""Insert a summary tag."""
4847
self.body.append("<summary>")
4948

5049

51-
def depart_summary(self, node: SummaryNode):
50+
def depart_summary(self, node: SummaryNode) -> None:
5251
"""Close a summary tag."""
5352
self.body.append("</summary>")
5453

5554

5655
class CodeRefsVisitor(nodes.SparseNodeVisitor):
5756
"""Replace :class:`DeferredCodeReferences` with table of concrete references."""
5857

59-
def __init__(self, *args, code_refs: Dict[str, List[CodeExample]], **kwargs):
58+
def __init__(
59+
self, *args, code_refs: dict[str, list[CodeExample]], **kwargs
60+
) -> None:
6061
super().__init__(*args, **kwargs)
6162
self.code_refs = code_refs
6263

63-
def unknown_departure(self, node):
64+
def unknown_departure(self, node) -> None:
6465
"""Ignore unknown nodes."""
6566

66-
def unknown_visit(self, node):
67+
def unknown_visit(self, node) -> None:
6768
"""Insert table in :class:`DeferredExamples`."""
6869
if not isinstance(node, DeferredExamples):
6970
return

0 commit comments

Comments
 (0)