From 9cfdf44784dc90085549490ff1eddd2afc37c1d6 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Sat, 9 Sep 2023 23:48:32 +0100 Subject: [PATCH] Rework infrastructure for linting Run mypy checks outside of `pre-commit` for completeness, and move to Ruff for style checks. --- .flake8 | 3 --- .pre-commit-config.yaml | 16 +++++----------- noxfile.py | 14 ++++++++++++++ pyproject.toml | 18 ++++++++++-------- src/furo/__init__.py | 37 ++++++++++++++++++++++++------------- src/furo/sphinxext.py | 2 +- 6 files changed, 54 insertions(+), 36 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 9410c7942..000000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -max-line-length = 88 -extend-ignore = E203,E501 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a895beae..cf8f56df1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,18 +34,12 @@ repos: - id: forbid-new-submodules - id: trailing-whitespace - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.0.287 hooks: - - id: flake8 - - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.4.1 - hooks: - - id: mypy - args: [--disallow-untyped-defs, --ignore-missing-imports] - files: src/.*\.py$ - additional_dependencies: [types-docutils] + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/PyCQA/pydocstyle rev: 6.3.0 diff --git a/noxfile.py b/noxfile.py index 98d671a08..96c2e9a28 100644 --- a/noxfile.py +++ b/noxfile.py @@ -84,6 +84,12 @@ def docs_live(session): @nox.session(reuse_venv=True) def lint(session): + session.notify("lint-pre-commit") + session.notify("lint-mypy") + + +@nox.session(reuse_venv=True, name="lint-pre-commit") +def lint_pre_commit(session): session.install("pre-commit") args = list(session.posargs) @@ -94,6 +100,14 @@ def lint(session): session.run("pre-commit", "run", *args) +@nox.session(reuse_venv=True, name="lint-mypy") +def lint_mypy(session): + session.install( + "-e", ".", "mypy", "types-docutils", "types-Pygments", "types-beautifulsoup4" + ) + session.run("mypy", "src") + + @nox.session def test(session): session.install("-e", ".", "-r", "tests/requirements.txt") diff --git a/pyproject.toml b/pyproject.toml index 69d80535a..0e4af5dbb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,9 +4,7 @@ build-backend = "sphinx_theme_builder" [tool.sphinx-theme-builder] node-version = "18.16.0" -additional-compiled-static-assets = [ - "styles/furo-extensions.css", -] +additional-compiled-static-assets = ["styles/furo-extensions.css"] [project] name = "furo" @@ -22,10 +20,8 @@ dependencies = [ "pygments >= 2.7", ] -license = { file = "LICENSE"} -authors = [ - {name = "Pradyun Gedam", email = "mail@pradyunsg.me"}, -] +license = { file = "LICENSE" } +authors = [{ name = "Pradyun Gedam", email = "mail@pradyunsg.me" }] classifiers = [ "Framework :: Sphinx", "Framework :: Sphinx :: Theme", @@ -45,7 +41,13 @@ classifiers = [ ] [project.entry-points] -"sphinx.html_themes" = {furo = "furo"} +"sphinx.html_themes" = { furo = "furo" } [project.urls] GitHub = "https://github.com/pradyunsg/furo" + +[tool.mypy] +strict = true + +[tool.ruff] +ignore = ["E501"] diff --git a/src/furo/__init__.py b/src/furo/__init__.py index 665c93125..70647ff37 100644 --- a/src/furo/__init__.py +++ b/src/furo/__init__.py @@ -7,7 +7,7 @@ import os from functools import lru_cache from pathlib import Path -from typing import Any, Dict, Iterator, List, Optional +from typing import Any, Dict, Iterator, List, Optional, cast import sphinx.application from docutils import nodes @@ -71,7 +71,7 @@ def has_not_enough_items_to_show_toc( toctree = TocTree(builder.env).get_toc_for(docname, builder) try: - self_toctree = toctree[0][1] + self_toctree = toctree[0][1] # type: ignore[index] except IndexError: val = True else: @@ -84,8 +84,8 @@ def get_pygments_style_colors( style: Style, *, fallbacks: Dict[str, str] ) -> Dict[str, str]: """Get background/foreground colors for given pygments style.""" - background = style.background_color - text_colors = style.style_for_token(Text) + background = style.background_color # type: ignore[attr-defined] + text_colors = style.style_for_token(Text) # type: ignore[attr-defined] foreground = text_colors["color"] if not background: @@ -172,9 +172,10 @@ def _add_asset_hashes(static: List[str], add_digest_to: List[str]) -> None: "theme-provide assets such as `html_style`." ) - if "?digest=" in static[index].filename: # make this idempotent + # Make this idempotent + if "?digest=" in static[index].filename: # type: ignore[attr-defined] continue - static[index].filename = _asset_hash(asset) # type: ignore + static[index].filename = _asset_hash(asset) # type: ignore[attr-defined] def _html_page_context( @@ -201,9 +202,11 @@ def _html_page_context( # Values computed from page-level context. context["furo_navigation_tree"] = _compute_navigation_tree(context) context["furo_hide_toc"] = _compute_hide_toc( - context, builder=app.builder, docname=pagename + context, builder=cast(StandaloneHTMLBuilder, app.builder), docname=pagename ) + assert _KNOWN_STYLES_IN_USE["light"] + assert _KNOWN_STYLES_IN_USE["dark"] # Inject information about styles context["furo_pygments"] = { "light": get_pygments_style_colors( @@ -248,10 +251,10 @@ def _builder_inited(app: sphinx.application.Sphinx) -> None: builder = app.builder assert ( - builder.highlighter is not None + builder.highlighter is not None # type: ignore[attr-defined] ), "there should be a default style known to Sphinx" assert ( - builder.dark_highlighter is None + builder.dark_highlighter is None # type: ignore[attr-defined] ), "this shouldn't be a dark style known to Sphinx" update_known_styles_state(app) @@ -273,17 +276,25 @@ def update_known_styles_state(app: sphinx.application.Sphinx) -> None: def _get_light_style(app: sphinx.application.Sphinx) -> Style: - return app.builder.highlighter.formatter_args["style"] + # fmt: off + # For https://github.com/psf/black/issues/3869 + return ( + app # type: ignore[no-any-return] + .builder + .highlighter # type: ignore[attr-defined] + .formatter_args["style"] + ) + # fmt: on def _get_dark_style(app: sphinx.application.Sphinx) -> Style: dark_style = app.config.pygments_dark_style - return PygmentsBridge("html", dark_style).formatter_args["style"] + return cast(Style, PygmentsBridge("html", dark_style).formatter_args["style"]) -def _get_styles(formatter: HtmlFormatter, *, prefix: str) -> Iterator[str]: +def _get_styles(formatter: HtmlFormatter[str], *, prefix: str) -> Iterator[str]: """Get styles out of a formatter, where everything has the correct prefix.""" - for line in formatter.get_linenos_style_defs(): + for line in formatter.get_linenos_style_defs(): # type: ignore[no-untyped-call] yield f"{prefix} {line}" yield from formatter.get_background_style_defs(prefix) yield from formatter.get_token_style_defs(prefix) diff --git a/src/furo/sphinxext.py b/src/furo/sphinxext.py index 713cee321..3ab22e8c5 100644 --- a/src/furo/sphinxext.py +++ b/src/furo/sphinxext.py @@ -20,7 +20,7 @@ from docutils import nodes from docutils.statemachine import StringList from sphinx.application import Sphinx -from sphinx.directives import SphinxDirective +from sphinx.directives import SphinxDirective # type: ignore[attr-defined] def _split_by_language(block_text: str) -> Tuple[str, str]: