py-modelrunner 0.18.0__tar.gz → 0.18.1__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.
Files changed (213) hide show
  1. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/PKG-INFO +1 -1
  2. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/user_manual.rst +13 -13
  3. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/_version.py +2 -2
  4. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/job.py +6 -3
  5. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/results.py +1 -1
  6. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/text_base.py +1 -1
  7. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/utils.py +17 -5
  8. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/PKG-INFO +1 -1
  9. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/SOURCES.txt +3 -0
  10. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/run_tests.py +16 -0
  11. py_modelrunner-0.18.1/scripts/tests_debug.sh +16 -0
  12. py_modelrunner-0.18.1/tests/run/scripts/custom.jinja +19 -0
  13. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/test_job.py +16 -2
  14. py_modelrunner-0.18.1/tests/storage/test_register_action.py +155 -0
  15. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/storage/test_storage_generic.py +1 -85
  16. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.github/workflows/build.yml +0 -0
  17. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.github/workflows/check_docs.yml +0 -0
  18. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.github/workflows/coverage_report.yml +0 -0
  19. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.github/workflows/release_pip.yml +0 -0
  20. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.gitignore +0 -0
  21. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/.readthedocs.yaml +0 -0
  22. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/LICENSE +0 -0
  23. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/README.md +0 -0
  24. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/Makefile +0 -0
  25. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/build_all.sh +0 -0
  26. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/requirements.txt +0 -0
  27. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/.gitignore +0 -0
  28. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/conf.py +0 -0
  29. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/examples.rst +0 -0
  30. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/index.rst +0 -0
  31. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/installation.rst +0 -0
  32. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/parse_examples.py +0 -0
  33. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/run_autodoc.py +0 -0
  34. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/docs/source/sphinx_simplify_typehints.py +0 -0
  35. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/io_hdf.py +0 -0
  36. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/io_json.py +0 -0
  37. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/io_yaml.py +0 -0
  38. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/model_class.py +0 -0
  39. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/model_decorator.py +0 -0
  40. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/model_function.py +0 -0
  41. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/model_storage_output.py +0 -0
  42. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/read_many.py +0 -0
  43. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/script_custom_func.py +0 -0
  44. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/script_function.py +0 -0
  45. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/script_many_classes.py +0 -0
  46. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/script_minimal.py +0 -0
  47. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/script_model_class.py +0 -0
  48. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/submit_function.py +0 -0
  49. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/submit_many_func.py +0 -0
  50. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/submit_many_iter.py +0 -0
  51. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/examples/submit_shebang.py +0 -0
  52. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/.gitignore +0 -0
  53. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/__init__.py +0 -0
  54. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/__main__.py +0 -0
  55. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/config.py +0 -0
  56. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/model/__init__.py +0 -0
  57. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/model/base.py +0 -0
  58. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/model/factory.py +0 -0
  59. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/model/parameters.py +0 -0
  60. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/py.typed +0 -0
  61. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/__init__.py +0 -0
  62. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/__main__.py +0 -0
  63. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/compatibility/__init__.py +0 -0
  64. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/compatibility/triage.py +0 -0
  65. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/compatibility/version0.py +0 -0
  66. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/compatibility/version1.py +0 -0
  67. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/compatibility/version2.py +0 -0
  68. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/launch.py +0 -0
  69. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/templates/background.jinja +0 -0
  70. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/templates/foreground.jinja +0 -0
  71. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/templates/qsub.jinja +0 -0
  72. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/run/templates/srun.jinja +0 -0
  73. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/__init__.py +0 -0
  74. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/access_modes.py +0 -0
  75. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/attributes.py +0 -0
  76. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/__init__.py +0 -0
  77. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/hdf.py +0 -0
  78. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/json.py +0 -0
  79. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/memory.py +0 -0
  80. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/utils.py +0 -0
  81. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/yaml.py +0 -0
  82. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/backend/zarr.py +0 -0
  83. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/base.py +0 -0
  84. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/group.py +0 -0
  85. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/tools.py +0 -0
  86. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/storage/trajectory.py +0 -0
  87. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/modelrunner/utils.py +0 -0
  88. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/dependency_links.txt +0 -0
  89. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/not-zip-safe +0 -0
  90. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/requires.txt +0 -0
  91. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/py_modelrunner.egg-info/top_level.txt +0 -0
  92. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/pyproject.toml +0 -0
  93. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/requirements.txt +0 -0
  94. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/requirements_full.txt +0 -0
  95. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/create_compatibility_files.py +0 -0
  96. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/format_code.sh +0 -0
  97. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/performance_hdf5_zarr.py +0 -0
  98. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_all.sh +0 -0
  99. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_codestyle.sh +0 -0
  100. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_coverage.sh +0 -0
  101. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_parallel.sh +0 -0
  102. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_run.sh +0 -0
  103. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/scripts/tests_types.sh +0 -0
  104. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/setup.cfg +0 -0
  105. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/0/result.hdf +0 -0
  106. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/0/result.json +0 -0
  107. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/0/result.pkl +0 -0
  108. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/0/result.yaml +0 -0
  109. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array.json +0 -0
  110. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array.pkl +0 -0
  111. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array.yaml +0 -0
  112. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array.zarr +0 -0
  113. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array_col.json +0 -0
  114. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array_col.pkl +0 -0
  115. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array_col.yaml +0 -0
  116. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/array_col.zarr +0 -0
  117. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/dict.json +0 -0
  118. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/dict.pkl +0 -0
  119. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/dict.yaml +0 -0
  120. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/dict.zarr +0 -0
  121. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/object.json +0 -0
  122. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/object.pkl +0 -0
  123. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/object.yaml +0 -0
  124. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/1/object.zarr +0 -0
  125. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array.hdf +0 -0
  126. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array.json +0 -0
  127. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array.pkl +0 -0
  128. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array.yaml +0 -0
  129. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array.zip +0 -0
  130. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array_col.hdf +0 -0
  131. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array_col.json +0 -0
  132. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array_col.pkl +0 -0
  133. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array_col.yaml +0 -0
  134. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/array_col.zip +0 -0
  135. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/dict.hdf +0 -0
  136. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/dict.json +0 -0
  137. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/dict.pkl +0 -0
  138. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/dict.yaml +0 -0
  139. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/dict.zip +0 -0
  140. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/nested.hdf +0 -0
  141. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/nested.json +0 -0
  142. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/nested.pkl +0 -0
  143. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/nested.yaml +0 -0
  144. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/2/nested.zip +0 -0
  145. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array.hdf +0 -0
  146. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array.json +0 -0
  147. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array.pkl +0 -0
  148. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array.yaml +0 -0
  149. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array.zip +0 -0
  150. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array_col.hdf +0 -0
  151. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array_col.json +0 -0
  152. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array_col.pkl +0 -0
  153. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array_col.yaml +0 -0
  154. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/array_col.zip +0 -0
  155. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/dict.hdf +0 -0
  156. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/dict.json +0 -0
  157. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/dict.pkl +0 -0
  158. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/dict.yaml +0 -0
  159. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/dict.zip +0 -0
  160. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array.hdf +0 -0
  161. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array.json +0 -0
  162. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array.pkl +0 -0
  163. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array.yaml +0 -0
  164. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array.zip +0 -0
  165. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array_col.hdf +0 -0
  166. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array_col.json +0 -0
  167. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array_col.pkl +0 -0
  168. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array_col.yaml +0 -0
  169. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_array_col.zip +0 -0
  170. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_dict.hdf +0 -0
  171. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_dict.json +0 -0
  172. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_dict.pkl +0 -0
  173. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_dict.yaml +0 -0
  174. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_dict.zip +0 -0
  175. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_nested.hdf +0 -0
  176. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_nested.json +0 -0
  177. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_nested.pkl +0 -0
  178. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_nested.yaml +0 -0
  179. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/model_nested.zip +0 -0
  180. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/nested.hdf +0 -0
  181. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/nested.json +0 -0
  182. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/nested.pkl +0 -0
  183. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/nested.yaml +0 -0
  184. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/3/nested.zip +0 -0
  185. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/compatibility/test_compatibility.py +0 -0
  186. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/conftest.py +0 -0
  187. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/helpers/__init__.py +0 -0
  188. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/helpers/asserts.py +0 -0
  189. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/helpers/storage.py +0 -0
  190. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/empty.py +0 -0
  191. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/function.py +0 -0
  192. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/function_main.py +0 -0
  193. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/function_marked.py +0 -0
  194. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/make_model.py +0 -0
  195. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/make_model_class.py +0 -0
  196. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/scripts/make_model_marked.py +0 -0
  197. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/test_model.py +0 -0
  198. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/model/test_parameters.py +0 -0
  199. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/requirements.txt +0 -0
  200. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/scripts/fail.py +0 -0
  201. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/scripts/function.py +0 -0
  202. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/scripts/print.py +0 -0
  203. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/scripts/script.py +0 -0
  204. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/test_results.py +0 -0
  205. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/run/test_run_main.py +0 -0
  206. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/storage/test_group.py +0 -0
  207. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/storage/test_storage_special.py +0 -0
  208. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/storage/test_trajectory.py +0 -0
  209. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/storage/test_utils.py +0 -0
  210. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/test_config.py +0 -0
  211. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/test_examples.py +0 -0
  212. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/test_main.py +0 -0
  213. {py_modelrunner-0.18.0 → py_modelrunner-0.18.1}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py-modelrunner
3
- Version: 0.18.0
3
+ Version: 0.18.1
4
4
  Summary: Python classes for organizing (HPC) simulations
5
5
  Author-email: David Zwicker <david.zwicker@ds.mpg.de>
6
6
  License: MIT
@@ -20,33 +20,33 @@ Defining parameters using :mod:`~modelrunner.model.parameters`:
20
20
  Defining models using :mod:`~modelrunner.model`:
21
21
  Models are augmented functions, which define input, calculations, and output.
22
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.
23
+ :class:`~modelrunner.model.base.ModelBase`, which is built on the parameter classes.
24
24
 
25
- Model results are captured by :mod:`~modelrunner.results`:
26
- Results are returned as the special :class:`~modelrunner.results.Result`, which
25
+ Model results are captured by :mod:`~modelrunner.run.results`:
26
+ Results are returned as the special :class:`~modelrunner.run.results.Result`, which
27
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
28
+ :class:`~modelrunner.run.results.ResultCollection` describes a collections of the same
29
29
  model evoked with different parameter values.
30
30
 
31
31
  Submitting models to HPC using :mod:`~modelrunner.run`:
32
32
  A single model can be submitted to a compute node using :func:`~modelrunner.run.job.submit_job`,
33
33
  e.g., to run the computation on a high performance compute cluster.
34
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`.
35
+ The results written to one directory can then be conveniently analyzed using :func:`~modelrunner.run.results.ResultCollection.from_folder`.
36
36
 
37
37
 
38
38
  Design philosophy
39
39
  -----------------
40
40
 
41
- The main requirements for the storage classes were
41
+ The main requirements for the package can be summarized as follows:
42
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
- - *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)
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.
49
- - *Efficiency*: The files should only store necessary information.
43
+ - **Usability**: The user should not need to think about how data is stored in different files. The :class:`~modelrunner.run.results.Result` class should simply work.
44
+ - **Flexibility**: :mod:`~modelrunner.storage` should provide a unified interface to write data in multiple file formats (JSON, 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
+ - **Modularity**: Different parts of the package (like :mod:`~modelrunner.storage`, :mod:`~modelrunner.model.parameters`, and :mod:`~modelrunner.run`) should be rather independent of each other, so they can be used in isolation
47
+ - **Extensibility**: Models inherting from :class:`~modelrunner.model.base.ModelBase` should be easy to subclass to implement more complicated requirements (e.g., additional parameters)
48
+ - **Self-explainability**: The files should in principle contain all information to reconstruct the data, even if the :mod:`modelrunner` package is no longer available.
49
+ - **Efficiency**: The files should only store necessary information.
50
50
 
51
51
  The last point results in particular constraints if we want to store temporal simulation results.
52
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.
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.18.0'
16
- __version_tuple__ = version_tuple = (0, 18, 0)
15
+ __version__ = version = '0.18.1'
16
+ __version_tuple__ = version_tuple = (0, 18, 1)
@@ -219,10 +219,13 @@ def submit_job(
219
219
  job_args = []
220
220
  if parameters is not None and len(parameters) > 0:
221
221
  if isinstance(parameters, dict):
222
- parameters = json.dumps(parameters)
223
- elif not isinstance(parameters, str):
222
+ parameters_json = json.dumps(parameters)
223
+ elif isinstance(parameters, str):
224
+ parameters_json = parameters
225
+ else:
224
226
  raise TypeError("Parameters need to be given as a string or a dict")
225
- job_args.append(f"--json {escape_string(parameters)}")
227
+ job_args.append(f"--json {escape_string(parameters_json)}")
228
+ script_args["PARAMETERS"] = parameters # allow using parameters in job script
226
229
 
227
230
  logger.debug("Job arguments: `%s`", job_args)
228
231
 
@@ -55,7 +55,7 @@ class Result:
55
55
  The result is represented as a hierarchical structure when safed using the
56
56
  :mod:`~modelrunner.storage`. The actual result is stored in the `result` group,
57
57
  whereas the model information can be found in `_model` group. Additional
58
- information is stored in the root attribute. Thus, the full :class:`Result` can
58
+ information is stored in the `storage` group. Thus, the full :class:`Result` can
59
59
  be read using :code:`storage[loc]`, where `loc` denotes the result location. If
60
60
  only the actual result is needed, :code:`storage[loc + "/result"]` can be read.
61
61
  """
@@ -80,7 +80,7 @@ class TextStorageBase(MemoryStorage, metaclass=ABCMeta):
80
80
  elif self._modified:
81
81
  # The storage was modified, but it cannot be written to the file. This
82
82
  # should not happen, but it's better to throw an explicit error
83
- raise AccessError("Cannot write to file")
83
+ raise AccessError("Cannot write modifications to file opened read-only")
84
84
 
85
85
  def close(self) -> None:
86
86
  """close the file and write the data to the file"""
@@ -159,13 +159,20 @@ class _StorageRegistry:
159
159
  allowed_actions = set(ActionType.__args__) # type: ignore
160
160
  """set: all actions that can be registered"""
161
161
 
162
- _hooks: dict[type, dict[str, Callable]]
162
+ _hooks: dict[type, dict[str, tuple[Callable, bool]]]
163
163
  """dict: register for all defined hooks"""
164
164
 
165
165
  def __init__(self):
166
166
  self._hooks = defaultdict(dict)
167
167
 
168
- def register(self, action: ActionType, cls: type, method_or_func: Callable) -> None:
168
+ def register(
169
+ self,
170
+ action: ActionType,
171
+ cls: type,
172
+ method_or_func: Callable,
173
+ *,
174
+ inherit: bool = True,
175
+ ) -> None:
169
176
  """register an action for the given class
170
177
 
171
178
  Example:
@@ -182,6 +189,9 @@ class _StorageRegistry:
182
189
  The class this action is associated with
183
190
  method_or_func (callable):
184
191
  The function/method that is called for the action
192
+ inherit (bool):
193
+ Determines whether child classes of `cls` inherit this action and will
194
+ be able to use it.
185
195
  """
186
196
  if action not in self.allowed_actions:
187
197
  raise ValueError(f"Unknown action `{action}` ")
@@ -192,9 +202,9 @@ class _StorageRegistry:
192
202
  """helper function to call the classmethod"""
193
203
  return method_or_func(cls, *args, **kwargs)
194
204
 
195
- self._hooks[cls][action] = _call_classmethod
205
+ self._hooks[cls][action] = (_call_classmethod, inherit)
196
206
  elif callable(method_or_func):
197
- self._hooks[cls][action] = method_or_func
207
+ self._hooks[cls][action] = (method_or_func, inherit)
198
208
  else:
199
209
  raise TypeError("`method_or_func` must be method or function")
200
210
 
@@ -214,7 +224,9 @@ class _StorageRegistry:
214
224
  classes = inspect.getmro(cls)[:-1]
215
225
  for c in classes:
216
226
  if c in self._hooks and action in self._hooks[c]:
217
- return self._hooks[c][action]
227
+ func, inherit = self._hooks[c][action]
228
+ if inherit or c is cls:
229
+ return func
218
230
 
219
231
  raise RuntimeError(f"No action `{action}` for `{cls.__name__}`")
220
232
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py-modelrunner
3
- Version: 0.18.0
3
+ Version: 0.18.1
4
4
  Summary: Python classes for organizing (HPC) simulations
5
5
  Author-email: David Zwicker <david.zwicker@ds.mpg.de>
6
6
  License: MIT
@@ -92,6 +92,7 @@ scripts/run_tests.py
92
92
  scripts/tests_all.sh
93
93
  scripts/tests_codestyle.sh
94
94
  scripts/tests_coverage.sh
95
+ scripts/tests_debug.sh
95
96
  scripts/tests_parallel.sh
96
97
  scripts/tests_run.sh
97
98
  scripts/tests_types.sh
@@ -197,11 +198,13 @@ tests/model/scripts/make_model_marked.py
197
198
  tests/run/test_job.py
198
199
  tests/run/test_results.py
199
200
  tests/run/test_run_main.py
201
+ tests/run/scripts/custom.jinja
200
202
  tests/run/scripts/fail.py
201
203
  tests/run/scripts/function.py
202
204
  tests/run/scripts/print.py
203
205
  tests/run/scripts/script.py
204
206
  tests/storage/test_group.py
207
+ tests/storage/test_register_action.py
205
208
  tests/storage/test_storage_generic.py
206
209
  tests/storage/test_storage_special.py
207
210
  tests/storage/test_trajectory.py
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import argparse
4
6
  import os
5
7
  import subprocess as sp
@@ -66,6 +68,7 @@ def run_unit_tests(
66
68
  coverage: bool = False,
67
69
  no_numba: bool = False,
68
70
  pattern: str = None,
71
+ pytest_args: list[str] = [],
69
72
  ) -> int:
70
73
  """run the unit tests
71
74
 
@@ -74,6 +77,9 @@ def run_unit_tests(
74
77
  coverage (bool): Whether to determine the test coverage
75
78
  no_numba (bool): Whether to disable numba jit compilation
76
79
  pattern (str): A pattern that determines which tests are ran
80
+ pytest_args (list of str):
81
+ Additional arguments forwarded to py.test. For instance ["--maxfail=1"]
82
+ fails tests early.
77
83
 
78
84
  Returns:
79
85
  int: The return code indicating success or failure
@@ -117,6 +123,8 @@ def run_unit_tests(
117
123
  ]
118
124
  )
119
125
 
126
+ args.extend(pytest_args)
127
+
120
128
  # specify the package to run
121
129
  args.append("tests")
122
130
 
@@ -191,6 +199,13 @@ def main():
191
199
  help="Write a report of the results",
192
200
  )
193
201
 
202
+ # set py.test arguments
203
+ group = parser.add_argument_group(
204
+ "py.test arguments",
205
+ description="Additional arguments separated by `--` are forward to py.test",
206
+ )
207
+ group.add_argument("pytest_args", nargs="*", help=argparse.SUPPRESS)
208
+
194
209
  # parse the command line arguments
195
210
  args = parser.parse_args()
196
211
  run_all = not (args.style or args.types or args.unit)
@@ -206,6 +221,7 @@ def main():
206
221
  parallel=args.parallel,
207
222
  no_numba=args.no_numba,
208
223
  pattern=args.pattern,
224
+ pytest_args=args.pytest_args,
209
225
  )
210
226
 
211
227
 
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+
3
+ export PYTHONPATH=../py-modelrunner # likely path of package, relative to current base path
4
+
5
+ if [ ! -z $1 ]
6
+ then
7
+ # test pattern was specified
8
+ echo 'Run unittests with pattern '$1':'
9
+ ./run_tests.py --unit --pattern "$1" -- \
10
+ -o log_cli=true --log-cli-level=debug -vv
11
+ else
12
+ # test pattern was not specified
13
+ echo 'Run all unittests:'
14
+ ./run_tests.py --unit -- \
15
+ -o log_cli=true --log-cli-level=debug -vv
16
+ fi
@@ -0,0 +1,19 @@
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 }} -m modelrunner {{ MODEL_FILE }} --a {{ PARAMETERS.a }}
@@ -57,8 +57,8 @@ def test_submit_job_stdout(tmp_path, method):
57
57
  overwrite_strategy="silent_overwrite",
58
58
  )
59
59
 
60
- assert outs == "3.0\n"
61
60
  assert errs == ""
61
+ assert outs == "3.0\n"
62
62
  assert Result.from_file(output).result is None
63
63
 
64
64
 
@@ -69,8 +69,8 @@ def test_submit_job_no_output():
69
69
  method="foreground",
70
70
  overwrite_strategy="silent_overwrite",
71
71
  )
72
- assert outs == "3.0\n"
73
72
  assert errs == ""
73
+ assert outs == "3.0\n"
74
74
 
75
75
 
76
76
  def test_submit_jobs(tmp_path):
@@ -137,3 +137,17 @@ def test_submit_job_no_modelrunner(tmp_path):
137
137
 
138
138
  assert run() == ("", "")
139
139
  assert run(a=1) == ('--json{"a": 1}', "")
140
+
141
+
142
+ def test_submit_job_own_template(tmp_path):
143
+ """test the submit_job function with a custom template"""
144
+ outs, errs = submit_job(
145
+ SCRIPT_PATH / "print.py",
146
+ method="foreground",
147
+ parameters={"a": 5, "b": 10}, # b is not used by template
148
+ template=SCRIPT_PATH / "custom.jinja",
149
+ overwrite_strategy="silent_overwrite",
150
+ )
151
+
152
+ assert errs == ""
153
+ assert outs == "7.0\n" # a + 2 (default value of b)
@@ -0,0 +1,155 @@
1
+ """
2
+ .. codeauthor:: David Zwicker <david.zwicker@ds.mpg.de>
3
+ """
4
+
5
+ import pytest
6
+
7
+ from helpers import STORAGE_EXT, STORAGE_OBJECTS, assert_data_equals
8
+ from modelrunner.storage import StorageGroup, open_storage, storage_actions
9
+
10
+
11
+ class A:
12
+
13
+ def __init__(self, value):
14
+ self.value = value
15
+ self.loaded = False
16
+
17
+ def save(self, storage, loc):
18
+ storage.write_object(loc, self.value, cls=self.__class__)
19
+
20
+ @classmethod
21
+ def load(cls, storage, loc):
22
+ obj = cls(storage.read_object(loc))
23
+ obj.loaded = True
24
+ return obj
25
+
26
+
27
+ def save_A(storage, loc, obj):
28
+ obj.save(storage, loc)
29
+
30
+
31
+ storage_actions.register("read_item", A, A.load, inherit=True)
32
+ storage_actions.register("write_item", A, save_A, inherit=True)
33
+
34
+
35
+ class A1(A): ...
36
+
37
+
38
+ class A2(A):
39
+
40
+ @classmethod
41
+ def load(cls, storage, loc):
42
+ obj = cls(storage.read_object(loc))
43
+ obj.loaded = "yes"
44
+ return obj
45
+
46
+
47
+ storage_actions.register("read_item", A2, A2.load, inherit=False)
48
+
49
+
50
+ class B:
51
+
52
+ def __init__(self, a, b):
53
+ self.a = a
54
+ self.b = b
55
+ self.loaded = False
56
+
57
+ def save(self, storage, loc):
58
+ group = storage.create_group(loc, cls=self.__class__)
59
+ self.a.save(group, "a")
60
+ group.write_object("b", self.b)
61
+
62
+ @classmethod
63
+ def load(cls, storage, loc):
64
+ group = StorageGroup(storage, loc)
65
+ obj = cls(a=group["a"], b=group.read_object("b"))
66
+ obj.loaded = True
67
+ return obj
68
+
69
+
70
+ storage_actions.register("read_item", B, B.load, inherit=False)
71
+ storage_actions.register("write_item", B, lambda s, l, o: o.save(s, l), inherit=False)
72
+
73
+
74
+ class B1(B): ...
75
+
76
+
77
+ @pytest.mark.parametrize("ext", STORAGE_EXT)
78
+ def test_register_class_action(ext, tmp_path):
79
+ """test loading custom classes"""
80
+
81
+ a = A({"a": 1})
82
+ assert not a.loaded
83
+
84
+ with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
85
+ store["a"] = a
86
+
87
+ with open_storage(tmp_path / f"file{ext}", mode="read") as store:
88
+ b = store["a"]
89
+
90
+ assert b.loaded
91
+ assert b.value == {"a": 1}
92
+
93
+
94
+ @pytest.mark.parametrize("ext", STORAGE_EXT)
95
+ def test_register_class_action_nested(tmp_path, ext):
96
+ """test loading custom nested classes"""
97
+
98
+ a = A({"a": 1})
99
+ b = B(a, "str")
100
+ assert not a.loaded and not b.loaded
101
+
102
+ with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
103
+ store["data"] = b
104
+
105
+ with open_storage(tmp_path / f"file{ext}", mode="read") as store:
106
+ res = store["data"]
107
+
108
+ assert res.loaded and res.a.loaded
109
+ assert res.a.value == {"a": 1}
110
+ assert res.b == "str"
111
+
112
+
113
+ @pytest.mark.parametrize("ext", STORAGE_EXT)
114
+ def test_register_class_action_subclass(ext, tmp_path):
115
+ """test loading custom classes and subclasses"""
116
+
117
+ a = A({"a": 1})
118
+ a1 = A1({"b": 2}) # has not defined hooks itself
119
+ a2 = A2({"c": 3}) # has own loading hook
120
+ assert not a.loaded and not a1.loaded and not a2.loaded
121
+
122
+ with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
123
+ store["a"] = a
124
+ store["a1"] = a1
125
+ store["a2"] = a2
126
+
127
+ with open_storage(tmp_path / f"file{ext}", mode="read") as store:
128
+ b = store["a"]
129
+ b1 = store["a1"]
130
+ b2 = store["a2"]
131
+
132
+ assert b.loaded and b1.loaded and b2.loaded == "yes"
133
+ assert b.value == {"a": 1} and b1.value == {"b": 2} and b2.value == {"c": 3}
134
+
135
+
136
+ @pytest.mark.parametrize("ext", STORAGE_EXT)
137
+ def test_register_class_action_no_inhert(ext, tmp_path):
138
+ """test loading custom classes and subclasses"""
139
+
140
+ a = B(A({"a": 1}), 2) # does not use hooks that inherit
141
+ a1 = B1(A({"a": 2}), 4) # has not defined hooks itself
142
+ assert not a.loaded and not a1.loaded
143
+
144
+ with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
145
+ store["b"] = a
146
+ store["b1"] = a1
147
+
148
+ with open_storage(tmp_path / f"file{ext}", mode="read") as store:
149
+ b = store["b"]
150
+ b1 = store["b1"]
151
+
152
+ assert b.loaded # B uses the hook class
153
+ assert not b1.loaded # B2 does not yse the hook classes
154
+ assert b.a.value == {"a": 1} and b.b == 2
155
+ assert b1.a.value == {"a": 2} and b1.b == 4
@@ -6,7 +6,7 @@ import numpy as np
6
6
  import pytest
7
7
 
8
8
  from helpers import STORAGE_EXT, STORAGE_OBJECTS, assert_data_equals
9
- from modelrunner.storage import AccessError, StorageGroup, open_storage, storage_actions
9
+ from modelrunner.storage import AccessError, open_storage
10
10
 
11
11
  OBJ = {"a": 1, "b": np.arange(5)}
12
12
  ARRAY_EXAMPLES = [
@@ -328,87 +328,3 @@ def test_storage_close(ext, tmp_path):
328
328
  assert reader["obj"] == 1
329
329
  reader.close()
330
330
  assert reader.closed
331
-
332
-
333
- class A:
334
-
335
- def __init__(self, value):
336
- self.value = value
337
- self.loaded = False
338
-
339
- def save(self, storage, loc):
340
- storage.write_object(loc, self.value, cls=self.__class__)
341
-
342
- @classmethod
343
- def load(cls, storage, loc):
344
- obj = cls(storage.read_object(loc))
345
- obj.loaded = True
346
- return obj
347
-
348
-
349
- def save_A(storage, loc, obj):
350
- obj.save(storage, loc)
351
-
352
-
353
- storage_actions.register("read_item", A, A.load)
354
- storage_actions.register("write_item", A, save_A)
355
-
356
-
357
- class B:
358
-
359
- def __init__(self, a, b):
360
- self.a = a
361
- self.b = b
362
- self.loaded = False
363
-
364
- def save(self, storage, loc):
365
- group = storage.create_group(loc, cls=self.__class__)
366
- self.a.save(group, "a")
367
- group.write_object("b", self.b)
368
-
369
- @classmethod
370
- def load(cls, storage, loc):
371
- group = StorageGroup(storage, loc)
372
- obj = cls(a=group["a"], b=group.read_object("b"))
373
- obj.loaded = True
374
- return obj
375
-
376
-
377
- storage_actions.register("read_item", B, B.load)
378
- storage_actions.register("write_item", B, lambda s, l, o: o.save(s, l))
379
-
380
-
381
- @pytest.mark.parametrize("ext", STORAGE_EXT)
382
- def test_register_class_action(ext, tmp_path):
383
- """test loading custom classes"""
384
-
385
- a = A({"a": 1})
386
- assert not a.loaded
387
-
388
- with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
389
- store["a"] = a
390
-
391
- with open_storage(tmp_path / f"file{ext}", mode="read") as store:
392
- b = store["a"]
393
-
394
- assert b.loaded
395
- assert b.value == {"a": 1}
396
-
397
-
398
- @pytest.mark.parametrize("ext", STORAGE_EXT)
399
- def test_register_class_action_nested(tmp_path, ext):
400
- """test loading custom nested classes"""
401
-
402
- a = A({"a": 1})
403
- b = B(a, "str")
404
- assert not a.loaded and not b.loaded
405
-
406
- with open_storage(tmp_path / f"file{ext}", mode="truncate") as store:
407
- store["data"] = b
408
-
409
- with open_storage(tmp_path / f"file{ext}", mode="read") as store:
410
- res = store["data"]
411
-
412
- assert res.loaded and res.a.loaded
413
- assert res.a.value == {"a": 1}
414
- assert res.b == "str"
File without changes