Python client for Josh ecological simulation runtime.
pip install joshpyFor parameter sweep functionality with Jinja templating:
pip install joshpy[jobs]For all optional dependencies:
pip install joshpy[all]from joshpy import Josh
client = Josh(server="https://your-josh-server.com", api_key="your-key")
code = """
start simulation Main
grid.size = 1000 m
grid.low = 33.7 degrees latitude, -115.4 degrees longitude
grid.high = 34.0 degrees latitude, -116.4 degrees longitude
steps.low = 0 count
steps.high = 10 count
end simulation
"""
# Check for errors
error = client.get_error(code)
if error:
print(f"Error: {error}")
# Get simulation metadata
metadata = client.get_metadata(code, "Main")
print(f"Grid size: {metadata.patch_size}")
# Run simulation
results = client.run_simulation(code, "Main", virtual_files=[], replicates=3)Generate multiple configuration files from a single template:
from pathlib import Path
from joshpy.jobs import JobConfig, SweepConfig, SweepParameter, JobExpander, to_run_config
from joshpy.cli import JoshCLI
# Define sweep configuration
config = JobConfig(
template_path=Path("templates/sweep_config.jshc.j2"),
source_path=Path("simulation.josh"),
simulation="Main",
sweep=SweepConfig(
parameters=[
SweepParameter(name="survivalProb", values=[85, 90, 95]),
SweepParameter(name="seedCount", values=[1000, 2000, 4000]),
]
),
)
# Expand to 3x3 = 9 concrete jobs
expander = JobExpander()
job_set = expander.expand(config)
# Execute via Josh CLI
cli = JoshCLI()
for job in job_set:
run_config = to_run_config(job)
result = cli.run(run_config)
status = "OK" if result.success else "FAIL"
print(f"[{status}] {job.parameters}")Use the CLI wrapper directly for individual commands:
from pathlib import Path
from joshpy.cli import JoshCLI, RunConfig, PreprocessConfig, ValidateConfig
cli = JoshCLI()
# Validate a Josh script
result = cli.validate(ValidateConfig(script=Path("simulation.josh")))
if not result.success:
print(f"Validation failed: {result.stderr}")
# Preprocess external data
result = cli.preprocess(PreprocessConfig(
script=Path("simulation.josh"),
simulation="Main",
data_file=Path("temperature.nc"),
variable="temp",
units="K",
output=Path("temperature.jshd"),
))
# Run a simulation
result = cli.run(RunConfig(
script=Path("simulation.josh"),
simulation="Main",
replicates=5,
data={"climate": Path("temperature.jshd")},
output=Path("results.csv"),
output_format="csv",
))Define sweeps in YAML for easier management:
# sweep_config.yaml
template_path: templates/sweep_config.jshc.j2
source_path: simulation.josh
simulation: Main
replicates: 3
sweep:
parameters:
# Explicit values
- name: scenario
values: [baseline, optimistic, pessimistic]
# Range with step (like numpy.arange)
- name: survivalProb
range: {start: 80, stop: 100, step: 5}
# Range with count (like numpy.linspace)
- name: seedCount
range: {start: 1000, stop: 5000, num: 5}Load and run:
from joshpy.jobs import JobExpander, to_run_config
from joshpy.cli import JoshCLI
config = JobConfig.from_yaml_file(Path("sweep_config.yaml"))
job_set = JobExpander().expand(config)
cli = JoshCLI()
for job in job_set:
result = cli.run(to_run_config(job))
print(f"[{'OK' if result.success else 'FAIL'}] {job.parameters}")Open in VS Code with the Dev Containers extension, or use GitHub Codespaces.
# Clone the repository
git clone https://github.com/SchmidtDSE/joshpy.git
cd joshpy
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
# Install with development dependencies
pip install -e ".[all,dev]"
# Run tests
python -m pytest joshpy/test_*.py -v
# Type checking
mypy joshpy/
# Linting
ruff check joshpy/BSD-3-Clause. See LICENSE for details.