diff --git a/babelizer/data/cookiecutter.json b/babelizer/data/cookiecutter.json index 3c2432eb..920018d9 100644 --- a/babelizer/data/cookiecutter.json +++ b/babelizer/data/cookiecutter.json @@ -6,7 +6,8 @@ "libraries": [], "library_dirs": [], "include_dirs": [], - "extra_compile_args": [] + "extra_compile_args": [], + "max_instances": 3 }, "info": { "full_name": "CSDMS", diff --git a/babelizer/data/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/lib/bmi_interoperability.f90 b/babelizer/data/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/lib/bmi_interoperability.f90 index 91ba3049..80bf7580 100644 --- a/babelizer/data/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/lib/bmi_interoperability.f90 +++ b/babelizer/data/{{cookiecutter.package_name}}/{{cookiecutter.package_name}}/lib/bmi_interoperability.f90 @@ -17,7 +17,7 @@ module bmi_interoperability implicit none - integer, parameter :: N_MODELS = 2048 + integer, parameter :: N_MODELS = {{ cookiecutter.build.max_instances }} type ({{ component.entry_point }}) :: model_array(N_MODELS) logical :: model_avail(N_MODELS) = .true. diff --git a/babelizer/metadata.py b/babelizer/metadata.py index 03be4d76..5bee02d0 100644 --- a/babelizer/metadata.py +++ b/babelizer/metadata.py @@ -230,6 +230,7 @@ def validate(config): "library_dirs", "include_dirs", "extra_compile_args", + "max_instances", ), ) validate_dict(config["package"], required=("name", "requirements"), optional={}) @@ -313,6 +314,9 @@ def norm(config): except KeyError: pass + if "max_instances" not in build: + build["max_instances"] = 8 + if "entry_point" in config["library"]: libraries = BabelMetadata._handle_old_style_entry_points(config["library"]) else: @@ -335,6 +339,7 @@ def norm(config): "library_dirs": build["library_dirs"], "include_dirs": build["include_dirs"], "extra_compile_args": build["extra_compile_args"], + "max_instances": build["max_instances"], }, "package": { "name": config["package"]["name"], @@ -446,6 +451,7 @@ def as_cookiecutter_context(self): "library_dirs": self._meta["build"]["library_dirs"], "include_dirs": self._meta["build"]["include_dirs"], "extra_compile_args": self._meta["build"]["extra_compile_args"], + "max_instances": self._meta["build"]["max_instances"], }, "info": { "full_name": self._meta["info"]["package_author"], diff --git a/external/tests/test_fortran.py b/external/tests/test_fortran.py index f1a5fba9..905a6d2a 100644 --- a/external/tests/test_fortran.py +++ b/external/tests/test_fortran.py @@ -6,6 +6,9 @@ import subprocess import sys +import git +import pytest +import toml from click.testing import CliRunner from babelizer.cli import babelize @@ -16,17 +19,59 @@ extra_opts += ["--no-build-isolation"] -def test_babelize_init_fortran(tmpdir, datadir): - runner = CliRunner() +@pytest.mark.dependency() +def test_babelize_init_works(tmpdir, datadir): + runner = CliRunner(mix_stderr=False) + with tmpdir.as_cwd(): + result = runner.invoke(babelize, ["init", str(datadir / "babel.toml")]) + + assert result.stdout.strip() == str(tmpdir / "pymt_heatf") + assert result.exit_code == 0 + assert pathlib.Path("pymt_heatf").exists() + assert (pathlib.Path("pymt_heatf") / "babel.toml").is_file() + + repo = git.Repo("pymt_heatf") + + assert not repo.bare + + +@pytest.mark.dependency(depends=["test_babelize_init_works"]) +@pytest.mark.parametrize("max_instances", [8, 32, None]) +def test_babelize_init_fortran_with_user_instances(tmpdir, datadir, max_instances): + runner = CliRunner(mix_stderr=False) + + babel_toml = toml.load(datadir / "babel.toml") + babel_toml["build"]["max_instances"] = max_instances + + if max_instances is None: + babel_toml["build"].pop("max_instances", None) + max_instances = 8 with tmpdir.as_cwd(): - shutil.copy(datadir / "babel.toml", ".") + with open("babel.toml", "w") as fp: + toml.dump(babel_toml, fp) + result = runner.invoke(babelize, ["init", "babel.toml"]) + assert result.stdout.strip() == str(tmpdir / "pymt_heatf") assert result.exit_code == 0 assert pathlib.Path("pymt_heatf").exists() assert (pathlib.Path("pymt_heatf") / "babel.toml").is_file() + meta = toml.load("pymt_heatf/babel.toml") + + assert "max_instances" in meta["build"] + assert meta["build"]["max_instances"] == max_instances + + +@pytest.mark.dependency(depends=["test_babelize_init_works"]) +def test_babelize_build_fortran_example(tmpdir, datadir): + runner = CliRunner(mix_stderr=False) + + with tmpdir.as_cwd(): + runner.invoke(babelize, ["init", str(datadir / "babel.toml")]) + + with tmpdir.as_cwd(): try: result = subprocess.run( ["pip", "install", "-e", "."] + extra_opts, @@ -63,3 +108,18 @@ def test_babelize_init_fortran(tmpdir, datadir): assert err.output is None, err.output assert result.returncode == 0 + + +@pytest.mark.dependency(depends=["test_babelize_init_works"]) +def test_babelize_update_fortran(tmpdir, datadir): + runner = CliRunner(mix_stderr=False) + + with tmpdir.as_cwd(): + runner.invoke(babelize, ["init", str(datadir / "babel.toml")]) + + with tmpdir.as_cwd(): + result = runner.invoke(babelize, ["--cd", "pymt_heatf", "update"]) + + assert result.exit_code == 0 + assert pathlib.Path("pymt_heatf").exists() + assert "re-rendering" in result.stderr