From d00c4786363be18b68f4d544a4391397c21673b5 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 05:21:43 -0400
Subject: [PATCH 01/14] Centralize resource embed URLs from conf.py
* Run create_resources_listing.py via main() instead of as __main__
* Move git ref and version read earlier in conf.py
* Template in globals via init_globals instead of complicated passing
* Encapsulate runpath.run_py call with default args
---
doc/conf.py | 50 +++++++++++++++++++++++---------
util/create_resources_listing.py | 34 +++++++++++++++++++++-
2 files changed, 70 insertions(+), 14 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index bea226a48..59acf3dc7 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,6 +1,8 @@
#!/usr/bin/env python
"""Sphinx configuration file"""
+from __future__ import annotations
from functools import cache
+from pathlib import Path
from textwrap import dedent
from typing import Any, NamedTuple
import docutils.nodes
@@ -20,12 +22,44 @@
# --- Pre-processing Tasks
+# These need to be earlier to get the right git ref
+sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath('../arcade'))
+
+# Don't change to
+# from arcade.version import VERSION
+# or read the docs build will fail.
+from version import VERSION # pyright: ignore [reportMissingImports]
+
+RELEASE = VERSION
+REPO_URL_BASE="https://github.com/pythonarcade/arcade"
+if 'dev' in RELEASE:
+ GIT_REF = 'development'
+else:
+ GIT_REF = RELEASE
+
+# We'll pass this to our generation scripts to initialize their globals
+RUNPY_INIT_GLOBALS = dict(
+ GIT_REF=GIT_REF,
+ BASE_URL_REPO=REPO_URL_BASE,
+ # This double-bracket escapes brackets in f-strings
+ FMT_URL_REF_PAGE=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}",
+ FMT_URL_REF_EMBED=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true",
+)
+
+
+def run_with_globals(path: str | Path, run_name="__main__", init_globals=RUNPY_INIT_GLOBALS):
+ """Centralize our script runs and globals."""
+ runpy.run_path(path, init_globals=init_globals, run_name=run_name)
+
+
# Make thumbnails for the example code screenshots
-runpy.run_path('../util/generate_example_thumbnails.py', run_name='__main__')
+run_with_globals('../util/generate_example_thumbnails.py', run_name="main")
# Create a listing of the resources
-runpy.run_path('../util/create_resources_listing.py', run_name='__main__')
+run_with_globals('../util/create_resources_listing.py')
# Run the generate quick API index script
-runpy.run_path('../util/update_quick_index.py', run_name='__main__')
+run_with_globals('../util/update_quick_index.py')
+
autodoc_inherit_docstrings = False
autodoc_default_options = {
@@ -39,16 +73,6 @@
# Special methods in api docs gets a special prefix emoji
prettyspecialmethods_signature_prefix = '🧙'
-sys.path.insert(0, os.path.abspath('..'))
-sys.path.insert(0, os.path.abspath('../arcade'))
-
-# Don't change to
-# from arcade.version import VERSION
-# or read the docs build will fail.
-from version import VERSION # pyright: ignore [reportMissingImports]
-
-RELEASE = VERSION
-
# -- General configuration ------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index 274aecd80..c0cc839b2 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -6,6 +6,9 @@
import sys
from pathlib import Path
from typing import List
+import logging
+
+log = logging.getLogger(__name__)
# Ensure we get utility and Arcade imports first
sys.path.insert(0, str(Path(__file__).parent.resolve()))
@@ -14,11 +17,39 @@
import arcade
from doc_helpers.vfs import Vfs
+if __name__ == "__main__":
+ log.warning("Running directly instead of via conf.py! May template globals!")
+
+ def announce_templating(var_name):
+ _v = globals()[var_name]
+ log.warning(f"Templated {var_name} as {_v!r}")
+
+ # The following are provided via runpy.run_path's init_globals keyword
+ # in conf.py. Uncomment for easy debugger run without IDE config.
+ _URL_BASE = "https://github.com/pythonarcade/arcade"
+ try:
+ _ = GIT_REF # noqa
+ except Exception as _:
+ GIT_REF = "development"
+ announce_templating("GIT_REF")
+ try:
+ _ = FMT_URL_REF_PAGE # noqa
+ except Exception as _:
+ FMT_URL_REF_PAGE = f"{_URL_BASE}/blob/{GIT_REF}/{{}}"
+ announce_templating("FMT_URL_REF_PAGE")
+ try:
+ _ = FMT_URL_REF_EMBED # noqa
+ except Exception as _:
+ FMT_URL_REF_EMBED = f"{_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true"
+ announce_templating("FMT_URL_REF_EMBED")
+
+
MODULE_DIR = Path(__file__).parent.resolve()
ARCADE_ROOT = MODULE_DIR.parent
RESOURCE_DIR = ARCADE_ROOT / "arcade" / "resources"
OUT_FILE = ARCADE_ROOT / "doc" / "api_docs" / "resources.rst"
-RESOURCE_URL = "https://github.com/pythonarcade/arcade/blob/development/{}?raw=true"
+RESOURCE_URL = FMT_URL_REF_EMBED # noqa # It exists, see above.
+
COLUMNS = 3
# Metadata for the resource list: utils\create_resource_list.py
@@ -34,6 +65,7 @@
".pyc",
]
+
def skipped_file(file_path: Path):
"""Return True if file should be skipped."""
return file_path.suffix in skip_extensions
From 9acca43c0b9eb1ab8756eeb3f01ac6ebb94d937c Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 06:19:06 -0400
Subject: [PATCH 02/14] Further cleanup of resource gen
* Remove redundant variable
* Stop doing repeated . access on path.suffix
* Compact the audio file embeds to use a dict
* Remove cruft from GLSL (it's not an audio file)
---
util/create_resources_listing.py | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index c0cc839b2..b29d349fe 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -48,7 +48,6 @@ def announce_templating(var_name):
ARCADE_ROOT = MODULE_DIR.parent
RESOURCE_DIR = ARCADE_ROOT / "arcade" / "resources"
OUT_FILE = ARCADE_ROOT / "doc" / "api_docs" / "resources.rst"
-RESOURCE_URL = FMT_URL_REF_EMBED # noqa # It exists, see above.
COLUMNS = 3
@@ -123,6 +122,11 @@ def process_resource_directory(out, dir: Path):
process_resource_directory(out, path)
+SUFFIX_TO_AUDIO_TYPE = {
+ '.wav': 'x-wav',
+ '.ogg': 'ogg',
+ '.mp3': 'mpeg',
+}
def process_resource_files(out, file_list: List[Path]):
start_row = True
@@ -130,33 +134,22 @@ def process_resource_files(out, file_list: List[Path]):
for path in file_list:
resource_path = path.relative_to(ARCADE_ROOT).as_posix()
-
+ suffix = path.suffix
if cell_count % COLUMNS == 0:
start_row = "*"
- if path.suffix in [".png", ".jpg", ".gif", ".svg"]:
+ if suffix in [".png", ".jpg", ".gif", ".svg"]:
out.write(f" {start_row} - .. image:: ../../{resource_path}\n\n")
out.write(f" {path.name}\n")
cell_count += 1
- elif path.suffix == ".wav":
- file_path = RESOURCE_URL.format(resource_path)
- out.write(f" {start_row} - .. raw:: html\n\n")
- out.write(f"
{path.name}\n")
- cell_count += 1
- elif path.suffix == ".mp3":
- file_path = RESOURCE_URL.format(resource_path)
- out.write(f" {start_row} - .. raw:: html\n\n")
- out.write(f"
{path.name}\n")
- cell_count += 1
- elif path.suffix == ".ogg":
- file_path = RESOURCE_URL.format(resource_path)
+ elif suffix in SUFFIX_TO_AUDIO_TYPE:
+ file_path = FMT_URL_REF_EMBED.format(resource_path)
+ src_type=SUFFIX_TO_AUDIO_TYPE[suffix]
out.write(f" {start_row} - .. raw:: html\n\n")
- out.write(f"
{path.name}\n")
+ out.write(f"
{path.name}\n")
cell_count += 1
elif path.suffix == ".glsl":
- file_path = RESOURCE_URL.format(resource_path)
+ file_path = FMT_URL_REF_PAGE.format(resource_path)
out.write(f" {start_row} - `{path.name} <{file_path}>`_\n")
- # out.write(f" {start_row} - .. raw:: html\n\n")
- # out.write(f"
{path.name}\n")
cell_count += 1
else:
out.write(f" {start_row} - {path.name}\n")
From c86aba79437279dce0fdbbbc6418bcb6ba5c758f Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 07:21:02 -0400
Subject: [PATCH 03/14] Fix column widths, embeds, and many links
* For n < 3 files, reduce the number of columns
* Actually use video embeds
* Link GitHub pages for Tiled map .json
---
util/create_resources_listing.py | 72 +++++++++++++++++++++++++-------
1 file changed, 57 insertions(+), 15 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index b29d349fe..059ee7761 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -3,7 +3,10 @@
Generate quick API indexes in Restructured Text Format for Sphinx documentation.
"""
+import math
import sys
+from collections import defaultdict
+from functools import lru_cache
from pathlib import Path
from typing import List
import logging
@@ -50,7 +53,6 @@ def announce_templating(var_name):
OUT_FILE = ARCADE_ROOT / "doc" / "api_docs" / "resources.rst"
-COLUMNS = 3
# Metadata for the resource list: utils\create_resource_list.py
skip_extensions = [
".glsl",
@@ -70,6 +72,7 @@ def skipped_file(file_path: Path):
return file_path.suffix in skip_extensions
+@lru_cache(maxsize=None) # Cache b/c re-using elsewhere
def create_resource_path(
path: Path,
prefix: str = "",
@@ -91,6 +94,20 @@ def create_resource_path(
return f"{prefix}:resources:{path.as_posix()}{suffix}"
+TABLE_COLS: dict[str, int] = defaultdict(lambda: 3)
+TABLE_COLS[':resources:video/'] = 1
+
+
+@lru_cache(maxsize=None)
+def get_header_num_cols(resource_stub: str, n_files = math.inf) -> int:
+ return int(min(TABLE_COLS[resource_stub], n_files))
+
+
+@lru_cache(maxsize=None)
+def get_column_widths_for_n(n: int) -> str:
+ width = str(100 // n)
+ return ' '.join((width for _ in range(n)))
+
def process_resource_directory(out, dir: Path):
"""
Go through resources in a directory.
@@ -102,7 +119,9 @@ def process_resource_directory(out, dir: Path):
# out.write("-" * len(cur_node.name) + "\n\n")
file_list = [item for item in path.iterdir() if not (item.is_dir() or skipped_file(item))]
- if len(file_list) > 0:
+ num_files = len(file_list)
+ if num_files > 0:
+
# header_title = f":resources:{path.relative_to(RESOURCE_DIR).as_posix()}/"
header_title = create_resource_path(path, suffix="/")
if header_title == ":resources:images/":
@@ -110,10 +129,11 @@ def process_resource_directory(out, dir: Path):
print(f.name)
# out.write(f"\n{header_title}\n")
# out.write("-" * (len(header_title)) + "\n\n")
-
+ n_cols = get_header_num_cols(header_title, num_files)
+ widths = get_column_widths_for_n(n_cols)
out.write(f"\n")
out.write(f".. list-table:: {header_title}\n")
- out.write(f" :widths: 33 33 33\n")
+ out.write(f" :widths: {widths}\n")
out.write(f" :header-rows: 0\n")
out.write(f" :class: resource-table\n\n")
@@ -122,40 +142,62 @@ def process_resource_directory(out, dir: Path):
process_resource_directory(out, path)
+
SUFFIX_TO_AUDIO_TYPE = {
'.wav': 'x-wav',
'.ogg': 'ogg',
'.mp3': 'mpeg',
}
+SUFFIX_TO_VIDEO_TYPE = {
+ '.mp4': 'mp4',
+ '.webm': 'webm',
+ '.avi': 'avi'
+}
def process_resource_files(out, file_list: List[Path]):
- start_row = True
+ start_row = "*"
cell_count = 0
+ prefix = create_resource_path(file_list[0].parent)
+ COLUMNS = get_header_num_cols(prefix, len(file_list))
+
for path in file_list:
resource_path = path.relative_to(ARCADE_ROOT).as_posix()
suffix = path.suffix
+
if cell_count % COLUMNS == 0:
start_row = "*"
+ else:
+ start_row = " "
+ name = path.name
+ resource_copyable = f"{create_resource_path(path)}"
if suffix in [".png", ".jpg", ".gif", ".svg"]:
out.write(f" {start_row} - .. image:: ../../{resource_path}\n\n")
- out.write(f" {path.name}\n")
- cell_count += 1
+ out.write(f" {name}\n")
elif suffix in SUFFIX_TO_AUDIO_TYPE:
file_path = FMT_URL_REF_EMBED.format(resource_path)
src_type=SUFFIX_TO_AUDIO_TYPE[suffix]
out.write(f" {start_row} - .. raw:: html\n\n")
- out.write(f"
{path.name}\n")
- cell_count += 1
- elif path.suffix == ".glsl":
+ out.write(f" \n")
+ out.write(f"
{resource_copyable}
\n")
+ # out.write(f"
{path.name} on GitHub\n")
+ elif suffix in SUFFIX_TO_VIDEO_TYPE:
+ file_path = FMT_URL_REF_EMBED.format(resource_path)
+ src_type = SUFFIX_TO_VIDEO_TYPE[suffix]
+ out.write(f" {start_row} - .. raw:: html\n\n")
+ out.write(f" \n")
+ out.write(f"
{resource_copyable}
\n")
+ elif suffix == ".glsl":
file_path = FMT_URL_REF_PAGE.format(resource_path)
- out.write(f" {start_row} - `{path.name} <{file_path}>`_\n")
- cell_count += 1
+ out.write(f" {start_row} - `{path} <{file_path}>`_\n")
+ elif suffix == ".json":
+ file_path = FMT_URL_REF_PAGE.format(resource_path)
+ out.write(f" {start_row} - `{name} <{file_path}>`_\n")
else:
- out.write(f" {start_row} - {path.name}\n")
- cell_count += 1
+ out.write(f" {start_row} - {name}\n")
+ # out.write(f"
{resource_copyable}
\n")
+ cell_count += 1
- start_row = " "
while cell_count % COLUMNS > 0:
out.write(f" -\n")
From 882a747b90338e91fd875f7f386bcc8566edd351 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 07:25:49 -0400
Subject: [PATCH 04/14] Cleanup before PR
* Add comments
* Remove unused vars
* Move config closer to top
---
util/create_resources_listing.py | 34 ++++++++++++++++----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index 059ee7761..b5aca255f 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -66,12 +66,25 @@ def announce_templating(var_name):
".pyc",
]
-
def skipped_file(file_path: Path):
"""Return True if file should be skipped."""
return file_path.suffix in skip_extensions
+TABLE_COLS: dict[str, int] = defaultdict(lambda: 3)
+TABLE_COLS[':resources:video/'] = 1
+
+@lru_cache(maxsize=None)
+def get_header_num_cols(resource_stub: str, n_files = math.inf) -> int:
+ return int(min(TABLE_COLS[resource_stub], n_files))
+
+
+@lru_cache(maxsize=None)
+def get_column_widths_for_n(n: int) -> str:
+ width = str(100 // n)
+ return ' '.join((width for _ in range(n)))
+
+
@lru_cache(maxsize=None) # Cache b/c re-using elsewhere
def create_resource_path(
path: Path,
@@ -94,20 +107,6 @@ def create_resource_path(
return f"{prefix}:resources:{path.as_posix()}{suffix}"
-TABLE_COLS: dict[str, int] = defaultdict(lambda: 3)
-TABLE_COLS[':resources:video/'] = 1
-
-
-@lru_cache(maxsize=None)
-def get_header_num_cols(resource_stub: str, n_files = math.inf) -> int:
- return int(min(TABLE_COLS[resource_stub], n_files))
-
-
-@lru_cache(maxsize=None)
-def get_column_widths_for_n(n: int) -> str:
- width = str(100 // n)
- return ' '.join((width for _ in range(n)))
-
def process_resource_directory(out, dir: Path):
"""
Go through resources in a directory.
@@ -155,7 +154,6 @@ def process_resource_directory(out, dir: Path):
}
def process_resource_files(out, file_list: List[Path]):
- start_row = "*"
cell_count = 0
prefix = create_resource_path(file_list[0].parent)
@@ -190,15 +188,17 @@ def process_resource_files(out, file_list: List[Path]):
elif suffix == ".glsl":
file_path = FMT_URL_REF_PAGE.format(resource_path)
out.write(f" {start_row} - `{path} <{file_path}>`_\n")
+ # Link Tiled maps
elif suffix == ".json":
file_path = FMT_URL_REF_PAGE.format(resource_path)
out.write(f" {start_row} - `{name} <{file_path}>`_\n")
else:
out.write(f" {start_row} - {name}\n")
+ # The below doesn't work because of how raw HTML / Sphinx images interact:
# out.write(f"
{resource_copyable}
\n")
cell_count += 1
-
+ # Finish any remaining columns with empty cells
while cell_count % COLUMNS > 0:
out.write(f" -\n")
cell_count += 1
From f65baa7b409da3dd42e29793e22ec894d8c6c4af Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 07:33:46 -0400
Subject: [PATCH 05/14] Add quotes to copyable literals
---
util/create_resources_listing.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index b5aca255f..eef1dcf31 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -177,14 +177,14 @@ def process_resource_files(out, file_list: List[Path]):
src_type=SUFFIX_TO_AUDIO_TYPE[suffix]
out.write(f" {start_row} - .. raw:: html\n\n")
out.write(f" \n")
- out.write(f"
{resource_copyable}
\n")
+ out.write(f"
"{resource_copyable}"
\n")
# out.write(f"
{path.name} on GitHub\n")
elif suffix in SUFFIX_TO_VIDEO_TYPE:
file_path = FMT_URL_REF_EMBED.format(resource_path)
src_type = SUFFIX_TO_VIDEO_TYPE[suffix]
out.write(f" {start_row} - .. raw:: html\n\n")
out.write(f" \n")
- out.write(f"
{resource_copyable}
\n")
+ out.write(f"
"{resource_copyable}"
\n")
elif suffix == ".glsl":
file_path = FMT_URL_REF_PAGE.format(resource_path)
out.write(f" {start_row} - `{path} <{file_path}>`_\n")
From d59c43060ed089fb15796599bddb6a6fd073a62c Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 08:00:47 -0400
Subject: [PATCH 06/14] Fix thumbnail creation and resource listing invocations
---
doc/conf.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index 59acf3dc7..3a8838bac 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -54,9 +54,9 @@ def run_with_globals(path: str | Path, run_name="__main__", init_globals=RUNPY_I
# Make thumbnails for the example code screenshots
-run_with_globals('../util/generate_example_thumbnails.py', run_name="main")
+run_with_globals('../util/generate_example_thumbnails.py')
# Create a listing of the resources
-run_with_globals('../util/create_resources_listing.py')
+run_with_globals('../util/create_resources_listing.py', run_name="main")
# Run the generate quick API index script
run_with_globals('../util/update_quick_index.py')
From 4f8777950d5fc6f3e2aae56687cdfd4275970b50 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 08:16:34 -0400
Subject: [PATCH 07/14] Attempt to revert the runpy changes?
---
doc/conf.py | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index 3a8838bac..cdbc41189 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -47,18 +47,12 @@
FMT_URL_REF_EMBED=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true",
)
-
-def run_with_globals(path: str | Path, run_name="__main__", init_globals=RUNPY_INIT_GLOBALS):
- """Centralize our script runs and globals."""
- runpy.run_path(path, init_globals=init_globals, run_name=run_name)
-
-
# Make thumbnails for the example code screenshots
-run_with_globals('../util/generate_example_thumbnails.py')
+runpy.run_path('../util/generate_example_thumbnails.py', run_name='__main__')
# Create a listing of the resources
-run_with_globals('../util/create_resources_listing.py', run_name="main")
+runpy.run_path('../util/create_resources_listing.py', run_name="main", init_globals=RUNPY_INIT_GLOBALS)
# Run the generate quick API index script
-run_with_globals('../util/update_quick_index.py')
+runpy.run_path('../util/update_quick_index.py', run_name='__main__')
autodoc_inherit_docstrings = False
From 0e407eeb057d0c826cb7c55f3838c712da1921e9 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 08:53:48 -0400
Subject: [PATCH 08/14] Remove over-clever run tricks
---
doc/conf.py | 31 ++++++++++++---------
util/create_resources_listing.py | 46 ++++++++++++++++----------------
2 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index cdbc41189..aecb04fce 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -22,24 +22,20 @@
# --- Pre-processing Tasks
-# These need to be earlier to get the right git ref
-sys.path.insert(0, os.path.abspath('..'))
-sys.path.insert(0, os.path.abspath('../arcade'))
+HERE = Path(__file__).resolve()
+REPO_LOCAL_ROOT = HERE.parent.parent
+
+_temp_version = (REPO_LOCAL_ROOT / "arcade" / "VERSION").read_text().replace("-",'')
-# Don't change to
-# from arcade.version import VERSION
-# or read the docs build will fail.
-from version import VERSION # pyright: ignore [reportMissingImports]
-RELEASE = VERSION
REPO_URL_BASE="https://github.com/pythonarcade/arcade"
-if 'dev' in RELEASE:
+if 'dev' in _temp_version:
GIT_REF = 'development'
else:
- GIT_REF = RELEASE
+ GIT_REF = _temp_version
# We'll pass this to our generation scripts to initialize their globals
-RUNPY_INIT_GLOBALS = dict(
+RESOURCE_GLOBALS = dict(
GIT_REF=GIT_REF,
BASE_URL_REPO=REPO_URL_BASE,
# This double-bracket escapes brackets in f-strings
@@ -47,10 +43,11 @@
FMT_URL_REF_EMBED=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true",
)
+
# Make thumbnails for the example code screenshots
runpy.run_path('../util/generate_example_thumbnails.py', run_name='__main__')
# Create a listing of the resources
-runpy.run_path('../util/create_resources_listing.py', run_name="main", init_globals=RUNPY_INIT_GLOBALS)
+runpy.run_path('../util/create_resources_listing.py', run_name="__main__", init_globals=RESOURCE_GLOBALS)
# Run the generate quick API index script
runpy.run_path('../util/update_quick_index.py', run_name='__main__')
@@ -67,6 +64,16 @@
# Special methods in api docs gets a special prefix emoji
prettyspecialmethods_signature_prefix = '🧙'
+sys.path.insert(0, os.path.abspath('..'))
+sys.path.insert(0, os.path.abspath('../arcade'))
+
+# Don't change to
+# from arcade.version import VERSION
+# or read the docs build will fail.
+from version import VERSION # pyright: ignore [reportMissingImports]
+
+
+RELEASE = VERSION
# -- General configuration ------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index eef1dcf31..897beb692 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -20,31 +20,29 @@
import arcade
from doc_helpers.vfs import Vfs
-if __name__ == "__main__":
- log.warning("Running directly instead of via conf.py! May template globals!")
- def announce_templating(var_name):
- _v = globals()[var_name]
- log.warning(f"Templated {var_name} as {_v!r}")
-
- # The following are provided via runpy.run_path's init_globals keyword
- # in conf.py. Uncomment for easy debugger run without IDE config.
+def announce_templating(var_name):
+ _v = globals()[var_name]
+ log.warning(f"Templated {var_name} as {_v!r}")
+
+# The following are provided via runpy.run_path's init_globals keyword
+# in conf.py. Uncomment for easy debugger run without IDE config.
+try:
+ _ = GIT_REF # noqa
+except Exception as _:
+ GIT_REF = "development"
+ announce_templating("GIT_REF")
+try:
_URL_BASE = "https://github.com/pythonarcade/arcade"
- try:
- _ = GIT_REF # noqa
- except Exception as _:
- GIT_REF = "development"
- announce_templating("GIT_REF")
- try:
- _ = FMT_URL_REF_PAGE # noqa
- except Exception as _:
- FMT_URL_REF_PAGE = f"{_URL_BASE}/blob/{GIT_REF}/{{}}"
- announce_templating("FMT_URL_REF_PAGE")
- try:
- _ = FMT_URL_REF_EMBED # noqa
- except Exception as _:
- FMT_URL_REF_EMBED = f"{_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true"
- announce_templating("FMT_URL_REF_EMBED")
+ _ = FMT_URL_REF_PAGE # noqa
+except Exception as _:
+ FMT_URL_REF_PAGE = f"{_URL_BASE}/blob/{GIT_REF}/{{}}"
+ announce_templating("FMT_URL_REF_PAGE")
+try:
+ _ = FMT_URL_REF_EMBED # noqa
+except Exception as _:
+ FMT_URL_REF_EMBED = f"{_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true"
+ announce_templating("FMT_URL_REF_EMBED")
MODULE_DIR = Path(__file__).parent.resolve()
@@ -228,8 +226,10 @@ def resources():
out.close()
print("Done creating resources.rst")
+
vfs = Vfs()
+
def main():
resources()
vfs.write()
From ba669bc7577b3099086dd9c54499f98ca649c999 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:10:42 -0400
Subject: [PATCH 09/14] Stop messing with relative paths in conf.py
* Set top-level pathlib.Path-based constants
* Use absolute paths as the base for the util runs
* Add a DRY helper
---
doc/conf.py | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index aecb04fce..a257a66e5 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -24,15 +24,25 @@
HERE = Path(__file__).resolve()
REPO_LOCAL_ROOT = HERE.parent.parent
+UTIL_DIR = REPO_LOCAL_ROOT / "util"
-_temp_version = (REPO_LOCAL_ROOT / "arcade" / "VERSION").read_text().replace("-",'')
+# _temp_version = (REPO_LOCAL_ROOT / "arcade" / "VERSION").read_text().replace("-",'')
+
+sys.path.insert(0, str(REPO_LOCAL_ROOT))
+sys.path.insert(0, str(REPO_LOCAL_ROOT / "arcade"))
+
+# Don't change to
+# from arcade.version import VERSION
+# or read the docs build will fail.
+from version import VERSION # pyright: ignore [reportMissingImports]
REPO_URL_BASE="https://github.com/pythonarcade/arcade"
-if 'dev' in _temp_version:
+if 'dev' in VERSION:
GIT_REF = 'development'
else:
- GIT_REF = _temp_version
+ GIT_REF = VERSION
+
# We'll pass this to our generation scripts to initialize their globals
RESOURCE_GLOBALS = dict(
@@ -43,13 +53,19 @@
FMT_URL_REF_EMBED=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true",
)
+def run_util(filename, init_globals=None):
+
+ kwargs = dict(run_name="__main__")
+ if init_globals is not None:
+ kwargs['init_globals'] = init_globals
+ runpy.run_path(str(UTIL_DIR / filename), **kwargs)
# Make thumbnails for the example code screenshots
-runpy.run_path('../util/generate_example_thumbnails.py', run_name='__main__')
-# Create a listing of the resources
-runpy.run_path('../util/create_resources_listing.py', run_name="__main__", init_globals=RESOURCE_GLOBALS)
+run_util("generate_example_thumbnails.py")
+# Create a tabular representation of the resources with embeds
+run_util("create_resources_listing.py", init_globals=RESOURCE_GLOBALS)
# Run the generate quick API index script
-runpy.run_path('../util/update_quick_index.py', run_name='__main__')
+run_util('../util/update_quick_index.py')
autodoc_inherit_docstrings = False
@@ -64,14 +80,6 @@
# Special methods in api docs gets a special prefix emoji
prettyspecialmethods_signature_prefix = '🧙'
-sys.path.insert(0, os.path.abspath('..'))
-sys.path.insert(0, os.path.abspath('../arcade'))
-
-# Don't change to
-# from arcade.version import VERSION
-# or read the docs build will fail.
-from version import VERSION # pyright: ignore [reportMissingImports]
-
RELEASE = VERSION
# -- General configuration ------------------------------------------------
From 60ef6ecdc6b4511bf147f4edfd7f94cb40adfffb Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:43:22 -0400
Subject: [PATCH 10/14] Even more obsessive logging
---
doc/conf.py | 38 +++++++++++++++++++++++++++++++++-----
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/doc/conf.py b/doc/conf.py
index a257a66e5..a1d00dce1 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -2,6 +2,7 @@
"""Sphinx configuration file"""
from __future__ import annotations
from functools import cache
+import logging
from pathlib import Path
from textwrap import dedent
from typing import Any, NamedTuple
@@ -22,26 +23,40 @@
# --- Pre-processing Tasks
+log = logging.getLogger('conf.py')
+logging.basicConfig(level=logging.INFO)
+
HERE = Path(__file__).resolve()
REPO_LOCAL_ROOT = HERE.parent.parent
+ARCADE_MODULE = REPO_LOCAL_ROOT / "arcade"
UTIL_DIR = REPO_LOCAL_ROOT / "util"
+log.info(f"Absolute path for our conf.py : {str(HERE)!r}")
+log.info(f"Absolute path for the repo root : {str(REPO_LOCAL_ROOT)!r}")
+log.info(f"Absolute path for the arcade module : {str(REPO_LOCAL_ROOT)!r}")
+log.info(f"Absolute path for the util dir : {str(UTIL_DIR)!r}")
+
# _temp_version = (REPO_LOCAL_ROOT / "arcade" / "VERSION").read_text().replace("-",'')
sys.path.insert(0, str(REPO_LOCAL_ROOT))
-sys.path.insert(0, str(REPO_LOCAL_ROOT / "arcade"))
+sys.path.insert(0, str(ARCADE_MODULE))
+log.info(f"Inserted elements in system path: First two are now:")
+for i in range(2):
+ log.info(f" {i}: {sys.path[i]!r}")
# Don't change to
# from arcade.version import VERSION
# or read the docs build will fail.
from version import VERSION # pyright: ignore [reportMissingImports]
-
+log.info(f"Got version {VERSION!r}")
REPO_URL_BASE="https://github.com/pythonarcade/arcade"
if 'dev' in VERSION:
GIT_REF = 'development'
+ log.info(f"Got .dev release: using {GIT_REF!r}")
else:
GIT_REF = VERSION
+ log.info(f"Got real release: using {GIT_REF!r}")
# We'll pass this to our generation scripts to initialize their globals
@@ -53,12 +68,25 @@
FMT_URL_REF_EMBED=f"{REPO_URL_BASE}/blob/{GIT_REF}/{{}}?raw=true",
)
-def run_util(filename, init_globals=None):
+def run_util(filename, run_name="__main__", init_globals=None):
+
+ full_absolute_path = UTIL_DIR / filename
+ full_str = str(full_absolute_path)
- kwargs = dict(run_name="__main__")
+ log.info(f"Running {full_str!r} with:")
+ log.info(f" run_name={run_name!r}")
+ kwargs = dict(run_name=run_name)
if init_globals is not None:
kwargs['init_globals'] = init_globals
- runpy.run_path(str(UTIL_DIR / filename), **kwargs)
+ log.info(f" init_globals={{")
+ num_left = len(init_globals)
+ for k, v in init_globals.items():
+ end = "," if num_left else ""
+ log.info(f" {k!r} : {v!r}{end}")
+ num_left -= num_left
+ log.info(f" }}")
+
+ runpy.run_path(full_str, **kwargs)
# Make thumbnails for the example code screenshots
run_util("generate_example_thumbnails.py")
From a5d7bf7e21a9fdc2e5ec2ff846a106d9ac2511fc Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:58:49 -0400
Subject: [PATCH 11/14] Spacing + rename default max cols
---
util/create_resources_listing.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index 897beb692..dfd105f38 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -69,12 +69,12 @@ def skipped_file(file_path: Path):
return file_path.suffix in skip_extensions
-TABLE_COLS: dict[str, int] = defaultdict(lambda: 3)
-TABLE_COLS[':resources:video/'] = 1
+MAX_COLS: dict[str, int] = defaultdict(lambda: 3)
+
@lru_cache(maxsize=None)
def get_header_num_cols(resource_stub: str, n_files = math.inf) -> int:
- return int(min(TABLE_COLS[resource_stub], n_files))
+ return int(min(MAX_COLS[resource_stub], n_files))
@lru_cache(maxsize=None)
From b5e542137ab9ae0b8b76a8a7f0756d93286adf77 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Wed, 16 Oct 2024 02:05:43 -0400
Subject: [PATCH 12/14] Fix sound listings to avoid overflowing the content
pane horizontally
---
util/create_resources_listing.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index dfd105f38..36e29a70c 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -70,6 +70,7 @@ def skipped_file(file_path: Path):
MAX_COLS: dict[str, int] = defaultdict(lambda: 3)
+MAX_COLS[":resources:sounds/"] = 2
@lru_cache(maxsize=None)
@@ -154,9 +155,10 @@ def process_resource_directory(out, dir: Path):
def process_resource_files(out, file_list: List[Path]):
cell_count = 0
- prefix = create_resource_path(file_list[0].parent)
+ prefix = create_resource_path(file_list[0].parent, suffix="/")
COLUMNS = get_header_num_cols(prefix, len(file_list))
+ log.info(f"Processing {prefix=!r} with {COLUMNS=!r}")
for path in file_list:
resource_path = path.relative_to(ARCADE_ROOT).as_posix()
suffix = path.suffix
From 6a65c124138540c2d0a33de09b07a10bb74d3be8 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Wed, 16 Oct 2024 02:31:46 -0400
Subject: [PATCH 13/14] Resources tweak
---
.../cybercity_background/foreground.png | Bin 15730 -> 15231 bytes
.../cybercity_background/public-license.txt | 2 ++
2 files changed, 2 insertions(+)
diff --git a/arcade/resources/assets/images/cybercity_background/foreground.png b/arcade/resources/assets/images/cybercity_background/foreground.png
index bcf427ba191e723355695d98ed4f2ccc3d455437..ae5b2f9f9795816474b77a36bf9b35e217e10b9c 100644
GIT binary patch
literal 15231
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
literal 15730
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
Kbd98G$o~P$Zda!O
diff --git a/arcade/resources/assets/images/cybercity_background/public-license.txt b/arcade/resources/assets/images/cybercity_background/public-license.txt
index 0029ea46b..5ef285294 100644
--- a/arcade/resources/assets/images/cybercity_background/public-license.txt
+++ b/arcade/resources/assets/images/cybercity_background/public-license.txt
@@ -1,3 +1,5 @@
+Modified & re-released under the same license below:
+below
Artwork created by Luis Zuno (@ansimuz)
https://ansimuz.itch.io/cyberpunk-street-environment
From 920f1ed694f5b382437ff965eb4dbe834e2b3d60 Mon Sep 17 00:00:00 2001
From: pushfoo <36696816+pushfoo@users.noreply.github.com>
Date: Wed, 16 Oct 2024 02:57:30 -0400
Subject: [PATCH 14/14] Quote resource folder captions + fix ":resources:./"
---
util/create_resources_listing.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/util/create_resources_listing.py b/util/create_resources_listing.py
index 36e29a70c..2562560f7 100644
--- a/util/create_resources_listing.py
+++ b/util/create_resources_listing.py
@@ -121,16 +121,20 @@ def process_resource_directory(out, dir: Path):
if num_files > 0:
# header_title = f":resources:{path.relative_to(RESOURCE_DIR).as_posix()}/"
- header_title = create_resource_path(path, suffix="/")
- if header_title == ":resources:images/":
+ raw_header = create_resource_path(path, suffix="/")
+ header_title = raw_header[:-2] if raw_header.endswith("./") else raw_header
+
+ if raw_header == ":resources:images/":
for f in file_list:
print(f.name)
# out.write(f"\n{header_title}\n")
# out.write("-" * (len(header_title)) + "\n\n")
- n_cols = get_header_num_cols(header_title, num_files)
+
+ n_cols = get_header_num_cols(raw_header, num_files)
widths = get_column_widths_for_n(n_cols)
+
out.write(f"\n")
- out.write(f".. list-table:: {header_title}\n")
+ out.write(f".. list-table:: \"{header_title}\"\n")
out.write(f" :widths: {widths}\n")
out.write(f" :header-rows: 0\n")
out.write(f" :class: resource-table\n\n")
@@ -156,6 +160,7 @@ def process_resource_files(out, file_list: List[Path]):
cell_count = 0
prefix = create_resource_path(file_list[0].parent, suffix="/")
+
COLUMNS = get_header_num_cols(prefix, len(file_list))
log.info(f"Processing {prefix=!r} with {COLUMNS=!r}")