From 810a5cf461bb9c966a1133a08e861c88041cd399 Mon Sep 17 00:00:00 2001 From: Paul V Craven Date: Fri, 9 Oct 2026 11:06:56 -0500 Subject: [PATCH] Fail the docs build on quick index config problems update_quick_index.py printed its warnings, so Sphinx never saw them and the build passed. It now collects them and raises at the end, which stops the build. Removes the seven config entries that produced the "No members parsed" warnings: re-export-only __init__ files, __main__, and arcade.types.numbers. AsFloat, the only thing in numbers.py, is now listed by name with a new "data" option and has a real description. Co-Authored-By: Claude Opus 5.5 --- arcade/types/numbers.py | 4 +-- util/update_quick_index.py | 54 +++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/arcade/types/numbers.py b/arcade/types/numbers.py index 318cab7b31..9b0982e670 100644 --- a/arcade/types/numbers.py +++ b/arcade/types/numbers.py @@ -5,8 +5,8 @@ circular imports or partially initialized modules. """ -#: 1. Makes pyright happier while also telling readers -#: 2. Tells readers we're converting any ints to floats +#: A float or an int. Arcade accepts either where it uses this type, +#: and works with the value as a float. AsFloat = float | int __all__ = ["AsFloat"] diff --git a/util/update_quick_index.py b/util/update_quick_index.py index da54efd882..d42eb18fb4 100644 --- a/util/update_quick_index.py +++ b/util/update_quick_index.py @@ -40,6 +40,16 @@ QUICK_INDEX_FILE_PATH = SharedPaths.API_DOC_ROOT / "quick_index.rst" IMPORT_TREE = build_import_tree(ARCADE_ROOT) +# Problems found while generating the pages. Any of them fails the docs +# build, so stale config can't go unnoticed. +ERRORS: list[str] = [] + + +def error(message: str) -> None: + print(f"ERROR: {message}") + ERRORS.append(message) + + # --- 1. Special rules & excludes --- RULE_SHOW_INHERITANCE = (":show-inheritance:",) @@ -64,12 +74,13 @@ "title": "Types", "use_declarations_in": [ "arcade.types", - "arcade.types.numbers", "arcade.types.vector_like", "arcade.types.color", "arcade.types.rect", "arcade.types.box", ], + # Type aliases, which the parser below can't find + "data": ["arcade.types.numbers.AsFloat"], }, "resources.rst": { "title": "Resources", @@ -105,7 +116,6 @@ "sprite_list.rst": { "title": "Sprite Lists", "use_declarations_in": [ - "arcade.sprite_list", "arcade.sprite_list.sprite_list", "arcade.sprite_list.spatial_hash", "arcade.sprite_list.collision", @@ -124,7 +134,6 @@ "texture.rst": { "title": "Texture Management", "use_declarations_in": [ - "arcade.texture", "arcade.texture.texture", "arcade.texture.loading", "arcade.texture.generate", @@ -150,7 +159,6 @@ "texture_atlas.rst": { "title": "Texture Atlas", "use_declarations_in": [ - "arcade.texture_atlas", "arcade.texture_atlas.base", "arcade.texture_atlas.atlas_default", "arcade.texture_atlas.region", @@ -187,10 +195,10 @@ "title": "Isometric Map (incomplete)", "use_declarations_in": ["arcade.isometric"], }, - "anim.rst": {"title": "Easing", "use_declarations_in": ["arcade.anim", "arcade.anim.easing"]}, + "anim.rst": {"title": "Easing", "use_declarations_in": ["arcade.anim.easing"]}, "utility.rst": { "title": "Misc Utility Functions", - "use_declarations_in": ["arcade", "arcade.__main__", "arcade.utils"], + "use_declarations_in": ["arcade", "arcade.utils"], }, "drawing_batch.rst": {"title": "Shape Lists", "use_declarations_in": ["arcade.shape_list"]}, "open_gl.rst": {"title": "OpenGL Context", "use_declarations_in": ["arcade.context"]}, @@ -199,7 +207,6 @@ "gui.rst": { "title": "GUI", "use_declarations_in": [ - "arcade.gui", "arcade.gui.constructs", "arcade.gui.mixins", "arcade.gui.surface", @@ -346,10 +353,10 @@ def get_file_declarations( parsed_values["*"].extend(parsed_raw) except Exception as e: - print(f"Exception processing {filename} on line {line_no}: {e}") + error(f"Exception processing {filename} on line {line_no}: {e}") break except Exception as e: - print(f"Failed to open {filepath}: {e}") + error(f"Failed to open {filepath}: {e}") return parsed_values @@ -372,7 +379,7 @@ def generate_api_file(api_file_name: str, vfs: Vfs): page_config = API_FILE_TO_TITLE_AND_MODULES.get(api_file_name, None) if not page_config: - print(f"ERROR: No config defined for API file {api_file_name!r}") + error(f"No config defined for API file {api_file_name!r}") return try: @@ -382,7 +389,7 @@ def generate_api_file(api_file_name: str, vfs: Vfs): # print(f"API filename {api_file_name} gets {title=} with {use_declarations_in=}") except Exception as e: - print(f"ERROR: Unintelligible config data for {api_file_name!r}: {e}") + error(f"Unintelligible config data for {api_file_name!r}: {e}") return # Open in "a" mode to append @@ -421,9 +428,8 @@ def generate_api_file(api_file_name: str, vfs: Vfs): for module_name in use_declarations_in: # Did we ever have tests in the path name? What? if "test" in module_name: - print( - f"WARNING: {module_name!r} appears to contain tests." - f"Those belong in the 'tests/' directory!" + error( + f"{module_name!r} appears to contain tests. Those belong in the 'tests/' directory!" ) continue @@ -433,10 +439,10 @@ def generate_api_file(api_file_name: str, vfs: Vfs): # Skip a file if we got no imports if not len(member_lists["*"]): - print( - f"WARNING: No members parsed for {module_name!r} with" - f" inferred path {module_path!r}. Check & update your" - f"config?" + error( + f"No members parsed for {module_name!r} with inferred path" + f" {module_path!r}. Remove it from API_FILE_TO_TITLE_AND_MODULES" + f" if it only re-exports names." ) continue @@ -486,6 +492,13 @@ def iter_declarations(kind: str) -> Generator[tuple[str, str], None, None]: api_file.close() + # Data such as type aliases, listed by name in the config + for full_name in page_config.get("data", EMPTY_TUPLE): + quick_index_file.write(f" * - :py:data:`{full_name}`\n") + quick_index_file.write(f" - {title}\n") + + api_file.write(f".. autodata:: {full_name}\n\n") + def main(): vfs = Vfs() @@ -520,6 +533,11 @@ def main(): vfs.write() + if ERRORS: + raise RuntimeError( + f"update_quick_index.py found {len(ERRORS)} problem(s):\n " + "\n ".join(ERRORS) + ) + print("Done creating quick_index.rst")