Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
a90a137
update pyproject.toml with optional dependencies for test suite and docs
edwardchalstrey1 Jan 28, 2026
adc322f
update GitHub actions to install optional dependencies when installin…
edwardchalstrey1 Jan 28, 2026
38ddfa2
add doc dependencies: Cython, numpy, scipy
edwardchalstrey1 Jan 28, 2026
4d54262
try GH actions without testing docs
edwardchalstrey1 Jan 28, 2026
0a46de2
Revert "try GH actions without testing docs"
edwardchalstrey1 Jan 28, 2026
7c59b5f
remove pip install that is already covered by build-system in pyproje…
edwardchalstrey1 Jan 28, 2026
fa8c42f
fix typo mistake in doc dependencies list
edwardchalstrey1 Jan 28, 2026
eadf1b4
remove Cython, numpy and scipy from doc dependency list as these are …
edwardchalstrey1 Jan 28, 2026
a403b5b
restore installation of build on linux job
edwardchalstrey1 Jan 28, 2026
06fe088
remove requirements.txt files
edwardchalstrey1 Jan 28, 2026
317e601
update docs for new installation method
edwardchalstrey1 Jan 28, 2026
d89b891
update documentation instructions
edwardchalstrey1 Jan 28, 2026
af6ece0
update readthedocs config
edwardchalstrey1 Jan 28, 2026
476efc1
try fixing linux build
edwardchalstrey1 Jan 28, 2026
b8db5ca
try again to fix linux job: let bash expand the filename first, then …
edwardchalstrey1 Jan 28, 2026
90a5e36
Create catalog dir and move one EFG and one NFG into it from contrib/…
edwardchalstrey1 Feb 3, 2026
83dd410
ignore catalog files copied into pygambit
edwardchalstrey1 Feb 3, 2026
7fc2199
add failing tests
edwardchalstrey1 Feb 3, 2026
3c53bea
improve tests
edwardchalstrey1 Feb 3, 2026
898a916
add pandas to pyproject.toml
edwardchalstrey1 Feb 3, 2026
8f916db
add test_catalog_load_invalid_slug
edwardchalstrey1 Feb 3, 2026
606dd8a
create load function
edwardchalstrey1 Feb 3, 2026
00beed3
add catalog to __init__
edwardchalstrey1 Feb 3, 2026
64eb310
add games() function
edwardchalstrey1 Feb 3, 2026
d24befd
refactor to define READERS once
edwardchalstrey1 Feb 3, 2026
72aade1
Big refactor to get catalog files from catalog dir external to pygambit
edwardchalstrey1 Feb 3, 2026
e7953e9
update Makefile.am for the 2 examples we moved into the catalog so far
edwardchalstrey1 Feb 3, 2026
7490ae6
update Game.comment to be Game.description in Python code
edwardchalstrey1 Feb 4, 2026
ebf6829
Revert "update Game.comment to be Game.description in Python code"
edwardchalstrey1 Feb 4, 2026
fbf6b89
Add initial update catalog script and RST page
edwardchalstrey1 Feb 4, 2026
1ca3461
rename table headers on output df from game() func
edwardchalstrey1 Feb 4, 2026
bd3c1f3
add generating the catalog csv for docs into GH actions
edwardchalstrey1 Feb 4, 2026
569148c
Revert "add generating the catalog csv for docs into GH actions"
edwardchalstrey1 Feb 4, 2026
8cf0396
refactor update script so its run from repo root
edwardchalstrey1 Feb 4, 2026
1b20438
update readthedocs to build the catalog csv before docs build
edwardchalstrey1 Feb 4, 2026
e977e64
add function which updates Makefile.am
edwardchalstrey1 Feb 4, 2026
af08d29
use a proper path for CATALOG_CSV
edwardchalstrey1 Feb 4, 2026
cd2ffc9
tidy update script
edwardchalstrey1 Feb 4, 2026
5675444
use explicit python executable from the virtualenv to create CSV for …
edwardchalstrey1 Feb 4, 2026
f574223
add developer doc for updating the catalog
edwardchalstrey1 Feb 4, 2026
5147278
Don't update Makefile.am by default
edwardchalstrey1 Feb 4, 2026
4b033c9
consistency in notebook comment
edwardchalstrey1 Feb 4, 2026
b14402a
demo loading from catalog in tutorial 1
edwardchalstrey1 Feb 4, 2026
264f7fb
load from catalog for game examples in advanced tutorials
edwardchalstrey1 Feb 4, 2026
0e268a2
Try using pip instead of setuptools to ensure pyproject.toml deps ins…
edwardchalstrey1 Feb 4, 2026
8649946
remove deleted contrib games from Makefile.am
edwardchalstrey1 Feb 4, 2026
adea4f2
add a warning about moving games from contrib
edwardchalstrey1 Feb 4, 2026
a72f7a2
check if pandas duplications error exists if we dont save outputs on …
edwardchalstrey1 Feb 4, 2026
57863d4
fix problem with print function
edwardchalstrey1 Feb 4, 2026
b687e20
resave notebook outputs
edwardchalstrey1 Feb 4, 2026
6562433
Update writer.cc
tturocy Feb 10, 2026
39fde9d
Merge branch 'master' into ehancement/731/take2
edwardchalstrey1 Feb 10, 2026
f84bcc8
move catalog update script into build support
edwardchalstrey1 Feb 10, 2026
d17f976
rename script
edwardchalstrey1 Feb 10, 2026
f07fdae
rename var
edwardchalstrey1 Feb 10, 2026
fd66e41
update path to catalog update script in readthedocs yml and docs page
edwardchalstrey1 Feb 10, 2026
bb1e920
move myserson fig into subfolder
edwardchalstrey1 Feb 10, 2026
5c7a60f
clarify script usage
edwardchalstrey1 Feb 10, 2026
dc7a373
add test_catalog_load_subdir_slug
edwardchalstrey1 Feb 10, 2026
7850585
update makefile
edwardchalstrey1 Feb 10, 2026
f6ea5df
update agent nb
edwardchalstrey1 Feb 10, 2026
f655645
add test for slug in subdir of catalog
edwardchalstrey1 Feb 10, 2026
56cd19a
update games func to list slugs correctly
edwardchalstrey1 Feb 10, 2026
6a4df8f
update test to avoid duplicates
edwardchalstrey1 Feb 10, 2026
886131c
fix code for handling slugs that duplicates of those in subfolders
edwardchalstrey1 Feb 10, 2026
68909b9
tidy the games() refactor
edwardchalstrey1 Feb 10, 2026
bb8f483
resave notebook
edwardchalstrey1 Feb 10, 2026
50e618b
strip nb outputs
edwardchalstrey1 Feb 10, 2026
67dedb2
remove modification to games() that was fixing a local issue
edwardchalstrey1 Feb 10, 2026
1794a83
fix the update script to get correct paths
edwardchalstrey1 Feb 10, 2026
079aacd
remove unused var
edwardchalstrey1 Feb 10, 2026
e57cfce
Add Windows handling
edwardchalstrey1 Feb 10, 2026
bdc5d3a
fix incorrect var name and make consistent
edwardchalstrey1 Feb 11, 2026
69d8cb9
use as_posix for slugs
edwardchalstrey1 Feb 11, 2026
d7290f4
add new notebook
edwardchalstrey1 Feb 12, 2026
cb5c210
Merge branch 'feature/677' into tutorial/732
edwardchalstrey1 Feb 12, 2026
d32570f
upgrade draw_tree version to 0.4.0
edwardchalstrey1 Feb 12, 2026
b56c95b
2smp game looks good
edwardchalstrey1 Feb 13, 2026
e73dfe8
add sections on saving images and further adjustments
edwardchalstrey1 Feb 13, 2026
1962e06
update headers
edwardchalstrey1 Feb 13, 2026
a4fc744
update header further
edwardchalstrey1 Feb 13, 2026
59dd0dd
add comment
edwardchalstrey1 Feb 13, 2026
c27f805
clear saved outputs from all tutorials
edwardchalstrey1 Feb 13, 2026
4be7887
typo
edwardchalstrey1 Feb 13, 2026
e1a7e98
tidy read and save sections
edwardchalstrey1 Feb 13, 2026
f4113e8
renumber and reorder tutorials
edwardchalstrey1 Feb 13, 2026
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
22 changes: 6 additions & 16 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ jobs:
- name: Set up dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools build cython wheel
pip install -r tests/requirements.txt
pip install -r doc/requirements.txt
python -m pip install build
- name: Build source distribution
run:
python -m build
- name: Build from source distribution
run: |
cd dist
pip install -v pygambit*.tar.gz
sdist=$(ls pygambit-*.tar.gz)
pip install -v "${sdist}[test,doc]"
- name: Run tests
run: pytest --run-tutorials

Expand All @@ -50,12 +49,9 @@ jobs:
- name: Set up dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools build cython wheel
pip install -r tests/requirements.txt
pip install -r doc/requirements.txt
- name: Build extension
run: |
python -m pip install -v .
python -m pip install -v .[test,doc]
- name: Run tests
run: pytest --run-tutorials

Expand All @@ -75,12 +71,9 @@ jobs:
- name: Set up dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools build cython wheel
pip install -r tests/requirements.txt
pip install -r doc/requirements.txt
- name: Build extension
run: |
python -m pip install -v .
python -m pip install -v .[test,doc]
- name: Run tests
run: pytest --run-tutorials

Expand All @@ -100,11 +93,8 @@ jobs:
- name: Set up dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools build cython wheel
pip install -r tests/requirements.txt
pip install -r doc/requirements.txt
- name: Build extension
run: |
python -m pip install -v .
python -m pip install -v .[test,doc]
- name: Run tests
run: pytest --run-tutorials
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ Gambit.app/*
*.ef
build_support/msw/gambit.wxs
build_support/osx/Info.plist
src/pygambit/catalog
doc/catalog.csv
9 changes: 7 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ build:
- libgmp-dev
- pandoc
- texlive-full
jobs:
# Create CSV for catalog table in docs
post_install:
- $READTHEDOCS_VIRTUALENV_PATH/bin/python build_support/catalog/update.py

python:
install:
- requirements: doc/requirements.txt
- method: setuptools
- method: pip
path: "."
extra_requirements:
- doc
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
recursive-include src/core *.cc *.h *.imp
recursive-include src/games *.cc *.h *.imp
recursive-include src/solvers *.c *.cc *.h *.imp
recursive-include catalog *
include src/gambit.h
include src/pygambit/*.pxd
include src/pygambit/*.pyx
Expand Down
10 changes: 5 additions & 5 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ EXTRA_DIST = \
src/gui/bitmaps/zoom1.xpm \
src/gui/bitmaps/gambitrc.rc \
contrib/games/2s2x2x2.efg \
contrib/games/2smp.efg \
contrib/games/2x2x2.efg \
contrib/games/4cards.efg \
contrib/games/artist1.efg \
Expand Down Expand Up @@ -169,7 +168,6 @@ EXTRA_DIST = \
contrib/games/my_3-3d.efg \
contrib/games/my_3-3e.efg \
contrib/games/my_3-4.efg \
contrib/games/myerson.efg \
contrib/games/nim7.efg \
contrib/games/nim.efg \
contrib/games/palf2.efg \
Expand All @@ -195,7 +193,6 @@ EXTRA_DIST = \
contrib/games/2x2a.nfg \
contrib/games/2x2const.nfg \
contrib/games/2x2.nfg \
contrib/games/2x2x2.nfg \
contrib/games/2x2x2x2.nfg \
contrib/games/2x2x2x2x2.nfg \
contrib/games/3x3x3.nfg \
Expand Down Expand Up @@ -224,7 +221,6 @@ EXTRA_DIST = \
contrib/games/mixdom2.nfg \
contrib/games/mixdom.nfg \
contrib/games/oneill.nfg \
contrib/games/pd.nfg \
contrib/games/perfect1.nfg \
contrib/games/perfect2.nfg \
contrib/games/perfect3.nfg \
Expand All @@ -240,7 +236,11 @@ EXTRA_DIST = \
contrib/games/winkels.nfg \
contrib/games/yamamoto.nfg \
contrib/games/zero.nfg \
src/README.rst
src/README.rst \
catalog/2smp.efg \
catalog/2x2x2.nfg \
catalog/myerson/fig_4_2.efg \
catalog/pd.nfg

core_SOURCES = \
src/core/core.h \
Expand Down
74 changes: 74 additions & 0 deletions build_support/catalog/update.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import argparse
from pathlib import Path

import pygambit as gbt

CATALOG_CSV = Path(__file__).parent.parent.parent / "doc" / "catalog.csv"
CATALOG_DIR = Path(__file__).parent.parent.parent / "catalog"
MAKEFILE_AM = Path(__file__).parent.parent.parent / "Makefile.am"


def update_makefile():
"""Update the Makefile.am with all games from the catalog."""

# Using rglob("*") to find files in all subdirectories
slugs = []
for resource_path in sorted(CATALOG_DIR.rglob("*.efg")):
if resource_path.is_file():
rel_path = resource_path.relative_to(CATALOG_DIR)
slugs.append(str(rel_path))
for resource_path in sorted(CATALOG_DIR.rglob("*.nfg")):
if resource_path.is_file():
rel_path = resource_path.relative_to(CATALOG_DIR)
slugs.append(str(rel_path))

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

with open(MAKEFILE_AM, encoding="utf-8") as f:
content = f.readlines()

with open(MAKEFILE_AM, "w", encoding="utf-8") as f:
in_gamefiles_section = False
for line in content:
# Add to the EXTRA_DIST after the README.rst line
if line.startswith(" src/README.rst \\"):
in_gamefiles_section = True
f.write(" src/README.rst \\\n")
for gf in game_files:
if gf == game_files[-1]:
f.write(f"\t{gf}\n")
else:
f.write(f"\t{gf} \\\n")
f.write("\n")
elif in_gamefiles_section:
if line.strip() == "":
in_gamefiles_section = False
continue # Skip old gamefiles lines
else:
f.write(line)

with open(MAKEFILE_AM, encoding="utf-8") as f:
updated_content = f.readlines()

if content != updated_content:
print(f"Updated {str(MAKEFILE_AM)}")
else:
print(f"No changes to add to {str(MAKEFILE_AM)}")


if __name__ == "__main__":

parser = argparse.ArgumentParser()
parser.add_argument("--build", action="store_true")
args = parser.parse_args()

# Create CSV used by RST docs page
gbt.catalog.games().to_csv(CATALOG_CSV, index=False)
print(f"Generated {CATALOG_CSV} for use in local docs build. DO NOT COMMIT.")

# Update the Makefile.am with the current list of catalog files
if args.build:
update_makefile()
File renamed without changes.
File renamed without changes.
60 changes: 60 additions & 0 deletions catalog/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from importlib.resources import as_file, files
from pathlib import Path

import pandas as pd

import pygambit as gbt

# Use the full string path to the virtual package we created
_CATALOG_RESOURCE = files(__name__)

READERS = {
".nfg": gbt.read_nfg,
".efg": gbt.read_efg,
}


def load(slug: str) -> gbt.Game:
"""
Load a game from the package catalog.
"""
slug = str(Path(slug)).replace("\\", "/")

for suffix, reader in READERS.items():
resource_path = _CATALOG_RESOURCE / f"{slug}{suffix}"

if resource_path.is_file():
# as_file ensures we have a real filesystem path for the reader
with as_file(resource_path) as path:
return reader(str(path))

raise FileNotFoundError(f"No catalog entry called {slug}.nfg or {slug}.efg")


def games() -> pd.DataFrame:
"""
List games available in the package catalog, including subdirectories.
"""
records: list[dict[str, str]] = []

# Using rglob("*") to find files in all subdirectories
for resource_path in sorted(_CATALOG_RESOURCE.rglob("*")):
reader = READERS.get(resource_path.suffix)

if reader is not None and resource_path.is_file():

# Calculate the path relative to the root resource
# and remove the suffix to get the "slug"
rel_path = resource_path.relative_to(_CATALOG_RESOURCE)
slug = rel_path.with_suffix("").as_posix()

with as_file(resource_path) as path:
game = reader(str(path))
records.append(
{
"Game": slug,
"Title": game.title,
}
)

return pd.DataFrame.from_records(records, columns=["Game", "Title"])
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions doc/catalog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Catalog of games
================

.. csv-table::
:file: catalog.csv
:header-rows: 1
:widths: 20, 80
:class: tight-table
6 changes: 5 additions & 1 deletion doc/developer.build.rst
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ Use `pip` to install from the **root directory of the source tree**:

python -m venv venv
source venv/bin/activate
python -m pip install .
python -m pip install .[test,doc]

.. tip::

The "test" and "doc" optional dependencies are useful for developers wishing to run the test suite or build this documentation locally.


Once installed, simply ``import pygambit`` in your Python shell or
Expand Down
45 changes: 45 additions & 0 deletions doc/developer.catalog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Updating the Games Catalog
==========================

This page covers the process for contributing to and updating Gambit's :ref:`Games Catalog <pygambit-catalog>`.
To do so, you will need to have the `gambit` GitHub repo cloned and be able to submit pull request via GitHub;
you may wish to first review the :ref:`contributor guidelines <contributing>`.

You can add games to the catalog saved in a valid representation :ref:`format <file-formats>`.
Currently supported representations are:

- `.efg` for extensive form games
- `.nfg` for normal form games

Add new games
-------------

1. **Create the game file:**

Use either :ref:`pygambit <pygambit>`, the Gambit :ref:`CLI <command-line>` or :ref:`GUI <section-gui>` to create and save game in a valid representation :ref:`format <file-formats>`.

2. **Add the game file:**

Create a new branch in the ``gambit`` repo. Add your new game file(s) inside the ``catalog`` dir and commit them.

3. **Update the catalog:**

Use the ``update.py`` script to update Gambit's documentation & build files.

.. code-block:: bash

python build_support/catalog/update.py --build

.. note::

Run this script in a Python environment where ``pygambit`` itself is also :ref:`installed <build-python>`.

.. warning::

Running the script with the ``--build`` flag updates `Makefile.am`. If you moved games that were previously in `contrib/games` you'll need to also manually remove those files from `EXTRA_DIST`.

4. **Submit a pull request to GitHub with all changes.**

.. warning::

Make sure you commit all changed files e.g. run ``git add --all`` before committing and pushing.
23 changes: 10 additions & 13 deletions doc/developer.contributing.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _contributing:

Contributing to Gambit
======================

Expand Down Expand Up @@ -102,19 +104,16 @@ Be sure to familiarise yourself with :ref:`contributing-code` before reading thi
By default, pull requests on GitHub will trigger the running of Gambit's test suite using GitHub Actions.
You can also run the tests locally before submitting your pull request, using `pytest`.

1. Install the test dependencies (into the virtual environment where you installed PyGambit): ::

pip install -r tests/requirements.txt

2. Navigate to the Gambit repository and run the tests: ::
1. Ensure `pygambit` is installed with test dependencies: see :ref:`build-python`.

pytest
2. Run pytest: ::

3. [Optional] If you wish to run the tutorial notebook tests, you will need to add the ``--run-tutorials`` flag, which require the `doc` dependencies: ::

pip install -r doc/requirements.txt
pytest --run-tutorials

.. tip::
You can omit the `--run-tutorials` to skip running the tutorial notebook tests which take longest to run.
Running tests including tutorials requires `doc` as well as `test` dependencies; see :ref:`build-python`.

Adding to the test suite
^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -134,9 +133,7 @@ You can also build the documentation locally to preview your changes before subm

1. `Install Pandoc <https://pandoc.org/installing.html>`_ for your OS

2. Install the docs dependencies (into the virtual environment where you installed PyGambit): ::

pip install -r doc/requirements.txt
2. Ensure `pygambit` is installed with doc dependencies: see :ref:`build-python`.

3. Navigate to the Gambit repo and build the docs: ::

Expand All @@ -156,7 +153,7 @@ To submit a tutorial for inclusion in the Gambit documentation, please follow th

3. Update `doc/pygambit.rst` to ensure the tutorial is listed in the docs at an appropriate location.

4. *[Optional]* If your tutorial requires additional dependencies not already listed in `doc/requirements.txt`, please add them to the file.
4. *[Optional]* If your tutorial requires additional dependencies not already listed in the ``doc`` list under ``[project.optional-dependencies]`` inside ``pyproject.toml``, please add them to the file.


Recognising contributions
Expand Down
1 change: 1 addition & 0 deletions doc/developer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ This section contains information for developers who want to contribute to the G

developer.build
developer.contributing
developer.catalog
Loading
Loading