h5rdmtoolbox 2.6.0__tar.gz → 2.6.2__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 (128) hide show
  1. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/LICENSE +1 -1
  2. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/PKG-INFO +102 -27
  3. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/README.md +101 -26
  4. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/__init__.py +5 -4
  5. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/_initialization.py +2 -1
  6. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/core.py +36 -0
  7. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/utils.py +19 -41
  8. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/references.py +7 -1
  9. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/protocols.py +2 -0
  10. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/utils.py +9 -8
  11. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/zenodo/core.py +39 -18
  12. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/PKG-INFO +102 -27
  13. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/SOURCES.txt +1 -0
  14. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/pyproject.toml +1 -1
  15. h5rdmtoolbox-2.6.2/tests/test_readme.py +22 -0
  16. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/__init__.py +0 -0
  17. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/_cfg.py +0 -0
  18. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/_repr.py +0 -0
  19. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/_version.py +0 -0
  20. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/abstracts.py +0 -0
  21. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/profiles.py +0 -0
  22. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/query_templates.py +0 -0
  23. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/stores/__init__.py +0 -0
  24. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/catalog/stores/hdf5.py +0 -0
  25. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/cli.py +0 -0
  26. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/consts.py +0 -0
  27. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/__init__.py +0 -0
  28. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/cfg.py +0 -0
  29. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/consts.py +0 -0
  30. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/core.py +0 -0
  31. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/errors.py +0 -0
  32. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/generate.py +0 -0
  33. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/ontology/__init__.py +0 -0
  34. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/ontology/h5ontocls.py +0 -0
  35. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/ontology/hdf_datatypes.py +0 -0
  36. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/standard_attributes.py +0 -0
  37. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/toolbox_validators.py +0 -0
  38. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/convention/utils.py +0 -0
  39. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/def_icon.png +0 -0
  40. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/fluid-v1.yml +0 -0
  41. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/h5tbx.yaml +0 -0
  42. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/id_icon.png +0 -0
  43. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/iri_icon.png +0 -0
  44. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/ld_icon.png +0 -0
  45. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/piv-v1.yml +0 -0
  46. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/style.css +0 -0
  47. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/tutorial_convention.yaml +0 -0
  48. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/tutorial_convention_vfuncs.py +0 -0
  49. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/tutorial_standard_name_table.yaml +0 -0
  50. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/data/type_icon.png +0 -0
  51. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/__init__.py +0 -0
  52. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/hdfdb/__init__.py +0 -0
  53. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/hdfdb/filedb.py +0 -0
  54. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/hdfdb/objdb.py +0 -0
  55. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/hdfdb/query.py +0 -0
  56. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/hdfdb/utils.py +0 -0
  57. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/interface.py +0 -0
  58. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/lazy.py +0 -0
  59. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/database/mongo.py +0 -0
  60. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/errors.py +0 -0
  61. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/__init__.py +0 -0
  62. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/magnitude.py +0 -0
  63. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/normalize.py +0 -0
  64. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/onto.py +0 -0
  65. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/units.py +0 -0
  66. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/extensions/vector.py +0 -0
  67. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/gui/__init__.py +0 -0
  68. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/gui/fairify.py +0 -0
  69. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/gui/src/__init__.py +0 -0
  70. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/gui/src/main.py +0 -0
  71. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/identifiers.py +0 -0
  72. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/layout/__init__.py +0 -0
  73. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/layout/core.py +0 -0
  74. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/__init__.py +0 -0
  75. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/globals.py +0 -0
  76. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/hdf/__init__.py +0 -0
  77. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/hdf/attributes.py +0 -0
  78. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/hdf/datasets.py +0 -0
  79. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/hdf/file.py +0 -0
  80. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/hdf/groups.py +0 -0
  81. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/rdf.py +0 -0
  82. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/shacl.py +0 -0
  83. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/__init__.py +0 -0
  84. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/attributes.py +0 -0
  85. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/datasets.py +0 -0
  86. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/file.py +0 -0
  87. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/groups.py +0 -0
  88. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/user/utils.py +0 -0
  89. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/ld/utils.py +0 -0
  90. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/plotting.py +0 -0
  91. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/protected_attributes.py +0 -0
  92. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/__init__.py +0 -0
  93. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/default_metamapper.py +0 -0
  94. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/interface.py +0 -0
  95. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/zenodo/__init__.py +0 -0
  96. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/zenodo/metadata.py +0 -0
  97. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/zenodo/tokens.py +0 -0
  98. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/repository/zenodo/utils.py +0 -0
  99. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/tutorial.py +0 -0
  100. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/user.py +0 -0
  101. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/utils.py +0 -0
  102. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/__init__.py +0 -0
  103. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/accessor.py +0 -0
  104. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/accessors/__init__.py +0 -0
  105. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/accessors/provenance.py +0 -0
  106. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/core.py +0 -0
  107. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/ds_decoder.py +0 -0
  108. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/h5attr.py +0 -0
  109. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/h5ext.py +0 -0
  110. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/h5utils.py +0 -0
  111. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/h5yaml.py +0 -0
  112. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/jsonld.py +0 -0
  113. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox/wrapper/xr2hdf.py +0 -0
  114. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/dependency_links.txt +0 -0
  115. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/entry_points.txt +0 -0
  116. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/requires.txt +0 -0
  117. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/h5rdmtoolbox.egg-info/top_level.txt +0 -0
  118. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/setup.cfg +0 -0
  119. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_cli.py +0 -0
  120. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_config.py +0 -0
  121. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_extensions.py +0 -0
  122. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_identifiers.py +0 -0
  123. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_plotting.py +0 -0
  124. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_repr.py +0 -0
  125. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_user.py +0 -0
  126. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_utils.py +0 -0
  127. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_version.py +0 -0
  128. {h5rdmtoolbox-2.6.0 → h5rdmtoolbox-2.6.2}/tests/test_xarray_export.py +0 -0
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-2023 Scott Chacon and others
1
+ Copyright (c) 2022-2026 h5rdmtoolbox contributors
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: h5rdmtoolbox
3
- Version: 2.6.0
3
+ Version: 2.6.2
4
4
  Summary: Supporting a FAIR Research Data lifecycle using Python and HDF5.
5
5
  Author-email: Matthias Probst <matth.probst@gmail.com>
6
6
  License-Expression: MIT
@@ -85,34 +85,109 @@ Dynamic: license-file
85
85
  ![Tests](https://github.com/matthiasprobst/h5RDMtoolbox/actions/workflows/tests.yml/badge.svg)
86
86
  [![codecov](https://codecov.io/gh/matthiasprobst/h5RDMtoolbox/graph/badge.svg?token=IVG4AQEW47)](https://codecov.io/gh/matthiasprobst/h5RDMtoolbox)
87
87
  [![Documentation Status](https://readthedocs.org/projects/h5rdmtoolbox/badge/?version=latest)](https://h5rdmtoolbox.readthedocs.io/en/latest/?badge=latest)
88
+ [![PyPI version](https://badge.fury.io/py/h5RDMtoolbox.svg)](https://badge.fury.io/py/h5RDMtoolbox)
88
89
  ![pyvers](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)
89
90
 
90
- *Note, that the project is still under development!*
91
-
92
- The "HDF5 Research Data Management Toolbox" (h5RDMtoolbox) is a Python package supporting everybody who is working with
93
- HDF5 to achieve a sustainable data lifecycle which follows
94
- the [FAIR (Findable, Accessible, Interoperable, Reusable)](https://www.nature.com/articles/sdata201618)
95
- principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and
96
- *reusing* data. Please visit the [documentation](https://h5rdmtoolbox.readthedocs.io/en/latest/) for detailed
97
- information of try the [quickstart using colab](#quickstart).
98
-
99
- ## Highlights
100
-
101
- - Combining HDF5 and [xarray](https://docs.xarray.dev/en/stable/) to allow easy access to metadata and data during
102
- analysis and processing (
103
- see [here](https://h5rdmtoolbox.readthedocs.io/en/latest/gettingstarted/quickoverview.html#datasets-xarray-interface)).
104
- - Assigning [metadata with "globally unique and persistent identifiers"]() as required
105
- by [F1 of the FAIR principles](https://www.go-fair.org/fair-principles/f1-meta-data-assigned-globally-unique-persistent-identifiers/).
106
- This can be achieved by using [RDF triples](https://www.w3.org/RDF/), which removes "ambiguity in the meaning of your
107
- published data".
108
- - Define standard attributes through
109
- [conventions](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/convention/index.html) and enforce users to use
110
- certain attributes in their HDF5 files, such as units and a description, for example.
111
- - Upload HDF5 files directly
112
- to [repositories](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/repository/index.html)
113
- like [Zenodo](https://zenodo.org/)
114
- or [use them with noSQL databases](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/database/index.html) like
115
- [mongoDB](https://www.mongodb.com/).
91
+ A Python package that helps researchers achieve sustainable
92
+ [**FAIR (Findable, Accessible, Interoperable, Reusable)**](https://www.nature.com/articles/sdata201618) data management with HDF5 files. The toolbox provides a comprehensive
93
+ approach to the research data lifecycle through five main stages: **planning**, **collecting**, **analyzing**,
94
+ **sharing**, and **reusing** data.
95
+
96
+ > **Note**: This project is actively under development.
97
+
98
+
99
+
100
+
101
+ ## ✨ Quick Start
102
+
103
+
104
+ One of the core features of the toolbox and success factors for achieving FAIR data, is using semantic metadata.
105
+
106
+ Let's see how we can use RDF (semantic metadata) together with HDF5 files using the toolbox:
107
+
108
+ ```bash
109
+ # Install the package
110
+ pip install h5RDMtoolbox
111
+ ```
112
+
113
+ ```python
114
+ import h5rdmtoolbox as h5tbx
115
+ import rdflib
116
+ import numpy as np
117
+
118
+ # Create a new HDF5 file with semantic metadata
119
+ M4I = rdflib.Namespace("http://w3id.org/nfdi4ing/metadata4ing#")
120
+
121
+ # Create a new HDF5 file with FAIR metadata
122
+ with h5tbx.File("example.h5", "w") as h5:
123
+ h5.create_dataset("temperature", data=np.array([20, 21, 19, 22]))
124
+ h5.attrs["units", M4I.hasUnit] = "degree_Celsius"
125
+ h5.rdf["units"].object = "http://qudt.org/vocab/unit/DEG_C"
126
+ h5.attrs["description", "https://schema.org/description"] = "Room temperature measurements"
127
+
128
+ ttl = h5.serialize("ttl")
129
+
130
+ ```
131
+ The serialization in Turtle (ttl) is teh RDF serialization of the HDF5 data (without arrays):
132
+ ```ttl
133
+ @prefix hdf: <http://purl.allotrope.org/ontologies/hdf5/1.8#> .
134
+ @prefix m4i: <http://w3id.org/nfdi4ing/metadata4ing#> .
135
+ @prefix schema: <https://schema.org/> .
136
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
137
+
138
+ hdf:H5T_INTEL_I64 a hdf:Datatype .
139
+
140
+ [] a hdf:File ;
141
+ hdf:rootGroup [ a hdf:Group ;
142
+ hdf:attribute [ a hdf:StringAttribute ;
143
+ hdf:data "Room temperature measurements" ;
144
+ hdf:name "description" ],
145
+ [ a hdf:StringAttribute ;
146
+ hdf:data "degree_Celsius" ;
147
+ hdf:name "units" ] ;
148
+ hdf:member [ a hdf:Dataset ;
149
+ hdf:dataspace [ a hdf:SimpleDataspace ;
150
+ hdf:dimension [ a hdf:DataspaceDimension ;
151
+ hdf:dimensionIndex 0 ;
152
+ hdf:size 4 ] ] ;
153
+ hdf:datatype hdf:H5T_INTEGER,
154
+ hdf:H5T_INTEL_I64 ;
155
+ hdf:layout hdf:H5D_CONTIGUOUS ;
156
+ hdf:maximumSize 4 ;
157
+ hdf:name "/temperature" ;
158
+ hdf:rank 1 ;
159
+ hdf:size 4 ] ;
160
+ hdf:name "/" ;
161
+ m4i:hasUnit <http://qudt.org/vocab/unit/DEG_C> ;
162
+ schema:description "Room temperature measurements" ] .
163
+ ```
164
+
165
+ [//]: # (The "HDF5 Research Data Management Toolbox" &#40;h5RDMtoolbox&#41; is a Python package supporting everybody who is working with)
166
+
167
+ [//]: # (HDF5 to achieve a sustainable data lifecycle which follows)
168
+
169
+ [//]: # (the [FAIR &#40;Findable, Accessible, Interoperable, Reusable&#41;]&#40;https://www.nature.com/articles/sdata201618&#41;)
170
+
171
+ [//]: # (principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and)
172
+
173
+ [//]: # (*reusing* data. Please visit the [documentation]&#40;https://h5rdmtoolbox.readthedocs.io/en/latest/&#41; for detailed)
174
+
175
+ [//]: # (information of try the [quickstart using colab]&#40;#quickstart&#41;.)
176
+
177
+
178
+ ## 🚀 Key Features
179
+
180
+ - **🔗 HDF5 + [Xarray](https://docs.xarray.dev/en/stable/) Integration**: Seamless access to metadata during data analysis with native xarray support
181
+ - **🏷️ Persistent Identifiers**: Assign globally unique identifiers using RDF triples for FAIR compliance
182
+ - **📋 Standardized Conventions**: Define and enforce community-specific metadata standards
183
+ - **☁️ Repository Integration**: Direct upload to Zenodo and other research repositories
184
+ - **🗄️ Database Support**: Use HDF5 files with MongoDB or native HDF5 databases
185
+ - **🔒 Semantic Enrichment**: Add RDF-based semantic meaning to your data
186
+ - **🌐 Catalog Integration**: Search and discover datasets through SPARQL-based catalogs
187
+
188
+
189
+ Find an example code in [![In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/matthiasprobst/h5RDMtoolbox/blob/main/docs/colab/quickstart.ipynb) or check out the
190
+ [📚 full Documentation](https://h5rdmtoolbox.readthedocs.io/en/latest/)
116
191
 
117
192
  ## Who is the package for?
118
193
 
@@ -3,34 +3,109 @@
3
3
  ![Tests](https://github.com/matthiasprobst/h5RDMtoolbox/actions/workflows/tests.yml/badge.svg)
4
4
  [![codecov](https://codecov.io/gh/matthiasprobst/h5RDMtoolbox/graph/badge.svg?token=IVG4AQEW47)](https://codecov.io/gh/matthiasprobst/h5RDMtoolbox)
5
5
  [![Documentation Status](https://readthedocs.org/projects/h5rdmtoolbox/badge/?version=latest)](https://h5rdmtoolbox.readthedocs.io/en/latest/?badge=latest)
6
+ [![PyPI version](https://badge.fury.io/py/h5RDMtoolbox.svg)](https://badge.fury.io/py/h5RDMtoolbox)
6
7
  ![pyvers](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)
7
8
 
8
- *Note, that the project is still under development!*
9
-
10
- The "HDF5 Research Data Management Toolbox" (h5RDMtoolbox) is a Python package supporting everybody who is working with
11
- HDF5 to achieve a sustainable data lifecycle which follows
12
- the [FAIR (Findable, Accessible, Interoperable, Reusable)](https://www.nature.com/articles/sdata201618)
13
- principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and
14
- *reusing* data. Please visit the [documentation](https://h5rdmtoolbox.readthedocs.io/en/latest/) for detailed
15
- information of try the [quickstart using colab](#quickstart).
16
-
17
- ## Highlights
18
-
19
- - Combining HDF5 and [xarray](https://docs.xarray.dev/en/stable/) to allow easy access to metadata and data during
20
- analysis and processing (
21
- see [here](https://h5rdmtoolbox.readthedocs.io/en/latest/gettingstarted/quickoverview.html#datasets-xarray-interface)).
22
- - Assigning [metadata with "globally unique and persistent identifiers"]() as required
23
- by [F1 of the FAIR principles](https://www.go-fair.org/fair-principles/f1-meta-data-assigned-globally-unique-persistent-identifiers/).
24
- This can be achieved by using [RDF triples](https://www.w3.org/RDF/), which removes "ambiguity in the meaning of your
25
- published data".
26
- - Define standard attributes through
27
- [conventions](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/convention/index.html) and enforce users to use
28
- certain attributes in their HDF5 files, such as units and a description, for example.
29
- - Upload HDF5 files directly
30
- to [repositories](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/repository/index.html)
31
- like [Zenodo](https://zenodo.org/)
32
- or [use them with noSQL databases](https://h5rdmtoolbox.readthedocs.io/en/latest/userguide/database/index.html) like
33
- [mongoDB](https://www.mongodb.com/).
9
+ A Python package that helps researchers achieve sustainable
10
+ [**FAIR (Findable, Accessible, Interoperable, Reusable)**](https://www.nature.com/articles/sdata201618) data management with HDF5 files. The toolbox provides a comprehensive
11
+ approach to the research data lifecycle through five main stages: **planning**, **collecting**, **analyzing**,
12
+ **sharing**, and **reusing** data.
13
+
14
+ > **Note**: This project is actively under development.
15
+
16
+
17
+
18
+
19
+ ## ✨ Quick Start
20
+
21
+
22
+ One of the core features of the toolbox and success factors for achieving FAIR data, is using semantic metadata.
23
+
24
+ Let's see how we can use RDF (semantic metadata) together with HDF5 files using the toolbox:
25
+
26
+ ```bash
27
+ # Install the package
28
+ pip install h5RDMtoolbox
29
+ ```
30
+
31
+ ```python
32
+ import h5rdmtoolbox as h5tbx
33
+ import rdflib
34
+ import numpy as np
35
+
36
+ # Create a new HDF5 file with semantic metadata
37
+ M4I = rdflib.Namespace("http://w3id.org/nfdi4ing/metadata4ing#")
38
+
39
+ # Create a new HDF5 file with FAIR metadata
40
+ with h5tbx.File("example.h5", "w") as h5:
41
+ h5.create_dataset("temperature", data=np.array([20, 21, 19, 22]))
42
+ h5.attrs["units", M4I.hasUnit] = "degree_Celsius"
43
+ h5.rdf["units"].object = "http://qudt.org/vocab/unit/DEG_C"
44
+ h5.attrs["description", "https://schema.org/description"] = "Room temperature measurements"
45
+
46
+ ttl = h5.serialize("ttl")
47
+
48
+ ```
49
+ The serialization in Turtle (ttl) is teh RDF serialization of the HDF5 data (without arrays):
50
+ ```ttl
51
+ @prefix hdf: <http://purl.allotrope.org/ontologies/hdf5/1.8#> .
52
+ @prefix m4i: <http://w3id.org/nfdi4ing/metadata4ing#> .
53
+ @prefix schema: <https://schema.org/> .
54
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
55
+
56
+ hdf:H5T_INTEL_I64 a hdf:Datatype .
57
+
58
+ [] a hdf:File ;
59
+ hdf:rootGroup [ a hdf:Group ;
60
+ hdf:attribute [ a hdf:StringAttribute ;
61
+ hdf:data "Room temperature measurements" ;
62
+ hdf:name "description" ],
63
+ [ a hdf:StringAttribute ;
64
+ hdf:data "degree_Celsius" ;
65
+ hdf:name "units" ] ;
66
+ hdf:member [ a hdf:Dataset ;
67
+ hdf:dataspace [ a hdf:SimpleDataspace ;
68
+ hdf:dimension [ a hdf:DataspaceDimension ;
69
+ hdf:dimensionIndex 0 ;
70
+ hdf:size 4 ] ] ;
71
+ hdf:datatype hdf:H5T_INTEGER,
72
+ hdf:H5T_INTEL_I64 ;
73
+ hdf:layout hdf:H5D_CONTIGUOUS ;
74
+ hdf:maximumSize 4 ;
75
+ hdf:name "/temperature" ;
76
+ hdf:rank 1 ;
77
+ hdf:size 4 ] ;
78
+ hdf:name "/" ;
79
+ m4i:hasUnit <http://qudt.org/vocab/unit/DEG_C> ;
80
+ schema:description "Room temperature measurements" ] .
81
+ ```
82
+
83
+ [//]: # (The "HDF5 Research Data Management Toolbox" &#40;h5RDMtoolbox&#41; is a Python package supporting everybody who is working with)
84
+
85
+ [//]: # (HDF5 to achieve a sustainable data lifecycle which follows)
86
+
87
+ [//]: # (the [FAIR &#40;Findable, Accessible, Interoperable, Reusable&#41;]&#40;https://www.nature.com/articles/sdata201618&#41;)
88
+
89
+ [//]: # (principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and)
90
+
91
+ [//]: # (*reusing* data. Please visit the [documentation]&#40;https://h5rdmtoolbox.readthedocs.io/en/latest/&#41; for detailed)
92
+
93
+ [//]: # (information of try the [quickstart using colab]&#40;#quickstart&#41;.)
94
+
95
+
96
+ ## 🚀 Key Features
97
+
98
+ - **🔗 HDF5 + [Xarray](https://docs.xarray.dev/en/stable/) Integration**: Seamless access to metadata during data analysis with native xarray support
99
+ - **🏷️ Persistent Identifiers**: Assign globally unique identifiers using RDF triples for FAIR compliance
100
+ - **📋 Standardized Conventions**: Define and enforce community-specific metadata standards
101
+ - **☁️ Repository Integration**: Direct upload to Zenodo and other research repositories
102
+ - **🗄️ Database Support**: Use HDF5 files with MongoDB or native HDF5 databases
103
+ - **🔒 Semantic Enrichment**: Add RDF-based semantic meaning to your data
104
+ - **🌐 Catalog Integration**: Search and discover datasets through SPARQL-based catalogs
105
+
106
+
107
+ Find an example code in [![In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/matthiasprobst/h5RDMtoolbox/blob/main/docs/colab/quickstart.ipynb) or check out the
108
+ [📚 full Documentation](https://h5rdmtoolbox.readthedocs.io/en/latest/)
34
109
 
35
110
  ## Who is the package for?
36
111
 
@@ -100,7 +100,7 @@ def _download_catalog_datasets(
100
100
 
101
101
  results = g.query(GET_ALL_METADATA_CATALOG_DATASETS.query)
102
102
 
103
- print("found datasets:", len(results))
103
+ logger.debug(f"found datasets: {len(results)}")
104
104
  list_of_ttl_web_resources = [
105
105
  WebResource(
106
106
  download_url=row.download,
@@ -113,11 +113,13 @@ def _download_catalog_datasets(
113
113
  ]
114
114
 
115
115
  n_ttl_resources = len(list_of_ttl_web_resources)
116
- print(
116
+ logger.debug(
117
117
  f"Found {n_ttl_resources} TTL web resources to download. Downloading to {download_directory}..."
118
118
  )
119
119
  return download(
120
- download_directory=download_directory, web_resources=list_of_ttl_web_resources
120
+ download_directory=download_directory,
121
+ web_resources=list_of_ttl_web_resources,
122
+ use_agent_header=True
121
123
  )
122
124
 
123
125
 
@@ -421,7 +423,6 @@ class CatalogManager:
421
423
  logger.debug("Adding Wikidata knowledge to the main RDF store...")
422
424
 
423
425
  if res.data.empty:
424
- print("empty")
425
426
  logger.info(
426
427
  "No Wikidata entities found in the main RDF store. Skipping Wikidata knowledge addition."
427
428
  )
@@ -84,5 +84,6 @@ def database_initialization(
84
84
  f"Found {len(list_of_ttl_web_resources)} TTL web resources to download. Downloading to {download_directory}...")
85
85
  return download(
86
86
  download_directory=download_directory,
87
- web_resources=list_of_ttl_web_resources
87
+ web_resources=list_of_ttl_web_resources,
88
+ use_agent_header=True
88
89
  )
@@ -383,6 +383,21 @@ class GraphDB(RemoteSparqlStore):
383
383
  )
384
384
  resp.raise_for_status()
385
385
 
386
+ def _post_update(self, update):
387
+ url = f"{self.endpoint}/repositories/{self.repository}/statements"
388
+ headers = {"Content-Type": "application/sparql-update"}
389
+ auth = (self.username, self.password) if self.username and self.password else None
390
+ r = requests.post(
391
+ url,
392
+ data=update.encode("utf-8"),
393
+ headers=headers,
394
+ auth=auth,
395
+ )
396
+ if not r.ok:
397
+ raise RuntimeError(
398
+ f"GraphDB SPARQL update failed "
399
+ f"(status {r.status_code}):\n{r.text}"
400
+ )
386
401
 
387
402
  class InMemoryRDFStore(RDFStore):
388
403
  """In-memory RDF database that can upload files and return a combined graph."""
@@ -565,6 +580,27 @@ class InMemoryRDFStore(RDFStore):
565
580
  self._combined_graph = rdflib.Graph()
566
581
  return self
567
582
 
583
+ def save(self, filename: Union[str, pathlib.Path]):
584
+ """Saves the combined graph to a file.
585
+
586
+ Parameters
587
+ ----------
588
+ filename : Union[str, pathlib.Path]
589
+ The path to the file where the graph will be saved.
590
+ """
591
+ filename = pathlib.Path(filename).resolve().absolute()
592
+ filename_suffix = filename.suffix.lower()
593
+ if filename_suffix == ".ttl":
594
+ _format = "turtle"
595
+ elif filename_suffix == ".rdf" or filename_suffix == ".xml":
596
+ _format = "xml"
597
+ elif filename_suffix == ".jsonld":
598
+ _format = "json-ld"
599
+ elif filename_suffix == ".nt":
600
+ _format = "nt"
601
+ else:
602
+ raise ValueError(f"File format '{filename_suffix}' not supported for saving.")
603
+ self.graph.serialize(destination=str(filename), format=_format)
568
604
 
569
605
  class AbstractQuery(ABC):
570
606
 
@@ -17,6 +17,7 @@ from pydantic.v1 import HttpUrl
17
17
  from rdflib import Graph
18
18
 
19
19
  from .. import logger
20
+ from .._version import __version__
20
21
 
21
22
  # --- minimal caster for common XSD datatypes ---
22
23
  _XSD = "http://www.w3.org/2001/XMLSchema#"
@@ -28,6 +29,10 @@ _NUM_DT = {
28
29
  _FLOAT_DT = {_XSD + "float", _XSD + "double"}
29
30
  _DEC_DT = {_XSD + "decimal"}
30
31
 
32
+ USER_AGENT_HEADER = {
33
+ "User-Agent": f"h5rdmtoolbox/{__version__} (https://github.com/matthiasprobst/h5rdmtoolbox)",
34
+ }
35
+
31
36
 
32
37
  def file_uri_or_path_to_path(value) -> pathlib.Path:
33
38
  # Keep behavior close to your code
@@ -190,40 +195,8 @@ def extract_record_id(value: str) -> str:
190
195
  raise ValueError(f"Could not extract a numeric record ID from '{value}'")
191
196
 
192
197
 
193
- def get_file_metadata(record: str, sandbox: bool = False) -> Iterator[Tuple[str, Dict]]:
194
- """
195
- Fetch the Zenodo record JSON and yield (filename, file-metadata-dict) tuples.
196
- """
197
- record_id = extract_record_id(record)
198
- base_url = "https://sandbox.zenodo.org/api/records" if sandbox else "https://zenodo.org/api/records"
199
- url = f"{base_url}/{record_id}"
200
-
201
- resp = requests.get(url)
202
- if resp.status_code != 200:
203
- raise RuntimeError(
204
- f"Failed to fetch record {record_id}: HTTP {resp.status_code} - {resp.text}"
205
- )
206
198
 
207
- data = resp.json()
208
199
 
209
- # Zenodo records normally have 'files' at the top level
210
- files = data.get("files", [])
211
-
212
- if not files:
213
- # Some records may store file info differently; handle gracefully
214
- raise RuntimeError(f"No files found in record {record_id} (or unexpected schema).")
215
-
216
- for f in files:
217
- # Common fields in Zenodo API
218
- name = f.get("key") or f.get("filename") or "<unknown>"
219
- yield name, f
220
-
221
-
222
- def _is_sandbox_doi(doi: str) -> bool:
223
- """Return True if the provided doi string looks like a sandbox URL/DOI."""
224
- if "10.5281/zenodo" in doi:
225
- return True
226
- return False
227
200
 
228
201
 
229
202
  def download_and_verify_file(file_meta: Dict, dest_dir: pathlib.Path) -> Tuple[pathlib.Path, bool, str, str]:
@@ -312,7 +285,8 @@ def parse_checksum(raw: str) -> Tuple[str, str]:
312
285
  return algo.lower(), val.lower()
313
286
 
314
287
 
315
- def download(download_directory: pathlib.Path, web_resources: List[WebResource]) -> List[DownloadStatus]:
288
+ def download(download_directory: pathlib.Path, web_resources: List[WebResource], use_agent_header=True) -> List[
289
+ DownloadStatus]:
316
290
  """Download and verify a list of WebResource items.
317
291
 
318
292
  For each resource:
@@ -403,7 +377,11 @@ def download(download_directory: pathlib.Path, web_resources: List[WebResource])
403
377
  # stream download to tmp file while computing md5
404
378
  tmp_path = record_dir / (filename + ".tmp")
405
379
  try:
406
- resp = requests.get(url, stream=True, timeout=60)
380
+ if use_agent_header:
381
+ kwargs_request = {"headers": USER_AGENT_HEADER}
382
+ else:
383
+ kwargs_request = {}
384
+ resp = requests.get(url, stream=True, timeout=60, **kwargs_request)
407
385
  resp.raise_for_status()
408
386
 
409
387
  md5 = hashlib.md5()
@@ -426,27 +404,27 @@ def download(download_directory: pathlib.Path, web_resources: List[WebResource])
426
404
  # move tmp to final
427
405
  tmp_path.replace(dest_path)
428
406
  message = f"saved to {dest_path}"
429
- print(f" > OK: {filename} -> {dest_path} (md5 matches)")
407
+ logger.debug(f" > OK: {filename} -> {dest_path} (md5 matches)")
430
408
  else:
431
409
  # conflict: keep both, rename new file with record id + short hash
432
410
  new_name = f"{pathlib.Path(filename).stem}__{rec_id}__{computed[:8]}{pathlib.Path(filename).suffix}"
433
411
  new_path = record_dir / new_name
434
412
  tmp_path.replace(new_path)
435
413
  message = f"checksum mismatch: expected={expected_val}, computed={computed}; saved as {new_path}"
436
- print(
414
+ logger.error(
437
415
  f" > MISMATCH: {filename} -> {new_path} (expected md5: {expected_val}, computed md5: {computed})")
438
416
  else:
439
417
  # no expected checksum provided — accept and move
440
418
  tmp_path.replace(dest_path)
441
419
  ok = True
442
420
  message = f"saved to {dest_path} (no expected checksum)"
443
- print(f" > SAVED (no expected checksum): {filename} -> {dest_path}")
421
+ logger.debug(f" > SAVED (no expected checksum): {filename} -> {dest_path}")
444
422
  else:
445
423
  # unsupported algorithm: save file but mark as not-verified
446
424
  tmp_path.replace(dest_path)
447
425
  ok = False
448
426
  message = f"saved to {dest_path} (unsupported checksum algorithm: {expected_algo})"
449
- print(f" > SAVED (unsupported checksum alg '{expected_algo}'): {filename} -> {dest_path}")
427
+ logger.debug(f" > SAVED (unsupported checksum alg '{expected_algo}'): {filename} -> {dest_path}")
450
428
 
451
429
  overall.append(DownloadStatus(rec_id, dest_path, ok, message))
452
430
 
@@ -457,13 +435,13 @@ def download(download_directory: pathlib.Path, web_resources: List[WebResource])
457
435
  tmp_path.unlink()
458
436
  except Exception:
459
437
  pass
460
- print(f" > ERROR downloading {filename}: {exc}")
438
+ logger.error(f" > ERROR downloading {filename}: {exc}")
461
439
  overall.append(DownloadStatus(rec_id, dest_path, False, str(exc)))
462
440
 
463
441
  # summary
464
442
  total = len(overall)
465
443
  ok_count = sum(1 for o in overall if o.ok)
466
- print(f"Summary: {ok_count}/{total} files verified successfully")
444
+ logger.debug(f"Summary: {ok_count}/{total} files verified successfully")
467
445
 
468
446
  return overall
469
447
 
@@ -542,7 +520,7 @@ def database_initialization(
542
520
  mediaType="text/turtle"
543
521
  ) for row in results]
544
522
 
545
- print(
523
+ logger.debug(
546
524
  f"Found {len(list_of_ttl_web_resources)} TTL web resources to download. Downloading to {download_directory}...")
547
525
  return download(
548
526
  download_directory=download_directory,
@@ -1,5 +1,11 @@
1
1
  import requests
2
2
 
3
+ from h5rdmtoolbox import __version__
4
+
5
+ USER_AGENT_HEADER = {
6
+ "User-Agent": f"h5rdmtoolbox/{__version__} (https://github.com/matthiasprobst/h5rdmtoolbox)",
7
+ }
8
+
3
9
 
4
10
  def validate_url(url: str) -> bool:
5
11
  """Validate URL
@@ -15,7 +21,7 @@ def validate_url(url: str) -> bool:
15
21
  True if URL
16
22
  """
17
23
  try:
18
- response = requests.get(url)
24
+ response = requests.get(url, headers=USER_AGENT_HEADER)
19
25
  except requests.exceptions.MissingSchema:
20
26
  return False
21
27
  if response.status_code == 200:
@@ -149,6 +149,8 @@ class H5TbxAttributeManager(Protocol):
149
149
  def parent(self):
150
150
  ...
151
151
 
152
+ def items(self):
153
+ pass
152
154
 
153
155
  class H5TbxHLObject(Protocol):
154
156
  name: str
@@ -3,7 +3,7 @@ import logging
3
3
  import pathlib
4
4
  import uuid
5
5
  import warnings
6
- from typing import Optional, Union
6
+ from typing import Optional, Union, Dict
7
7
 
8
8
  import requests
9
9
 
@@ -15,7 +15,8 @@ def download_file(file_url,
15
15
  target_folder: Union[str, pathlib.Path] = None,
16
16
  access_token: Optional[str] = None,
17
17
  checksum: Optional[str] = None,
18
- checksum_algorithm: Optional[str] = None) -> pathlib.Path:
18
+ checksum_algorithm: Optional[str] = None,
19
+ headers: Optional[Dict]=None) -> pathlib.Path:
19
20
  logger.debug(f'Attempting to provide file from URL (download or return from cache): {file_url}')
20
21
  from ..utils import DownloadFileManager
21
22
  dfm = DownloadFileManager()
@@ -54,11 +55,11 @@ def download_file(file_url,
54
55
  raise ValueError(f"Unsupported checksum algorithm: {checksum_algorithm}")
55
56
 
56
57
  try:
57
- response = requests.get(file_url, stream=True)
58
+ response = requests.get(file_url, stream=True, headers=headers)
58
59
  if response.status_code == 403:
59
- response = requests.get(file_url, stream=True, params={'access_token': access_token})
60
+ response = requests.get(file_url, stream=True, params={'access_token': access_token}, headers=headers)
60
61
  except requests.RequestException as e:
61
- response = requests.get(file_url, stream=True, params={'access_token': access_token})
62
+ response = requests.get(file_url, stream=True, params={'access_token': access_token}, headers=headers)
62
63
  response.raise_for_status()
63
64
 
64
65
  chunk_size = 1024 # Define chunk size for download
@@ -107,7 +108,7 @@ def download_file(file_url,
107
108
  # f'but got: {file_checksum}')
108
109
  else:
109
110
  try:
110
- r = requests.get(file_url)
111
+ r = requests.get(file_url, headers=headers)
111
112
  except requests.RequestException as e:
112
113
  r = requests.get(file_url, params={'access_token': access_token})
113
114
 
@@ -126,9 +127,9 @@ def download_file(file_url,
126
127
  file.write(r.content)
127
128
  if links_content:
128
129
  try:
129
- _content_response = requests.get(links_content)
130
+ _content_response = requests.get(links_content, headers=headers)
130
131
  except requests.RequestException:
131
- _content_response = requests.get(links_content, params={'access_token': access_token})
132
+ _content_response = requests.get(links_content, params={'access_token': access_token}, headers=headers)
132
133
  if _content_response.ok:
133
134
  with open(target_filename, 'wb') as file:
134
135
  file.write(_content_response.content)