imas-python 2.1.0.post1__tar.gz → 2.2.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.
Files changed (227) hide show
  1. {imas_python-2.1.0.post1/imas_python.egg-info → imas_python-2.2.0}/PKG-INFO +1 -1
  2. {imas_python-2.1.0.post1 → imas_python-2.2.0}/conftest.py +2 -32
  3. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/api.rst +12 -4
  4. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/multi-dd.rst +98 -15
  5. imas_python-2.2.0/imas/__init__.py +58 -0
  6. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_to_xarray.py +1 -1
  7. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_version.py +3 -3
  8. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/db_entry_impl.py +1 -1
  9. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/al_context.py +3 -3
  10. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/db_entry_al.py +26 -19
  11. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/imas_interface.py +9 -22
  12. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/mdsplus_model.py +19 -2
  13. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/uda_support.py +2 -2
  14. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/db_entry_nc.py +1 -1
  15. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc2ids.py +10 -2
  16. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc_metadata.py +3 -4
  17. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/cli.py +68 -3
  18. imas_python-2.2.0/imas/convert_core_edge_plasma.py +124 -0
  19. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/db_entry.py +3 -3
  20. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/exception.py +2 -4
  21. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_base.py +3 -3
  22. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_convert.py +3 -5
  23. imas_python-2.2.0/imas/ids_defs.py +131 -0
  24. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_factory.py +18 -1
  25. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_metadata.py +6 -6
  26. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_toplevel.py +3 -9
  27. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_cli.py +38 -3
  28. imas_python-2.2.0/imas/test/test_convert_core_edge_plasma.py +68 -0
  29. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_dbentry.py +3 -3
  30. imas_python-2.2.0/imas/test/test_dbentry_uda.py +80 -0
  31. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_exception.py +1 -1
  32. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_ascii_data.py +1 -1
  33. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_toplevel.py +1 -1
  34. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_validate.py +1 -1
  35. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_autofill.py +1 -3
  36. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_lazy_loading.py +5 -5
  37. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nbc_change.py +1 -1
  38. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_snippets.py +1 -1
  39. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_static_ids.py +1 -1
  40. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_to_xarray.py +1 -1
  41. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_util.py +3 -3
  42. {imas_python-2.1.0.post1 → imas_python-2.2.0/imas_python.egg-info}/PKG-INFO +1 -1
  43. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/SOURCES.txt +3 -1
  44. {imas_python-2.1.0.post1 → imas_python-2.2.0}/setup.cfg +0 -1
  45. imas_python-2.1.0.post1/imas/__init__.py +0 -30
  46. imas_python-2.1.0.post1/imas/ids_defs.py +0 -171
  47. imas_python-2.1.0.post1/tools/extract_test_data.py +0 -57
  48. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.git-blame-ignore-revs +0 -0
  49. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.git_archival.txt +0 -0
  50. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.gitattributes +0 -0
  51. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/CODEOWNERS +0 -0
  52. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/linting.yml +0 -0
  53. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/publish.yml +0 -0
  54. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/test_with_pytest.yml +0 -0
  55. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/verify_sphinx_doc.yml +0 -0
  56. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.gitignore +0 -0
  57. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.pylintrc +0 -0
  58. {imas_python-2.1.0.post1 → imas_python-2.2.0}/.readthedocs.yml +0 -0
  59. {imas_python-2.1.0.post1 → imas_python-2.2.0}/CODE_OF_CONDUCT.md +0 -0
  60. {imas_python-2.1.0.post1 → imas_python-2.2.0}/CONTRIBUTING.md +0 -0
  61. {imas_python-2.1.0.post1 → imas_python-2.2.0}/LICENSE.txt +0 -0
  62. {imas_python-2.1.0.post1 → imas_python-2.2.0}/MANIFEST.in +0 -0
  63. {imas_python-2.1.0.post1 → imas_python-2.2.0}/README.md +0 -0
  64. {imas_python-2.1.0.post1 → imas_python-2.2.0}/asv.conf.json +0 -0
  65. {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/__init__.py +0 -0
  66. {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/core_profiles.py +0 -0
  67. {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/edge_profiles.py +0 -0
  68. {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/technical.py +0 -0
  69. {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/utils.py +0 -0
  70. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/.gitignore +0 -0
  71. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/Makefile +0 -0
  72. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/.gitignore +0 -0
  73. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_static/imas.css +0 -0
  74. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_static/imas_200x200.png +0 -0
  75. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor.rst +0 -0
  76. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_attribute.rst +0 -0
  77. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_callable.rst +0 -0
  78. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_method.rst +0 -0
  79. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/base.rst +0 -0
  80. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/custom-class-template.rst +0 -0
  81. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/custom-module-template.rst +0 -0
  82. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/layout.html +0 -0
  83. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/api-hidden.rst +0 -0
  84. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/benchmarking.rst +0 -0
  85. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/changelog.rst +0 -0
  86. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/ci_config.rst +0 -0
  87. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/cli.rst +0 -0
  88. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/code_style.rst +0 -0
  89. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/conf.py +0 -0
  90. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/configuring.rst +0 -0
  91. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/dd_versions.rst +0 -0
  92. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/explore.rst +0 -0
  93. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/hashing.rst +0 -0
  94. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/alternative_coordinates.py +0 -0
  95. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/autoconvert_get.py +0 -0
  96. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/autoconvert_put.py +0 -0
  97. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/calc_with_units.py +0 -0
  98. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/coordinates.py +0 -0
  99. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/dd_versions.py +0 -0
  100. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/explore_data.py +0 -0
  101. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/explore_structures.py +0 -0
  102. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/hashing.py +0 -0
  103. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/ids_convert.py +0 -0
  104. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/ids_to_xarray.py +0 -0
  105. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/tensorized_ids_to_xarray.py +0 -0
  106. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/metadata.rst +0 -0
  107. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/xarray.rst +0 -0
  108. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced_user_training.rst +0 -0
  109. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/analyze.rst +0 -0
  110. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/core_profiles_ne_timeslice.png +0 -0
  111. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/core_profiles_te.png +0 -0
  112. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/create.rst +0 -0
  113. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/explore.rst +0 -0
  114. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_inspect.png +0 -0
  115. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/create_core_profiles.py +0 -0
  116. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_data_entry.py +0 -0
  117. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_public_ec_launchers.py +0 -0
  118. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_public_pf_active.py +0 -0
  119. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_training_data.py +0 -0
  120. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/find_paths.py +0 -0
  121. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/iterate_core_profiles.py +0 -0
  122. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/plot_core_profiles_ne_timeslice.py +0 -0
  123. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/plot_core_profiles_te.py +0 -0
  124. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/print_idss.py +0 -0
  125. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/read_core_profiles_ne_timeslice.py +0 -0
  126. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/read_equilibrium_time_array.py +0 -0
  127. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/read_whole_equilibrium.py +0 -0
  128. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/transform_grid.py +0 -0
  129. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/interactive_tab_core_profiles_toplevel.png +0 -0
  130. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/print_tree_ids_properties.png +0 -0
  131. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/setup.rst +0 -0
  132. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/transform.rst +0 -0
  133. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic_user_training.rst +0 -0
  134. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples/custom_conversion_em_coupling.py +0 -0
  135. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples/custom_conversion_em_coupling.rst +0 -0
  136. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples.rst +0 -0
  137. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/identifiers.rst +0 -0
  138. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/imas_architecture.rst +0 -0
  139. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/imas_structure.png +0 -0
  140. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/index.rst +0 -0
  141. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/installing.rst +0 -0
  142. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/intro.rst +0 -0
  143. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/lazy_loading.rst +0 -0
  144. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/mdsplus.rst +0 -0
  145. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/metadata.rst +0 -0
  146. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/netcdf/conventions.rst +0 -0
  147. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/netcdf.rst +0 -0
  148. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/release_imas.rst +0 -0
  149. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/resampling.rst +0 -0
  150. {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/validation.rst +0 -0
  151. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/__main__.py +0 -0
  152. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_util.py +0 -0
  153. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDSDef2MDSpreTree.xsl +0 -0
  154. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_fake_toplevel.xml +0 -0
  155. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal.xml +0 -0
  156. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_2.xml +0 -0
  157. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_struct_array.xml +0 -0
  158. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_types.xml +0 -0
  159. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/ITER_134173_106_core_profiles.ids +0 -0
  160. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/ITER_134173_106_equilibrium.ids +0 -0
  161. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/README.md +0 -0
  162. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/core_profiles.ids +0 -0
  163. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/equilibrium.ids +0 -0
  164. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/__init__.py +0 -0
  165. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/__init__.py +0 -0
  166. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/db_entry_helpers.py +0 -0
  167. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/__init__.py +0 -0
  168. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/ids2nc.py +0 -0
  169. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/ids_tensorizer.py +0 -0
  170. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/iterators.py +0 -0
  171. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc_validate.py +0 -0
  172. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/db_analysis.py +0 -0
  173. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/helpers.py +0 -0
  174. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/timer.py +0 -0
  175. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/dd_zip.py +0 -0
  176. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_coordinates.py +0 -0
  177. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_data_type.py +0 -0
  178. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_identifiers.py +0 -0
  179. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_path.py +0 -0
  180. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_primitive.py +0 -0
  181. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_struct_array.py +0 -0
  182. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_structure.py +0 -0
  183. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/setup_logging.py +0 -0
  184. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_all_dd_versions.py +0 -0
  185. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_dd_zip.py +0 -0
  186. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_deepcopy.py +0 -0
  187. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_get_sample.py +0 -0
  188. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_hash.py +0 -0
  189. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_helpers.py +0 -0
  190. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_identifiers.py +0 -0
  191. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids2nc.py +0 -0
  192. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_convert.py +0 -0
  193. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_coordinates.py +0 -0
  194. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_data_type.py +0 -0
  195. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_factory.py +0 -0
  196. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_metadata.py +0 -0
  197. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_mixin.py +0 -0
  198. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_path.py +0 -0
  199. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_primitive.py +0 -0
  200. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_struct_array.py +0 -0
  201. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_structure.py +0 -0
  202. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_manual.py +0 -0
  203. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_resample.py +0 -0
  204. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_list_occurrences.py +0 -0
  205. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal.py +0 -0
  206. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_conversion.py +0 -0
  207. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_io.py +0 -0
  208. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_struct_array_io.py +0 -0
  209. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types.py +0 -0
  210. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types_io.py +0 -0
  211. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types_io_automatic.py +0 -0
  212. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_autofill.py +0 -0
  213. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_entry.py +0 -0
  214. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_metadata.py +0 -0
  215. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_validation.py +0 -0
  216. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_str_1d.py +0 -0
  217. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_time_slicing.py +0 -0
  218. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_uda_support.py +0 -0
  219. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/training.py +0 -0
  220. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/util.py +0 -0
  221. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/dependency_links.txt +0 -0
  222. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/entry_points.txt +0 -0
  223. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/requires.txt +0 -0
  224. {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/top_level.txt +0 -0
  225. {imas_python-2.1.0.post1 → imas_python-2.2.0}/pyproject.toml +0 -0
  226. {imas_python-2.1.0.post1 → imas_python-2.2.0}/tools/compare_lowlevel_access_patterns.py +0 -0
  227. {imas_python-2.1.0.post1 → imas_python-2.2.0}/tools/get_tagnames.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: imas-python
3
- Version: 2.1.0.post1
3
+ Version: 2.2.0
4
4
  Summary: Pythonic wrappers for the IMAS Access Layer
5
5
  Author: ITER Organization
6
6
  Author-email: Karel Lucas van de Plassche <karelvandeplassche@gmail.com>, Daan van Vugt <dvanvugt@ignitioncomputing.com>, Maarten Sebregts <msebregts@ignitioncomputing.com>, imas-support@iter.org
@@ -9,7 +9,6 @@
9
9
  import functools
10
10
  import logging
11
11
  import os
12
- import sys
13
12
  from copy import deepcopy
14
13
  from pathlib import Path
15
14
 
@@ -22,7 +21,6 @@ import numpy as np
22
21
  import pytest
23
22
  from packaging.version import Version
24
23
 
25
- from imas.backends.imas_core.imas_interface import has_imas as _has_imas
26
24
  from imas.backends.imas_core.imas_interface import ll_interface, lowlevel
27
25
  from imas.dd_zip import dd_etree, dd_xml_versions, latest_dd_version
28
26
  from imas.ids_defs import (
@@ -39,17 +37,7 @@ logger.setLevel(logging.INFO)
39
37
 
40
38
  os.environ["IMAS_AL_DISABLE_VALIDATE"] = "1"
41
39
 
42
-
43
- try:
44
- import imas # noqa
45
- except ImportError:
46
-
47
- class SkipOnIMASAccess:
48
- def __getattr__(self, attr):
49
- pytest.skip("This test requires the `imas` HLI, which is not available.")
50
-
51
- # Any test that tries to access an attribute from the `imas` package will be skipped
52
- sys.modules["imas"] = SkipOnIMASAccess()
40
+ import imas # noqa
53
41
 
54
42
 
55
43
  def pytest_addoption(parser):
@@ -78,7 +66,6 @@ except ImasCoreBackendException as iex:
78
66
  if "not available" in str(iex.message):
79
67
  _BACKENDS.pop("mdsplus")
80
68
 
81
-
82
69
  try:
83
70
  import pytest_xdist
84
71
  except ImportError:
@@ -91,28 +78,11 @@ except ImportError:
91
78
  @pytest.fixture(params=_BACKENDS)
92
79
  def backend(pytestconfig: pytest.Config, request: pytest.FixtureRequest):
93
80
  backends_provided = any(map(pytestconfig.getoption, _BACKENDS))
94
- if not _has_imas:
95
- if backends_provided:
96
- raise RuntimeError(
97
- "Explicit backends are provided, but IMAS is not available."
98
- )
99
- pytest.skip("No IMAS available, skip tests using a backend")
100
81
  if backends_provided and not pytestconfig.getoption(request.param):
101
82
  pytest.skip(f"Tests for {request.param} backend are skipped.")
102
83
  return _BACKENDS[request.param]
103
84
 
104
85
 
105
- @pytest.fixture()
106
- def has_imas():
107
- return _has_imas
108
-
109
-
110
- @pytest.fixture()
111
- def requires_imas():
112
- if not _has_imas:
113
- pytest.skip("No IMAS available")
114
-
115
-
116
86
  def pytest_generate_tests(metafunc):
117
87
  if "ids_name" in metafunc.fixturenames:
118
88
  if metafunc.config.getoption("ids"):
@@ -214,7 +184,7 @@ def _lowlevel_wrapper(original_method):
214
184
 
215
185
 
216
186
  @pytest.fixture
217
- def log_lowlevel_calls(monkeypatch, requires_imas):
187
+ def log_lowlevel_calls(monkeypatch):
218
188
  """Debugging fixture to log calls to the imas lowlevel module."""
219
189
  for al_function in dir(lowlevel):
220
190
  if al_function.startswith("ual_") or al_function.startswith("al"):
@@ -7,16 +7,24 @@ This page provides an auto-generated summary of IMAS-Python's API. For more deta
7
7
  and examples, refer to the relevant chapters in the main part of the
8
8
  documentation.
9
9
 
10
- IMAS-Python IDS manipulation
11
- ----------------------------
10
+ IMAS-Python public API
11
+ ----------------------
12
12
 
13
13
  .. currentmodule:: imas
14
14
 
15
15
  .. autosummary::
16
16
 
17
+ convert_core_edge_plasma.convert_to_plasma_profiles
18
+ convert_core_edge_plasma.convert_to_plasma_sources
19
+ convert_core_edge_plasma.convert_to_plasma_transport
17
20
  db_entry.DBEntry
21
+ ids_convert.convert_ids
22
+ ids_data_type.IDSDataType
18
23
  ids_factory.IDSFactory
19
- ids_toplevel.IDSToplevel
24
+ ids_identifiers.identifiers
25
+ ids_metadata.IDSMetadata
26
+ ids_metadata.IDSType
20
27
  ids_primitive.IDSPrimitive
21
- ids_structure.IDSStructure
22
28
  ids_struct_array.IDSStructArray
29
+ ids_structure.IDSStructure
30
+ ids_toplevel.IDSToplevel
@@ -276,27 +276,110 @@ You need to explicitly convert the data, which you can do as follows:
276
276
  entry.put(imas.convert_ids(equilibrium, entry.dd_version))
277
277
 
278
278
 
279
+ .. _`UDA backend and DD versions`:
279
280
 
280
- .. _`DD background`:
281
+ UDA backend caching and Data Dictionary versions
282
+ ------------------------------------------------
281
283
 
282
- Background information
283
- ----------------------
284
+ If you try to load data from a different Data Dictionary version with the UDA backend,
285
+ you may see the following error:
286
+
287
+ .. code-block:: text
288
+
289
+ The Data Dictionary version of the data (3.38.1) is different from the Data
290
+ Dictionary version of the DBEntry (3.42.0). This is not supported when using the
291
+ UDA backend.
292
+
293
+ There are three possible workarounds. The first two require passing an additional option
294
+ in the IMAS UDA URI: please see the `imas-core documentation
295
+ <https://imas-core.readthedocs.io/en/stable/user_guide/backends_guide.html#query-keys-specific-for-the-uda-backend>`__
296
+ for more details on these URI options.
297
+
298
+ 1. Use UDA fetch to bypass the cache problem. You can do this by appending ``&fetch=1``
299
+ to the URI when you create the :py:class:`~imas.db_entry.DBEntry`.
300
+
301
+ Note that this will download the entire IDS files from the remote server, this may
302
+ not be desired if you only want to read a single time slice.
303
+ 2. Disable the UDA cache. You can do this by appending ``&cache_mode=none`` to the URI
304
+ when you create the :py:class:`~imas.db_entry.DBEntry`.
305
+
306
+ Note that this may make the ``get()`` (a lot) slower, since a separate request needs
307
+ to be sent to the remote UDA server for every data variable. However, this may still
308
+ be the best performing option if you are only interested in a subset of all the data
309
+ in an IDS (and use :ref:`lazy loading`).
310
+ 3. Explicitly provide the data dictionary version when you create the
311
+ :py:class:`~imas.db_entry.DBEntry`, setting it to match the Data Dictionary version
312
+ of the data you want to load. To obtain the version of the data on the remote server
313
+ from the field `ids_properties.put_version.data_dictionary` via a _lazy_ ``get()``
314
+ with ``autoconvert=False`` option and using the ``&cache_mode=none`` query in the URI.
315
+
316
+ Note that you may need to call ``imas.convert_ids`` to convert the IDS to your
317
+ desired Data Dictionary version.
318
+
319
+ All three possible workarounds are shown in the examples below:
320
+
321
+ .. md-tab-set::
322
+
323
+ .. md-tab-item:: Original code
324
+
325
+ .. code-block:: python
326
+
327
+ import imas
328
+
329
+ URI = (
330
+ "imas://uda.iter.org:56565/uda?backend=hdf5"
331
+ "&path=/work/imas/shared/imasdb/ITER/3/121013/50"
332
+ )
333
+ with imas.DBEntry(URI, "r") as entry:
334
+ cp = entry.get("core_profiles")
284
335
 
285
- Since IMAS-Python needs to have access to multiple DD versions it was chosen to
286
- bundle these with the code at build-time, in setup.py. If a git clone of the
287
- Data Dictionary succeeds, the setup tools automatically download saxon and
288
- generate ``IDSDef.xml`` for each of the tagged versions in the DD git
289
- repository. These are then gathered into ``IDSDef.zip``, which is
290
- distributed inside the IMAS-Python package.
336
+ .. md-tab-item:: 1. Use UDA fetch
291
337
 
292
- To update the set of data dictionaries new versions can be added to the zipfile.
293
- A reinstall of the package will ensure that all available versions are included
294
- in IMAS-Python. Additionally an explicit path to an XML file can be specified, which
295
- is useful for development.
338
+ .. code-block:: python
296
339
 
297
- Automated tests have been provided that check the loading of all of the DD
298
- versions tagged in the data-dictionary git repository.
340
+ import imas
299
341
 
342
+ URI = (
343
+ "imas://uda.iter.org:56565/uda?backend=hdf5"
344
+ "&path=/work/imas/shared/imasdb/ITER/3/121013/50&fetch=1"
345
+ )
346
+ with imas.DBEntry(URI, "r") as entry:
347
+ cp = entry.get("core_profiles")
348
+
349
+ .. md-tab-item:: 2. Disable the UDA cache
350
+
351
+ .. code-block:: python
352
+
353
+ import imas
354
+
355
+ URI = (
356
+ "imas://uda.iter.org:56565/uda?backend=hdf5"
357
+ "&path=/work/imas/shared/imasdb/ITER/3/121013/50&cache_mode=none"
358
+ )
359
+ with imas.DBEntry(URI, "r") as entry:
360
+ cp = entry.get("core_profiles")
361
+
362
+ .. md-tab-item:: 3. Explicitly provide the DD version
363
+
364
+ .. code-block:: python
365
+
366
+ import imas
367
+
368
+ URI = (
369
+ "imas://uda.iter.org:56565/uda?backend=hdf5"
370
+ "&path=/work/imas/shared/imasdb/ITER/3/121013/50"
371
+ )
372
+ with imas.DBEntry(URI, "r", dd_version="3.38.1") as entry:
373
+ cp = entry.get("core_profiles")
374
+
375
+ # Optional: convert the IDS to your desired DD version
376
+ cp = imas.convert_ids(cp, "3.42.0")
377
+
378
+
379
+ .. _`DD background`:
380
+
381
+ Background information
382
+ ----------------------
300
383
 
301
384
  Data Dictionary definitions
302
385
  '''''''''''''''''''''''''''
@@ -0,0 +1,58 @@
1
+ # This file is part of IMAS-Python.
2
+ # You should have received the IMAS-Python LICENSE file with this project.
3
+
4
+ from packaging.version import Version as _V
5
+
6
+ # Import logging _first_
7
+ # isort: off
8
+ from . import setup_logging # noqa: F401
9
+
10
+ # isort: on
11
+
12
+ # Ensure that `imas.util` is loaded when importing imas
13
+ from . import util # noqa: F401
14
+
15
+ # Public API:
16
+ from ._version import version as __version__
17
+ from ._version import version_tuple
18
+ from .convert_core_edge_plasma import (
19
+ convert_to_plasma_profiles,
20
+ convert_to_plasma_sources,
21
+ convert_to_plasma_transport,
22
+ )
23
+ from .db_entry import DBEntry
24
+ from .ids_convert import convert_ids
25
+ from .ids_data_type import IDSDataType
26
+ from .ids_factory import IDSFactory
27
+ from .ids_identifiers import identifiers
28
+ from .ids_metadata import IDSMetadata, IDSType
29
+ from .ids_primitive import IDSPrimitive
30
+ from .ids_struct_array import IDSStructArray
31
+ from .ids_structure import IDSStructure
32
+ from .ids_toplevel import IDSToplevel
33
+
34
+ PUBLISHED_DOCUMENTATION_ROOT = "https://imas-python.readthedocs.io/en/latest/"
35
+ """URL to the published documentation."""
36
+ OLDEST_SUPPORTED_VERSION = _V("3.22.0")
37
+ """Oldest Data Dictionary version that is supported by IMAS-Python."""
38
+
39
+ __all__ = [
40
+ "__version__",
41
+ "version_tuple",
42
+ "DBEntry",
43
+ "IDSDataType",
44
+ "IDSFactory",
45
+ "IDSMetadata",
46
+ "IDSPrimitive",
47
+ "IDSStructure",
48
+ "IDSStructArray",
49
+ "IDSToplevel",
50
+ "IDSType",
51
+ "convert_ids",
52
+ "convert_to_plasma_profiles",
53
+ "convert_to_plasma_sources",
54
+ "convert_to_plasma_transport",
55
+ "identifiers",
56
+ "PUBLISHED_DOCUMENTATION_ROOT",
57
+ "OLDEST_SUPPORTED_VERSION",
58
+ ]
@@ -27,7 +27,7 @@ def to_xarray(ids: IDSToplevel, *paths: str) -> xarray.Dataset:
27
27
  # block checks if the paths are valid, and by using "metadata.path_string" we ensure
28
28
  # that / are used as separator.
29
29
  try:
30
- paths = [ids.metadata[path].path_string for path in paths]
30
+ paths: list[str] = [ids.metadata[path].path_string for path in paths]
31
31
  except KeyError as exc:
32
32
  raise ValueError(str(exc)) from None
33
33
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.1.0.post1'
32
- __version_tuple__ = version_tuple = (2, 1, 0, 'post1')
31
+ __version__ = version = '2.2.0'
32
+ __version_tuple__ = version_tuple = (2, 2, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g72d7ea383'
34
+ __commit_id__ = commit_id = 'g049c5f765'
@@ -78,7 +78,7 @@ class DBEntryImpl(ABC):
78
78
  destination: IDSToplevel,
79
79
  lazy: bool,
80
80
  nbc_map: Optional[NBCPathMap],
81
- ) -> None:
81
+ ) -> IDSToplevel:
82
82
  """Implement DBEntry.get/get_slice/get_sample. Load data from the data source.
83
83
 
84
84
  Args:
@@ -115,7 +115,7 @@ class ALContext:
115
115
  tmin: float,
116
116
  tmax: float,
117
117
  dtime: Optional[numpy.ndarray],
118
- interpolation_method: int,
118
+ interpolation_method: Optional[int],
119
119
  ) -> "ALContext":
120
120
  """Begin a new timerange action for use in a ``with`` context."""
121
121
  ctx = ll_interface.begin_timerange_action(
@@ -163,7 +163,7 @@ class ALContext:
163
163
  """Call ual_write_data with this context."""
164
164
  status = ll_interface.write_data(self.ctx, path, timebasepath, data)
165
165
  if status != 0:
166
- raise LowlevelError(f"write data at {path!r}: {status=}")
166
+ raise LowlevelError(f"write data at {path!r}", status)
167
167
 
168
168
  def list_all_occurrences(self, ids_name: str) -> List[int]:
169
169
  """List all occurrences of this IDS."""
@@ -359,7 +359,7 @@ class LazyALContext:
359
359
  tmin: float,
360
360
  tmax: float,
361
361
  dtime: Optional[numpy.ndarray],
362
- interpolation_method: int,
362
+ interpolation_method: Optional[int],
363
363
  ) -> Iterator["LazyALContext"]:
364
364
  """Lazily start a lowlevel timerange action, see
365
365
  :meth:`ALContext.timerange_action`.
@@ -38,8 +38,8 @@ from imas.ids_toplevel import IDSToplevel
38
38
 
39
39
  from .al_context import ALContext, LazyALContext
40
40
  from .db_entry_helpers import delete_children, get_children, put_children
41
- from .imas_interface import LLInterfaceError, has_imas, ll_interface
42
- from .mdsplus_model import mdsplus_model_dir
41
+ from .imas_interface import LLInterfaceError, ll_interface
42
+ from .mdsplus_model import mdsplus_model_dir, get_mdsplus_model_var
43
43
  from .uda_support import extract_idsdef, get_dd_version_from_idsdef_xml
44
44
 
45
45
  _OPEN_MODES = {
@@ -52,14 +52,6 @@ _OPEN_MODES = {
52
52
  logger = logging.getLogger(__name__)
53
53
 
54
54
 
55
- def require_imas_available():
56
- if not has_imas:
57
- raise RuntimeError(
58
- "The IMAS Core library is not available. Please install 'imas_core', "
59
- "or load a supported IMAS module if you use an HPC environment."
60
- )
61
-
62
-
63
55
  class ALDBEntryImpl(DBEntryImpl):
64
56
  """DBEntry implementation using imas_core as a backend."""
65
57
 
@@ -86,7 +78,6 @@ class ALDBEntryImpl(DBEntryImpl):
86
78
 
87
79
  @classmethod
88
80
  def from_uri(cls, uri: str, mode: str, factory: IDSFactory) -> "ALDBEntryImpl":
89
- require_imas_available()
90
81
  if mode not in _OPEN_MODES:
91
82
  modes = list(_OPEN_MODES)
92
83
  raise ValueError(f"Unknown mode {mode!r}, was expecting any of {modes}")
@@ -105,9 +96,6 @@ class ALDBEntryImpl(DBEntryImpl):
105
96
  options: Any,
106
97
  factory: IDSFactory,
107
98
  ) -> "ALDBEntryImpl":
108
- # Raise an error if imas is not available
109
- require_imas_available()
110
-
111
99
  # Set defaults
112
100
  user_name = user_name or getpass.getuser()
113
101
  data_version = data_version or factory.dd_version
@@ -131,7 +119,7 @@ class ALDBEntryImpl(DBEntryImpl):
131
119
  # Building the MDS+ models is required when creating a new Data Entry
132
120
  ids_path = mdsplus_model_dir(factory)
133
121
  if ids_path:
134
- os.environ["ids_path"] = ids_path
122
+ os.environ[get_mdsplus_model_var()] = ids_path
135
123
 
136
124
  elif backend == "uda":
137
125
  # Set IDSDEF_PATH to point the UDA backend to the selected DD version
@@ -149,7 +137,7 @@ class ALDBEntryImpl(DBEntryImpl):
149
137
  if idsdef_path is None:
150
138
  # Extract XML from the DD zip and point UDA to it
151
139
  idsdef_path = extract_idsdef(factory.version)
152
- os.environ["IDSDEF_PATH"] = idsdef_path
140
+ os.environ["IDSDEF_PATH"] = str(idsdef_path)
153
141
 
154
142
  elif backend in ["hdf5", "memory", "ascii", "flexbuffers"]:
155
143
  pass # nothing to set up
@@ -184,7 +172,7 @@ class ALDBEntryImpl(DBEntryImpl):
184
172
  destination: IDSToplevel,
185
173
  lazy: bool,
186
174
  nbc_map: Optional[NBCPathMap],
187
- ) -> None:
175
+ ) -> IDSToplevel:
188
176
  if self._db_ctx is None:
189
177
  raise RuntimeError("Database entry is not open.")
190
178
  if lazy and self.backend == "ascii":
@@ -268,6 +256,22 @@ class ALDBEntryImpl(DBEntryImpl):
268
256
  raise DataEntryException(
269
257
  f"IDS {ids_name!r}, occurrence {occurrence} is empty."
270
258
  )
259
+
260
+ # UDA caching doesn't play well when the DD version of the on-disk IDS doesn't
261
+ # match the DD version of this DBEntry. See GH#97
262
+ if self.backend == "uda" and dd_version != self._ids_factory.dd_version:
263
+ cache_mode = self._querydict.get("cache_mode")
264
+ fetch = self._querydict.get("fetch")
265
+ if cache_mode != "none" and fetch not in ("1", "true"):
266
+ raise RuntimeError(
267
+ f"The Data Dictionary version of the data ({dd_version}) is "
268
+ "different from the Data Dictionary version of the DBEntry "
269
+ f"({self._ids_factory.dd_version}). This is not supported when "
270
+ f"using the UDA backend. See {imas.PUBLISHED_DOCUMENTATION_ROOT}"
271
+ "multi-dd.html#uda-backend-caching-and-data-dictionary-versions "
272
+ "for more details and workarounds."
273
+ )
274
+
271
275
  return dd_version
272
276
 
273
277
  def put(self, ids: IDSToplevel, occurrence: int, is_slice: bool) -> None:
@@ -299,7 +303,7 @@ class ALDBEntryImpl(DBEntryImpl):
299
303
  if occurrence != 0:
300
304
  ll_path += f"/{occurrence}"
301
305
 
302
- time_mode = ids.ids_properties.homogeneous_time
306
+ time_mode = int(ids.ids_properties.homogeneous_time)
303
307
  if is_slice:
304
308
  with self._db_ctx.global_action(ll_path, READ_OP) as read_ctx:
305
309
  db_time_mode = read_ctx.read_data(
@@ -344,9 +348,12 @@ class ALDBEntryImpl(DBEntryImpl):
344
348
  ll_path += f"/{occurrence}"
345
349
  ids = self._ids_factory.new(ids_name)
346
350
  with self._db_ctx.global_action(ll_path, WRITE_OP) as write_ctx:
347
- delete_children(ids.metadata, write_ctx, "")
351
+ delete_children(ids.metadata, write_ctx)
348
352
 
349
353
  def list_all_occurrences(self, ids_name: str) -> List[int]:
354
+ if self._db_ctx is None:
355
+ raise RuntimeError("Database entry is not open.")
356
+
350
357
  try:
351
358
  occurrence_list = self._db_ctx.list_all_occurrences(ids_name)
352
359
  except LLInterfaceError:
@@ -12,30 +12,17 @@ import logging
12
12
 
13
13
  from packaging.version import Version
14
14
 
15
- logger = logging.getLogger(__name__)
15
+ # Import the Access Layer module
16
+ # First try to import imas_core, which is available since AL 5.2
17
+ from imas_core import _al_lowlevel as lowlevel
18
+ from imas_core import imasdef # noqa: F401
16
19
 
20
+ logger = logging.getLogger(__name__)
17
21
 
18
- # Import the Access Layer module
19
- has_imas = True
20
- try:
21
- # First try to import imas_core, which is available since AL 5.2
22
- from imas_core import _al_lowlevel as lowlevel
23
- from imas_core import imasdef
24
-
25
- # Enable throwing exceptions from the _al_lowlevel interface
26
- enable_exceptions = getattr(lowlevel, "imas_core_config_enable_exceptions", None)
27
- if enable_exceptions:
28
- enable_exceptions()
29
-
30
- except ImportError as exc:
31
- imas = None
32
- has_imas = False
33
- imasdef = None
34
- lowlevel = None
35
- logger.warning(
36
- "Could not import 'imas_core': %s. Some functionality is not available.",
37
- exc,
38
- )
22
+ # Enable throwing exceptions from the _al_lowlevel interface
23
+ enable_exceptions = getattr(lowlevel, "imas_core_config_enable_exceptions", None)
24
+ if enable_exceptions:
25
+ enable_exceptions()
39
26
 
40
27
 
41
28
  class LLInterfaceError(RuntimeError):
@@ -14,6 +14,7 @@ import uuid
14
14
  from pathlib import Path
15
15
  from subprocess import CalledProcessError, check_output
16
16
  from zlib import crc32
17
+ from packaging.version import Version
17
18
 
18
19
  try:
19
20
  from importlib.resources import as_file, files
@@ -24,6 +25,8 @@ from imas.dd_zip import get_dd_xml, get_dd_xml_crc
24
25
  from imas.exception import MDSPlusModelError
25
26
  from imas.ids_factory import IDSFactory
26
27
 
28
+ from .imas_interface import ll_interface
29
+
27
30
  logger = logging.getLogger(__name__)
28
31
 
29
32
 
@@ -292,6 +295,20 @@ def create_model_ids_xml(cache_dir_path, fname, version):
292
295
  raise e
293
296
 
294
297
 
298
+ def get_mdsplus_model_var() -> str:
299
+ """
300
+ Return the environemnt variable name used by IMAS-Core to locate models:
301
+
302
+ - 'ids_path' for IMAS-Core<5.6
303
+ - 'MDSPLUS_MODELS_PATH' for IMAS-Core>=5.6
304
+ """
305
+ return (
306
+ "ids_path"
307
+ if ll_interface._al_version < Version("5.6.0")
308
+ else "MDSPLUS_MODELS_PATH"
309
+ )
310
+
311
+
295
312
  def create_mdsplus_model(cache_dir_path: Path) -> None:
296
313
  """Use jtraverser to compile a valid MDS model file."""
297
314
  try:
@@ -322,7 +339,7 @@ def create_mdsplus_model(cache_dir_path: Path) -> None:
322
339
  env={
323
340
  "PATH": os.environ.get("PATH", ""),
324
341
  "LD_LIBRARY_PATH": os.environ.get("LD_LIBRARY_PATH", ""),
325
- "ids_path": str(cache_dir_path),
342
+ get_mdsplus_model_var(): str(cache_dir_path),
326
343
  },
327
344
  )
328
345
  # Touch a file to show that we have finished the model
@@ -349,7 +366,7 @@ def jTraverser_jar() -> Path:
349
366
  for component in os.environ.get("CLASSPATH", "").split(":"):
350
367
  if component.endswith(".jar"):
351
368
  if re.search(".*jTraverser.jar", component):
352
- return component
369
+ return Path(component)
353
370
  else: # assume its a directory (strip any '*' suffix)
354
371
  search_dirs.append(component.rstrip("*"))
355
372
 
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from pathlib import Path
3
- from typing import Union
3
+ from typing import Union, Optional
4
4
  from xml.etree import ElementTree as ET
5
5
 
6
6
  from imas import dd_zip
@@ -10,7 +10,7 @@ from .mdsplus_model import _get_xdg_cache_dir
10
10
  logger = logging.getLogger(__name__)
11
11
 
12
12
 
13
- def get_dd_version_from_idsdef_xml(path: Union[str, Path]) -> str:
13
+ def get_dd_version_from_idsdef_xml(path: Union[str, Path]) -> Optional[str]:
14
14
  """Parse the IDSDef.xml up to the point where the Data Dictionary version is set.
15
15
 
16
16
  Returns:
@@ -100,7 +100,7 @@ class NCDBEntryImpl(DBEntryImpl):
100
100
  destination: IDSToplevel,
101
101
  lazy: bool,
102
102
  nbc_map: Optional[NBCPathMap],
103
- ) -> None:
103
+ ) -> IDSToplevel:
104
104
  # Feature compatibility checks
105
105
  if parameters is not None:
106
106
  if isinstance(parameters, GetSliceParameters):
@@ -157,6 +157,8 @@ class NC2IDS:
157
157
  for index, node in indexed_tree_iter(self.ids, target_metadata):
158
158
  value = data[index]
159
159
  if value != getattr(var, "_FillValue", None):
160
+ if isinstance(value, np.generic):
161
+ value = value.item()
160
162
  # NOTE: bypassing IDSPrimitive.value.setter logic
161
163
  node._IDSPrimitive__value = value
162
164
 
@@ -166,10 +168,16 @@ class NC2IDS:
166
168
  # here, we'll let IDSPrimitive.value.setter take care of it:
167
169
  self.ids[target_metadata.path].value = data
168
170
 
169
- else:
171
+ # We need to unpack 0D ints, floats and complex numbers. For better
172
+ # performance this check is done outside the for-loop:
173
+ elif metadata.ndim or metadata.data_type is IDSDataType.STR:
170
174
  for index, node in indexed_tree_iter(self.ids, target_metadata):
171
175
  # NOTE: bypassing IDSPrimitive.value.setter logic
172
176
  node._IDSPrimitive__value = data[index]
177
+ else:
178
+ for index, node in indexed_tree_iter(self.ids, target_metadata):
179
+ # NOTE: bypassing IDSPrimitive.value.setter logic
180
+ node._IDSPrimitive__value = data[index].item() # Unpack 0D value
173
181
 
174
182
  def validate_variables(self) -> None:
175
183
  """Validate that all variables in the netCDF Group exist and match the DD."""
@@ -365,7 +373,7 @@ class LazyContext:
365
373
  value = var[self.index]
366
374
 
367
375
  if value is not None:
368
- if isinstance(value, np.ndarray):
376
+ if isinstance(value, (np.ndarray, np.generic)):
369
377
  if value.ndim == 0: # Unpack 0D numpy arrays:
370
378
  value = value.item()
371
379
  else:
@@ -1,7 +1,6 @@
1
1
  # This file is part of IMAS-Python.
2
2
  # You should have received the IMAS-Python LICENSE file with this project.
3
- """NetCDF metadata for dimensions and tensorization of IDSs.
4
- """
3
+ """NetCDF metadata for dimensions and tensorization of IDSs."""
5
4
 
6
5
  from functools import lru_cache
7
6
  from typing import Dict, List, Optional, Set, Tuple
@@ -89,7 +88,7 @@ class NCMetadata:
89
88
  # Add cache for public API
90
89
  self.get_dimensions = lru_cache(maxsize=None)(self.get_dimensions)
91
90
 
92
- def get_coordinates(self, path: str, homogeneous_time: bool) -> Tuple[str]:
91
+ def get_coordinates(self, path: str, homogeneous_time: bool) -> Tuple[str, ...]:
93
92
  """Get the coordinates (adhering to CF conventions) for a netCDF variable.
94
93
 
95
94
  Args:
@@ -109,7 +108,7 @@ class NCMetadata:
109
108
  for coord in self.coordinates[path]
110
109
  )
111
110
 
112
- def get_dimensions(self, path: str, homogeneous_time: bool) -> Tuple[str]:
111
+ def get_dimensions(self, path: str, homogeneous_time: bool) -> Tuple[str, ...]:
113
112
  """Get the dimensions for a netCDF variable.
114
113
 
115
114
  Args: