From 1046bf3bf62026f00b3af0a58c73df3d3911f18d Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 16 Jun 2026 13:35:35 +0100 Subject: [PATCH 1/3] feat: add validation warning for missing game descriptions --- build_support/catalog/test_update.py | 38 ++++++++++++++++++++++++++++ build_support/catalog/update.py | 22 ++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/build_support/catalog/test_update.py b/build_support/catalog/test_update.py index 1ee941b6c..a786eb71d 100644 --- a/build_support/catalog/test_update.py +++ b/build_support/catalog/test_update.py @@ -821,3 +821,41 @@ def test_empty_catalog_produces_valid_am(self, tmp_path): update.update_makefile(catalog_dir=tmp_path, am_path=am) content = am.read_text() assert content.startswith("CATALOG_FILES =") + + +@pytest.mark.catalog_update +class TestWarnMissingDescriptions: + """Tests for ``_warn_missing_descriptions(df)``. + + The function prints to stderr for each game in a supported format that has + an empty description. Tests use ``capsys`` to capture stderr output. + """ + + def test_game_without_description_warns(self, capsys): + """A game with an empty description produces a WARNING on stderr.""" + df = _make_df(_efg_row("journals/nobody2025/fig1", description="")) + update._warn_missing_descriptions(df) + err = capsys.readouterr().err + assert "WARNING" in err + assert "journals/nobody2025/fig1" in err + + def test_game_with_description_does_not_warn(self, capsys): + """A game with a non-empty description produces no output.""" + df = _make_df(_efg_row("journals/nobody2025/fig1")) + update._warn_missing_descriptions(df) + err = capsys.readouterr().err + assert err == "" + + def test_unknown_format_does_not_warn(self, capsys): + """A row with an unsupported format is ignored even if description is empty.""" + row = { + "Game": "unknown/game", + "Title": "Unknown", + "Description": "", + "Download": ":download:`game.xyz <../catalog/unknown/game.xyz>`", + "Format": "xyz", + } + df = _make_df(row) + update._warn_missing_descriptions(df) + err = capsys.readouterr().err + assert err == "" diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py index f61acc014..f9d766a22 100644 --- a/build_support/catalog/update.py +++ b/build_support/catalog/update.py @@ -1,5 +1,6 @@ import argparse import shutil +import sys from pathlib import Path import pandas as pd @@ -93,6 +94,26 @@ def _node_label(prefix: str, labels: dict[str, str]) -> str: return Path(prefix).name.replace("_", " ").title() +def _warn_missing_descriptions(df: pd.DataFrame) -> None: + """Print a warning to stderr for each game that lacks a description. + + Games without descriptions are silently excluded from the catalog page by + ``_build_slug_tree``. This function makes that visible so contributors + know to add a description before the game will appear. + """ + for _, row in df.iterrows(): + if row.get("Format") not in SUPPORTED_GAME_FORMATS: + continue + if str(row.get("Description", "")).strip(): + continue + slug = row["Game"] + print( + f"WARNING: '{slug}' has no description and will not appear in the catalog.\n" + f"Add a description to the game file to include it.", + file=sys.stderr, + ) + + def _build_slug_tree(df: pd.DataFrame) -> dict: """Build a nested dict tree from the slugs in *df*. @@ -392,6 +413,7 @@ def update_makefile( # Create RST list-table used by doc/catalog.rst df = gbt.catalog.games(include_descriptions=True) + _warn_missing_descriptions(df) generate_rst_table(df, CATALOG_RST_TABLE, regenerate_images=args.regenerate_images) print(f"Generated {CATALOG_RST_TABLE} for use in local docs build. DO NOT COMMIT.") if args.build: From 6683c120d9c2b593f615379700aab41701986ec9 Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 16 Jun 2026 13:41:21 +0100 Subject: [PATCH 2/3] remove superfluous test --- build_support/catalog/test_update.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/build_support/catalog/test_update.py b/build_support/catalog/test_update.py index a786eb71d..b3abfa56b 100644 --- a/build_support/catalog/test_update.py +++ b/build_support/catalog/test_update.py @@ -845,17 +845,3 @@ def test_game_with_description_does_not_warn(self, capsys): update._warn_missing_descriptions(df) err = capsys.readouterr().err assert err == "" - - def test_unknown_format_does_not_warn(self, capsys): - """A row with an unsupported format is ignored even if description is empty.""" - row = { - "Game": "unknown/game", - "Title": "Unknown", - "Description": "", - "Download": ":download:`game.xyz <../catalog/unknown/game.xyz>`", - "Format": "xyz", - } - df = _make_df(row) - update._warn_missing_descriptions(df) - err = capsys.readouterr().err - assert err == "" From d0da3311e59cfc28f913ee905436f8788f047fff Mon Sep 17 00:00:00 2001 From: Ed Chalstrey Date: Tue, 16 Jun 2026 13:43:32 +0100 Subject: [PATCH 3/3] simplify --- build_support/catalog/update.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build_support/catalog/update.py b/build_support/catalog/update.py index f9d766a22..ccfb77634 100644 --- a/build_support/catalog/update.py +++ b/build_support/catalog/update.py @@ -102,13 +102,10 @@ def _warn_missing_descriptions(df: pd.DataFrame) -> None: know to add a description before the game will appear. """ for _, row in df.iterrows(): - if row.get("Format") not in SUPPORTED_GAME_FORMATS: - continue if str(row.get("Description", "")).strip(): continue - slug = row["Game"] print( - f"WARNING: '{slug}' has no description and will not appear in the catalog.\n" + f"WARNING: '{row['Game']}' has no description and will not appear in the catalog.\n" f"Add a description to the game file to include it.", file=sys.stderr, )