diff --git a/.babel.cfg b/.babel.cfg new file mode 100644 index 00000000..cc4c9de0 --- /dev/null +++ b/.babel.cfg @@ -0,0 +1,3 @@ +[javascript: **.js] + +[jinja2: **.html] diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 2bcd70e3..00000000 --- a/.flake8 +++ /dev/null @@ -1,2 +0,0 @@ -[flake8] -max-line-length = 88 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..8452ef07 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: monthly + assignees: + - "ezio-melotti" + groups: + actions: + patterns: + - "*" diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..9d1e0987 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,5 @@ +changelog: + exclude: + authors: + - dependabot + - pre-commit-ci diff --git a/.github/workflows/documentation-links.yml b/.github/workflows/documentation-links.yml new file mode 100644 index 00000000..a4de7dcd --- /dev/null +++ b/.github/workflows/documentation-links.yml @@ -0,0 +1,24 @@ +name: Read the Docs PR preview +# Automatically edits a pull request's descriptions with a link +# to the documentation's preview on Read the Docs. + +on: + pull_request_target: + types: + - opened + +permissions: + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + documentation-links: + runs-on: ubuntu-latest + steps: + - uses: readthedocs/actions/preview@v1 + with: + project-slug: "python-docs-theme-previews" + single-version: "true" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 85097631..88c0c7cb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.x" - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/pypi-package.yml b/.github/workflows/pypi-package.yml index 355a35fd..744d49bd 100644 --- a/.github/workflows/pypi-package.yml +++ b/.github/workflows/pypi-package.yml @@ -11,6 +11,9 @@ on: permissions: contents: read +env: + FORCE_COLOR: 1 + jobs: # Always build & lint package. build-package: @@ -20,14 +23,16 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: hynek/build-and-inspect-python-package@v1 + - uses: hynek/build-and-inspect-python-package@v2 # Upload to real PyPI on GitHub Releases. release-pypi: name: Publish to PyPI environment: release-pypi # Only run for published releases. - if: github.repository_owner == 'python' && github.event.action == 'published' + if: | + github.repository_owner == 'python' + && github.event.action == 'published' runs-on: ubuntu-latest needs: build-package @@ -36,10 +41,12 @@ jobs: steps: - name: Download packages built by build-and-inspect-python-package - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Packages path: dist - name: Upload package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 + with: + attestations: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9407ac7e..23e6c7e6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,12 +12,12 @@ jobs: strategy: fail-fast: false matrix: - branch: ["origin/main", "3.12", "3.11", "3.10", "3.9", "3.8"] + branch: ["3.14", "3.13", "3.12"] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: - python-version: 3 + python-version: ${{ matrix.branch }} allow-prereleases: true cache: pip - name: Clone docsbuild scripts @@ -34,17 +34,56 @@ jobs: --build-root ./build_root --www-root ./www --log-directory ./logs - --group $(id -g) + --group "$(id -g)" --skip-cache-invalidation - --theme $(pwd) - --language en - --branch ${{ matrix.branch }} + --theme "$(pwd)" + --languages en + --branches ${{ matrix.branch }} + ${{ matrix.branch == '3.14' && '--select-output no-html' || '' }} - name: Show logs if: failure() run: | cat ./logs/docsbuild.log - name: Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: doc-html + name: doc-html-${{ matrix.branch }} path: www/ + + translations: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: ["ubuntu-latest", "windows-latest"] + # Test minimum supported and latest stable from 3.x series + python-version: ["3.12", "3"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + allow-prereleases: true + cache: pip + - name: Install dependencies + run: | + pip install --upgrade pip + pip install -r requirements.txt + - name: Remove locale file for testing + shell: bash + run: rm -rf locales/pt_BR/ + - run: python babel_runner.py extract + - run: python babel_runner.py init -l pt_BR + - run: python babel_runner.py update + - run: python babel_runner.py update -l pt_BR + - run: python babel_runner.py compile + - run: python babel_runner.py compile -l pt_BR + - name: Print .pot file + shell: bash + run: cat locales/messages.pot + - name: Print .po file + shell: bash + run: cat locales/pt_BR/LC_MESSAGES/messages.po + - name: list files in locales dir + shell: bash + run: ls -R locales/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 008784c6..9a7e83b3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,50 +1,51 @@ repos: - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.3 hooks: - - id: pyupgrade - args: [--py38-plus] + - id: ruff + args: [--exit-non-zero-on-fix] - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.9.1 + rev: 24.10.0 hooks: - id: black - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - args: [--add-import=from __future__ import annotations] - - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - additional_dependencies: - [flake8-2020, flake8-implicit-str-concat, flake8-logging] - - - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.10.0 - hooks: - - id: python-check-blanket-noqa - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-case-conflict - - id: check-executables-have-shebangs - id: check-merge-conflict - - id: check-json - id: check-toml - id: check-yaml - id: debug-statements - id: end-of-file-fixer - id: trailing-whitespace + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.31.0 + hooks: + - id: check-dependabot + - id: check-github-workflows + + - repo: https://github.com/rhysd/actionlint + rev: v1.7.7 + hooks: + - id: actionlint + + - repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.5.0 + hooks: + - id: pyproject-fmt + - repo: https://github.com/abravalheri/validate-pyproject - rev: v0.14 + rev: v0.23 hooks: - id: validate-pyproject + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes + ci: autoupdate_schedule: quarterly diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f44760d2..fb43a9f1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,27 +1,107 @@ -========= Changelog ========= -`2024.1 `_ ----------------------------------------------------------------------------- +`2025.4.1 `_ +------------------------------------------------------------------------------- + +* Fix copy button with multiple tracebacks by @tomasr8 in https://github.com/python/python-docs-theme/pull/240 + +`2025.4 `_ +--------------------------------------------------------------------------- + +* Require Sphinx 7.3 by @AA-Turner in https://github.com/python/python-docs-theme/pull/221 +* Add support for Python 3.14 by @hugovk https://github.com/python/python-docs-theme/pull/236 +* Drop support for Python 3.10 and 3.11 by @hugovk in https://github.com/python/python-docs-theme/pull/234 +* Add a copy button to code samples by @tomasr8 in https://github.com/python/python-docs-theme/pull/231 +* Add missing i18n for copy button titles by @tomasr8 in https://github.com/python/python-docs-theme/pull/225 +* Use consistent line-height for light & dark theme by @tomasr8 in https://github.com/python/python-docs-theme/pull/227 +* Remove self-closing tags by @hugovk in https://github.com/python/python-docs-theme/pull/226 +* Replace deprecated classifier with licence expression (PEP 639) by @hugovk in https://github.com/python/python-docs-theme/pull/237 + +`2025.2 `_ +--------------------------------------------------------------------------- + +- Note minimum requirements for Sphinx (#216) + Contributed by Adam Turner +- Horizontally centre the sidebar collapse button (#219) + Contributed by Tomas Roun +- Make sidebar width more flexible (#218) + Contributed by Tomas Roun +- Set ``__version__`` in the runtime package (#222) + Contributed by Adam Turner + +`2024.12 `_ +----------------------------------------------------------------------------- + +- Hide header and search bar when printing (#204) + Contributed by Hugo van Kemenade + +`2024.10 `_ +----------------------------------------------------------------------------- + +- Add support for Python 3.13 (#196) + Contributed by Hugo van Kemenade +- Drop support for Python 3.8 (#197) + Contributed by Hugo van Kemenade +- Add script for handling translations (#195) + Contributed by Rafael Fontenelle +- Generate digital attestations for PyPI (PEP 740) (#198) + Contributed by Hugo van Kemenade + +`2024.6 `_ +--------------------------------------------------------------------------- + +- Add backgrounds and borders to admonitions (#190) + Contributed by Hugo van Kemenade +- Use different colour for 'Return value: Borrowed reference' (#188) + Contributed by Hugo van Kemenade + +`2024.4 `_ +--------------------------------------------------------------------------- + +- Add colour to version change directives (#185) + Contributed by Hugo van Kemenade +- Only show 'Last updated on ...' when ``last_updated`` defined (#183) + Contributed by Hugo van Kemenade +- Use system font stack for all code (#186) + Contributed by Hugo van Kemenade + +`2024.3 `_ +--------------------------------------------------------------------------- + +- Modernise font: use system font stack to improve text readability and webpage performance (#174) + Contributed by Hugo van Kemenade +- Remove incorrect CSS property (#178) + Contributed by Kerim Kabirov + +`2024.2 `_ +--------------------------------------------------------------------------- + +- Do not underline navigation links (#169) + Contributed by Hugo van Kemenade +- Only apply underline offset to code formatting for underline visibility (#171) + Contributed by Hugo van Kemenade + +`2024.1 `_ +--------------------------------------------------------------------------- - Underline links for readability and a11y (#160, #166) - Contributed by Hugo van Kemenade + Contributed by Hugo van Kemenade - Add ``hosted_on`` variable for a link in the footer (#165) - Contributed by Hugo van Kemenade + Contributed by Hugo van Kemenade - Consistently reference ``theme_root_icon`` (#163) - Contributed by Marko Budiselic + Contributed by Marko Budiselic - Dark mode: fix contrast of footer highlight (#162) - Contributed by Hugo van Kemenade + Contributed by Hugo van Kemenade -`2023.9 `_ ----------------------------------------------------------------------------- +`2023.9 `_ +--------------------------------------------------------------------------- - Focus search box when pressing slash (#153) Contributed by Hugo van Kemenade -`2023.8 `_ ----------------------------------------------------------------------------- +`2023.8 `_ +--------------------------------------------------------------------------- - Add Python 3.12 and 3.13 classifiers (#147) Contributed by Hugo van Kemenade @@ -30,10 +110,10 @@ Changelog - Restore the menu on mobile devices (inadvertently broken in 2023.7) (#146) Contributed by Hugo van Kemenade -`2023.7 `_ ----------------------------------------------------------------------------- +`2023.7 `_ +--------------------------------------------------------------------------- -- Fix compatability with Sphinx 7.1 (#137) +- Fix compatibility with Sphinx 7.1 (#137) Contributed by Pradyun Gedam - Enable the slash keypress to focus the search field (#141) Contributed by Mike Fiedler @@ -46,8 +126,8 @@ Changelog - Test with Python 3.12 (#140) Contributed by Hugo van Kemenade -`2023.5 `_ ----------------------------------------------------------------------------- +`2023.5 `_ +--------------------------------------------------------------------------- - Add a dark theme. (#44) Contributed by Nils K @@ -61,14 +141,14 @@ Changelog Contributed by Hugo van Kemenade -`2023.3.1 `_ --------------------------------------------------------------------------------- +`2023.3.1 `_ +------------------------------------------------------------------------------- - Skip cache-busting for old Sphinx #113 -`2023.3 `_ ----------------------------------------------------------------------------- +`2023.3 `_ +--------------------------------------------------------------------------- - Fix problem with monospace rendering in Vivaldi #104 - Fix mobile nav obstructing content #96 @@ -76,30 +156,30 @@ Changelog - Append a hash ?digest to CSS files for cache-busting #108 -`2022.1 `_ ----------------------------------------------------------------------------------- +`2022.1 `_ +---------------------------------------------------------------------------- - Add a configuration for license URL. (#90) - Exclude the floating navbar from CHM help. (#84) - Make sidebar scrollable and sticky (on modern browsers) (#91) -`2021.11.1 `_ ------------------------------------------------------------------------------------ +`2021.11.1 `_ +---------------------------------------------------------------------------------- - Fix monospace again, on buggy Google Chrome (#87) Contributed by Tushar Sadhwani -`2021.11 `_ -------------------------------------------------------------------------------- +`2021.11 `_ +------------------------------------------------------------------------------ - Fix monospace on buggy Google Chrome (#85) Contributed by Tushar Sadhwani -`2021.8 `_ ------------------------------------------------------------------------------- +`2021.8 `_ +----------------------------------------------------------------------------- - Add the copyright_url variable in the theme (#67) Contributed by jablonskidev @@ -111,8 +191,8 @@ Changelog Contributed by Olga Bulat -`2021.5 `_ ------------------------------------------------------------------------------- +`2021.5 `_ +----------------------------------------------------------------------------- - Make the theme responsive (#46) Contributed by Olga Bulat. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2533e96a..c85b77ca 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -2,7 +2,7 @@ How to release -------------- - Update ``CHANGELOG.rst`` -- Bump version (YYYY.MM) in ``pyproject.toml`` +- Bump version (YYYY.MM) in ``python_docs_theme/__init__.py`` - Commit - Push to check tests pass on `GitHub Actions `__ diff --git a/README.md b/README.md new file mode 100644 index 00000000..fedd7f76 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Python Docs Sphinx Theme + +This is the theme for the Python documentation. +It requires Python 3.12 or newer and Sphinx 7.3 or newer. + +Note that when adopting this theme, you're also borrowing an element of the +trust and credibility established by the CPython core developers over the +years. That's fine, and you're welcome to do so for other Python community +projects if you so choose, but please keep in mind that in doing so you're also +choosing to accept some of the responsibility for maintaining that collective +trust. + +To use the theme, install it into your docs build environment via `pip` +(preferably in a virtual environment). + + +## Configuration options + +To use this theme, add the following to `conf.py`: + +- `html_theme = 'python_docs_theme'` + +- `html_sidebars`, defaults taken from https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_sidebars + +## Preview + +See a demo of the CPython docs using this theme: + +- https://python-docs-theme-previews.readthedocs.io + +The kitchen sink is a showcase of every Sphinx feature: + +- https://sphinx-themes.org/sample-sites/python-docs-theme/kitchen-sink/ diff --git a/README.rst b/README.rst deleted file mode 100644 index 0a8db3fb..00000000 --- a/README.rst +++ /dev/null @@ -1,24 +0,0 @@ -Python Docs Sphinx Theme -========================= - -This is the theme for the Python documentation. - -Note that when adopting this theme, you're also borrowing an element of the -trust and credibility established by the CPython core developers over the -years. That's fine, and you're welcome to do so for other Python community -projects if you so choose, but please keep in mind that in doing so you're also -choosing to accept some of the responsibility for maintaining that collective -trust. - -To use the theme, install it into your docs build environment via ``pip`` -(preferably in a virtual environment). - - -Configuration options ---------------------- - -To use this theme, add the following to ``conf.py``: - -- ``html_theme = 'python_docs_theme'`` - -- ``html_sidebars``, defaults taken from http://www.sphinx-doc.org/en/stable/config.html#confval-html_sidebars diff --git a/babel_runner.py b/babel_runner.py new file mode 100755 index 00000000..0785ae2f --- /dev/null +++ b/babel_runner.py @@ -0,0 +1,128 @@ +#!/usr/bin/venv python3 +"""Script for handling translations with Babel""" +from __future__ import annotations + +import argparse +import ast +import subprocess +import tomllib +from pathlib import Path + +PROJECT_DIR = Path(__file__).resolve().parent +PYPROJECT_TOML = PROJECT_DIR / "pyproject.toml" +INIT_PY = PROJECT_DIR / "python_docs_theme" / "__init__.py" + +# Global variables used by pybabel below (paths relative to PROJECT_DIR) +DOMAIN = "messages" +COPYRIGHT_HOLDER = "Python Software Foundation" +LOCALES_DIR = "locales" +POT_FILE = Path(LOCALES_DIR, f"{DOMAIN}.pot") +SOURCE_DIR = "python_docs_theme" +MAPPING_FILE = ".babel.cfg" + + +def get_project_info() -> dict: + """Retrieve project's info to populate the message catalog template""" + pyproject_text = PYPROJECT_TOML.read_text(encoding="utf-8") + project_data = tomllib.loads(pyproject_text)["project"] + + # read __version__ from __init__.py + for child in ast.parse(INIT_PY.read_bytes()).body: + if not isinstance(child, ast.Assign): + continue + target = child.targets[0] + if not isinstance(target, ast.Name) or target.id != "__version__": + continue + version_node = child.value + if not isinstance(version_node, ast.Constant): + continue + project_data["version"] = version_node.value + break + + return project_data + + +def extract_messages() -> None: + """Extract messages from all source files into message catalog template""" + Path(PROJECT_DIR, LOCALES_DIR).mkdir(parents=True, exist_ok=True) + project_data = get_project_info() + subprocess.run( + [ + "pybabel", + "extract", + "-F", + MAPPING_FILE, + "--copyright-holder", + COPYRIGHT_HOLDER, + "--project", + project_data["name"], + "--version", + project_data["version"], + "--msgid-bugs-address", + project_data["urls"]["Issue tracker"], + "-o", + POT_FILE, + SOURCE_DIR, + ], + cwd=PROJECT_DIR, + check=True, + ) + + +def init_locale(locale: str) -> None: + """Initialize a new locale based on existing message catalog template""" + pofile = PROJECT_DIR / LOCALES_DIR / locale / "LC_MESSAGES" / f"{DOMAIN}.po" + if pofile.exists(): + print(f"There is already a message catalog for locale {locale}, skipping.") + return + cmd = ["pybabel", "init", "-i", POT_FILE, "-d", LOCALES_DIR, "-l", locale] + subprocess.run(cmd, cwd=PROJECT_DIR, check=True) + + +def update_catalogs(locale: str) -> None: + """Update translations from existing message catalogs""" + cmd = ["pybabel", "update", "-i", POT_FILE, "-d", LOCALES_DIR] + if locale: + cmd.extend(["-l", locale]) + subprocess.run(cmd, cwd=PROJECT_DIR, check=True) + + +def compile_catalogs(locale: str) -> None: + """Compile existing message catalogs""" + cmd = ["pybabel", "compile", "-d", LOCALES_DIR] + if locale: + cmd.extend(["-l", locale]) + subprocess.run(cmd, cwd=PROJECT_DIR, check=True) + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "command", + choices=["extract", "init", "update", "compile"], + help="command to be executed", + ) + parser.add_argument( + "-l", + "--locale", + default="", + help="language code (needed for init, optional for update and compile)", + ) + + args = parser.parse_args() + locale = args.locale + + if args.command == "extract": + extract_messages() + elif args.command == "init": + if not locale: + parser.error("init requires passing the --locale option") + init_locale(locale) + elif args.command == "update": + update_catalogs(locale) + elif args.command == "compile": + compile_catalogs(locale) + + +if __name__ == "__main__": + main() diff --git a/code_of_conduct.rst b/code_of_conduct.rst deleted file mode 100644 index 4bc6630f..00000000 --- a/code_of_conduct.rst +++ /dev/null @@ -1,13 +0,0 @@ -Code of Conduct -=============== - -Please note that all interactions on -`Python Software Foundation `__-supported -infrastructure is `covered -`__ -by the `PSF Code of Conduct `__, -which includes all infrastructure used in the development of Python itself -(e.g. mailing lists, issue trackers, GitHub, etc.). - -In general this means everyone is expected to be open, considerate, and -respectful of others no matter what their position is within the project. diff --git a/pyproject.toml b/pyproject.toml index ce22aed0..a614351d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,45 +1,73 @@ [build-system] build-backend = "flit_core.buildapi" requires = [ - "flit_core>=3.7", + "flit-core>=3.7", ] [project] name = "python-docs-theme" -version = "2024.1" description = "The Sphinx theme for the CPython docs and related projects" -readme = "README.rst" -license.file = "LICENSE" -authors = [{name = "PyPA", email = "distutils-sig@python.org"}] -requires-python = ">=3.8" +readme = "README.md" +license = "PSF-2.0" +license-files = [ "LICENSE" ] +authors = [ { name = "PyPA", email = "distutils-sig@python.org" } ] +requires-python = ">=3.12" classifiers = [ "Development Status :: 5 - Production/Stable", "Framework :: Sphinx :: Theme", "Intended Audience :: Developers", - "License :: OSI Approved :: Python Software Foundation License", "Operating System :: OS Independent", "Programming Language :: Python", "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", + "Programming Language :: Python :: 3.14", "Topic :: Documentation", "Topic :: Software Development :: Documentation", ] +dynamic = [ "version" ] + +dependencies = [ + "sphinx>=7.3", +] + urls.Code = "https://github.com/python/python-docs-theme" urls.Download = "https://pypi.org/project/python-docs-theme/" urls.Homepage = "https://github.com/python/python-docs-theme/" urls."Issue tracker" = "https://github.com/python/python-docs-theme/issues" -[project.entry-points."sphinx.html_themes"] -python_docs_theme = 'python_docs_theme' +entry-points."sphinx.html_themes".python_docs_theme = "python_docs_theme" [tool.flit.module] name = "python_docs_theme" [tool.flit.sdist] -include = [ - "python_docs_theme/", +include = [ "python_docs_theme/" ] + +[tool.ruff] +fix = true + +lint.select = [ + "C4", # flake8-comprehensions + "E", # pycodestyle errors + "F", # pyflakes errors + "I", # isort + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "PGH", # pygrep-hooks + "PYI", # flake8-pyi + "RUF022", # unsorted-dunder-all + "RUF100", # unused noqa (yesqa) + "UP", # pyupgrade + "W", # pycodestyle warnings + "YTT", # flake8-2020 +] +lint.ignore = [ + "E203", # Whitespace before ':' + "E221", # Multiple spaces before operator + "E226", # Missing whitespace around arithmetic operator + "E241", # Multiple spaces after ',' ] +lint.isort.required-imports = [ "from __future__ import annotations" ] + +[tool.pyproject-fmt] +max_supported_python = "3.14" diff --git a/python_docs_theme/__init__.py b/python_docs_theme/__init__.py index 77476754..75459e1a 100644 --- a/python_docs_theme/__init__.py +++ b/python_docs_theme/__init__.py @@ -1,64 +1,24 @@ from __future__ import annotations -import hashlib -import os -from functools import lru_cache from pathlib import Path -from typing import Any -import sphinx.application -from sphinx.builders.html import StandaloneHTMLBuilder +TYPE_CHECKING = False +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata -THEME_PATH = Path(__file__).parent.resolve() +__version__ = "2025.4.1" +THEME_PATH = Path(__file__).resolve().parent -@lru_cache(maxsize=None) -def _asset_hash(path: str) -> str: - """Append a `?digest=` to an url based on the file content.""" - full_path = THEME_PATH / path.replace("_static/", "static/") - digest = hashlib.sha1(full_path.read_bytes()).hexdigest() - return f"{path}?digest={digest}" +def setup(app: Sphinx) -> ExtensionMetadata: + app.require_sphinx("7.3") - -def _add_asset_hashes(static: list[str], add_digest_to: list[str]) -> None: - for asset in add_digest_to: - index = static.index(asset) - static[index].filename = _asset_hash(asset) # type: ignore - - -def _html_page_context( - app: sphinx.application.Sphinx, - pagename: str, - templatename: str, - context: dict[str, Any], - doctree: Any, -) -> None: - if app.config.html_theme != "python_docs_theme": - return - - assert isinstance(app.builder, StandaloneHTMLBuilder) - - if (4,) <= sphinx.version_info < (7, 1) and "css_files" in context: - if "_static/pydoctheme.css" not in context["css_files"]: - raise ValueError( - "This documentation is not using `pydoctheme.css` as the stylesheet. " - "If you have set `html_style` in your conf.py file, remove it." - ) - - _add_asset_hashes( - context["css_files"], - ["_static/pydoctheme.css"], - ) - - -def setup(app): - current_dir = os.path.abspath(os.path.dirname(__file__)) - app.add_html_theme("python_docs_theme", current_dir) - - app.connect("html-page-context", _html_page_context) + app.add_html_theme("python_docs_theme", str(THEME_PATH)) return { + "version": __version__, "parallel_read_safe": True, "parallel_write_safe": True, } diff --git a/python_docs_theme/footerdonate.html b/python_docs_theme/footerdonate.html index 2aef2ac2..010014d6 100644 --- a/python_docs_theme/footerdonate.html +++ b/python_docs_theme/footerdonate.html @@ -1,3 +1,3 @@ {% trans %}The Python Software Foundation is a non-profit corporation.{% endtrans %} {% trans %}Please donate.{% endtrans %} -
+
diff --git a/python_docs_theme/layout.html b/python_docs_theme/layout.html index d387ef38..a74517c9 100644 --- a/python_docs_theme/layout.html +++ b/python_docs_theme/layout.html @@ -14,7 +14,7 @@

{{ _('Navigation') }}

{%- endfor %} {%- block rootrellink %} -
  • {{ theme_root_icon_alt_text }}
  • +
  • {{ theme_root_icon_alt_text }}
  • {{theme_root_name}}{{ reldelim1 }}
  • @@ -48,8 +48,8 @@

    {{ _('Navigation') }}

    {%- if builder != "htmlhelp" %} {%- endif %} @@ -71,7 +71,7 @@

    {{ _('Navigation') }}

    {%- block extrahead -%} - + {%- if builder != "htmlhelp" %} {%- if not embedded %} @@ -93,14 +93,14 @@

    {{ _('Navigation') }}

    {%- if builder != 'htmlhelp' %}
    + aria-pressed="false" aria-expanded="false" role="button" aria-label="{{ _('Menu')}}">