Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,26 @@ jobs:
run: python -m pip install cython-lint
- name: cython-lint
run: cython-lint .

catalog-am-sync:
name: catalog.am is up to date
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
steps:
- uses: actions/checkout@v7
- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: "3.14"
- name: Install pygambit (editable, picks up catalog/games directly)
run: |
python -m pip install -v -e ".[doc]"
pip install "gtdraw @ git+https://github.com/gambitproject/gtdraw.git@main"
- name: Regenerate catalog/catalog.am
run: python catalog/build.py --build --skip-table
- name: Fail if catalog.am is out of sync with catalog/games
run: |
if ! git diff --exit-code -- catalog/catalog.am; then
echo "::error::catalog/catalog.am is out of sync with catalog/games. Run 'python catalog/build.py --build' and commit the result."
exit 1
fi
14 changes: 8 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ Gambit.app/*
Gambit.app/*
*.ipynb_checkpoints
doc/**/*.ef
catalog/doc/**/*.ef
build_support/msw/gambit.wxs
build_support/osx/Info.plist
src/pygambit/catalog
doc/catalog_table.rst
catalog/img/**/*.pdf
catalog/img/**/*.png
catalog/img/**/*.tex
catalog/img/**/*.ef
catalog/img/**/*.svg
catalog/doc/_table.rst
catalog/doc/_build
catalog/games/img/**/*.pdf
catalog/games/img/**/*.png
catalog/games/img/**/*.tex
catalog/games/img/**/*.ef
catalog/games/img/**/*.svg
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ build:
- pdf2svg
jobs:
post_install:
# Required by the tutorials (jupyter_tikz game-tree rendering), not by the catalog —
# the catalog is now built as its own separate RTD project (see catalog/doc/).
- pip install "gtdraw @ git+https://github.com/gambitproject/gtdraw.git@main"
# Create RST for catalog table in docs
- $READTHEDOCS_VIRTUALENV_PATH/bin/python build_support/catalog/update.py

python:
install:
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
recursive-include src/core *.cc *.h
recursive-include src/games *.cc *.h *.imp
recursive-include src/solvers *.cc *.h *.imp
recursive-include catalog *
recursive-include catalog/games *
include src/gambit.h
include src/games.h
include src/solvers.h
Expand Down
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##

include build_support/catalog/catalog.am
include catalog/catalog.am

EXTRA_DIST = \
build_support/GAMBIT_VERSION \
Expand Down
53 changes: 0 additions & 53 deletions build_support/catalog/catalog.am

This file was deleted.

33 changes: 33 additions & 0 deletions catalog/.readthedocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: 2

# This config file is for a SEPARATE ReadTheDocs project from the main Gambit docs
# (which use the root-level .readthedocs.yml). Setting it up requires creating a second
# project in the ReadTheDocs dashboard for this same GitHub repo, configured to use this
# file instead of the root one — that dashboard step is not something a git commit can do.

sphinx:
configuration: catalog/doc/conf.py

formats: all

build:
os: ubuntu-22.04
tools:
python: "3.14"
apt_packages:
- libgmp-dev
- texlive-full
- imagemagick
- pdf2svg
jobs:
post_install:
- pip install "gtdraw @ git+https://github.com/gambitproject/gtdraw.git@main"
# Regenerate catalog/doc/_table.rst (and the game images) from the current catalog.
- $READTHEDOCS_VIRTUALENV_PATH/bin/python catalog/build.py

python:
install:
- method: pip
path: "."
extra_requirements:
- doc
1 change: 1 addition & 0 deletions catalog/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0
52 changes: 32 additions & 20 deletions build_support/catalog/update.py → catalog/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

import pygambit as gbt

CATALOG_RST_TABLE = Path(__file__).parent.parent.parent / "doc" / "catalog_table.rst"
CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog"
MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am"
CATALOG_RST_TABLE = Path(__file__).parent / "doc" / "_table.rst"
CATALOG_DIR = Path(__file__).parent / "games"
MAKEFILE_AM = Path(__file__).parent.parent / "Makefile.am"
GTDRAW_SETTINGS_CONFIG = Path(__file__).parent / "gtdraw_settings.yaml"
CATALOG_HIERARCHY_CONFIG = Path(__file__).parent / "catalog_hierarchy.yaml"
CATALOG_HIERARCHY_CONFIG = Path(__file__).parent / "hierarchy.yaml"
SUPPORTED_GAME_FORMATS = {"efg", "nfg"}


Expand Down Expand Up @@ -60,8 +60,8 @@ def catalog_ef_file_variants(slug: str, catalog_dir: Path) -> list[dict] | None:

File-naming convention::

catalog/{slug}.ef primary variant → label "Default"
catalog/{slug}__{suffix}.ef additional variant → label derived from suffix
catalog/games/{slug}.ef primary variant → label "Default"
catalog/games/{slug}__{suffix}.ef additional variant → label derived from suffix

The suffix part (after ``__``) is title-cased with underscores replaced by
spaces, e.g. ``fig1__very_wide.ef`` → label "Very Wide".
Expand Down Expand Up @@ -230,10 +230,10 @@ def _write_game_entry(
for variant in ef_variants:
vkey = variant["variant_key"]
for ext in ["ef", "tex", "png", "pdf", "svg"]:
download_links.append(f":download:`{vkey}.{ext} <../catalog/img/{vkey}.{ext}>`")
download_links.append(f":download:`{vkey}.{ext} <../games/img/{vkey}.{ext}>`")
else:
for ext in all_exts:
download_links.append(f":download:`{slug}.{ext} <../catalog/img/{slug}.{ext}>`")
download_links.append(f":download:`{slug}.{ext} <../games/img/{slug}.{ext}>`")
f.write(f"{i1}.. dropdown:: Download game and image files\n")
f.write(f"{i1} \n")
f.write(f"{i2}{' '.join(download_links)}\n")
Expand All @@ -257,7 +257,7 @@ def _write_game_entry(
f.write(f"{i4}import pygambit\n")
f.write(f"{i4}from gtdraw import draw\n")
if variant["ef_path"].exists():
f.write(f'{i4}draw("../catalog/{vkey}.ef", {settings_str})\n')
f.write(f'{i4}draw("../games/{vkey}.ef", {settings_str})\n')
else:
f.write(f'{i4}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
f.write(f"{i2}\n")
Expand All @@ -274,13 +274,13 @@ def _write_game_entry(
)
curated_ef = catalog_dir / f"{slug}.ef"
if curated_ef.exists():
f.write(f'{i2}draw("../catalog/{slug}.ef", {settings_str})\n')
f.write(f'{i2}draw("../games/{slug}.ef", {settings_str})\n')
else:
f.write(f'{i2}draw(pygambit.catalog.load("{slug}"), {settings_str})\n')
elif row["Format"] == "nfg":
f.write(
f'{i2}draw(pygambit.catalog.load("{slug}"), '
f'save_to="../catalog/img/{slug}.png")\n'
f'save_to="../games/img/{slug}.png")\n'
)
f.write(f"{i1}\n")

Expand Down Expand Up @@ -376,7 +376,7 @@ def update_makefile(

game_files = []
for slug in slugs:
game_files.append(f"catalog/{slug}")
game_files.append(f"catalog/games/{slug}")
game_files.sort()

if am_path.exists():
Expand Down Expand Up @@ -404,15 +404,16 @@ def update_makefile(
parser = argparse.ArgumentParser(
description=(
"Update Gambit catalog documentation and build files. "
"Always regenerates doc/catalog_table.rst from the current catalog. "
"Run from the repo root or build_support/catalog/."
"Regenerates catalog/doc/_table.rst from the current catalog by default; "
"pass --skip-table to skip this (it requires a LaTeX toolchain via gtdraw). "
"Run from the repo root or catalog/."
)
)
parser.add_argument(
"--build",
action="store_true",
help=(
"Also update build_support/catalog/catalog.am with the current list of "
"Also update catalog/catalog.am with the current list of "
"catalog game files. Required after adding or removing games."
),
)
Expand All @@ -425,13 +426,24 @@ def update_makefile(
"gtdraw_settings.yaml."
),
)
parser.add_argument(
"--skip-table",
action="store_true",
help=(
"Skip regenerating catalog/doc/_table.rst and any missing game images. "
"Table/image generation requires a LaTeX toolchain (gtdraw's tex/pdf/png/svg "
"functions); use this with --build in contexts (e.g. CI) that only need "
"catalog.am checked or updated."
),
)
args = parser.parse_args()

# Create RST list-table used by doc/catalog.rst
df = _catalog_games()
_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 not args.skip_table:
# Create RST list-table used by catalog/doc/index.rst
df = _catalog_games()
_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:
# Update the Makefile.am with the current list of catalog files
update_makefile()
53 changes: 53 additions & 0 deletions catalog/catalog.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
CATALOG_FILES = \
catalog/games/books/myerson1991/fig2_1.efg \
catalog/games/books/myerson1991/fig4_2.efg \
catalog/games/books/shohamleytonbrown2008/fig5_1.efg \
catalog/games/books/shohamleytonbrown2008/fig5_10.efg \
catalog/games/books/shohamleytonbrown2008/fig5_10__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_11.efg \
catalog/games/books/shohamleytonbrown2008/fig5_11__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_12.efg \
catalog/games/books/shohamleytonbrown2008/fig5_12__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_15.efg \
catalog/games/books/shohamleytonbrown2008/fig5_15__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_1__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_2.efg \
catalog/games/books/shohamleytonbrown2008/fig5_2__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig5_9.efg \
catalog/games/books/shohamleytonbrown2008/fig5_9__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig6_2.efg \
catalog/games/books/shohamleytonbrown2008/fig6_2__original_layout.ef \
catalog/games/books/shohamleytonbrown2008/fig6_8.efg \
catalog/games/books/shohamleytonbrown2008/fig6_8__original_layout.ef \
catalog/games/books/vonstengel2022/fig10.1.efg \
catalog/games/books/vonstengel2022/fig10.12.efg \
catalog/games/books/vonstengel2022/fig10.5.efg \
catalog/games/books/vonstengel2022/fig10.7.efg \
catalog/games/books/watson2013/exercise29_6.efg \
catalog/games/books/watson2013/fig29_1.efg \
catalog/games/conf/itcs/jakobsen2016/fig1a.efg \
catalog/games/conf/itcs/jakobsen2016/fig1b.efg \
catalog/games/conf/itcs/jakobsen2016/fig1c.efg \
catalog/games/conf/itcs/jakobsen2016/fig3.efg \
catalog/games/journals/dcg/vonstengel1999/6x6_game_with_75_eq.nfg \
catalog/games/journals/dcg/vonstengel1999/6x6_game_with_75_eq_small_payoffs.nfg \
catalog/games/journals/geb/bagwell1995.efg \
catalog/games/journals/geb/gilboa1997/fig1.efg \
catalog/games/journals/geb/gilboa1997/fig2.efg \
catalog/games/journals/geb/wichardt2008.efg \
catalog/games/journals/ijgt/nau2004/sec3.nfg \
catalog/games/journals/ijgt/nau2004/sec4.nfg \
catalog/games/journals/ijgt/nau2004/sec5.nfg \
catalog/games/journals/ijgt/nau2004/sec6.nfg \
catalog/games/journals/ijgt/selten1975/fig1.efg \
catalog/games/journals/ijgt/selten1975/fig2.efg \
catalog/games/journals/ijgt/selten1975/fig3.efg \
catalog/games/journals/mor/vonstengelforges2008/fig1.efg \
catalog/games/journals/mor/vonstengelforges2008/fig1__Original_Layout.ef \
catalog/games/journals/mor/vonstengelforges2008/fig6.efg \
catalog/games/journals/mor/vonstengelforges2008/fig6__Original_Layout.ef \
catalog/games/journals/mor/vonstengelforges2008/fig9.efg \
catalog/games/journals/mor/vonstengelforges2008/fig9__Original_Layout.ef \
catalog/games/journals/other/reiley2008/fig1.efg \
catalog/games/journals/other/shapley1974/fig2.nfg \
catalog/games/journals/other/shapley1974/fig3.nfg
45 changes: 45 additions & 0 deletions catalog/doc/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import pathlib
import sys

# The shared bibtex citation style lives in the main docs project; import it from
# there rather than duplicating it (see doc/_bibstyle.py).
sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / "doc"))
import _bibstyle # noqa: E402,F401 registers the shared "keystyle" pybtex plugin

# -- General configuration -----------------------------------------------------

extensions = [
"sphinx_design",
"jupyter_sphinx",
"sphinxcontrib.bibtex",
]

bibtex_bibfiles = [str(pathlib.Path(__file__).parent.parent.parent / "doc" / "references.bib")]

source_suffix = {".rst": "restructuredtext"}
master_doc = "index"

project = "Gambit Catalog"
copyright = "1994-2026, The Gambit Project" # noqa

_version_file = pathlib.Path(__file__).parent.parent.parent / "build_support" / "GAMBIT_VERSION"
if _version_file.exists():
_full_version = _version_file.read_text().strip()
version = ".".join(_full_version.split(".")[:2])
release = _full_version
else:
raise FileNotFoundError("GAMBIT_VERSION file not found")

exclude_patterns = ["_build", "_table.rst"]

pygments_style = "sphinx"

# -- Options for HTML output ---------------------------------------------------

html_theme = "pydata_sphinx_theme"
html_theme_options = {
"external_links": [
{"name": "Gambit documentation", "url": "https://gambitproject.readthedocs.io/"},
{"name": "GitHub", "url": "https://github.com/gambitproject/gambit"},
],
}
Loading
Loading