py-modelrunner 0.15.0__tar.gz → 0.16.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.15.0 → py-modelrunner-0.16.0}/PKG-INFO +1 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/requirements.txt +1 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/.gitignore +1 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/conf.py +17 -10
- py-modelrunner-0.16.0/docs/source/examples.rst +10 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/index.rst +4 -2
- py-modelrunner-0.16.0/docs/source/parse_examples.py +65 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/run_autodoc.py +1 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/sphinx_simplify_typehints.py +1 -1
- py-modelrunner-0.16.0/docs/source/user_manual.rst +53 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/__init__.py +0 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/__main__.py +2 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/_version.py +2 -2
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/compatibility/triage.py +8 -8
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/compatibility/version0.py +5 -5
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/compatibility/version1.py +17 -20
- py-modelrunner-0.16.0/modelrunner/config.py +149 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/model.py +23 -25
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/parameters.py +44 -88
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/results.py +17 -16
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/__main__.py +3 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/job.py +103 -32
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/templates/background.template +8 -8
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/templates/foreground.template +8 -8
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/templates/qsub.template +10 -12
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/templates/srun.template +10 -12
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/access_modes.py +11 -5
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/attributes.py +2 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/hdf.py +41 -19
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/memory.py +5 -5
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/text_base.py +7 -6
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/utils.py +1 -29
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/zarr.py +7 -8
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/base.py +29 -32
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/group.py +31 -23
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/tools.py +19 -4
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/trajectory.py +32 -22
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/utils.py +17 -27
- py-modelrunner-0.16.0/modelrunner/utils.py +71 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/PKG-INFO +1 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/SOURCES.txt +7 -2
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/requirements.txt +1 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/requirements_full.txt +0 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/format_code.sh +5 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/run_tests.py +12 -2
- py-modelrunner-0.16.0/tests/conftest.py +4 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/requirements.txt +2 -1
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/storage/test_storage_generic.py +46 -3
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/storage/test_trajectory.py +81 -4
- py-modelrunner-0.16.0/tests/test_config.py +107 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_examples.py +2 -3
- py-modelrunner-0.15.0/codecov.yml +0 -11
- py-modelrunner-0.15.0/docs/source/structure.rst +0 -61
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.github/workflows/build.yml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.github/workflows/check_docs.yml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.github/workflows/coverage_report.yml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.github/workflows/release_pip.yml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.gitignore +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/.readthedocs.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/LICENSE +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/README.md +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/Makefile +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/build_all.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/docs/source/installation.rst +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/io_hdf.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/io_json.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/io_yaml.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/model_class.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/model_decorator.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/model_function.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/model_storage_output.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/read_many.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/script_custom_func.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/script_function.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/script_many_classes.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/script_minimal.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/script_model_class.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/submit_function.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/submit_many_func.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/submit_many_iter.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/examples/submit_shebang.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/compatibility/__init__.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/py.typed +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/run/__init__.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/__init__.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/__init__.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/json.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/modelrunner/storage/backend/yaml.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/dependency_links.txt +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/not-zip-safe +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/requires.txt +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/py_modelrunner.egg-info/top_level.txt +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/pyproject.toml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/create_compatibility_files.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/performance_hdf5_zarr.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_all.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_codestyle.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_coverage.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_parallel.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_run.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/scripts/tests_types.sh +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/setup.cfg +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/0/result.hdf +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/0/result.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/0/result.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/0/result.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array.zarr +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array_col.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array_col.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array_col.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/array_col.zarr +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/dict.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/dict.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/dict.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/dict.zarr +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/object.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/object.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/object.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/1/object.zarr +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array.hdf +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array.zip +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array_col.hdf +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array_col.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array_col.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array_col.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/array_col.zip +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/dict.hdf +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/dict.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/dict.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/dict.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/dict.zip +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/nested.hdf +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/nested.json +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/nested.pkl +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/nested.yaml +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/2/nested.zip +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/compatibility/test_compatibility.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/helpers/__init__.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/helpers/asserts.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/helpers/storage.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/run/scripts/function.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/run/scripts/script.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/run/test_job.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/run/test_run_main.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/empty.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/function.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/function_main.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/function_marked.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/make_model.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/make_model_class.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/scripts/make_model_marked.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/storage/test_group.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/storage/test_storage_special.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/storage/test_utils.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_main.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_model.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_parameters.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_results.py +0 -0
- {py-modelrunner-0.15.0 → py-modelrunner-0.16.0}/tests/test_version.py +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
#
|
|
3
2
|
# Configuration file for the Sphinx documentation builder.
|
|
4
3
|
#
|
|
@@ -226,8 +225,8 @@ napoleon_numpy_docstring = False
|
|
|
226
225
|
napoleon_include_init_with_doc = False
|
|
227
226
|
napoleon_include_private_with_doc = False
|
|
228
227
|
napoleon_include_special_with_doc = False
|
|
229
|
-
napoleon_use_admonition_for_examples =
|
|
230
|
-
napoleon_use_admonition_for_notes =
|
|
228
|
+
napoleon_use_admonition_for_examples = True
|
|
229
|
+
napoleon_use_admonition_for_notes = True
|
|
231
230
|
napoleon_use_admonition_for_references = False
|
|
232
231
|
napoleon_use_ivar = False
|
|
233
232
|
napoleon_use_param = True
|
|
@@ -239,13 +238,16 @@ napoleon_custom_sections = None
|
|
|
239
238
|
|
|
240
239
|
# Example configuration for intersphinx: refer to the Python standard library.
|
|
241
240
|
intersphinx_mapping = {
|
|
242
|
-
"https://docs.
|
|
243
|
-
"https://
|
|
244
|
-
"https://
|
|
245
|
-
"https://
|
|
246
|
-
"
|
|
247
|
-
"https://
|
|
248
|
-
"https://py-
|
|
241
|
+
"h5py": ("https://docs.h5py.org/en/latest", None),
|
|
242
|
+
"matplotlib": ("https://matplotlib.org/stable", None),
|
|
243
|
+
"modelrunner": ("https://py-modelrunner.readthedocs.io/en/latest", None),
|
|
244
|
+
"napari": ("https://napari.org/", None),
|
|
245
|
+
"numba": ("https://numba.pydata.org/numba-doc/latest/", None),
|
|
246
|
+
"numpy": ("https://numpy.org/doc/stable", None),
|
|
247
|
+
"pde": ("https://py-pde.readthedocs.io/en/latest", None),
|
|
248
|
+
"python": ("https://docs.python.org/3/", None),
|
|
249
|
+
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
|
|
250
|
+
"sympy": ("https://docs.sympy.org/latest/", None),
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
|
|
@@ -255,6 +257,11 @@ graphviz_output_format = "svg"
|
|
|
255
257
|
# for the graph, which we here corrected manually, but which lead to issues if we also
|
|
256
258
|
# used the inheritance_diagram extension
|
|
257
259
|
|
|
260
|
+
# create all example files
|
|
261
|
+
from parse_examples import main
|
|
262
|
+
|
|
263
|
+
main()
|
|
264
|
+
|
|
258
265
|
# run autodoc
|
|
259
266
|
autodoc_typehints = "description"
|
|
260
267
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import pathlib
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
# Root direcotry of the package
|
|
7
|
+
ROOT = pathlib.Path(__file__).absolute().parents[2]
|
|
8
|
+
# directory where all the examples reside
|
|
9
|
+
INPUT = ROOT / "examples"
|
|
10
|
+
# directory to which the documents are writen
|
|
11
|
+
OUTPUT = ROOT / "docs" / "source" / "examples"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
"""parse all examples and write them in a special example module"""
|
|
16
|
+
# create the output directory
|
|
17
|
+
OUTPUT.mkdir(parents=True, exist_ok=True)
|
|
18
|
+
|
|
19
|
+
regex = r'"""((?!""").*?)"""'
|
|
20
|
+
|
|
21
|
+
# iterate over all examples
|
|
22
|
+
for path_in in INPUT.glob("*.py"):
|
|
23
|
+
path_out = OUTPUT / (path_in.stem + ".rst")
|
|
24
|
+
print(f"Found example {path_in}")
|
|
25
|
+
with path_in.open("r") as file_in, path_out.open("w") as file_out:
|
|
26
|
+
# write the header for the rst file
|
|
27
|
+
file_out.write(path_in.name + "\n")
|
|
28
|
+
file_out.write("-" * len(path_in.name) + "\n\n")
|
|
29
|
+
|
|
30
|
+
# read all content
|
|
31
|
+
file_content = file_in.read()
|
|
32
|
+
|
|
33
|
+
# identify shebang
|
|
34
|
+
if file_content.startswith("#"):
|
|
35
|
+
shebang, file_content = file_content.split("\n", 1)
|
|
36
|
+
if shebang == "#!/usr/bin/env python3":
|
|
37
|
+
shebang = "" # filter trivial case
|
|
38
|
+
else:
|
|
39
|
+
shebang = None
|
|
40
|
+
|
|
41
|
+
# locate file docstring
|
|
42
|
+
matches = re.search(regex, file_content, re.DOTALL)
|
|
43
|
+
if matches:
|
|
44
|
+
for line in matches.group(1).split("\n"):
|
|
45
|
+
if ".. codeauthor::" in line:
|
|
46
|
+
continue
|
|
47
|
+
file_out.write(f"{line}\n")
|
|
48
|
+
|
|
49
|
+
file_content = file_content[matches.end(0) :]
|
|
50
|
+
|
|
51
|
+
# write actual code
|
|
52
|
+
file_out.write(".. code-block:: python\n\n")
|
|
53
|
+
if shebang:
|
|
54
|
+
file_out.write(f" {shebang}\n\n")
|
|
55
|
+
header = True
|
|
56
|
+
for line in file_content.split("\n"):
|
|
57
|
+
# skip the shebang, comments and empty lines in the beginning
|
|
58
|
+
if header and (line.startswith("#") or len(line.strip()) == 0):
|
|
59
|
+
continue
|
|
60
|
+
header = False # first real line was reached
|
|
61
|
+
file_out.write(f" {line}\n")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
main()
|
|
@@ -83,7 +83,7 @@ REPLACEMENTS = collections.OrderedDict(
|
|
|
83
83
|
# replacement rules based on regular expressions
|
|
84
84
|
REPLACEMENTS_REGEX = {
|
|
85
85
|
# remove full package path and only leave the module/class identifier
|
|
86
|
-
"multicomp\.(\w+\.)*": "",
|
|
86
|
+
r"multicomp\.(\w+\.)*": "",
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
User Manual
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
Main structure of the package
|
|
5
|
+
-----------------------------
|
|
6
|
+
|
|
7
|
+
The package offers several different components that can be used separately or together:
|
|
8
|
+
|
|
9
|
+
Hierarchical input/output using :mod:`~modelrunner.storage`:
|
|
10
|
+
The module provides an abstract interface for writing and reading data using an
|
|
11
|
+
hierarchical organization.
|
|
12
|
+
Storages are conveniently created by :func:`~modelrunner.storage.tools.open_storage`,
|
|
13
|
+
which returns a storage object that offers a dict-like interface.
|
|
14
|
+
|
|
15
|
+
Defining parameters using :mod:`~modelrunner.parameters`:
|
|
16
|
+
The module provides the :class:`~modelrunner.parameters.Parameter` class, describing a single parameter.
|
|
17
|
+
This can be used together with the mixin :class:`~modelrunner.parameters.Parametrized`,
|
|
18
|
+
which allows to equip classes with default parameters and some convenience methods.
|
|
19
|
+
|
|
20
|
+
Defining models using :mod:`~modelrunner.model`:
|
|
21
|
+
Models are augmented functions, which define input, calculations, and output.
|
|
22
|
+
Models can be conveniently created by decorating a function or by subclassing
|
|
23
|
+
:class:`~modelrunner.model.ModelBase`, which is built on the parameter classes.
|
|
24
|
+
|
|
25
|
+
Model results are captured by :mod:`~modelrunner.results`:
|
|
26
|
+
Results are returned as the special :class:`~modelrunner.results.Result`, which
|
|
27
|
+
keeps track of the input parameters and the data calculated by the model.
|
|
28
|
+
:class:`~modelrunner.results.ResultCollection` describes a collections of the same
|
|
29
|
+
model evoked with different parameter values.
|
|
30
|
+
|
|
31
|
+
Submitting models to HPC using :mod:`~modelrunner.run`:
|
|
32
|
+
A single model can be submitted to a compute node using :func:`~modelrunner.run.job.submit_job`,
|
|
33
|
+
e.g., to run the computation on a high performance compute cluster.
|
|
34
|
+
A parameter study using multiple jobs can be conveniently submitted using :func:`~modelrunner.run.job.submit_jobs`.
|
|
35
|
+
The results written to one directory can then be conveniently analyzed using :meth:`~modelrunner.results.ResultCollection.from_folder`.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Design philosophy
|
|
39
|
+
-----------------
|
|
40
|
+
|
|
41
|
+
The main requirements for the storage classes were
|
|
42
|
+
|
|
43
|
+
- *Usability*: The user should not need to think about how data is stored in different files
|
|
44
|
+
- *Flexibility*: We want a general interface to write data in multiple file formats (YAML, HDF, zarr, ...)
|
|
45
|
+
- *Stability*: Future versions of the package should be able to read older files even when the internal definitions of file formats change
|
|
46
|
+
- *Extensibility*: States should be subclasses to implement more complicated requirements (e.g., particular serialization)
|
|
47
|
+
- *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
|
+
- *Efficiency*: The files should only store necessary information.
|
|
49
|
+
|
|
50
|
+
The last point results in particular constraints if we want to store temporal simulation results.
|
|
51
|
+
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
|
+
We denote by `attributes` the parameters that are kept fixed and by `data` the data that varies over time.
|
|
53
|
+
The state classes are already prepared to deal with such data, in conjuction with the :mod:`~modelrunner.storage.trajectory` module.
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING, Any, Mapping,
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Mapping, Union
|
|
12
12
|
|
|
13
13
|
from ..model import ModelBase
|
|
14
14
|
from ..results import Result
|
|
@@ -42,7 +42,7 @@ def guess_format(path: Path) -> str:
|
|
|
42
42
|
return "zarr" # fallback to the default storage method based on zarr
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def normalize_zarr_store(store: Store, mode: str = "a") ->
|
|
45
|
+
def normalize_zarr_store(store: Store, mode: str = "a") -> Store | None:
|
|
46
46
|
"""determine best file format for zarr storage
|
|
47
47
|
|
|
48
48
|
In particular, we use a :class:`~zarr.storage.ZipStore` when a path looking like a
|
|
@@ -70,7 +70,7 @@ def normalize_zarr_store(store: Store, mode: str = "a") -> Optional[Store]:
|
|
|
70
70
|
return store
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
def _find_version(data: Mapping[str, Any], label: str) ->
|
|
73
|
+
def _find_version(data: Mapping[str, Any], label: str) -> int | None:
|
|
74
74
|
"""try finding version information in different places in `data`
|
|
75
75
|
|
|
76
76
|
Args:
|
|
@@ -83,7 +83,7 @@ def _find_version(data: Mapping[str, Any], label: str) -> Optional[int]:
|
|
|
83
83
|
int: The format version or None if it could not be found
|
|
84
84
|
"""
|
|
85
85
|
|
|
86
|
-
def read_version(item) ->
|
|
86
|
+
def read_version(item) -> str | None:
|
|
87
87
|
"""try reading attribute from a particular item"""
|
|
88
88
|
if hasattr(item, "attrs"):
|
|
89
89
|
return read_version(item.attrs)
|
|
@@ -111,8 +111,8 @@ def _find_version(data: Mapping[str, Any], label: str) -> Optional[int]:
|
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
def result_check_load_old_version(
|
|
114
|
-
path: Path, loc: str, *, model:
|
|
115
|
-
) ->
|
|
114
|
+
path: Path, loc: str, *, model: ModelBase | None = None
|
|
115
|
+
) -> Result | None:
|
|
116
116
|
"""check whether the resource can be loaded with an older version of the package
|
|
117
117
|
|
|
118
118
|
Args:
|
|
@@ -132,13 +132,13 @@ def result_check_load_old_version(
|
|
|
132
132
|
# check for compatibility
|
|
133
133
|
fmt = guess_format(path)
|
|
134
134
|
if fmt == "json":
|
|
135
|
-
with open(path
|
|
135
|
+
with open(path) as fp:
|
|
136
136
|
format_version = _find_version(json.load(fp), label)
|
|
137
137
|
|
|
138
138
|
elif fmt == "yaml":
|
|
139
139
|
import yaml
|
|
140
140
|
|
|
141
|
-
with open(path
|
|
141
|
+
with open(path) as fp:
|
|
142
142
|
format_version = _find_version(yaml.safe_load(fp), label)
|
|
143
143
|
|
|
144
144
|
elif fmt == "hdf":
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Mapping
|
|
11
|
+
from typing import Any, Mapping
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ def read_hdf_data(node):
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def _Result_from_simple_objects(
|
|
35
|
-
content: Mapping[str, Any], model:
|
|
35
|
+
content: Mapping[str, Any], model: ModelBase | None = None
|
|
36
36
|
) -> Result:
|
|
37
37
|
"""read result from simple object (like loaded from a JSON file) using version 0
|
|
38
38
|
|
|
@@ -54,7 +54,7 @@ def _Result_from_simple_objects(
|
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def _Result_from_hdf(hdf_element, model:
|
|
57
|
+
def _Result_from_hdf(hdf_element, model: ModelBase | None = None) -> Result:
|
|
58
58
|
"""old reader for backward compatible reading"""
|
|
59
59
|
model_data = {key: json.loads(value) for key, value in hdf_element.attrs.items()}
|
|
60
60
|
if "result" in hdf_element:
|
|
@@ -80,14 +80,14 @@ def result_from_file_v0(path: Path, **kwargs) -> Result:
|
|
|
80
80
|
"""
|
|
81
81
|
fmt = guess_format(path)
|
|
82
82
|
if fmt == "json":
|
|
83
|
-
with open(path
|
|
83
|
+
with open(path) as fp:
|
|
84
84
|
content = json.load(fp)
|
|
85
85
|
return _Result_from_simple_objects(content, **kwargs)
|
|
86
86
|
|
|
87
87
|
elif fmt == "yaml":
|
|
88
88
|
import yaml
|
|
89
89
|
|
|
90
|
-
with open(path
|
|
90
|
+
with open(path) as fp:
|
|
91
91
|
content = yaml.safe_load(fp)
|
|
92
92
|
return _Result_from_simple_objects(content, **kwargs)
|
|
93
93
|
|
|
@@ -10,7 +10,7 @@ import json
|
|
|
10
10
|
import warnings
|
|
11
11
|
from abc import ABCMeta
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import TYPE_CHECKING, Any,
|
|
13
|
+
from typing import TYPE_CHECKING, Any, TypeVar, Union
|
|
14
14
|
|
|
15
15
|
import numpy as np
|
|
16
16
|
|
|
@@ -55,10 +55,10 @@ class StateBase(metaclass=ABCMeta):
|
|
|
55
55
|
_state_format_version = 2
|
|
56
56
|
"""int: number indicating the version of the file format"""
|
|
57
57
|
|
|
58
|
-
_state_classes:
|
|
58
|
+
_state_classes: dict[str, type[StateBase]] = {}
|
|
59
59
|
"""dict: class-level list of all subclasses of StateBase"""
|
|
60
60
|
|
|
61
|
-
def _state_init(self, attributes:
|
|
61
|
+
def _state_init(self, attributes: dict[str, Any], data=NoData) -> None:
|
|
62
62
|
"""initialize the state with attributes and (optionally) data
|
|
63
63
|
|
|
64
64
|
Args:
|
|
@@ -71,7 +71,7 @@ class StateBase(metaclass=ABCMeta):
|
|
|
71
71
|
self._state_attributes = attributes
|
|
72
72
|
|
|
73
73
|
@classmethod
|
|
74
|
-
def from_data(cls:
|
|
74
|
+
def from_data(cls: type[TState], attributes: dict[str, Any], data=NoData) -> TState:
|
|
75
75
|
"""create instance of any state class from attributes and data
|
|
76
76
|
|
|
77
77
|
Args:
|
|
@@ -84,7 +84,8 @@ class StateBase(metaclass=ABCMeta):
|
|
|
84
84
|
# copy attributes since they are modified in this function
|
|
85
85
|
attributes = attributes.copy()
|
|
86
86
|
cls_name = attributes["__class__"]
|
|
87
|
-
|
|
87
|
+
if cls_name != cls.__name__:
|
|
88
|
+
raise RuntimeError(f"Expected `{cls.__name__}` but data had `{cls_name}`")
|
|
88
89
|
|
|
89
90
|
format_version = attributes.pop("__version__", 0)
|
|
90
91
|
if format_version != 1:
|
|
@@ -97,7 +98,7 @@ class StateBase(metaclass=ABCMeta):
|
|
|
97
98
|
return obj
|
|
98
99
|
|
|
99
100
|
@classmethod
|
|
100
|
-
def _from_simple_objects(cls, content:
|
|
101
|
+
def _from_simple_objects(cls, content: dict[str, Any]) -> StateBase:
|
|
101
102
|
"""create state from text data
|
|
102
103
|
|
|
103
104
|
Args:
|
|
@@ -115,7 +116,7 @@ class StateBase(metaclass=ABCMeta):
|
|
|
115
116
|
return ArrayCollectionState.from_data(content["attributes"], col_data)
|
|
116
117
|
|
|
117
118
|
elif cls_name == "DictState":
|
|
118
|
-
dict_data:
|
|
119
|
+
dict_data: dict[str, StateBase] = {}
|
|
119
120
|
for label, substate in content["data"].items():
|
|
120
121
|
dict_data[label] = cls._from_simple_objects(substate)
|
|
121
122
|
|
|
@@ -128,7 +129,7 @@ class StateBase(metaclass=ABCMeta):
|
|
|
128
129
|
raise TypeError(f"Do not know how to load `{cls_name}`")
|
|
129
130
|
|
|
130
131
|
@classmethod
|
|
131
|
-
def _from_zarr(cls, zarr_element:
|
|
132
|
+
def _from_zarr(cls, zarr_element: zarrElement, *, index=...) -> StateBase:
|
|
132
133
|
"""create instance of correct subclass from data stored in zarr"""
|
|
133
134
|
# determine the class that knows how to read this data
|
|
134
135
|
cls_name = zarr_element.attrs["__class__"]
|
|
@@ -163,24 +164,20 @@ class StateBase(metaclass=ABCMeta):
|
|
|
163
164
|
raise TypeError(f"Do not know how to load `{cls_name}`")
|
|
164
165
|
|
|
165
166
|
|
|
166
|
-
class ArrayState(StateBase):
|
|
167
|
-
...
|
|
167
|
+
class ArrayState(StateBase): ...
|
|
168
168
|
|
|
169
169
|
|
|
170
|
-
class ArrayCollectionState(StateBase):
|
|
171
|
-
...
|
|
170
|
+
class ArrayCollectionState(StateBase): ...
|
|
172
171
|
|
|
173
172
|
|
|
174
|
-
class DictState(StateBase):
|
|
175
|
-
...
|
|
173
|
+
class DictState(StateBase): ...
|
|
176
174
|
|
|
177
175
|
|
|
178
|
-
class ObjectState(StateBase):
|
|
179
|
-
...
|
|
176
|
+
class ObjectState(StateBase): ...
|
|
180
177
|
|
|
181
178
|
|
|
182
179
|
def _Result_from_simple_objects(
|
|
183
|
-
content:
|
|
180
|
+
content: dict[str, Any], model: ModelBase | None = None
|
|
184
181
|
) -> Result:
|
|
185
182
|
"""read result from simple object (like loaded from a JSON file) using version 1
|
|
186
183
|
|
|
@@ -202,7 +199,7 @@ def _Result_from_simple_objects(
|
|
|
202
199
|
|
|
203
200
|
|
|
204
201
|
def _Result_from_zarr(
|
|
205
|
-
zarr_element:
|
|
202
|
+
zarr_element: zarrElement, *, index=..., model: ModelBase | None = None
|
|
206
203
|
) -> Result:
|
|
207
204
|
"""create result from data stored in zarr"""
|
|
208
205
|
attributes = {key: json.loads(value) for key, value in zarr_element.attrs.items()}
|
|
@@ -236,14 +233,14 @@ def result_from_file_v1(store: Path, *, label: str = "data", **kwargs) -> Result
|
|
|
236
233
|
"""
|
|
237
234
|
fmt = guess_format(store)
|
|
238
235
|
if fmt == "json":
|
|
239
|
-
with open(store
|
|
236
|
+
with open(store) as fp:
|
|
240
237
|
content = json.load(fp)
|
|
241
238
|
return _Result_from_simple_objects(content, **kwargs)
|
|
242
239
|
|
|
243
240
|
elif fmt == "yaml":
|
|
244
241
|
import yaml
|
|
245
242
|
|
|
246
|
-
with open(store
|
|
243
|
+
with open(store) as fp:
|
|
247
244
|
content = yaml.safe_load(fp)
|
|
248
245
|
return _Result_from_simple_objects(content, **kwargs)
|
|
249
246
|
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Handles configuration variables
|
|
3
|
+
|
|
4
|
+
.. autosummary::
|
|
5
|
+
:nosignatures:
|
|
6
|
+
|
|
7
|
+
Config
|
|
8
|
+
|
|
9
|
+
.. codeauthor:: David Zwicker <david.zwicker@ds.mpg.de>
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import collections
|
|
15
|
+
import contextlib
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any, Sequence
|
|
18
|
+
|
|
19
|
+
from .parameters import DeprecatedParameter, Parameter
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Config(collections.UserDict):
|
|
23
|
+
"""class handling the package configuration"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
default: Sequence[Parameter] | None = None,
|
|
28
|
+
mode: str = "update",
|
|
29
|
+
*,
|
|
30
|
+
check_validity: bool = True,
|
|
31
|
+
include_deprecated: bool = True,
|
|
32
|
+
):
|
|
33
|
+
"""
|
|
34
|
+
Args:
|
|
35
|
+
default (sequence of :class:`~modelrunner.parameters.Parameter`, optional):
|
|
36
|
+
Default configuration values. The default configuration also defines
|
|
37
|
+
what parameters can typically be defined and it provides additional
|
|
38
|
+
information for these parameters.
|
|
39
|
+
mode (str):
|
|
40
|
+
Defines the mode in which the configuration is used. Possible values are
|
|
41
|
+
|
|
42
|
+
* `insert`: any new configuration key can be inserted
|
|
43
|
+
* `update`: only the values defined by `default` can be updated
|
|
44
|
+
* `locked`: no values can be changed
|
|
45
|
+
|
|
46
|
+
Note that the items specified by `items` will always be inserted,
|
|
47
|
+
independent of the `mode`.
|
|
48
|
+
check_validity (bool):
|
|
49
|
+
Determines whether a `ValueError` is raised if there are keys in
|
|
50
|
+
parameters that are not in the defaults. If `False`, additional items
|
|
51
|
+
are simply stored in `self.parameters`
|
|
52
|
+
include_deprecated (bool):
|
|
53
|
+
Include deprecated parameters
|
|
54
|
+
"""
|
|
55
|
+
if default is None:
|
|
56
|
+
default = []
|
|
57
|
+
self._default = default
|
|
58
|
+
|
|
59
|
+
# initialize parameters with default ones
|
|
60
|
+
self.mode = "insert" # temporarily allow inserting items
|
|
61
|
+
super().__init__()
|
|
62
|
+
for param_obj in default:
|
|
63
|
+
if include_deprecated or not isinstance(param_obj, DeprecatedParameter):
|
|
64
|
+
self[param_obj.name] = param_obj.convert(strict=check_validity)
|
|
65
|
+
|
|
66
|
+
# set the mode for future additions
|
|
67
|
+
self.mode = mode
|
|
68
|
+
|
|
69
|
+
def load(self, path: str | Path):
|
|
70
|
+
"""load configuration from yaml file"""
|
|
71
|
+
import yaml
|
|
72
|
+
|
|
73
|
+
with open(path) as fp:
|
|
74
|
+
self.update(yaml.safe_load(fp))
|
|
75
|
+
|
|
76
|
+
def save(self, path: str | Path):
|
|
77
|
+
"""save configuration to yaml file"""
|
|
78
|
+
import yaml
|
|
79
|
+
|
|
80
|
+
with open(path, "w") as fp:
|
|
81
|
+
yaml.dump(self.to_dict(), fp)
|
|
82
|
+
|
|
83
|
+
def __getitem__(self, key: str):
|
|
84
|
+
"""retrieve item `key`"""
|
|
85
|
+
parameter = self.data[key]
|
|
86
|
+
if isinstance(parameter, Parameter):
|
|
87
|
+
return parameter.convert()
|
|
88
|
+
else:
|
|
89
|
+
return parameter
|
|
90
|
+
|
|
91
|
+
def __setitem__(self, key: str, value):
|
|
92
|
+
"""update item `key` with `value`"""
|
|
93
|
+
if self.mode == "insert":
|
|
94
|
+
self.data[key] = value
|
|
95
|
+
|
|
96
|
+
elif self.mode == "update":
|
|
97
|
+
if key not in self:
|
|
98
|
+
raise KeyError(
|
|
99
|
+
f"{key} is not present, but config is in `{self.mode}` mode"
|
|
100
|
+
)
|
|
101
|
+
self.data[key] = value
|
|
102
|
+
|
|
103
|
+
elif self.mode == "locked":
|
|
104
|
+
raise RuntimeError("Configuration is locked")
|
|
105
|
+
|
|
106
|
+
else:
|
|
107
|
+
raise ValueError(f"Unsupported configuration mode `{self.mode}`")
|
|
108
|
+
|
|
109
|
+
def __delitem__(self, key: str):
|
|
110
|
+
"""removes item `key`"""
|
|
111
|
+
if self.mode == "insert":
|
|
112
|
+
del self.data[key]
|
|
113
|
+
else:
|
|
114
|
+
raise RuntimeError("Configuration is not in `insert` mode")
|
|
115
|
+
|
|
116
|
+
def copy(self) -> Config:
|
|
117
|
+
"""return a copy of the configuration"""
|
|
118
|
+
obj = self.__class__(self._default, self.mode)
|
|
119
|
+
obj.update(self)
|
|
120
|
+
return obj
|
|
121
|
+
|
|
122
|
+
def to_dict(self) -> dict[str, Any]:
|
|
123
|
+
"""convert the configuration to a simple dictionary
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
dict: A representation of the configuration in a normal :class:`dict`.
|
|
127
|
+
"""
|
|
128
|
+
return {k: v for k, v in self.items()}
|
|
129
|
+
|
|
130
|
+
def __repr__(self) -> str:
|
|
131
|
+
"""represent the configuration as a string"""
|
|
132
|
+
return f"{self.__class__.__name__}({repr(self.to_dict())})"
|
|
133
|
+
|
|
134
|
+
@contextlib.contextmanager
|
|
135
|
+
def __call__(self, values: dict[str, Any] | None = None, **kwargs):
|
|
136
|
+
"""context manager temporarily changing the configuration
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
values (dict): New configuration parameters
|
|
140
|
+
**kwargs: New configuration parameters
|
|
141
|
+
"""
|
|
142
|
+
data_initial = self.to_dict() # save old configuration
|
|
143
|
+
# set new configuration
|
|
144
|
+
if values is not None:
|
|
145
|
+
self.update(values)
|
|
146
|
+
self.update(kwargs)
|
|
147
|
+
yield # return to caller
|
|
148
|
+
# restore old configuration
|
|
149
|
+
self.update(data_initial)
|