Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
084550c
feat: modernize test infrastructure with entry-point model discovery
pgierz Mar 27, 2026
3ee01f9
feat: add tutorial dataset system with xarray.tutorial-like API
pgierz Mar 27, 2026
0c64694
fix: handle absolute symlinks in tarballs on Python 3.12+ (tarfile fi…
pgierz Mar 30, 2026
0ab52d4
fix: convert loader doctests to code-blocks and update pi_uxarray URL…
pgierz Mar 30, 2026
ba35add
fix: use pycmor.enable_xarray_accessor() instead of pycmor.accessors …
pgierz Mar 30, 2026
969e328
fix: use valid CMIP6 source_id (AWI-ESM-1-1-LR instead of FESOM)
pgierz Mar 30, 2026
690e750
fix: unpin external test data package and use configs dict in accesso…
pgierz Mar 30, 2026
8456e44
fix: Python 3.9 entry_points() compatibility in CLI (cherry-pick from…
pgierz Mar 30, 2026
081502e
fix: extract tarballs into cache_dir directly to avoid double nesting
pgierz Mar 30, 2026
c4be8f9
fix: add PYCMOR_FORCE_REEXTRACT env var to bypass stale extraction cache
pgierz Mar 30, 2026
f4a5b15
fix: tutorial data_fetcher also had double-nesting extraction bug
pgierz Mar 30, 2026
71efbd6
debug: add logging to get_variable to trace model_variable value
pgierz Mar 30, 2026
966170e
debug: run only fesom_2p6-native-nodask-cmip6 with model_variable tra…
pgierz Mar 30, 2026
ebc26d0
ci: restore full integration tests with PYCMOR_FORCE_REEXTRACT on all…
pgierz Mar 30, 2026
9e5964a
ci: trigger rebuild to pick up fesom_dev config fixes from external p…
pgierz Mar 30, 2026
6be2697
fix: accept DataArray results in test_library_process assertions
pgierz Mar 31, 2026
e8a812c
fix: pin pycmor-test-data-fesom to v0.2.0
pgierz Mar 31, 2026
105475c
fix: set output_directory on per-rule level in test_cli_process
pgierz Mar 31, 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
115 changes: 115 additions & 0 deletions .github/scripts/discover_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python
"""Discover registered model runs and orchestrator configs for GitHub Actions matrix.

This script outputs JSON for both models and orchestrator configurations that
can be used in a GitHub Actions matrix strategy.

This script only reads entry point names without loading the classes, so it
doesn't require test dependencies to be installed.
"""

import importlib.metadata
import json
import sys


def discover_model_names():
"""Discover registered model run names from entry points.

Returns just the entry point names without loading the actual classes,
so this works even without test dependencies installed.
"""
# Python 3.9 vs 3.10+ compatibility
try:
# Try Python 3.10+ API first
eps = importlib.metadata.entry_points(group="pycmor.fixtures.model_runs")
except TypeError:
# Fall back to Python 3.9 API
all_eps = importlib.metadata.entry_points()
eps = all_eps.get("pycmor.fixtures.model_runs", [])

# Just get the names, don't load the classes
model_names = [ep.name for ep in eps]

return model_names


def get_orchestrator_configs():
"""Get orchestrator configurations for the test matrix.

Returns the standard orchestrator configurations used in integration tests.
This is the single source of truth for orchestrator combinations.
"""
return [
{
"id": "prefect-dask",
"pipeline_workflow_orchestrator": "prefect",
"enable_dask": "yes",
},
{
"id": "native-dask",
"pipeline_workflow_orchestrator": "native",
"enable_dask": "yes",
},
{
"id": "native-nodask",
"pipeline_workflow_orchestrator": "native",
"enable_dask": "no",
},
]


def main():
"""Discover models and orchestrators, output as JSON for GitHub Actions matrix."""
import argparse

parser = argparse.ArgumentParser(description="Discover models and orchestrators for CI matrix")
parser.add_argument(
"--output",
choices=["models", "orchestrators", "both"],
default="models",
help="What to output",
)
args = parser.parse_args()

try:
if args.output == "models":
model_names = discover_model_names()
model_names = sorted(model_names)
print(json.dumps(model_names))
print(
f"# Discovered {len(model_names)} models: {', '.join(model_names)}",
file=sys.stderr,
)
elif args.output == "orchestrators":
orchestrators = get_orchestrator_configs()
print(json.dumps(orchestrators))
orchestrator_ids = [o["id"] for o in orchestrators]
print(
f"# Orchestrators: {', '.join(orchestrator_ids)}",
file=sys.stderr,
)
elif args.output == "both":
result = {
"models": sorted(discover_model_names()),
"orchestrators": get_orchestrator_configs(),
}
print(json.dumps(result))
print(
f"# Discovered {len(result['models'])} models and {len(result['orchestrators'])} orchestrator configs",
file=sys.stderr,
)

return 0
except Exception as e:
print(f"# Error discovering CI matrix config: {e}", file=sys.stderr)
# Return empty array/object on error so workflow doesn't fail
if args.output == "both":
print('{"models": [], "orchestrators": []}')
else:
print("[]")
return 1


if __name__ == "__main__":
sys.exit(main())
4 changes: 4 additions & 0 deletions .github/workflows/CI-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ jobs:
run: |
docker run --rm \
-e PYCMOR_USE_REAL_TEST_DATA=1 \
-e PYCMOR_FORCE_REEXTRACT=1 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_ENGINE=netcdf4 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_PARALLEL=no \
-e PREFECT_SERVER_EPHEMERAL_STARTUP_TIMEOUT_SECONDS=300 \
Expand Down Expand Up @@ -663,6 +664,7 @@ jobs:
run: |
docker run --rm \
-e PYCMOR_USE_REAL_TEST_DATA=1 \
-e PYCMOR_FORCE_REEXTRACT=1 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_ENGINE=netcdf4 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_PARALLEL=no \
-e PREFECT_SERVER_EPHEMERAL_STARTUP_TIMEOUT_SECONDS=300 \
Expand Down Expand Up @@ -709,6 +711,7 @@ jobs:
run: |
docker run --rm \
-e PYCMOR_USE_REAL_TEST_DATA=1 \
-e PYCMOR_FORCE_REEXTRACT=1 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_ENGINE=netcdf4 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_PARALLEL=no \
-e PREFECT_SERVER_EPHEMERAL_STARTUP_TIMEOUT_SECONDS=300 \
Expand Down Expand Up @@ -755,6 +758,7 @@ jobs:
run: |
docker run --rm \
-e PYCMOR_USE_REAL_TEST_DATA=1 \
-e PYCMOR_FORCE_REEXTRACT=1 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_ENGINE=netcdf4 \
-e PYCMOR_XARRAY_OPEN_MFDATASET_PARALLEL=no \
-e PREFECT_SERVER_EPHEMERAL_STARTUP_TIMEOUT_SECONDS=300 \
Expand Down
Loading
Loading