py-modelrunner 0.16.0__tar.gz → 0.17.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/PKG-INFO +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/user_manual.rst +3 -2
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/io_hdf.py +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/io_json.py +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/io_yaml.py +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/model_storage_output.py +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/script_function.py +1 -1
- py-modelrunner-0.17.0/modelrunner/.gitignore +1 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/_version.py +2 -2
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/model.py +14 -8
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/results.py +36 -7
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/run/job.py +16 -10
- py-modelrunner-0.17.0/modelrunner/run/templates/background.jinja +27 -0
- py-modelrunner-0.17.0/modelrunner/run/templates/foreground.jinja +26 -0
- py-modelrunner-0.16.0/modelrunner/run/templates/qsub.template → py-modelrunner-0.17.0/modelrunner/run/templates/qsub.jinja +8 -8
- py-modelrunner-0.16.0/modelrunner/run/templates/srun.template → py-modelrunner-0.17.0/modelrunner/run/templates/srun.jinja +8 -8
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/memory.py +15 -9
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/group.py +42 -8
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/tools.py +4 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/PKG-INFO +1 -1
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/SOURCES.txt +7 -4
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/pyproject.toml +5 -2
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/test_compatibility.py +2 -2
- py-modelrunner-0.17.0/tests/run/scripts/fail.py +3 -0
- py-modelrunner-0.17.0/tests/run/scripts/print.py +3 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/run/test_job.py +43 -4
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/storage/test_group.py +15 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/storage/test_storage_generic.py +8 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/storage/test_trajectory.py +2 -2
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_model.py +27 -27
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_results.py +5 -5
- py-modelrunner-0.16.0/modelrunner/run/templates/background.template +0 -29
- py-modelrunner-0.16.0/modelrunner/run/templates/foreground.template +0 -29
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.github/workflows/build.yml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.github/workflows/check_docs.yml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.github/workflows/coverage_report.yml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.github/workflows/release_pip.yml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.gitignore +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/.readthedocs.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/LICENSE +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/README.md +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/Makefile +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/build_all.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/requirements.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/.gitignore +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/conf.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/examples.rst +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/index.rst +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/installation.rst +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/parse_examples.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/run_autodoc.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/docs/source/sphinx_simplify_typehints.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/model_class.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/model_decorator.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/model_function.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/read_many.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/script_custom_func.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/script_many_classes.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/script_minimal.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/script_model_class.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/submit_function.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/submit_many_func.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/submit_many_iter.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/examples/submit_shebang.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/__main__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/compatibility/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/compatibility/triage.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/compatibility/version0.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/compatibility/version1.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/config.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/parameters.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/py.typed +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/run/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/run/__main__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/access_modes.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/attributes.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/hdf.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/json.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/text_base.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/utils.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/yaml.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/backend/zarr.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/base.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/trajectory.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/storage/utils.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/modelrunner/utils.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/dependency_links.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/not-zip-safe +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/requires.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/py_modelrunner.egg-info/top_level.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/requirements.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/requirements_full.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/create_compatibility_files.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/format_code.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/performance_hdf5_zarr.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/run_tests.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_all.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_codestyle.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_coverage.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_parallel.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_run.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/scripts/tests_types.sh +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/setup.cfg +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/0/result.hdf +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/0/result.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/0/result.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/0/result.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array.zarr +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array_col.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array_col.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array_col.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/array_col.zarr +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/dict.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/dict.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/dict.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/dict.zarr +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/object.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/object.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/object.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/1/object.zarr +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array.hdf +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array.zip +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array_col.hdf +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array_col.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array_col.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array_col.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/array_col.zip +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/dict.hdf +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/dict.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/dict.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/dict.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/dict.zip +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/nested.hdf +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/nested.json +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/nested.pkl +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/nested.yaml +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/compatibility/2/nested.zip +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/conftest.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/helpers/__init__.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/helpers/asserts.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/helpers/storage.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/requirements.txt +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/run/scripts/function.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/run/scripts/script.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/run/test_run_main.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/empty.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/function.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/function_main.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/function_marked.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/make_model.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/make_model_class.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/scripts/make_model_marked.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/storage/test_storage_special.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/storage/test_utils.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_config.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_examples.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_main.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_parameters.py +0 -0
- {py-modelrunner-0.16.0 → py-modelrunner-0.17.0}/tests/test_version.py +0 -0
|
@@ -43,11 +43,12 @@ The main requirements for the storage classes were
|
|
|
43
43
|
- *Usability*: The user should not need to think about how data is stored in different files
|
|
44
44
|
- *Flexibility*: We want a general interface to write data in multiple file formats (YAML, HDF, zarr, ...)
|
|
45
45
|
- *Stability*: Future versions of the package should be able to read older files even when the internal definitions of file formats change
|
|
46
|
-
- *
|
|
46
|
+
- *Modularity*: Different parts of the package (like :mod:`~modelrunner.storage`, :mod:`~modelrunner.parameters`, and :mod:`~modelrunner.run`) should be rather independent of each other, so they can be used in isolation
|
|
47
|
+
- *Extensibility*: Models should be easy to subclass to implement more complicated requirements (e.g., additional parameters)
|
|
47
48
|
- *Self-explainability*: The files should in principle contain all information to reconstruct the data, even if the `py-modelrunner` package is no longer available.
|
|
48
49
|
- *Efficiency*: The files should only store necessary information.
|
|
49
50
|
|
|
50
51
|
The last point results in particular constraints if we want to store temporal simulation results.
|
|
51
52
|
In most cases, there are are some data that are kept fixed for the simulation (describing physical parameters) and others that evolve with time.
|
|
52
53
|
We denote by `attributes` the parameters that are kept fixed and by `data` the data that varies over time.
|
|
53
|
-
The
|
|
54
|
+
The :mod:`~modelrunner.storage.trajectory` module deals with such data.
|
|
@@ -24,4 +24,4 @@ with tempfile.NamedTemporaryFile(suffix=".yaml") as fp:
|
|
|
24
24
|
# read the file and check whether all the data is there
|
|
25
25
|
with open_storage(fp.name) as storage:
|
|
26
26
|
print("Stored data:", storage["data"])
|
|
27
|
-
print("Model result:", storage["result"].
|
|
27
|
+
print("Model result:", storage["result"].result)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/_version.py
|
|
@@ -64,7 +64,11 @@ class ModelBase(Parameterized, metaclass=ABCMeta):
|
|
|
64
64
|
:meth:`~Parameterized.get_parameters` or displayed by calling
|
|
65
65
|
:meth:`~Parameterized.show_parameters`.
|
|
66
66
|
output (str):
|
|
67
|
-
Path where the output file will be written.
|
|
67
|
+
Path where the output file will be written. The output will be written
|
|
68
|
+
using :mod:`~modelrunner.storage` and might contain two groups: `result`
|
|
69
|
+
to which the final result of the model is written, and `data`, which
|
|
70
|
+
can contain extra information that is written using
|
|
71
|
+
:attr:`~ModelBase.storage`.
|
|
68
72
|
mode (str or :class:`~modelrunner.storage.access_modes.ModeType`):
|
|
69
73
|
The file mode with which the storage is accessed, which determines the
|
|
70
74
|
allowed operations. Common options are "read", "full", "append", and
|
|
@@ -87,7 +91,9 @@ class ModelBase(Parameterized, metaclass=ABCMeta):
|
|
|
87
91
|
if self.output is None:
|
|
88
92
|
raise RuntimeError("Output file needs to be specified")
|
|
89
93
|
self._storage = open_storage(self.output, mode=self.mode)
|
|
90
|
-
|
|
94
|
+
return self._storage.create_group("data")
|
|
95
|
+
else:
|
|
96
|
+
return self._storage.open_group("data")
|
|
91
97
|
|
|
92
98
|
def close(self) -> None:
|
|
93
99
|
"""close any opened storages"""
|
|
@@ -124,21 +130,21 @@ class ModelBase(Parameterized, metaclass=ABCMeta):
|
|
|
124
130
|
result:
|
|
125
131
|
The result data. If omitted, the model is run to obtain results
|
|
126
132
|
"""
|
|
133
|
+
from .results import Result # @Reimport
|
|
134
|
+
|
|
127
135
|
if self.output is None:
|
|
128
136
|
raise RuntimeError("Output file needs to be specified")
|
|
129
137
|
|
|
130
138
|
if result is None:
|
|
131
139
|
result = self.get_result()
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
assert isinstance(result, Result)
|
|
140
|
+
elif not isinstance(result, Result):
|
|
141
|
+
raise TypeError(f"result has type {result.__class__} instead of `Result`")
|
|
136
142
|
|
|
137
143
|
if self._storage is not None:
|
|
138
144
|
# reuse the opened storage
|
|
139
|
-
result.to_file(self.
|
|
145
|
+
result.to_file(self._storage, loc="result")
|
|
140
146
|
else:
|
|
141
|
-
result.to_file(self.output, mode=self.mode)
|
|
147
|
+
result.to_file(self.output, loc="result", mode=self.mode)
|
|
142
148
|
|
|
143
149
|
@classmethod
|
|
144
150
|
def _prepare_argparser(cls, name: str | None = None) -> argparse.ArgumentParser:
|
|
@@ -47,7 +47,12 @@ class Result:
|
|
|
47
47
|
"""int: number indicating the version of the file format"""
|
|
48
48
|
|
|
49
49
|
def __init__(
|
|
50
|
-
self,
|
|
50
|
+
self,
|
|
51
|
+
model: ModelBase,
|
|
52
|
+
result: Any,
|
|
53
|
+
*,
|
|
54
|
+
storage: StorageID = None,
|
|
55
|
+
info: dict[str, Any] | None = None,
|
|
51
56
|
):
|
|
52
57
|
"""
|
|
53
58
|
Args:
|
|
@@ -55,18 +60,23 @@ class Result:
|
|
|
55
60
|
The model from which the result was obtained
|
|
56
61
|
result:
|
|
57
62
|
The actual result
|
|
63
|
+
storage:
|
|
64
|
+
A storage containing additional data from the model run
|
|
58
65
|
info (dict):
|
|
59
66
|
Additional information for this result
|
|
60
67
|
"""
|
|
61
68
|
if not isinstance(model, ModelBase):
|
|
62
69
|
raise TypeError("The model should be of type `ModelBase`")
|
|
63
|
-
self.model = model
|
|
64
70
|
self.result = result
|
|
71
|
+
self.model = model
|
|
72
|
+
self.storage = storage
|
|
65
73
|
self.info: Attrs = {} if info is None else info
|
|
66
74
|
|
|
67
75
|
@property
|
|
68
76
|
def data(self):
|
|
69
77
|
"""direct access to the underlying state data"""
|
|
78
|
+
# deprecated on 2024-04-13
|
|
79
|
+
warnings.warn("`.data` attribute was renamed to `.result`", DeprecationWarning)
|
|
70
80
|
return self.result
|
|
71
81
|
|
|
72
82
|
@classmethod
|
|
@@ -74,7 +84,9 @@ class Result:
|
|
|
74
84
|
cls,
|
|
75
85
|
model_data: dict[str, Any],
|
|
76
86
|
result,
|
|
87
|
+
*,
|
|
77
88
|
model: ModelBase | None = None,
|
|
89
|
+
storage: StorageID = None,
|
|
78
90
|
info: dict[str, Any] | None = None,
|
|
79
91
|
) -> Result:
|
|
80
92
|
"""create result from data
|
|
@@ -86,6 +98,8 @@ class Result:
|
|
|
86
98
|
The actual result data
|
|
87
99
|
model (:class:`ModelBase`):
|
|
88
100
|
The model from which the result was obtained
|
|
101
|
+
storage:
|
|
102
|
+
A storage containing additional data from the model run
|
|
89
103
|
info (dict):
|
|
90
104
|
Additional information for this result
|
|
91
105
|
|
|
@@ -103,7 +117,7 @@ class Result:
|
|
|
103
117
|
model.name = model_data.get("name")
|
|
104
118
|
model.description = model_data.get("description")
|
|
105
119
|
|
|
106
|
-
return cls(model, result, info)
|
|
120
|
+
return cls(model, result, storage=storage, info=info)
|
|
107
121
|
|
|
108
122
|
@property
|
|
109
123
|
def parameters(self) -> dict[str, Any]:
|
|
@@ -119,13 +133,20 @@ class Result:
|
|
|
119
133
|
):
|
|
120
134
|
"""load object from a file
|
|
121
135
|
|
|
136
|
+
This function loads the results from a hierachical storage. It also attempts to
|
|
137
|
+
read information about the model that was used to create this result and
|
|
138
|
+
additional data that might have been stored in a
|
|
139
|
+
:attr:`~modelrunner.results.Result.storage` while the model was running.
|
|
140
|
+
|
|
122
141
|
Args:
|
|
123
142
|
store (str or :class:`zarr.Store`):
|
|
124
143
|
Path or instance describing the storage, which is either a file path or
|
|
125
144
|
a :class:`zarr.Storage`.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
145
|
+
loc:
|
|
146
|
+
The location where the result is stored in the storage. This should
|
|
147
|
+
rarely be modified.
|
|
148
|
+
model (:class:`~modelrunner.model.ModelBase`):
|
|
149
|
+
The model which lead to this result
|
|
129
150
|
"""
|
|
130
151
|
if isinstance(storage, (str, Path)):
|
|
131
152
|
# check whether the file was written with an old format version
|
|
@@ -141,10 +162,15 @@ class Result:
|
|
|
141
162
|
format_version = attrs.pop("format_version", None)
|
|
142
163
|
if format_version == cls._format_version:
|
|
143
164
|
# current version of storing results
|
|
165
|
+
if "data" in storage_obj:
|
|
166
|
+
data_storage = open_storage(storage, loc="data", mode="read")
|
|
167
|
+
else:
|
|
168
|
+
data_storage = None
|
|
144
169
|
return cls.from_data(
|
|
145
170
|
model_data=attrs.get("model", {}),
|
|
146
171
|
result=storage_obj.read_item(loc, use_class=False),
|
|
147
172
|
model=model,
|
|
173
|
+
storage=data_storage,
|
|
148
174
|
info=attrs.pop("info", {}), # load additional info,
|
|
149
175
|
)
|
|
150
176
|
|
|
@@ -154,7 +180,10 @@ class Result:
|
|
|
154
180
|
def to_file(
|
|
155
181
|
self, storage: StorageID, loc: str = "result", *, mode: ModeType = "insert"
|
|
156
182
|
) -> None:
|
|
157
|
-
"""write
|
|
183
|
+
"""write the results to a file
|
|
184
|
+
|
|
185
|
+
Note that this does only write the actual `results` but omits additional data
|
|
186
|
+
that might have been stored in a storage that is associated with the results.
|
|
158
187
|
|
|
159
188
|
Args:
|
|
160
189
|
storage (:class:`StorageBase` or :class:`StorageGroup`):
|
|
@@ -11,7 +11,7 @@ import itertools
|
|
|
11
11
|
import json
|
|
12
12
|
import logging
|
|
13
13
|
import os
|
|
14
|
-
import
|
|
14
|
+
import shlex
|
|
15
15
|
import subprocess as sp
|
|
16
16
|
import sys
|
|
17
17
|
import warnings
|
|
@@ -26,7 +26,7 @@ from ..parameters import Parameter
|
|
|
26
26
|
|
|
27
27
|
def escape_string(obj) -> str:
|
|
28
28
|
"""escape a string for the command line"""
|
|
29
|
-
return
|
|
29
|
+
return shlex.quote(str(obj))
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def ensure_directory_exists(folder):
|
|
@@ -130,7 +130,7 @@ def submit_job(
|
|
|
130
130
|
parameters: str | dict[str, Any] | None = None,
|
|
131
131
|
config: str | dict[str, Any] | None = None,
|
|
132
132
|
*,
|
|
133
|
-
log_folder: str | Path =
|
|
133
|
+
log_folder: str | Path | None = None,
|
|
134
134
|
method: str = "auto",
|
|
135
135
|
use_modelrunner: bool = True,
|
|
136
136
|
template: str | Path | None = None,
|
|
@@ -153,7 +153,10 @@ def submit_job(
|
|
|
153
153
|
Configuration for the job, which determines how the job is run. Can be either
|
|
154
154
|
a python dictionary or a string containing a JSON-encoded dictionary.
|
|
155
155
|
log_folder (str of :class:`~pathlib.Path`):
|
|
156
|
-
Path to the logging folder
|
|
156
|
+
Path to the logging folder. If omitted, the default of the template is used,
|
|
157
|
+
which typically sends data to stdout for local scripts (which is thus
|
|
158
|
+
captured and returned by this function) or writes log files to the current
|
|
159
|
+
working directory for remote jobs.
|
|
157
160
|
method (str):
|
|
158
161
|
Specifies the submission method. Currently `background`, `foreground`,
|
|
159
162
|
'srun', and `qsub` are supported. The special value `auto` reads the method
|
|
@@ -169,7 +172,9 @@ def submit_job(
|
|
|
169
172
|
`error`, `warn_skip`, `silent_skip`, `overwrite`, and `silent_overwrite`.
|
|
170
173
|
|
|
171
174
|
Returns:
|
|
172
|
-
tuple: The result `(stdout, stderr)` of the submission call
|
|
175
|
+
tuple: The result `(stdout, stderr)` of the submission call. These two strings
|
|
176
|
+
can contain the output from the actual scripts that is run when `log_folder`
|
|
177
|
+
is `None`.
|
|
173
178
|
"""
|
|
174
179
|
from jinja2 import Template
|
|
175
180
|
|
|
@@ -191,7 +196,7 @@ def submit_job(
|
|
|
191
196
|
|
|
192
197
|
# load the correct template
|
|
193
198
|
if template is None:
|
|
194
|
-
template_path = Path(__file__).parent / "templates" / (method + ".
|
|
199
|
+
template_path = Path(__file__).parent / "templates" / (method + ".jinja")
|
|
195
200
|
else:
|
|
196
201
|
template_path = Path(template)
|
|
197
202
|
logger.info("Load template `%s`", template_path)
|
|
@@ -199,15 +204,16 @@ def submit_job(
|
|
|
199
204
|
script_template = fp.read()
|
|
200
205
|
|
|
201
206
|
# prepare submission script
|
|
202
|
-
ensure_directory_exists(log_folder)
|
|
203
207
|
script_args: dict[str, Any] = {
|
|
204
208
|
"PACKAGE_PATH": Path(__file__).parents[2],
|
|
205
|
-
"LOG_FOLDER": log_folder,
|
|
206
209
|
"JOB_NAME": name,
|
|
207
210
|
"MODEL_FILE": escape_string(script),
|
|
208
211
|
"USE_MODELRUNNER": use_modelrunner,
|
|
209
212
|
"CONFIG": configuration,
|
|
210
213
|
}
|
|
214
|
+
if log_folder is not None:
|
|
215
|
+
ensure_directory_exists(log_folder)
|
|
216
|
+
script_args["LOG_FOLDER"] = log_folder
|
|
211
217
|
|
|
212
218
|
# add the parameters to the job arguments
|
|
213
219
|
job_args = []
|
|
@@ -244,9 +250,9 @@ def submit_job(
|
|
|
244
250
|
|
|
245
251
|
# check whether output points to a directory or whether this should be a file
|
|
246
252
|
if output.is_dir():
|
|
247
|
-
script_args["OUTPUT_FOLDER"] =
|
|
253
|
+
script_args["OUTPUT_FOLDER"] = shlex.quote(str(output))
|
|
248
254
|
else:
|
|
249
|
-
script_args["OUTPUT_FOLDER"] =
|
|
255
|
+
script_args["OUTPUT_FOLDER"] = shlex.quote(str(output.parent))
|
|
250
256
|
job_args.append(f"--output {escape_string(output)}")
|
|
251
257
|
|
|
252
258
|
else:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/bin/bash -l
|
|
2
|
+
|
|
3
|
+
export PYTHONPATH={{ PACKAGE_PATH }}:$PYTHONPATH
|
|
4
|
+
|
|
5
|
+
{% if CONFIG.num_threads is number %}
|
|
6
|
+
# set the number of threads to use
|
|
7
|
+
export MKL_NUM_THREADS={{ CONFIG.num_threads }}
|
|
8
|
+
export NUMBA_NUM_THREADS={{ CONFIG.num_threads }}
|
|
9
|
+
export NUMEXPR_NUM_THREADS={{ CONFIG.num_threads }}
|
|
10
|
+
export OMP_NUM_THREADS={{ CONFIG.num_threads }}
|
|
11
|
+
export OPENBLAS_NUM_THREADS={{ CONFIG.num_threads }}
|
|
12
|
+
{% endif %}
|
|
13
|
+
|
|
14
|
+
{% if OUTPUT_FOLDER is defined and OUTPUT_FOLDER %}
|
|
15
|
+
mkdir -p {{ OUTPUT_FOLDER }}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
# Run the program in the background
|
|
19
|
+
nohup {{ CONFIG.python_bin }} \
|
|
20
|
+
{% if USE_MODELRUNNER is defined and USE_MODELRUNNER %} -m modelrunner {% endif %} \
|
|
21
|
+
{{ MODEL_FILE }} \
|
|
22
|
+
{{ JOB_ARGS }} \
|
|
23
|
+
{% if LOG_FOLDER is defined -%}
|
|
24
|
+
> {{ LOG_FOLDER }}/{{ JOB_NAME }}.out.txt \
|
|
25
|
+
2> {{ LOG_FOLDER }}/{{ JOB_NAME }}.err.txt \
|
|
26
|
+
{% endif -%}
|
|
27
|
+
&
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash -l
|
|
2
|
+
|
|
3
|
+
export PYTHONPATH={{ PACKAGE_PATH }}:$PYTHONPATH
|
|
4
|
+
|
|
5
|
+
{% if CONFIG.num_threads is number %}
|
|
6
|
+
# set the number of threads to use
|
|
7
|
+
export MKL_NUM_THREADS={{ CONFIG.num_threads }}
|
|
8
|
+
export NUMBA_NUM_THREADS={{ CONFIG.num_threads }}
|
|
9
|
+
export NUMEXPR_NUM_THREADS={{ CONFIG.num_threads }}
|
|
10
|
+
export OMP_NUM_THREADS={{ CONFIG.num_threads }}
|
|
11
|
+
export OPENBLAS_NUM_THREADS={{ CONFIG.num_threads }}
|
|
12
|
+
{% endif %}
|
|
13
|
+
|
|
14
|
+
{% if OUTPUT_FOLDER is defined and OUTPUT_FOLDER %}
|
|
15
|
+
mkdir -p {{ OUTPUT_FOLDER }}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
# Run the program
|
|
19
|
+
{{ CONFIG.python_bin }} \
|
|
20
|
+
{% if USE_MODELRUNNER is defined and USE_MODELRUNNER %} -m modelrunner {% endif %} \
|
|
21
|
+
{{ MODEL_FILE }} \
|
|
22
|
+
{{ JOB_ARGS }} \
|
|
23
|
+
{% if LOG_FOLDER is defined -%}
|
|
24
|
+
> {{ LOG_FOLDER }}/{{ JOB_NAME }}.out.txt \
|
|
25
|
+
2> {{ LOG_FOLDER }}/{{ JOB_NAME }}.err.txt \
|
|
26
|
+
{% endif -%}
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
hostname
|
|
19
19
|
echo $JOB_ID
|
|
20
20
|
|
|
21
|
-
{% if CONFIG
|
|
21
|
+
{% if CONFIG.num_threads is number %}
|
|
22
22
|
# set the number of threads to use
|
|
23
|
-
export MKL_NUM_THREADS={{ CONFIG
|
|
24
|
-
export NUMBA_NUM_THREADS={{ CONFIG
|
|
25
|
-
export NUMEXPR_NUM_THREADS={{ CONFIG
|
|
26
|
-
export OMP_NUM_THREADS={{ CONFIG
|
|
27
|
-
export OPENBLAS_NUM_THREADS={{ CONFIG
|
|
23
|
+
export MKL_NUM_THREADS={{ CONFIG.num_threads }}
|
|
24
|
+
export NUMBA_NUM_THREADS={{ CONFIG.num_threads }}
|
|
25
|
+
export NUMEXPR_NUM_THREADS={{ CONFIG.num_threads }}
|
|
26
|
+
export OMP_NUM_THREADS={{ CONFIG.num_threads }}
|
|
27
|
+
export OPENBLAS_NUM_THREADS={{ CONFIG.num_threads }}
|
|
28
28
|
{% endif %}
|
|
29
29
|
|
|
30
30
|
{% if OUTPUT_FOLDER is defined and OUTPUT_FOLDER %}
|
|
@@ -33,7 +33,7 @@ mkdir -p {{ OUTPUT_FOLDER }}
|
|
|
33
33
|
|
|
34
34
|
# Run the program
|
|
35
35
|
{% if USE_MODELRUNNER is defined and USE_MODELRUNNER %}
|
|
36
|
-
{{ CONFIG
|
|
36
|
+
{{ CONFIG.python_bin }} -m modelrunner {{ MODEL_FILE }} {{ JOB_ARGS }}
|
|
37
37
|
{% else %}
|
|
38
|
-
{{ CONFIG
|
|
38
|
+
{{ CONFIG.python_bin }} {{ MODEL_FILE }} {{ JOB_ARGS }}
|
|
39
39
|
{% endif %}
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
hostname
|
|
17
17
|
echo $JOB_ID
|
|
18
18
|
|
|
19
|
-
{% if CONFIG
|
|
19
|
+
{% if CONFIG.num_threads is number %}
|
|
20
20
|
# set the number of threads to use
|
|
21
|
-
export MKL_NUM_THREADS={{ CONFIG
|
|
22
|
-
export NUMBA_NUM_THREADS={{ CONFIG
|
|
23
|
-
export NUMEXPR_NUM_THREADS={{ CONFIG
|
|
24
|
-
export OMP_NUM_THREADS={{ CONFIG
|
|
25
|
-
export OPENBLAS_NUM_THREADS={{ CONFIG
|
|
21
|
+
export MKL_NUM_THREADS={{ CONFIG.num_threads }}
|
|
22
|
+
export NUMBA_NUM_THREADS={{ CONFIG.num_threads }}
|
|
23
|
+
export NUMEXPR_NUM_THREADS={{ CONFIG.num_threads }}
|
|
24
|
+
export OMP_NUM_THREADS={{ CONFIG.num_threads }}
|
|
25
|
+
export OPENBLAS_NUM_THREADS={{ CONFIG.num_threads }}
|
|
26
26
|
{% endif %}
|
|
27
27
|
|
|
28
28
|
{% if OUTPUT_FOLDER is defined and OUTPUT_FOLDER %}
|
|
@@ -31,7 +31,7 @@ mkdir -p {{ OUTPUT_FOLDER }}
|
|
|
31
31
|
|
|
32
32
|
# Run the program
|
|
33
33
|
{% if USE_MODELRUNNER is defined and USE_MODELRUNNER %}
|
|
34
|
-
{{ CONFIG
|
|
34
|
+
{{ CONFIG.python_bin }} -m modelrunner {{ MODEL_FILE }} {{ JOB_ARGS }}
|
|
35
35
|
{% else %}
|
|
36
|
-
{{ CONFIG
|
|
36
|
+
{{ CONFIG.python_bin }} {{ MODEL_FILE }} {{ JOB_ARGS }}
|
|
37
37
|
{% endif %}
|
|
@@ -56,17 +56,20 @@ class MemoryStorage(StorageBase):
|
|
|
56
56
|
(group, str):
|
|
57
57
|
A tuple consisting of the parent group and the name of the current item
|
|
58
58
|
"""
|
|
59
|
-
|
|
59
|
+
if check_write and not self.is_group(loc[:-1]):
|
|
60
|
+
raise TypeError(f"Location `/{'/'.join(loc[:-1])}` is not a group")
|
|
61
|
+
|
|
62
|
+
parent = self._data
|
|
60
63
|
for part in loc[:-1]:
|
|
61
64
|
try:
|
|
62
|
-
|
|
65
|
+
parent = parent[part]
|
|
63
66
|
except KeyError:
|
|
64
|
-
if isinstance(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
if isinstance(parent, dict):
|
|
68
|
+
parent[part] = {}
|
|
69
|
+
parent = parent[part]
|
|
67
70
|
else:
|
|
68
71
|
raise TypeError(f"Cannot add item to `/{'/'.join(loc)}`")
|
|
69
|
-
if not isinstance(
|
|
72
|
+
if not isinstance(parent, dict):
|
|
70
73
|
raise TypeError(f"Cannot add item to `/{'/'.join(loc)}`")
|
|
71
74
|
|
|
72
75
|
try:
|
|
@@ -74,14 +77,17 @@ class MemoryStorage(StorageBase):
|
|
|
74
77
|
except IndexError:
|
|
75
78
|
raise KeyError(f"Location `/{'/'.join(loc)}` has no parent")
|
|
76
79
|
|
|
77
|
-
if check_write and not self.mode.overwrite and name in
|
|
80
|
+
if check_write and not self.mode.overwrite and name in parent:
|
|
78
81
|
raise AccessError(f"Overwriting `/{'/'.join(loc)}` disabled")
|
|
79
|
-
return
|
|
82
|
+
return parent, name
|
|
80
83
|
|
|
81
84
|
def __getitem__(self, loc: Sequence[str]) -> Any:
|
|
82
85
|
if loc:
|
|
83
86
|
parent, name = self._get_parent(loc)
|
|
84
|
-
|
|
87
|
+
try:
|
|
88
|
+
return parent[name]
|
|
89
|
+
except KeyError as e:
|
|
90
|
+
raise KeyError(f"Item `{name}` not in group {parent.keys()}") from e
|
|
85
91
|
else:
|
|
86
92
|
return self._data
|
|
87
93
|
|
|
@@ -57,6 +57,37 @@ class StorageGroup:
|
|
|
57
57
|
def __repr__(self):
|
|
58
58
|
return f'StorageGroup(storage={self._storage}, loc="/{"/".join(self.loc)}")'
|
|
59
59
|
|
|
60
|
+
def tree(self) -> None:
|
|
61
|
+
"""print the hierarchical storage as a tree structure"""
|
|
62
|
+
vertic = "│ "
|
|
63
|
+
cross = "├──"
|
|
64
|
+
corner = "└──"
|
|
65
|
+
space = " "
|
|
66
|
+
|
|
67
|
+
def print_tree(loc: list[str], header: str = ""):
|
|
68
|
+
"""recursive function printing information about one group"""
|
|
69
|
+
group = StorageGroup(self._storage, loc)
|
|
70
|
+
for i, key in enumerate(sorted(group.keys())):
|
|
71
|
+
last = i == len(group) - 1
|
|
72
|
+
if self._storage.is_group(loc + [key]):
|
|
73
|
+
cls = self._storage._read_attrs(loc).get("__class__")
|
|
74
|
+
if cls is None:
|
|
75
|
+
# item is a sub group
|
|
76
|
+
print(header + (corner if last else cross) + key)
|
|
77
|
+
print_tree(
|
|
78
|
+
loc + [key], header=header + (space if last else vertic)
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
# item contains information to restore a certain class
|
|
82
|
+
print(header + (corner if last else cross) + f"{key} ({cls})")
|
|
83
|
+
else:
|
|
84
|
+
# item is a simple, scalar item
|
|
85
|
+
print(header + (corner if last else cross) + key)
|
|
86
|
+
|
|
87
|
+
if self.loc:
|
|
88
|
+
print("/" + "/".join(self.loc))
|
|
89
|
+
print_tree(self.loc)
|
|
90
|
+
|
|
60
91
|
def _get_loc(self, loc: Location) -> list[str]:
|
|
61
92
|
"""return a normalized location from various input
|
|
62
93
|
|
|
@@ -74,7 +105,7 @@ class StorageGroup:
|
|
|
74
105
|
if loc_data is None or loc_data == "":
|
|
75
106
|
return []
|
|
76
107
|
elif isinstance(loc_data, str):
|
|
77
|
-
return loc_data.split("/")
|
|
108
|
+
return loc_data.strip("/").split("/")
|
|
78
109
|
else:
|
|
79
110
|
return sum((parse_loc(k) for k in loc_data), start=list())
|
|
80
111
|
|
|
@@ -82,11 +113,11 @@ class StorageGroup:
|
|
|
82
113
|
|
|
83
114
|
def __getitem__(self, loc: Location) -> Any:
|
|
84
115
|
"""read state or trajectory from storage"""
|
|
85
|
-
|
|
86
|
-
if self._storage.is_group(
|
|
87
|
-
if "__class__" not in self._storage._read_attrs(
|
|
116
|
+
loc_list = self._get_loc(loc)
|
|
117
|
+
if self._storage.is_group(loc_list): # storage points to a group
|
|
118
|
+
if "__class__" not in self._storage._read_attrs(loc_list):
|
|
88
119
|
# group does not contain class information => just return a subgroup
|
|
89
|
-
return StorageGroup(self._storage,
|
|
120
|
+
return StorageGroup(self._storage, loc_list)
|
|
90
121
|
# reconstruct objected stored at this place
|
|
91
122
|
return self.read_item(loc, use_class=True)
|
|
92
123
|
|
|
@@ -97,6 +128,9 @@ class StorageGroup:
|
|
|
97
128
|
"""return name of all stored items in this group"""
|
|
98
129
|
return self._storage.keys(self.loc)
|
|
99
130
|
|
|
131
|
+
def __len__(self) -> int:
|
|
132
|
+
return len(self.keys())
|
|
133
|
+
|
|
100
134
|
def __iter__(self) -> Iterator[Any]:
|
|
101
135
|
"""iterate over all stored items in this group"""
|
|
102
136
|
for loc in self.keys():
|
|
@@ -169,15 +203,15 @@ class StorageGroup:
|
|
|
169
203
|
Returns:
|
|
170
204
|
The reconstructed python object
|
|
171
205
|
"""
|
|
172
|
-
loc_list = self._get_loc(loc)
|
|
173
206
|
if use_class:
|
|
174
|
-
cls = self.get_class(
|
|
207
|
+
cls = self.get_class(loc)
|
|
175
208
|
if cls is not None:
|
|
176
209
|
# create object using a registered action
|
|
177
210
|
read_item = storage_actions.get(cls, "read_item")
|
|
178
|
-
return read_item(self._storage,
|
|
211
|
+
return read_item(self._storage, loc)
|
|
179
212
|
|
|
180
213
|
# read the item using the generic classes
|
|
214
|
+
loc_list = self._get_loc(loc)
|
|
181
215
|
obj_type = self._storage._read_attrs(loc_list).get("__type__")
|
|
182
216
|
if obj_type in {"array", "dynamic_array"}:
|
|
183
217
|
arr = self._storage.read_array(loc_list)
|
|
@@ -48,7 +48,9 @@ class open_storage(StorageGroup):
|
|
|
48
48
|
r"""
|
|
49
49
|
Args:
|
|
50
50
|
storage:
|
|
51
|
-
The path to a file or directory or a :class:`StorageBase` instance
|
|
51
|
+
The path to a file or directory or a :class:`StorageBase` instance. The
|
|
52
|
+
special value `None` creates a
|
|
53
|
+
:class:`~modelrunner.storage.backend.memory.MemoryStorage`
|
|
52
54
|
loc (str or list of str):
|
|
53
55
|
Denotes the location that will be opened within the storage. The default
|
|
54
56
|
`None` opens the root group of the storage.
|
|
@@ -60,6 +62,7 @@ class open_storage(StorageGroup):
|
|
|
60
62
|
All other arguments are passed on to the storage class
|
|
61
63
|
"""
|
|
62
64
|
store_obj: StorageBase | None = None
|
|
65
|
+
|
|
63
66
|
if isinstance(storage, StorageBase):
|
|
64
67
|
# storage is of type `StorageBase`
|
|
65
68
|
self._close = False
|
|
@@ -38,6 +38,7 @@ examples/submit_function.py
|
|
|
38
38
|
examples/submit_many_func.py
|
|
39
39
|
examples/submit_many_iter.py
|
|
40
40
|
examples/submit_shebang.py
|
|
41
|
+
modelrunner/.gitignore
|
|
41
42
|
modelrunner/__init__.py
|
|
42
43
|
modelrunner/__main__.py
|
|
43
44
|
modelrunner/_version.py
|
|
@@ -54,10 +55,10 @@ modelrunner/compatibility/version1.py
|
|
|
54
55
|
modelrunner/run/__init__.py
|
|
55
56
|
modelrunner/run/__main__.py
|
|
56
57
|
modelrunner/run/job.py
|
|
57
|
-
modelrunner/run/templates/background.
|
|
58
|
-
modelrunner/run/templates/foreground.
|
|
59
|
-
modelrunner/run/templates/qsub.
|
|
60
|
-
modelrunner/run/templates/srun.
|
|
58
|
+
modelrunner/run/templates/background.jinja
|
|
59
|
+
modelrunner/run/templates/foreground.jinja
|
|
60
|
+
modelrunner/run/templates/qsub.jinja
|
|
61
|
+
modelrunner/run/templates/srun.jinja
|
|
61
62
|
modelrunner/storage/__init__.py
|
|
62
63
|
modelrunner/storage/access_modes.py
|
|
63
64
|
modelrunner/storage/attributes.py
|
|
@@ -145,7 +146,9 @@ tests/helpers/asserts.py
|
|
|
145
146
|
tests/helpers/storage.py
|
|
146
147
|
tests/run/test_job.py
|
|
147
148
|
tests/run/test_run_main.py
|
|
149
|
+
tests/run/scripts/fail.py
|
|
148
150
|
tests/run/scripts/function.py
|
|
151
|
+
tests/run/scripts/print.py
|
|
149
152
|
tests/run/scripts/script.py
|
|
150
153
|
tests/scripts/empty.py
|
|
151
154
|
tests/scripts/function.py
|