Skip to content

Commit a21bb3d

Browse files
committed
Adopt Ruff and use stricter MyPy settings
1 parent c5ec8d7 commit a21bb3d

File tree

13 files changed

+188
-85
lines changed

13 files changed

+188
-85
lines changed

.flake8

Lines changed: 0 additions & 4 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ jobs:
7171
runs-on: ubuntu-latest
7272
strategy:
7373
matrix:
74-
env: [flake8, mypy]
74+
env:
75+
- ruff
76+
- mypy
7577

7678
steps:
7779
- uses: actions/checkout@v3

.ruff.toml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
target-version = "py39" # Pin Ruff to Python 3.9
2+
output-format = "full"
3+
line-length = 95
4+
5+
[lint]
6+
preview = true
7+
select = [
8+
# "ANN", # flake8-annotations
9+
"C4", # flake8-comprehensions
10+
"COM", # flake8-commas
11+
"B", # flake8-bugbear
12+
"DTZ", # flake8-datetimez
13+
"E", # pycodestyle
14+
"EM", # flake8-errmsg
15+
"EXE", # flake8-executable
16+
"F", # pyflakes
17+
"FA", # flake8-future-annotations
18+
"FLY", # flynt
19+
"FURB", # refurb
20+
"G", # flake8-logging-format
21+
"I", # isort
22+
"ICN", # flake8-import-conventions
23+
"INT", # flake8-gettext
24+
"LOG", # flake8-logging
25+
"PERF", # perflint
26+
"PGH", # pygrep-hooks
27+
"PIE", # flake8-pie
28+
"PT", # flake8-pytest-style
29+
"SIM", # flake8-simplify
30+
"SLOT", # flake8-slots
31+
"TCH", # flake8-type-checking
32+
"UP", # pyupgrade
33+
"W", # pycodestyle
34+
"YTT", # flake8-2020
35+
]
36+
ignore = [
37+
"E116",
38+
"E241",
39+
"E251",
40+
]
41+
42+
[lint.per-file-ignores]
43+
"tests/*" = [
44+
"ANN", # tests don't need annotations
45+
]
46+
47+
[lint.isort]
48+
forced-separate = [
49+
"tests",
50+
]
51+
required-imports = [
52+
"from __future__ import annotations",
53+
]

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ clean-mypyfiles:
4747

4848
.PHONY: style-check
4949
style-check:
50-
@flake8
50+
@ruff check
5151

5252
.PHONY: type-check
5353
type-check:

pyproject.toml

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ test = [
4848
"html5lib",
4949
]
5050
lint = [
51-
"flake8",
51+
"ruff==0.5.5",
5252
"mypy",
53-
"docutils-stubs",
53+
"types-docutils",
5454
]
5555
standalone = [
5656
"Sphinx>=5",
@@ -73,4 +73,34 @@ include = [
7373
]
7474

7575
[tool.mypy]
76-
ignore_missing_imports = true
76+
python_version = "3.9"
77+
packages = [
78+
"sphinxcontrib",
79+
"tests",
80+
]
81+
exclude = [
82+
"tests/roots",
83+
]
84+
check_untyped_defs = true
85+
disallow_any_generics = true
86+
disallow_incomplete_defs = true
87+
disallow_subclassing_any = true
88+
disallow_untyped_calls = true
89+
disallow_untyped_decorators = true
90+
disallow_untyped_defs = true
91+
#explicit_package_bases = true
92+
extra_checks = true
93+
no_implicit_reexport = true
94+
show_column_numbers = true
95+
show_error_context = true
96+
strict_optional = true
97+
warn_redundant_casts = true
98+
warn_unused_configs = true
99+
warn_unused_ignores = true
100+
enable_error_code = [
101+
"type-arg",
102+
"redundant-self",
103+
"truthy-iterable",
104+
"ignore-without-code",
105+
"unused-awaitable",
106+
]

sphinxcontrib/htmlhelp/__init__.py

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
import html
66
import os
77
from os import path
8-
from typing import Any
9-
10-
from docutils import nodes
11-
from docutils.nodes import Element, Node, document
8+
from pathlib import Path
9+
from typing import TYPE_CHECKING, Any
1210

1311
import sphinx
12+
from docutils import nodes
1413
from sphinx import addnodes
15-
from sphinx.application import Sphinx
1614
from sphinx.builders.html import StandaloneHTMLBuilder
17-
from sphinx.config import Config
1815
from sphinx.environment.adapters.indexentries import IndexEntries
1916
from sphinx.locale import get_translation
2017
from sphinx.util import logging
@@ -23,10 +20,15 @@
2320
from sphinx.util.osutil import make_filename_from_project, relpath
2421
from sphinx.util.template import SphinxRenderer
2522

23+
if TYPE_CHECKING:
24+
from docutils.nodes import Element, Node, document
25+
from sphinx.application import Sphinx
26+
from sphinx.config import Config
27+
2628
if sphinx.version_info[:2] >= (6, 1):
2729
from sphinx.util.display import progress_message
2830
else:
29-
from sphinx.util import progress_message # type: ignore[attr-defined,no-redef]
31+
from sphinx.util import progress_message # type: ignore[no-redef]
3032

3133
__version__ = '2.0.6'
3234
__version_info__ = (2, 0, 6)
@@ -126,8 +128,8 @@ def depart_list_item(self, node: Element) -> None:
126128

127129
def visit_reference(self, node: Element) -> None:
128130
title = chm_htmlescape(node.astext(), True)
129-
self.append(' <param name="Name" value="%s">' % title)
130-
self.append(' <param name="Local" value="%s">' % node['refuri'])
131+
self.append(f' <param name="Name" value="{title}">')
132+
self.append(f' <param name="Local" value="{node["refuri"]}">')
131133
self.append('</OBJECT>')
132134
raise nodes.SkipNode
133135

@@ -170,7 +172,13 @@ def prepare_writing(self, docnames: set[str]) -> None:
170172
super().prepare_writing(docnames)
171173
self.globalcontext['html5_doctype'] = False
172174

173-
def update_page_context(self, pagename: str, templatename: str, ctx: dict, event_arg: str) -> None: # NOQA
175+
def update_page_context(
176+
self,
177+
pagename: str,
178+
templatename: str,
179+
ctx: dict[str, Any],
180+
event_arg: str,
181+
) -> None:
174182
ctx['encoding'] = self.encoding
175183

176184
def handle_finish(self) -> None:
@@ -180,14 +188,14 @@ def handle_finish(self) -> None:
180188
self.build_hhx(self.outdir, self.config.htmlhelp_basename)
181189

182190
def write_doc(self, docname: str, doctree: document) -> None:
183-
for node in doctree.traverse(nodes.reference):
191+
for node in doctree.findall(nodes.reference):
184192
# add ``target=_blank`` attributes to external links
185193
if node.get('internal') is None and 'refuri' in node:
186194
node['target'] = '_blank'
187195

188196
super().write_doc(docname, doctree)
189197

190-
def render(self, name: str, context: dict) -> str:
198+
def render(self, name: str, context: dict[str, Any]) -> str:
191199
template = SphinxRenderer(template_dir)
192200
return template.render(name, context)
193201

@@ -220,40 +228,39 @@ def build_project_file(self) -> None:
220228
fn = relpath(path.join(root, fn), self.outdir)
221229
project_files.append(fn.replace(os.sep, '\\'))
222230

223-
filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhp')
224-
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
225-
context = {
226-
'outname': self.config.htmlhelp_basename,
227-
'title': self.config.html_title,
228-
'version': self.config.version,
229-
'project': self.config.project,
230-
'lcid': self.lcid,
231-
'master_doc': self.config.master_doc + self.out_suffix,
232-
'files': project_files,
233-
}
234-
body = self.render('project.hhp', context)
235-
f.write(body)
231+
context = {
232+
'outname': self.config.htmlhelp_basename,
233+
'title': self.config.html_title,
234+
'version': self.config.version,
235+
'project': self.config.project,
236+
'lcid': self.lcid,
237+
'master_doc': self.config.master_doc + self.out_suffix,
238+
'files': project_files,
239+
}
240+
body = self.render('project.hhp', context)
241+
filename = Path(self.outdir, f'{self.config.htmlhelp_basename}.hhp')
242+
filename.write_text(body, encoding=self.encoding, errors='xmlcharrefreplace')
236243

237244
@progress_message(__('writing TOC file'))
238245
def build_toc_file(self) -> None:
239246
"""Create a ToC file (.hhp) on outdir."""
240-
filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhc')
241-
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
242-
toctree = self.env.get_and_resolve_doctree(self.config.master_doc, self,
243-
prune_toctrees=False)
244-
visitor = ToCTreeVisitor(toctree)
245-
matcher = NodeMatcher(addnodes.compact_paragraph, toctree=True)
246-
for node in toctree.traverse(matcher): # type: addnodes.compact_paragraph
247-
node.walkabout(visitor)
248-
249-
context = {
250-
'body': visitor.astext(),
251-
'suffix': self.out_suffix,
252-
'short_title': self.config.html_short_title,
253-
'master_doc': self.config.master_doc,
254-
'domain_indices': self.domain_indices,
255-
}
256-
f.write(self.render('project.hhc', context))
247+
toctree = self.env.get_and_resolve_doctree(self.config.master_doc, self,
248+
prune_toctrees=False)
249+
visitor = ToCTreeVisitor(toctree)
250+
matcher = NodeMatcher(addnodes.compact_paragraph, toctree=True)
251+
for node in toctree.findall(matcher):
252+
node.walkabout(visitor)
253+
254+
context = {
255+
'body': visitor.astext(),
256+
'suffix': self.out_suffix,
257+
'short_title': self.config.html_short_title,
258+
'master_doc': self.config.master_doc,
259+
'domain_indices': self.domain_indices,
260+
}
261+
body = self.render('project.hhc', context)
262+
filename = Path(self.outdir, f'{self.config.htmlhelp_basename}.hhc')
263+
filename.write_text(body, encoding=self.encoding, errors='xmlcharrefreplace')
257264

258265
def build_hhx(self, outdir: str | os.PathLike[str], outname: str) -> None:
259266
logger.info(__('writing index file...'))
@@ -262,9 +269,13 @@ def build_hhx(self, outdir: str | os.PathLike[str], outname: str) -> None:
262269
with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f:
263270
f.write('<UL>\n')
264271

265-
def write_index(title: str, refs: list[tuple[str, str]], subitems: list[tuple[str, list[tuple[str, str]]]]) -> None: # NOQA
272+
def write_index(
273+
title: str,
274+
refs: list[tuple[str, str]],
275+
subitems: list[tuple[str, list[tuple[str, str]]]],
276+
) -> None:
266277
def write_param(name: str, value: str) -> None:
267-
item = ' <param name="%s" value="%s">\n' % (name, value)
278+
item = f' <param name="{name}" value="{value}">\n'
268279
f.write(item)
269280
title = chm_htmlescape(title, True)
270281
f.write('<LI> <OBJECT type="text/sitemap">\n')
@@ -284,9 +295,9 @@ def write_param(name: str, value: str) -> None:
284295
for subitem in subitems:
285296
write_index(subitem[0], subitem[1], [])
286297
f.write('</UL>')
287-
for (key, group) in index:
288-
for title, (refs, subitems, key_) in group:
289-
write_index(title, refs, subitems) # type: ignore[arg-type]
298+
for (_group_key, group) in index:
299+
for title, (refs, subitems, _category_key) in group:
300+
write_index(title, refs, subitems)
290301
f.write('</UL>\n')
291302

292303

sphinxcontrib/htmlhelp/py.typed

Whitespace-only changes.

tests/conftest.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1+
from __future__ import annotations
2+
13
from pathlib import Path
24

35
import pytest
46

5-
import sphinx
6-
7-
pytest_plugins = 'sphinx.testing.fixtures'
7+
pytest_plugins = (
8+
'sphinx.testing.fixtures',
9+
)
810

911

1012
@pytest.fixture(scope='session')
11-
def rootdir():
12-
if sphinx.version_info[:2] < (7, 2):
13-
from sphinx.testing.path import path
14-
15-
return path(__file__).parent.abspath() / 'roots'
16-
13+
def rootdir() -> Path:
1714
return Path(__file__).resolve().parent / 'roots'

tests/roots/test-basic/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
from __future__ import annotations
2+
13
project = 'Python'

tests/roots/test-chm/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
from __future__ import annotations
2+
13
project = 'test'

tests/roots/test-hhc/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
from __future__ import annotations
2+
13
project = 'Python'
24
html_short_title = "Sphinx's documentation"

0 commit comments

Comments
 (0)