Source code for modelly.zoo.copy
"""Copy a zoo model into a folder of its own, to start a project from it."""
from __future__ import annotations
from pathlib import Path
from modelly.zoo.registry import ZooModel, get
MODEL_FILE = "model.py"
README_FILE = "README.md"
README_TEMPLATE = """\
# {title}
{summary}
Copied from the Modelly zoo (`modelly zoo info {name}`). Field: {field}.
Validated in the zoo against: {validation}.
```python
from model import {model}, {scenario}
model = {model}({scenario}(rng=42))
model.run()
model.datacollector.get_model_vars_dataframe()
```
The model's description and references are in the docstring of `model.py`.
"""
[docs]
def parameters(entry: ZooModel) -> dict[str, object]:
"""The scenario's parameters and their default values."""
_, scenario = entry.load()
return dict(scenario._scenario_defaults)
[docs]
def readme(entry: ZooModel) -> str:
"""The README written next to a copied model."""
return README_TEMPLATE.format(**vars(entry))
[docs]
def copy_model(name: str, directory: str | Path) -> list[Path]:
"""Write zoo model ``name`` into ``directory`` as ``model.py`` and ``README.md``.
The folder is created if needed. Nothing is overwritten.
Example:
>>> import tempfile
>>> folder = Path(tempfile.mkdtemp()) / "my_epidemic"
>>> [path.name for path in copy_model("age_seir", folder)]
['model.py', 'README.md']
Raises:
KeyError: if there is no zoo model ``name``.
FileExistsError: if ``model.py`` or ``README.md`` already exists there.
"""
entry = get(name)
folder = Path(directory)
targets = {
folder / MODEL_FILE: entry.source.read_text(encoding="utf-8"),
folder / README_FILE: readme(entry),
}
existing = [str(path) for path in targets if path.exists()]
if existing:
raise FileExistsError(f"Not overwriting {', '.join(existing)}.")
folder.mkdir(parents=True, exist_ok=True)
for path, text in targets.items():
path.write_text(text, encoding="utf-8", newline="\n")
return list(targets)