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.
- {imas_python-2.1.0.post1/imas_python.egg-info → imas_python-2.2.0}/PKG-INFO +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/conftest.py +2 -32
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/api.rst +12 -4
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/multi-dd.rst +98 -15
- imas_python-2.2.0/imas/__init__.py +58 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_to_xarray.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_version.py +3 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/db_entry_impl.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/al_context.py +3 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/db_entry_al.py +26 -19
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/imas_interface.py +9 -22
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/mdsplus_model.py +19 -2
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/uda_support.py +2 -2
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/db_entry_nc.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc2ids.py +10 -2
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc_metadata.py +3 -4
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/cli.py +68 -3
- imas_python-2.2.0/imas/convert_core_edge_plasma.py +124 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/db_entry.py +3 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/exception.py +2 -4
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_base.py +3 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_convert.py +3 -5
- imas_python-2.2.0/imas/ids_defs.py +131 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_factory.py +18 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_metadata.py +6 -6
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_toplevel.py +3 -9
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_cli.py +38 -3
- imas_python-2.2.0/imas/test/test_convert_core_edge_plasma.py +68 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_dbentry.py +3 -3
- imas_python-2.2.0/imas/test/test_dbentry_uda.py +80 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_exception.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_ascii_data.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_toplevel.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_validate.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_autofill.py +1 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_lazy_loading.py +5 -5
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nbc_change.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_snippets.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_static_ids.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_to_xarray.py +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_util.py +3 -3
- {imas_python-2.1.0.post1 → imas_python-2.2.0/imas_python.egg-info}/PKG-INFO +1 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/SOURCES.txt +3 -1
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/setup.cfg +0 -1
- imas_python-2.1.0.post1/imas/__init__.py +0 -30
- imas_python-2.1.0.post1/imas/ids_defs.py +0 -171
- imas_python-2.1.0.post1/tools/extract_test_data.py +0 -57
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.git-blame-ignore-revs +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.git_archival.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.gitattributes +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/CODEOWNERS +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/linting.yml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/publish.yml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/test_with_pytest.yml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.github/workflows/verify_sphinx_doc.yml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.gitignore +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.pylintrc +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/.readthedocs.yml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/CODE_OF_CONDUCT.md +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/CONTRIBUTING.md +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/LICENSE.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/MANIFEST.in +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/README.md +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/asv.conf.json +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/__init__.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/core_profiles.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/edge_profiles.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/technical.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/benchmarks/utils.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/.gitignore +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/Makefile +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/.gitignore +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_static/imas.css +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_static/imas_200x200.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_attribute.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_callable.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/accessor_method.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/autosummary/base.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/custom-class-template.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/custom-module-template.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/_templates/layout.html +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/api-hidden.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/benchmarking.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/changelog.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/ci_config.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/cli.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/code_style.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/conf.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/configuring.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/dd_versions.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/explore.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/hashing.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/alternative_coordinates.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/autoconvert_get.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/autoconvert_put.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/calc_with_units.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/coordinates.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/dd_versions.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/explore_data.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/explore_structures.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/hashing.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/ids_convert.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/ids_to_xarray.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/imas_snippets/tensorized_ids_to_xarray.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/metadata.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced/xarray.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/advanced_user_training.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/analyze.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/core_profiles_ne_timeslice.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/core_profiles_te.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/create.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/explore.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_inspect.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/create_core_profiles.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_data_entry.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_public_ec_launchers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_public_pf_active.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/explore_training_data.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/find_paths.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/iterate_core_profiles.py +0 -0
- {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
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/plot_core_profiles_te.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/print_idss.py +0 -0
- {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
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/read_equilibrium_time_array.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/read_whole_equilibrium.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/imas_snippets/transform_grid.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/interactive_tab_core_profiles_toplevel.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/print_tree_ids_properties.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/setup.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic/transform.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/courses/basic_user_training.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples/custom_conversion_em_coupling.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples/custom_conversion_em_coupling.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/examples.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/identifiers.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/imas_architecture.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/imas_structure.png +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/index.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/installing.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/intro.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/lazy_loading.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/mdsplus.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/metadata.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/netcdf/conventions.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/netcdf.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/release_imas.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/resampling.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/docs/source/validation.rst +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/__main__.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/_util.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDSDef2MDSpreTree.xsl +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_fake_toplevel.xml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal.xml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_2.xml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_struct_array.xml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/IDS_minimal_types.xml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/ITER_134173_106_core_profiles.ids +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/ITER_134173_106_equilibrium.ids +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/README.md +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/core_profiles.ids +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/assets/equilibrium.ids +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/__init__.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/__init__.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/imas_core/db_entry_helpers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/__init__.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/ids2nc.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/ids_tensorizer.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/iterators.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/backends/netcdf/nc_validate.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/db_analysis.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/helpers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/command/timer.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/dd_zip.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_coordinates.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_data_type.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_identifiers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_path.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_primitive.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_struct_array.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/ids_structure.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/setup_logging.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_all_dd_versions.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_dd_zip.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_deepcopy.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_get_sample.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_hash.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_helpers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_identifiers.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids2nc.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_convert.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_coordinates.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_data_type.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_factory.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_metadata.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_mixin.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_path.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_primitive.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_struct_array.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_ids_structure.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_manual.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_latest_dd_resample.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_list_occurrences.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_conversion.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_io.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_struct_array_io.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types_io.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_minimal_types_io_automatic.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_autofill.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_entry.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_metadata.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_nc_validation.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_str_1d.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_time_slicing.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/test/test_uda_support.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/training.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas/util.py +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/dependency_links.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/entry_points.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/requires.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/imas_python.egg-info/top_level.txt +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/pyproject.toml +0 -0
- {imas_python-2.1.0.post1 → imas_python-2.2.0}/tools/compare_lowlevel_access_patterns.py +0 -0
- {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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
281
|
+
UDA backend caching and Data Dictionary versions
|
|
282
|
+
------------------------------------------------
|
|
281
283
|
|
|
282
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
32
|
-
__version_tuple__ = version_tuple = (2,
|
|
31
|
+
__version__ = version = '2.2.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 2, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g049c5f765'
|
|
@@ -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}
|
|
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,
|
|
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[
|
|
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
|
-
) ->
|
|
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
|
-
|
|
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
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
) ->
|
|
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
|
-
|
|
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:
|