From c1b04d66ade94e687a73bcc23c068bda951ed406 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Fri, 30 May 2025 15:09:28 -0400 Subject: [PATCH 1/2] Remove temp fix for Sphinx _static file bug * Remove util/sphinx_static_file_temp_fix and invocation in conf.py * Upgrade to Sphinx 8.2.3 to include fix for temp files * Add mention of requiring Python 3.11 as comments in pyproject.toml * Update Python versions for CI doc build (readthedocs + GitHub) * Explain the contents of the dev deps --- .github/workflows/test.yml | 2 +- .readthedocs.yaml | 2 +- doc/conf.py | 4 - make.py | 15 ++- pyproject.toml | 9 +- util/sphinx_static_file_temp_fix.py | 140 ---------------------------- 6 files changed, 17 insertions(+), 155 deletions(-) delete mode 100644 util/sphinx_static_file_temp_fix.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b89cde3c1..65dc6aa371 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,7 +83,7 @@ jobs: matrix: os: [ubuntu-latest] # python-version in must be kept in sync with .readthedocs.yaml - python-version: ['3.10'] # July 2024 | Match our contributor dev version; see pyproject.toml + python-version: ['3.11'] # July 2024 | Match our contributor dev version; see pyproject.toml architecture: ['x64'] steps: diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 786dca377f..8c3b111a82 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,7 +10,7 @@ build: tools: # If you change this, you also need to update .github/workflows/test.yml # to make sure doc test builds run on the same version. - python: "3.10" # July 2024 | See autobuild info in pyproject.toml's dev dependencies + python: "3.11" # July 2024 | See autobuild info in pyproject.toml's dev dependencies python: install: diff --git a/doc/conf.py b/doc/conf.py index 21558432d2..149f4a9569 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -122,10 +122,6 @@ def run_util(filename, run_name="__main__", init_globals=None): runpy.run_path(full_str, **kwargs) -# Temp fix for Sphinx not copying static files # pending: post-3.0 refactor -# Enable by creating a .ENABLE_DEVMACHINE_SPHINX_STATIC_FIX -run_util("sphinx_static_file_temp_fix.py") - # Make thumbnails for the example code screenshots run_util("generate_example_thumbnails.py") # Create a tabular representation of the resources with embeds diff --git a/make.py b/make.py index 463de5daf0..26402fabde 100755 --- a/make.py +++ b/make.py @@ -17,9 +17,11 @@ from contextlib import contextmanager from pathlib import Path from shutil import rmtree, which -from typing import Union +from typing import Union, Annotated, Optional from collections.abc import Generator +from typer import Option + PathLike = Union[Path, str, bytes] @@ -171,23 +173,26 @@ def clean(): os.remove(item) if os.path.isfile(item) else rmtree(item) +JobsAnnotation = Annotated[Optional[str], Option(help="Specify a number of parallel build tasks (defaults no N_CORES)")] + + @app.command(rich_help_panel="Docs") -def html(): +def html(jobs: JobsAnnotation = "auto"): """ Build the documentation (HTML) """ - run_doc([SPHINX_BUILD, "-b", "html", *ALLSPHINXOPTS, f"{BUILD_DIR}/html"]) + run_doc([SPHINX_BUILD, "--jobs", jobs, "-b", "html", *ALLSPHINXOPTS, f"{BUILD_DIR}/html"]) print() print(f"Build finished. The HTML pages are in {FULL_BUILD_DIR}/html.") @app.command(rich_help_panel="Docs") -def serve(): +def serve(jobs: JobsAnnotation = "auto"): """ Build and serve the docs with automatic rebuilds and live reload. """ run_doc( - [SPHINX_AUTOBUILD, *SPHINXAUTOBUILDOPTS, "-b", "html", *ALLSPHINXOPTS, f"{BUILD_DIR}/html"] + [SPHINX_AUTOBUILD, *SPHINXAUTOBUILDOPTS, "--jobs", jobs, "-b", "html", *ALLSPHINXOPTS, f"{BUILD_DIR}/html"] ) diff --git a/pyproject.toml b/pyproject.toml index b840af03f0..ec7bfb951c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,15 +37,16 @@ Book = "https://learn.arcade.academy" [project.optional-dependencies] # Used for dev work dev = [ - "sphinx==8.1.3", # April 2024 | Updated 2024-07-15, 7.4+ is broken with sphinx-autobuild - "sphinx_rtd_theme==3.0.2", # Nov 2024 + # Python >= 3.11 required for development + "sphinx==8.2.3", # May 2025 | Updated 2025-05-30 + "sphinx_rtd_theme", # Nov 2024 "sphinx-rtd-dark-mode==1.3.0", - "sphinx-autobuild==2024.10.3", # April 2024 | Due to this, Python 3.10+ is required to serve docs + "sphinx-autobuild", # May 2025: Seems to work with latest Sphinx now "sphinx-copybutton==0.5.2", # April 2023 "sphinx-sitemap==2.6.0", # April 2024 "sphinx-togglebutton==0.3.2", # May 2025 "pygments==2.19.1", # 2.18 has breaking changes in lexer - "docutils==0.21.2", # ? + "docutils==0.21.2", # Core sphinx dependency (ReST) # "pyyaml==6.0.1", # "readthedocs-sphinx-search==0.3.2", # "sphinx-autodoc-typehints==2.0.1", diff --git a/util/sphinx_static_file_temp_fix.py b/util/sphinx_static_file_temp_fix.py deleted file mode 100644 index b728b9b485..0000000000 --- a/util/sphinx_static_file_temp_fix.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python3 -""" -Gets 3.0 out the door by temp fixing Sphinx rebuild not copying CSS. - -IMPORTANT: ONLY LOCAL DEVELOPER MACHINES NEED THIS! - -## Who should use this? - -If `./make.py clean` seems like the only way to get `./make.py html` or -`./make.py serve` to serve your modified CSS, then yes, it's for you. - -## How do I use this? - -1. `cd` to the repo root -2. `touch .ENABLE_DEVMACHINE_SPHINX_STATIC_FIX` -3. `./make.py html` with working CSS change updates copying - -## When should I be careful? - -Keep the following in mind: - -1. It is a temp fix which *seems* to work with both: - - * `./make.py html` - * `./make.py serve` - -3. No real config options other on/off via file presence - -## What's Broken in Sphinx? - -1. Sphinx has a long-standing bug which fails to copy static files - https://github.com/sphinx-doc/sphinx/issues/1810 - -2. The fix is slated for 8.2.0 and the fix PR merged on Jan 13, 2025: - https://github.com/sphinx-doc/sphinx/pull/13236 - -3. No, Arcade 3.0 **will not wait** for the following: - - 1. Sphinx 3.2.0 to ship the fix for the problem - 2. Themes to become compatible - 3. Plugins to become compatible - 4. Our customizations to be tested with all of the above - -""" - -import shutil -import sys -import logging -from pathlib import Path - -FILE = Path(__file__) -UTIL_DIR = FILE.parent.resolve() -REPO_ROOT = UTIL_DIR.parent.resolve() - -# Ensure we get utility & Arcade imports first -sys.path.insert(0, str(REPO_ROOT)) - -log = logging.getLogger(str(FILE.relative_to(REPO_ROOT))) - -DOC_DIR = REPO_ROOT / "doc" - -ENABLE_DEVMACHINE_SPHINX_STATIC_FIX = REPO_ROOT / ".ENABLE_DEVMACHINE_SPHINX_STATIC_FIX" - -BUILD_ROOT = REPO_ROOT / "build" -BUILD_HTML_DIR = BUILD_ROOT / "html" - -SOURCE_STATIC_DIR = DOC_DIR / "_static" -BUILD_STATIC_DIR = BUILD_HTML_DIR / "_static" - -BUILD_CSS_DIR = BUILD_STATIC_DIR / "css" -SOURCE_CSS_DIR = SOURCE_STATIC_DIR / "css" - -BUILD_JS_DIR = BUILD_STATIC_DIR / "js" -SOURCE_JS_DIR = SOURCE_STATIC_DIR / "js" - -force_copy_on_change: dict[Path, Path] = { # pending: sphinx >= 8.1.4 - # You can add per-dir config the lazy way: - # 1. copy & paste this block - # 2. modifying it with filtering - **{source_file: BUILD_CSS_DIR / source_file.name for source_file in SOURCE_CSS_DIR.glob("*.*")}, - **{source_file: BUILD_JS_DIR / source_file.name for source_file in SOURCE_JS_DIR.glob("*.*")}, -} - - -# pending: some clever use of util/doc_helpers/vfs.py -def force_sync(src: Path, dest: Path, dry: bool = False) -> None: - """Sync a single file from ``src`` to ``dest``. - - Caveats: - - 1. Assumes both are `pathlib.Path` instances - 2. Assumes both are small - 3. Fails hard when a file isn't found - - """ - - try: - if src.read_text() == dest.read_text(): - log.info(f" SKIP: {src} is current!") - elif dry: - log.info(f" DRY : {src} was out of date, but dry run left it as-is!") - else: - log.info(f" SYNC: {src} was out of date!") - shutil.copyfile(src, dest) - except Exception as e: - log.error(f" FAIL: {src} failed: {e}") - raise e - - -def main(): - skip_reason = None - - if not ENABLE_DEVMACHINE_SPHINX_STATIC_FIX.exists(): - skip_reason = ( - f"SKIP: Force sync not enabled by a {ENABLE_DEVMACHINE_SPHINX_STATIC_FIX} file!" - ) - elif not BUILD_HTML_DIR.exists(): - skip_reason = f"SKIP: {BUILD_HTML_DIR} does not exist yet." - - if skip_reason is not None: - log.info(" " + skip_reason) - else: - # indented so we can grep for Done force-syncing in the logs - from sphinx import __version__ as sphinx_version - - log.info(f" SYNC: Force-sync enable file found and build-dir exists") - if sphinx_version >= "8.1.4": - log.warning( - " Sphinx >= 8.1.4 may patch broken _static copy\n" - " (see https://github.com/sphinx-doc/sphinx/issues/1810)" - ) - - for src, dest in force_copy_on_change.items(): - force_sync(src, dest) - - log.info(" Done force-syncing.") - - -if __name__ == "__main__": - main() From a3990cbddc4779dccffba31a1460e76c6711d130 Mon Sep 17 00:00:00 2001 From: pushfoo <36696816+pushfoo@users.noreply.github.com> Date: Fri, 30 May 2025 16:13:09 -0400 Subject: [PATCH 2/2] Format make.py with ruff --- make.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/make.py b/make.py index 26402fabde..9d0d7e6d69 100755 --- a/make.py +++ b/make.py @@ -173,7 +173,9 @@ def clean(): os.remove(item) if os.path.isfile(item) else rmtree(item) -JobsAnnotation = Annotated[Optional[str], Option(help="Specify a number of parallel build tasks (defaults no N_CORES)")] +JobsAnnotation = Annotated[ + Optional[str], Option(help="Specify a number of parallel build tasks (defaults no N_CORES)") +] @app.command(rich_help_panel="Docs") @@ -192,7 +194,16 @@ def serve(jobs: JobsAnnotation = "auto"): Build and serve the docs with automatic rebuilds and live reload. """ run_doc( - [SPHINX_AUTOBUILD, *SPHINXAUTOBUILDOPTS, "--jobs", jobs, "-b", "html", *ALLSPHINXOPTS, f"{BUILD_DIR}/html"] + [ + SPHINX_AUTOBUILD, + *SPHINXAUTOBUILDOPTS, + "--jobs", + jobs, + "-b", + "html", + *ALLSPHINXOPTS, + f"{BUILD_DIR}/html", + ] )