From 4abd79ca08be9a324ffeed2b158a62866e1fa98e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 31 Jan 2023 17:26:36 +0000 Subject: [PATCH 01/40] Bump version --- CHANGES | 4 ++++ sphinxcontrib/htmlhelp/__init__.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index cf0663d..934f82d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +Release 2.0.2 (unreleased) +========================== + + Release 2.0.1 (2023-01-31) ========================== diff --git a/sphinxcontrib/htmlhelp/__init__.py b/sphinxcontrib/htmlhelp/__init__.py index fa6fe28..5681bf5 100644 --- a/sphinxcontrib/htmlhelp/__init__.py +++ b/sphinxcontrib/htmlhelp/__init__.py @@ -35,8 +35,8 @@ else: from sphinx.util import progress_message # type: ignore[attr-defined,no-redef] -__version__ = '2.0.1' -__version_info__ = (2, 0, 1) +__version__ = '2.0.2' +__version_info__ = (2, 0, 2) logger = logging.getLogger(__name__) __ = get_translation(__name__, 'console') From 8eb63c28a0acc8b976144dbc72e64acb951e7754 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Thu, 16 Mar 2023 23:11:37 +0000 Subject: [PATCH 02/40] Drop ``setuptools`` --- MANIFEST.in | 9 --------- pyproject.toml | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 7031593..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include README.rst -include LICENSE -include CHANGES - -include tox.ini - -recursive-include sphinxcontrib/htmlhelp/templates * -recursive-include sphinxcontrib/htmlhelp/locales * -recursive-include tests * diff --git a/pyproject.toml b/pyproject.toml index 0434071..db5919e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["setuptools>=64"] -build-backend = "setuptools.build_meta" +requires = ["flit_core>=3.7"] +build-backend = "flit_core.buildapi" # project metadata [project] @@ -57,8 +57,17 @@ lint = [ name = "Georg Brandl" email = "georg@python.org" -[tool.setuptools.dynamic] -version.attr = "sphinxcontrib.htmlhelp.__version__" +[tool.flit.module] +name = "sphinxcontrib.htmlhelp" + +[tool.flit.sdist] +include = [ + "CHANGES", + "LICENSE", + # Tests + "tests/", + "tox.ini", +] [tool.mypy] ignore_missing_imports = true From 5a4cbeee53b7bd65453b1847805e6432cfd34b3c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:45:10 +0100 Subject: [PATCH 03/40] Support Python 3.9 and later --- .github/workflows/test.yml | 11 ++++++----- CHANGES | 2 ++ pyproject.toml | 8 +++++--- tox.ini | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bb8b901..fe363d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,8 @@ name: Test -on: [push, pull_request] +on: + push: + pull_request: + workflow_dispatch: permissions: contents: read @@ -14,11 +17,11 @@ jobs: strategy: matrix: python: - - "3.8" - "3.9" - "3.10" - "3.11" - "3.12-dev" + - "3.13-dev" fail-fast: false steps: @@ -41,9 +44,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - env: - - flake8 - - mypy + env: [flake8, mypy] steps: - uses: actions/checkout@v3 diff --git a/CHANGES b/CHANGES index 934f82d..4b8dbaa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ Release 2.0.2 (unreleased) ========================== +* Drop support for Python 3.8 +* Raise minimum required Sphinx version to 5.0 Release 2.0.1 (2023-01-31) ========================== diff --git a/pyproject.toml b/pyproject.toml index db5919e..d704e4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ urls.Download = "https://pypi.org/project/sphinxcontrib-htmlhelp/" urls.Homepage = "https://www.sphinx-doc.org/" urls."Issue tracker" = "https://github.com/sphinx-doc/sphinx/issues" license.text = "BSD-2-Clause" -requires-python = ">=3.8" +requires-python = ">=3.9" # Classifiers list: https://pypi.org/classifiers/ classifiers = [ @@ -27,11 +27,11 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Framework :: Sphinx", "Framework :: Sphinx :: Extension", "Topic :: Documentation", @@ -39,7 +39,9 @@ classifiers = [ "Topic :: Text Processing", "Topic :: Utilities", ] -dependencies = [] +dependencies = [ + "Sphinx>=5", +] dynamic = ["version"] [project.optional-dependencies] diff --git a/tox.ini b/tox.ini index a67743f..859d9a6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] minversion = 2.4.0 envlist = - py{38,39,310,311,312}, + py{39,310,311,312,313}, flake8, mypy isolated_build = True From bf22cc076be75c7d15264dd40f615540425d7c7a Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:46:17 +0100 Subject: [PATCH 04/40] Add GHA release workflow --- .github/workflows/create-release.yml | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .github/workflows/create-release.yml diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..1907927 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,90 @@ +name: Create release + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish-pypi: + runs-on: ubuntu-latest + name: PyPI Release + environment: release + permissions: + id-token: write # for PyPI trusted publishing + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3 + cache: pip + cache-dependency-path: pyproject.toml + + - name: Install build dependencies (pypa/build, twine) + run: | + pip install -U pip + pip install build twine + + - name: Build distribution + run: python -m build + + - name: Mint PyPI API token + id: mint-token + uses: actions/github-script@v6 + with: + # language=JavaScript + script: | + // retrieve the ambient OIDC token + const oidc_request_token = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; + const oidc_request_url = process.env.ACTIONS_ID_TOKEN_REQUEST_URL; + const oidc_resp = await fetch(`${oidc_request_url}&audience=pypi`, { + headers: {Authorization: `bearer ${oidc_request_token}`}, + }); + const oidc_token = (await oidc_resp.json()).value; + + // exchange the OIDC token for an API token + const mint_resp = await fetch('https://pypi.org/_/oidc/github/mint-token', { + method: 'post', + body: `{"token": "${oidc_token}"}` , + headers: {'Content-Type': 'application/json'}, + }); + const api_token = (await mint_resp.json()).token; + + // mask the newly minted API token, so that we don't accidentally leak it + core.setSecret(api_token) + core.setOutput('api-token', api_token) + + - name: Upload to PyPI + env: + TWINE_NON_INTERACTIVE: "true" + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: "${{ steps.mint-token.outputs.api-token }}" + run: | + twine check dist/* + twine upload dist/* + + github-release: + runs-on: ubuntu-latest + name: GitHub release + environment: release + permissions: + contents: write # for softprops/action-gh-release to create GitHub release + steps: + - uses: actions/checkout@v3 + - name: Get release version + id: get_version + uses: actions/github-script@v6 + with: + script: core.setOutput('version', context.ref.replace("refs/tags/v", "")) + + - name: Create GitHub release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + name: "sphinxcontrib-htmlhelp ${{ steps.get_version.outputs.version }}" + body: "Changelog: https://www.sphinx-doc.org/en/master/changes.html" From 9bbb7575f33fe7e36d696d0a95e73854833501dd Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:01:39 +0100 Subject: [PATCH 05/40] Invoke pytest directly --- .github/workflows/test.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fe363d4..b974e1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +env: + FORCE_COLOR: "1" + PYTHONDEVMODE: "1" # -X dev + PYTHONWARNDEFAULTENCODING: "1" # -X warn_default_encoding + jobs: tests: runs-on: ubuntu-latest @@ -33,12 +38,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install --upgrade tox + python -m pip install --upgrade pytest + python -m pip install --upgrade Sphinx @ git+https://github.com/sphinx-doc/sphinx - - name: Run tox - run: | - python -V - tox -- -v --durations=25 + - name: Test with pytest + run: python -m pytest --durations 25 lint: runs-on: ubuntu-latest From 18ec20f8f25027ac3eb2cfa4ff392ebfcf3ea4cb Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:05:35 +0100 Subject: [PATCH 06/40] Fix the quoting for installation from git --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b974e1f..54dc417 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install --upgrade pytest - python -m pip install --upgrade Sphinx @ git+https://github.com/sphinx-doc/sphinx + python -m pip install "Sphinx @ git+https://github.com/sphinx-doc/sphinx" - name: Test with pytest run: python -m pytest --durations 25 From 1683f505a9b5129f1dd9475381f4ccc585aa300c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:09:04 +0100 Subject: [PATCH 07/40] Fix test failures --- .github/workflows/test.yml | 10 ++++++++-- tests/conftest.py | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 54dc417..082f9ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,14 +31,20 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Setup Python ${{ matrix.python }} + - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 + if: "!endsWith(matrix.python, '-dev')" + with: + python-version: ${{ matrix.python }} + - name: Set up Python ${{ matrix.python }} (deadsnakes) + uses: deadsnakes/action@v2.1.1 + if: "endsWith(matrix.python, '-dev')" with: python-version: ${{ matrix.python }} - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install --upgrade pytest + python -m pip install .[test] python -m pip install "Sphinx @ git+https://github.com/sphinx-doc/sphinx" - name: Test with pytest diff --git a/tests/conftest.py b/tests/conftest.py index ae725dc..c80a172 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,13 +6,13 @@ :license: BSD, see LICENSE for details. """ -import pytest +from pathlib import Path -from sphinx.testing.path import path +import pytest pytest_plugins = 'sphinx.testing.fixtures' @pytest.fixture(scope='session') def rootdir(): - return path(__file__).parent.abspath() / 'roots' + return Path(__file__).resolve().parent / 'roots' From 8c7a3f8edfadb036aa8bc72b8fc13f511029ce35 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:29:47 +0100 Subject: [PATCH 08/40] Fix path operations in tests --- tests/test_htmlhelp.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_htmlhelp.py b/tests/test_htmlhelp.py index 8774d4b..917e266 100644 --- a/tests/test_htmlhelp.py +++ b/tests/test_htmlhelp.py @@ -63,10 +63,8 @@ def test_chm(app): # check .hhk file outname = app.builder.config.htmlhelp_basename - hhk_path = str(app.outdir / outname + '.hhk') - - with open(hhk_path, 'rb') as f: - data = f.read() + hhk_path = (app.outdir / outname).with_suffix('.hhk') + data = hhk_path.read_bytes() m = re.search(br'&#[xX][0-9a-fA-F]+;', data) assert m is None, 'Hex escaping exists in .hhk file: ' + str(m.group(0)) From b3c072543449c5ddc25c902bf35de5b9f23b0998 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:54:07 +0100 Subject: [PATCH 09/40] Fix mypy errors --- sphinxcontrib/htmlhelp/__init__.py | 3 ++- tox.ini | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinxcontrib/htmlhelp/__init__.py b/sphinxcontrib/htmlhelp/__init__.py index 5681bf5..58e2011 100644 --- a/sphinxcontrib/htmlhelp/__init__.py +++ b/sphinxcontrib/htmlhelp/__init__.py @@ -11,6 +11,7 @@ import html import os from os import path +from pathlib import Path from typing import Any, Dict, List, Set, Tuple, Type from docutils import nodes @@ -267,7 +268,7 @@ def build_toc_file(self) -> None: } f.write(self.render('project.hhc', context)) - def build_hhx(self, outdir: str, outname: str) -> None: + def build_hhx(self, outdir: Path, outname: str) -> None: logger.info(__('writing index file...')) index = IndexEntries(self.env).create_index(self) filename = path.join(outdir, outname + '.hhk') diff --git a/tox.ini b/tox.ini index 859d9a6..52e72d9 100644 --- a/tox.ini +++ b/tox.ini @@ -42,4 +42,4 @@ description = extras = lint commands= - mypy sphinxcontrib/ + mypy sphinxcontrib/ --explicit-package-bases From 4a4014835b556d3f2564d16ff9816110e6838523 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 7 Aug 2023 19:17:53 +0100 Subject: [PATCH 10/40] Convert type comments to annotations --- sphinxcontrib/htmlhelp/__init__.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sphinxcontrib/htmlhelp/__init__.py b/sphinxcontrib/htmlhelp/__init__.py index 58e2011..9799423 100644 --- a/sphinxcontrib/htmlhelp/__init__.py +++ b/sphinxcontrib/htmlhelp/__init__.py @@ -8,11 +8,13 @@ :license: BSD, see LICENSE for details. """ +from __future__ import annotations + import html import os from os import path from pathlib import Path -from typing import Any, Dict, List, Set, Tuple, Type +from typing import Any from docutils import nodes from docutils.nodes import Element, Node, document @@ -99,7 +101,7 @@ def chm_htmlescape(s: str, quote: bool = True) -> str: class ToCTreeVisitor(nodes.NodeVisitor): def __init__(self, document: document) -> None: super().__init__(document) - self.body = [] # type: List[str] + self.body: list[str] = [] self.depth = 0 def append(self, text: str) -> None: @@ -175,15 +177,15 @@ def init(self) -> None: self.lcid, self.encoding = locale @property - def default_translator_class(self) -> "Type[nodes.NodeVisitor]": # type: ignore + def default_translator_class(self) -> type[nodes.NodeVisitor]: # Use HTML4 writer always return HTMLTranslator - def prepare_writing(self, docnames: Set[str]) -> None: + def prepare_writing(self, docnames: set[str]) -> None: super().prepare_writing(docnames) self.globalcontext['html5_doctype'] = False - def update_page_context(self, pagename: str, templatename: str, ctx: Dict, event_arg: str) -> None: # NOQA + def update_page_context(self, pagename: str, templatename: str, ctx: dict, event_arg: str) -> None: # NOQA ctx['encoding'] = self.encoding def handle_finish(self) -> None: @@ -200,7 +202,7 @@ def write_doc(self, docname: str, doctree: document) -> None: super().write_doc(docname, doctree) - def render(self, name: str, context: Dict) -> str: + def render(self, name: str, context: dict) -> str: template = SphinxRenderer(template_dir) return template.render(name, context) @@ -223,7 +225,7 @@ def copy_stopword_list(self) -> None: def build_project_file(self) -> None: """Create a project file (.hhp) on outdir.""" # scan project files - project_files = [] # type: List[str] + project_files: list[str] = [] for root, dirs, files in os.walk(self.outdir): dirs.sort() files.sort() @@ -275,7 +277,7 @@ def build_hhx(self, outdir: Path, outname: str) -> None: with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f: f.write('') for (key, group) in index: for title, (refs, subitems, key_) in group: - write_index(title, refs, subitems) + write_index(title, refs, subitems) # type: ignore[arg-type] f.write('\n') diff --git a/tests/roots/test-basic/conf.py b/tests/roots/test-basic/conf.py index e69de29..329280d 100644 --- a/tests/roots/test-basic/conf.py +++ b/tests/roots/test-basic/conf.py @@ -0,0 +1 @@ +project = 'Python' diff --git a/tests/roots/test-hhc/conf.py b/tests/roots/test-hhc/conf.py index 20447e0..7825564 100644 --- a/tests/roots/test-hhc/conf.py +++ b/tests/roots/test-hhc/conf.py @@ -1 +1,2 @@ +project = 'Python' html_short_title = "Sphinx's documentation" From 49998fdc1e911048e35fbf6fe0f135a47d338214 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 20 Jul 2024 12:58:00 +0100 Subject: [PATCH 28/40] Bump to 2.0.6 final --- CHANGES | 2 +- sphinxcontrib/htmlhelp/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 30caf3e..c4ebd56 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Release 2.0.6 (unreleased) +Release 2.0.6 (2024-07-20) ========================== * Fix tests for Sphinx 7.4 and later. diff --git a/sphinxcontrib/htmlhelp/__init__.py b/sphinxcontrib/htmlhelp/__init__.py index 36e80b3..8ac975e 100644 --- a/sphinxcontrib/htmlhelp/__init__.py +++ b/sphinxcontrib/htmlhelp/__init__.py @@ -28,8 +28,8 @@ else: from sphinx.util import progress_message # type: ignore[attr-defined,no-redef] -__version__ = '2.0.5' -__version_info__ = (2, 0, 5) +__version__ = '2.0.6' +__version_info__ = (2, 0, 6) logger = logging.getLogger(__name__) __ = get_translation(__name__, 'console') From c5ec8d7d7ca8520b9f6eac2bfb71f37ddc6eef65 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:38:40 +0100 Subject: [PATCH 29/40] Update .gitignore --- .gitignore | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fe75ce5..10cef94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,17 @@ *.pyc -*.egg -*.so -*.swp .DS_Store +idea/ +.vscode/ + .mypy_cache/ +.pytest_cache/ +.ruff_cache/ .tags .tox/ +.venv/ +venv/ + build/ dist/ -sphinxcontrib_htmlhelp.egg-info/ From a21bb3dc83b14ee2518dc548229f9902ea7aadcc Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sun, 28 Jul 2024 05:02:28 +0100 Subject: [PATCH 30/40] Adopt Ruff and use stricter MyPy settings --- .flake8 | 4 -- .github/workflows/test.yml | 4 +- .ruff.toml | 53 +++++++++++++++ Makefile | 2 +- pyproject.toml | 36 +++++++++- sphinxcontrib/htmlhelp/__init__.py | 105 ++++++++++++++++------------- sphinxcontrib/htmlhelp/py.typed | 0 tests/conftest.py | 15 ++--- tests/roots/test-basic/conf.py | 2 + tests/roots/test-chm/conf.py | 2 + tests/roots/test-hhc/conf.py | 2 + tests/test_htmlhelp.py | 42 +++++++----- tox.ini | 6 +- 13 files changed, 188 insertions(+), 85 deletions(-) delete mode 100644 .flake8 create mode 100644 .ruff.toml create mode 100644 sphinxcontrib/htmlhelp/py.typed diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 5af0a95..0000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-line-length = 95 -ignore = E116,E241,E251 -exclude = .git,.tox,.venv diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8cd7db1..856df5b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,7 +71,9 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - env: [flake8, mypy] + env: + - ruff + - mypy steps: - uses: actions/checkout@v3 diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..4b7dd2a --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,53 @@ +target-version = "py39" # Pin Ruff to Python 3.9 +output-format = "full" +line-length = 95 + +[lint] +preview = true +select = [ +# "ANN", # flake8-annotations + "C4", # flake8-comprehensions + "COM", # flake8-commas + "B", # flake8-bugbear + "DTZ", # flake8-datetimez + "E", # pycodestyle + "EM", # flake8-errmsg + "EXE", # flake8-executable + "F", # pyflakes + "FA", # flake8-future-annotations + "FLY", # flynt + "FURB", # refurb + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "INT", # flake8-gettext + "LOG", # flake8-logging + "PERF", # perflint + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PT", # flake8-pytest-style + "SIM", # flake8-simplify + "SLOT", # flake8-slots + "TCH", # flake8-type-checking + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] +ignore = [ + "E116", + "E241", + "E251", +] + +[lint.per-file-ignores] +"tests/*" = [ + "ANN", # tests don't need annotations +] + +[lint.isort] +forced-separate = [ + "tests", +] +required-imports = [ + "from __future__ import annotations", +] diff --git a/Makefile b/Makefile index 26f411a..438ee54 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ clean-mypyfiles: .PHONY: style-check style-check: - @flake8 + @ruff check .PHONY: type-check type-check: diff --git a/pyproject.toml b/pyproject.toml index fb933af..5db9843 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,9 +48,9 @@ test = [ "html5lib", ] lint = [ - "flake8", + "ruff==0.5.5", "mypy", - "docutils-stubs", + "types-docutils", ] standalone = [ "Sphinx>=5", @@ -73,4 +73,34 @@ include = [ ] [tool.mypy] -ignore_missing_imports = true +python_version = "3.9" +packages = [ + "sphinxcontrib", + "tests", +] +exclude = [ + "tests/roots", +] +check_untyped_defs = true +disallow_any_generics = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +#explicit_package_bases = true +extra_checks = true +no_implicit_reexport = true +show_column_numbers = true +show_error_context = true +strict_optional = true +warn_redundant_casts = true +warn_unused_configs = true +warn_unused_ignores = true +enable_error_code = [ + "type-arg", + "redundant-self", + "truthy-iterable", + "ignore-without-code", + "unused-awaitable", +] diff --git a/sphinxcontrib/htmlhelp/__init__.py b/sphinxcontrib/htmlhelp/__init__.py index 8ac975e..90c61bb 100644 --- a/sphinxcontrib/htmlhelp/__init__.py +++ b/sphinxcontrib/htmlhelp/__init__.py @@ -5,16 +5,13 @@ import html import os from os import path -from typing import Any - -from docutils import nodes -from docutils.nodes import Element, Node, document +from pathlib import Path +from typing import TYPE_CHECKING, Any import sphinx +from docutils import nodes from sphinx import addnodes -from sphinx.application import Sphinx from sphinx.builders.html import StandaloneHTMLBuilder -from sphinx.config import Config from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.locale import get_translation from sphinx.util import logging @@ -23,10 +20,15 @@ from sphinx.util.osutil import make_filename_from_project, relpath from sphinx.util.template import SphinxRenderer +if TYPE_CHECKING: + from docutils.nodes import Element, Node, document + from sphinx.application import Sphinx + from sphinx.config import Config + if sphinx.version_info[:2] >= (6, 1): from sphinx.util.display import progress_message else: - from sphinx.util import progress_message # type: ignore[attr-defined,no-redef] + from sphinx.util import progress_message # type: ignore[no-redef] __version__ = '2.0.6' __version_info__ = (2, 0, 6) @@ -126,8 +128,8 @@ def depart_list_item(self, node: Element) -> None: def visit_reference(self, node: Element) -> None: title = chm_htmlescape(node.astext(), True) - self.append(' ' % title) - self.append(' ' % node['refuri']) + self.append(f' ') + self.append(f' ') self.append('') raise nodes.SkipNode @@ -170,7 +172,13 @@ def prepare_writing(self, docnames: set[str]) -> None: super().prepare_writing(docnames) self.globalcontext['html5_doctype'] = False - def update_page_context(self, pagename: str, templatename: str, ctx: dict, event_arg: str) -> None: # NOQA + def update_page_context( + self, + pagename: str, + templatename: str, + ctx: dict[str, Any], + event_arg: str, + ) -> None: ctx['encoding'] = self.encoding def handle_finish(self) -> None: @@ -180,14 +188,14 @@ def handle_finish(self) -> None: self.build_hhx(self.outdir, self.config.htmlhelp_basename) def write_doc(self, docname: str, doctree: document) -> None: - for node in doctree.traverse(nodes.reference): + for node in doctree.findall(nodes.reference): # add ``target=_blank`` attributes to external links if node.get('internal') is None and 'refuri' in node: node['target'] = '_blank' super().write_doc(docname, doctree) - def render(self, name: str, context: dict) -> str: + def render(self, name: str, context: dict[str, Any]) -> str: template = SphinxRenderer(template_dir) return template.render(name, context) @@ -220,40 +228,39 @@ def build_project_file(self) -> None: fn = relpath(path.join(root, fn), self.outdir) project_files.append(fn.replace(os.sep, '\\')) - filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhp') - with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f: - context = { - 'outname': self.config.htmlhelp_basename, - 'title': self.config.html_title, - 'version': self.config.version, - 'project': self.config.project, - 'lcid': self.lcid, - 'master_doc': self.config.master_doc + self.out_suffix, - 'files': project_files, - } - body = self.render('project.hhp', context) - f.write(body) + context = { + 'outname': self.config.htmlhelp_basename, + 'title': self.config.html_title, + 'version': self.config.version, + 'project': self.config.project, + 'lcid': self.lcid, + 'master_doc': self.config.master_doc + self.out_suffix, + 'files': project_files, + } + body = self.render('project.hhp', context) + filename = Path(self.outdir, f'{self.config.htmlhelp_basename}.hhp') + filename.write_text(body, encoding=self.encoding, errors='xmlcharrefreplace') @progress_message(__('writing TOC file')) def build_toc_file(self) -> None: """Create a ToC file (.hhp) on outdir.""" - filename = path.join(self.outdir, self.config.htmlhelp_basename + '.hhc') - with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f: - toctree = self.env.get_and_resolve_doctree(self.config.master_doc, self, - prune_toctrees=False) - visitor = ToCTreeVisitor(toctree) - matcher = NodeMatcher(addnodes.compact_paragraph, toctree=True) - for node in toctree.traverse(matcher): # type: addnodes.compact_paragraph - node.walkabout(visitor) - - context = { - 'body': visitor.astext(), - 'suffix': self.out_suffix, - 'short_title': self.config.html_short_title, - 'master_doc': self.config.master_doc, - 'domain_indices': self.domain_indices, - } - f.write(self.render('project.hhc', context)) + toctree = self.env.get_and_resolve_doctree(self.config.master_doc, self, + prune_toctrees=False) + visitor = ToCTreeVisitor(toctree) + matcher = NodeMatcher(addnodes.compact_paragraph, toctree=True) + for node in toctree.findall(matcher): + node.walkabout(visitor) + + context = { + 'body': visitor.astext(), + 'suffix': self.out_suffix, + 'short_title': self.config.html_short_title, + 'master_doc': self.config.master_doc, + 'domain_indices': self.domain_indices, + } + body = self.render('project.hhc', context) + filename = Path(self.outdir, f'{self.config.htmlhelp_basename}.hhc') + filename.write_text(body, encoding=self.encoding, errors='xmlcharrefreplace') def build_hhx(self, outdir: str | os.PathLike[str], outname: str) -> None: logger.info(__('writing index file...')) @@ -262,9 +269,13 @@ def build_hhx(self, outdir: str | os.PathLike[str], outname: str) -> None: with open(filename, 'w', encoding=self.encoding, errors='xmlcharrefreplace') as f: f.write('