h5rdmtoolbox 2.7.4__tar.gz → 2.8.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 (163) hide show
  1. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/PKG-INFO +30 -7
  2. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/README.md +25 -6
  3. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/__init__.py +23 -1
  4. h5rdmtoolbox-2.8.0/h5rdmtoolbox/cli.py +4 -0
  5. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/__init__.py +4 -1
  6. h5rdmtoolbox-2.8.0/h5rdmtoolbox/ld/metrics.py +279 -0
  7. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/__init__.py +15 -0
  8. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/chat.py +340 -0
  9. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/errors.py +22 -0
  10. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/executor.py +56 -0
  11. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/interfaces.py +17 -0
  12. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/models.py +85 -0
  13. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/ontology.py +171 -0
  14. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/prompting.py +157 -0
  15. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/providers/__init__.py +6 -0
  16. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/providers/openai_adapter.py +61 -0
  17. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/sparql_guard.py +124 -0
  18. h5rdmtoolbox-2.8.0/h5rdmtoolbox/llm/summary.py +77 -0
  19. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/static/graph.css +337 -0
  20. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/static/graph.js +568 -0
  21. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/static/style.css +11 -0
  22. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/templates/graph.html +127 -0
  23. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/templates/index.html +0 -0
  24. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/templates/resource.html +0 -0
  25. h5rdmtoolbox-2.8.0/h5rdmtoolbox/server.py +3211 -0
  26. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/user.py +18 -11
  27. h5rdmtoolbox-2.8.0/h5rdmtoolbox/wrapper/accessors/__init__.py +0 -0
  28. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/core.py +27 -0
  29. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox.egg-info/PKG-INFO +30 -7
  30. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox.egg-info/SOURCES.txt +23 -0
  31. h5rdmtoolbox-2.8.0/h5rdmtoolbox.egg-info/entry_points.txt +2 -0
  32. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox.egg-info/requires.txt +5 -0
  33. h5rdmtoolbox-2.8.0/h5rdmtoolbox.egg-info/top_level.txt +2 -0
  34. h5rdmtoolbox-2.8.0/h5rdmtoolbox_cli.py +168 -0
  35. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/pyproject.toml +14 -3
  36. h5rdmtoolbox-2.8.0/tests/test_cli.py +190 -0
  37. h5rdmtoolbox-2.8.0/tests/test_server.py +1771 -0
  38. h5rdmtoolbox-2.7.4/h5rdmtoolbox/cli.py +0 -61
  39. h5rdmtoolbox-2.7.4/h5rdmtoolbox.egg-info/entry_points.txt +0 -2
  40. h5rdmtoolbox-2.7.4/h5rdmtoolbox.egg-info/top_level.txt +0 -1
  41. h5rdmtoolbox-2.7.4/tests/test_cli.py +0 -69
  42. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/LICENSE +0 -0
  43. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/_cfg.py +0 -0
  44. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/_repr.py +0 -0
  45. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/_version.py +0 -0
  46. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/__init__.py +0 -0
  47. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/_initialization.py +0 -0
  48. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/abstracts.py +0 -0
  49. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/core.py +0 -0
  50. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/profiles.py +0 -0
  51. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/query_templates.py +0 -0
  52. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/stores/__init__.py +0 -0
  53. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/stores/hdf5.py +0 -0
  54. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/catalog/utils.py +0 -0
  55. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/consts.py +0 -0
  56. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/__init__.py +0 -0
  57. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/cfg.py +0 -0
  58. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/consts.py +0 -0
  59. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/core.py +0 -0
  60. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/errors.py +0 -0
  61. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/generate.py +0 -0
  62. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/ontology/__init__.py +0 -0
  63. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/ontology/h5ontocls.py +0 -0
  64. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/ontology/hdf_datatypes.py +0 -0
  65. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/references.py +0 -0
  66. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/standard_attributes.py +0 -0
  67. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/toolbox_validators.py +0 -0
  68. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/convention/utils.py +0 -0
  69. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/def_icon.png +0 -0
  70. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/fluid-v1.yml +0 -0
  71. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/h5tbx.yaml +0 -0
  72. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/id_icon.png +0 -0
  73. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/iri_icon.png +0 -0
  74. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/ld_icon.png +0 -0
  75. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/piv-v1.yml +0 -0
  76. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/style.css +0 -0
  77. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/tutorial_convention.yaml +0 -0
  78. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/tutorial_convention_vfuncs.py +0 -0
  79. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/tutorial_standard_name_table.yaml +0 -0
  80. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/data/type_icon.png +0 -0
  81. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/__init__.py +0 -0
  82. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/hdfdb/__init__.py +0 -0
  83. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/hdfdb/filedb.py +0 -0
  84. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/hdfdb/objdb.py +0 -0
  85. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/hdfdb/query.py +0 -0
  86. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/hdfdb/utils.py +0 -0
  87. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/interface.py +0 -0
  88. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/lazy.py +0 -0
  89. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/database/mongo.py +0 -0
  90. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/errors.py +0 -0
  91. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/__init__.py +0 -0
  92. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/magnitude.py +0 -0
  93. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/normalize.py +0 -0
  94. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/onto.py +0 -0
  95. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/units.py +0 -0
  96. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/extensions/vector.py +0 -0
  97. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/gui/__init__.py +0 -0
  98. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/gui/fairify.py +0 -0
  99. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/gui/src/__init__.py +0 -0
  100. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/gui/src/main.py +0 -0
  101. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/identifiers.py +0 -0
  102. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/layout/__init__.py +0 -0
  103. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/layout/core.py +0 -0
  104. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/_types.py +0 -0
  105. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/globals.py +0 -0
  106. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/hdf/__init__.py +0 -0
  107. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/hdf/attributes.py +0 -0
  108. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/hdf/datasets.py +0 -0
  109. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/hdf/file.py +0 -0
  110. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/hdf/groups.py +0 -0
  111. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/rdf.py +0 -0
  112. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/shacl.py +0 -0
  113. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/sparql.py +0 -0
  114. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/__init__.py +0 -0
  115. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/attributes.py +0 -0
  116. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/datasets.py +0 -0
  117. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/file.py +0 -0
  118. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/groups.py +0 -0
  119. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/user/utils.py +0 -0
  120. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/ld/utils.py +0 -0
  121. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/plotting.py +0 -0
  122. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/protected_attributes.py +0 -0
  123. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/protocols.py +0 -0
  124. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/__init__.py +0 -0
  125. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/default_metamapper.py +0 -0
  126. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/interface.py +0 -0
  127. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/utils.py +0 -0
  128. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/zenodo/__init__.py +0 -0
  129. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/zenodo/core.py +0 -0
  130. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/zenodo/metadata.py +0 -0
  131. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/zenodo/tokens.py +0 -0
  132. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/repository/zenodo/utils.py +0 -0
  133. /h5rdmtoolbox-2.7.4/h5rdmtoolbox/wrapper/accessors/__init__.py → /h5rdmtoolbox-2.8.0/h5rdmtoolbox/server/templates/file.html +0 -0
  134. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/tutorial.py +0 -0
  135. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/__init__.py +0 -0
  136. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/docstring.py +0 -0
  137. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/download.py +0 -0
  138. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/file_io.py +0 -0
  139. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/hdf5.py +0 -0
  140. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils/string.py +0 -0
  141. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/utils.py +0 -0
  142. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/__init__.py +0 -0
  143. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/accessor.py +0 -0
  144. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/accessors/provenance.py +0 -0
  145. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/ds_decoder.py +0 -0
  146. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/h5attr.py +0 -0
  147. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/h5ext.py +0 -0
  148. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/h5utils.py +0 -0
  149. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/h5yaml.py +0 -0
  150. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/jsonld.py +0 -0
  151. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox/wrapper/xr2hdf.py +0 -0
  152. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/h5rdmtoolbox.egg-info/dependency_links.txt +0 -0
  153. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/setup.cfg +0 -0
  154. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_config.py +0 -0
  155. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_extensions.py +0 -0
  156. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_identifiers.py +0 -0
  157. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_plotting.py +0 -0
  158. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_readme.py +0 -0
  159. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_repr.py +0 -0
  160. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_user.py +0 -0
  161. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_utils.py +0 -0
  162. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_version.py +0 -0
  163. {h5rdmtoolbox-2.7.4 → h5rdmtoolbox-2.8.0}/tests/test_xarray_export.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: h5rdmtoolbox
3
- Version: 2.7.4
3
+ Version: 2.8.0
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
@@ -78,6 +78,10 @@ Provides-Extra: complete
78
78
  Requires-Dist: h5rdmtoolbox[gui,test]; extra == "complete"
79
79
  Provides-Extra: complete-with-docs
80
80
  Requires-Dist: h5rdmtoolbox[complete,docs]; extra == "complete-with-docs"
81
+ Provides-Extra: server
82
+ Requires-Dist: fastapi>=0.95; extra == "server"
83
+ Requires-Dist: uvicorn[standard]>=0.22; extra == "server"
84
+ Requires-Dist: jinja2>=3.1; extra == "server"
81
85
  Dynamic: license-file
82
86
 
83
87
  # HDF5 Research Data Management Toolbox
@@ -233,18 +237,37 @@ hdf:H5T_INTEL_I64 a hdf:Datatype .
233
237
  hdf:size 4 .
234
238
  ```
235
239
 
236
- [//]: # (The "HDF5 Research Data Management Toolbox" &#40;h5RDMtoolbox&#41; is a Python package supporting everybody who is working with)
240
+ ## Command Line Interface
237
241
 
238
- [//]: # (HDF5 to achieve a sustainable data lifecycle which follows)
242
+ The `h5tbx` command provides quick access to linked-data serialization and local inspection from the shell.
239
243
 
240
- [//]: # (the [FAIR &#40;Findable, Accessible, Interoperable, Reusable&#41;]&#40;https://www.nature.com/articles/sdata201618&#41;)
244
+ Use `h5tbx ld dump example.h5` to print Turtle RDF, or write a specific format with:
241
245
 
242
- [//]: # (principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and)
246
+ ```bash
247
+ h5tbx ld dump example.h5 -o example.jsonld
248
+ ```
249
+
250
+ The dump command accepts `--format`, `--file-uri`, `--prefix`, `--structural=false`, and `--contextual=false`, so you can choose RDF output, assign stable RDF subject URIs, bind a compact prefix, and include only structural or user-provided contextual metadata when needed.
251
+
252
+ To inspect files in a browser, run:
253
+
254
+ ```bash
255
+ h5tbx serve example.h5
256
+ h5tbx serve data/ --h5ext=.h5 --h5ext=.hdf5
257
+ ```
258
+
259
+ The local web app links to Turtle, JSON-LD, N-Triples, RDF/XML, an interactive graph view, SPARQL query editor, graph metrics, and SHACL validation. Per-file buttons are scoped to that file; the landing page also offers a separate combined graph section for all served files plus loaded enrichment. Combined graph visualization is reduced by default with node/edge limits and search controls, and combined metrics skip exact largest-distance computation on very large graphs to keep the local server responsive. HDF5 object URLs such as `/example.h5/group/dataset` dereference to a browser HTML page by default, while `Accept: text/turtle`, `Accept: application/ld+json`, or `?format=ttl|jsonld|nt|xml|html` return the requested representation. For published DOI-style file URIs, use `/resolve?iri=https://doi.org/...%23path` to resolve an exact external RDF subject locally. The resolver uses the first matching served HDF5 subject, caches all served files in one shared query graph, and enriches that graph with known ontology TTL sources, QUDT unit definitions, Zenodo RDF attachments, generic ontology documents, and Wikidata direct claims where applicable. URI values in resource pages link back into `/resolve?iri=...` so browsing stays inside the local app; if a browser request cannot be resolved locally, the app opens the original IRI in a new tab as a fallback. `h5tbx serve` accepts files and folders; folder discovery uses `.h5`, `.hdf`, and `.hdf5` by default, or repeated `--h5ext` values. `--local-iri-pattern` is optional and only limits which external IRIs get local resolver links in the graph view. If no filename is provided, `h5tbx serve` lists all matching HDF5 files in the current directory.
260
+
261
+ The same graph metrics are available from Python:
243
262
 
244
- [//]: # (*reusing* data. Please visit the [documentation]&#40;https://h5rdmtoolbox.readthedocs.io/en/latest/&#41; for detailed)
263
+ ```python
264
+ import h5rdmtoolbox as h5tbx
245
265
 
246
- [//]: # (information of try the [quickstart using colab]&#40;#quickstart&#41;.)
266
+ metrics = h5tbx.compute_metrics("example.h5")
247
267
 
268
+ with h5tbx.File("example.h5") as h5:
269
+ metrics = h5.metrics()
270
+ ```
248
271
 
249
272
  ## 🚀 Key Features
250
273
 
@@ -151,18 +151,37 @@ hdf:H5T_INTEL_I64 a hdf:Datatype .
151
151
  hdf:size 4 .
152
152
  ```
153
153
 
154
- [//]: # (The "HDF5 Research Data Management Toolbox" &#40;h5RDMtoolbox&#41; is a Python package supporting everybody who is working with)
154
+ ## Command Line Interface
155
155
 
156
- [//]: # (HDF5 to achieve a sustainable data lifecycle which follows)
156
+ The `h5tbx` command provides quick access to linked-data serialization and local inspection from the shell.
157
157
 
158
- [//]: # (the [FAIR &#40;Findable, Accessible, Interoperable, Reusable&#41;]&#40;https://www.nature.com/articles/sdata201618&#41;)
158
+ Use `h5tbx ld dump example.h5` to print Turtle RDF, or write a specific format with:
159
159
 
160
- [//]: # (principles. It specifically supports the five main steps of *planning*, *collecting*, *analyzing*, *sharing* and)
160
+ ```bash
161
+ h5tbx ld dump example.h5 -o example.jsonld
162
+ ```
163
+
164
+ The dump command accepts `--format`, `--file-uri`, `--prefix`, `--structural=false`, and `--contextual=false`, so you can choose RDF output, assign stable RDF subject URIs, bind a compact prefix, and include only structural or user-provided contextual metadata when needed.
165
+
166
+ To inspect files in a browser, run:
167
+
168
+ ```bash
169
+ h5tbx serve example.h5
170
+ h5tbx serve data/ --h5ext=.h5 --h5ext=.hdf5
171
+ ```
172
+
173
+ The local web app links to Turtle, JSON-LD, N-Triples, RDF/XML, an interactive graph view, SPARQL query editor, graph metrics, and SHACL validation. Per-file buttons are scoped to that file; the landing page also offers a separate combined graph section for all served files plus loaded enrichment. Combined graph visualization is reduced by default with node/edge limits and search controls, and combined metrics skip exact largest-distance computation on very large graphs to keep the local server responsive. HDF5 object URLs such as `/example.h5/group/dataset` dereference to a browser HTML page by default, while `Accept: text/turtle`, `Accept: application/ld+json`, or `?format=ttl|jsonld|nt|xml|html` return the requested representation. For published DOI-style file URIs, use `/resolve?iri=https://doi.org/...%23path` to resolve an exact external RDF subject locally. The resolver uses the first matching served HDF5 subject, caches all served files in one shared query graph, and enriches that graph with known ontology TTL sources, QUDT unit definitions, Zenodo RDF attachments, generic ontology documents, and Wikidata direct claims where applicable. URI values in resource pages link back into `/resolve?iri=...` so browsing stays inside the local app; if a browser request cannot be resolved locally, the app opens the original IRI in a new tab as a fallback. `h5tbx serve` accepts files and folders; folder discovery uses `.h5`, `.hdf`, and `.hdf5` by default, or repeated `--h5ext` values. `--local-iri-pattern` is optional and only limits which external IRIs get local resolver links in the graph view. If no filename is provided, `h5tbx serve` lists all matching HDF5 files in the current directory.
174
+
175
+ The same graph metrics are available from Python:
161
176
 
162
- [//]: # (*reusing* data. Please visit the [documentation]&#40;https://h5rdmtoolbox.readthedocs.io/en/latest/&#41; for detailed)
177
+ ```python
178
+ import h5rdmtoolbox as h5tbx
163
179
 
164
- [//]: # (information of try the [quickstart using colab]&#40;#quickstart&#41;.)
180
+ metrics = h5tbx.compute_metrics("example.h5")
165
181
 
182
+ with h5tbx.File("example.h5") as h5:
183
+ metrics = h5.metrics()
184
+ ```
166
185
 
167
186
  ## 🚀 Key Features
168
187
 
@@ -19,7 +19,7 @@ _stream_handler = logging.StreamHandler()
19
19
  _stream_handler.setLevel(DEFAULT_LOGGING_LEVEL)
20
20
  _stream_handler.setFormatter(_formatter)
21
21
 
22
- _file_handler = RotatingFileHandler(USER_LOG_DIR / 'h5rdmtoolbox.log')
22
+ _file_handler = RotatingFileHandler(USER_LOG_DIR / 'h5rdmtoolbox.log', delay=True)
23
23
  _file_handler.setLevel(logging.DEBUG) # log everything to file!
24
24
  _file_handler.setFormatter(_formatter)
25
25
 
@@ -146,6 +146,28 @@ def get_ld(
146
146
  )
147
147
 
148
148
 
149
+ def compute_metrics(
150
+ hdf_filename: Union[str, pathlib.Path],
151
+ structural: bool = True,
152
+ contextual: bool = True,
153
+ skipND: int = 1,
154
+ file_uri: Optional[str] = None,
155
+ context: Optional[Dict] = None,
156
+ rdf_mappings: Dict[str, RDFMappingEntry] = None,
157
+ ) -> Dict[str, object]:
158
+ """Compute RDF knowledge graph metrics for an HDF5 file."""
159
+ from .ld.metrics import compute_metrics as _compute_metrics
160
+ return _compute_metrics(
161
+ hdf_filename,
162
+ structural=structural,
163
+ contextual=contextual,
164
+ skipND=skipND,
165
+ file_uri=file_uri,
166
+ context=context,
167
+ rdf_mappings=rdf_mappings,
168
+ )
169
+
170
+
149
171
  def _optimize_ld_context(graph: rdflib.Graph, context: Optional[Dict]) -> Dict:
150
172
  from .ld import optimize_context
151
173
  return optimize_context(graph, context or {})
@@ -0,0 +1,4 @@
1
+ from h5rdmtoolbox_cli import h5tbx
2
+
3
+ if __name__ == '__main__':
4
+ h5tbx(obj={})
@@ -12,7 +12,7 @@ from .utils import optimize_context
12
12
 
13
13
  BINARY_AS_STRING = True
14
14
 
15
- __all__ = ["get_ld", "hdf2jsonld", "hdf2ttl", "sparql"]
15
+ __all__ = ["get_ld", "hdf2jsonld", "hdf2ttl", "sparql", "compute_metrics", "compute_graph_metrics"]
16
16
 
17
17
 
18
18
  def _validate_file_uri(file_uri: Optional[str]) -> None:
@@ -280,3 +280,6 @@ def _hdf2ld(
280
280
  f.write(_serialize_graph(graph, fmt=fmt, indent=indent, context=context))
281
281
 
282
282
  return metadata_filename
283
+
284
+
285
+ from .metrics import compute_graph_metrics, compute_metrics # noqa: E402
@@ -0,0 +1,279 @@
1
+ """Knowledge graph metrics for RDF extracted from HDF5 files."""
2
+
3
+ import pathlib
4
+ import re
5
+ from typing import Dict, Optional, Union
6
+
7
+ import rdflib
8
+
9
+ from . import get_ld
10
+
11
+ STANDARD_PREFIXES = {
12
+ "dcat": "http://www.w3.org/ns/dcat#",
13
+ "dcterms": "http://purl.org/dc/terms/",
14
+ "doi": "https://doi.org/",
15
+ "foaf": "http://xmlns.com/foaf/0.1/",
16
+ "prof": "http://www.w3.org/ns/dx/prof/",
17
+ "prov": "http://www.w3.org/ns/prov#",
18
+ "qudt": "http://qudt.org/schema/qudt/",
19
+ "quantitykind": "http://qudt.org/vocab/quantitykind/",
20
+ "schema": "https://schema.org/",
21
+ "skos": "http://www.w3.org/2004/02/skos/core#",
22
+ "ssno": "https://matthiasprobst.github.io/ssno#",
23
+ "unit": "http://qudt.org/vocab/unit/",
24
+ "zenodo": "https://zenodo.org/records/",
25
+ "zenodo_record": "https://zenodo.org/record/",
26
+ }
27
+
28
+
29
+ def bind_standard_prefixes(graph: rdflib.Graph) -> None:
30
+ """Bind common namespaces without replacing prefixes already defined by the graph."""
31
+ for prefix, namespace in STANDARD_PREFIXES.items():
32
+ graph.bind(prefix, rdflib.Namespace(namespace), override=False, replace=False)
33
+
34
+
35
+ def graph_label(value, rdf_graph: Optional[rdflib.Graph] = None) -> str:
36
+ """Return a compact display label for an RDF term."""
37
+ if isinstance(value, rdflib.URIRef):
38
+ namespace_manager = rdf_graph.namespace_manager if rdf_graph is not None else rdflib.Graph().namespace_manager
39
+ text = str(value)
40
+ try:
41
+ normalized = str(namespace_manager.normalizeUri(value))
42
+ if not normalized.startswith("<") and not re.match(r"^ns\d+:", normalized):
43
+ return normalized
44
+ except Exception:
45
+ pass
46
+ for prefix, namespace in STANDARD_PREFIXES.items():
47
+ if text.startswith(namespace) and text != namespace:
48
+ return f"{prefix}:{text[len(namespace):]}"
49
+ try:
50
+ return namespace_manager.qname(value)
51
+ except Exception:
52
+ pass
53
+ if rdf_graph is not None:
54
+ namespaces = sorted(
55
+ ((prefix, str(namespace)) for prefix, namespace in rdf_graph.namespaces() if prefix),
56
+ key=lambda item: len(item[1]),
57
+ reverse=True,
58
+ )
59
+ for prefix, namespace in namespaces:
60
+ if text.startswith(namespace) and text != namespace:
61
+ return f"{prefix}:{text[len(namespace):]}"
62
+ return text.rsplit("#", 1)[-1].rsplit("/", 1)[-1] or text
63
+ text = str(value)
64
+ return text if len(text) <= 48 else f"{text[:45]}..."
65
+
66
+
67
+ def _percent(numerator: int, denominator: int) -> float:
68
+ return (numerator / denominator * 100.0) if denominator else 0.0
69
+
70
+
71
+ def _external_namespace(value) -> str:
72
+ text = str(value)
73
+ if "#" in text:
74
+ return text.rsplit("#", 1)[0] + "#"
75
+ if "/" in text:
76
+ return text.rsplit("/", 1)[0] + "/"
77
+ return text
78
+
79
+
80
+ def _resource_terms(subject, predicate, obj) -> list:
81
+ return [
82
+ term
83
+ for term in (subject, predicate, obj)
84
+ if isinstance(term, (rdflib.URIRef, rdflib.BNode))
85
+ ]
86
+
87
+
88
+ def compute_graph_metrics(
89
+ rdf_graph: rdflib.Graph,
90
+ base_namespace: Optional[str] = None,
91
+ compute_distances: bool = True,
92
+ distance_node_limit: int = 2000,
93
+ ) -> Dict[str, object]:
94
+ """Compute RDF knowledge graph metrics for an existing graph."""
95
+ bind_standard_prefixes(rdf_graph)
96
+ triples = list(rdf_graph)
97
+ subjects = set()
98
+ objects = set()
99
+ predicates = set()
100
+ iris = set()
101
+ blank_nodes = set()
102
+ resource_nodes = set()
103
+ literal_count = 0
104
+ untyped_literal_count = 0
105
+ empty_literal_count = 0
106
+ predicate_counts = {}
107
+ subject_triple_counts = {}
108
+ class_instances = {}
109
+ datatype_counts = {}
110
+ language_counts = {}
111
+ labels = set()
112
+ typed_subjects = set()
113
+ same_as_count = 0
114
+ external_iri_counts = {}
115
+ out_degree = {}
116
+ in_degree = {}
117
+ adjacency = {}
118
+
119
+ for subject, predicate, obj in triples:
120
+ subjects.add(subject)
121
+ predicates.add(predicate)
122
+ objects.add(obj)
123
+ subject_triple_counts[subject] = subject_triple_counts.get(subject, 0) + 1
124
+
125
+ for term in _resource_terms(subject, predicate, obj):
126
+ if isinstance(term, rdflib.URIRef):
127
+ iris.add(term)
128
+ namespace = _external_namespace(term)
129
+ if not base_namespace or not str(term).startswith(base_namespace):
130
+ external_iri_counts[namespace] = external_iri_counts.get(namespace, 0) + 1
131
+ elif isinstance(term, rdflib.BNode):
132
+ blank_nodes.add(term)
133
+
134
+ predicate_label = graph_label(predicate, rdf_graph)
135
+ predicate_counts[predicate_label] = predicate_counts.get(predicate_label, 0) + 1
136
+
137
+ if predicate == rdflib.RDF.type:
138
+ typed_subjects.add(subject)
139
+ class_label = graph_label(obj, rdf_graph)
140
+ class_instances.setdefault(class_label, set()).add(subject)
141
+
142
+ if predicate == rdflib.RDFS.label:
143
+ labels.add(subject)
144
+
145
+ if predicate == rdflib.OWL.sameAs:
146
+ same_as_count += 1
147
+
148
+ resource_nodes.add(subject)
149
+
150
+ if isinstance(obj, rdflib.Literal):
151
+ literal_count += 1
152
+ datatype_label = graph_label(obj.datatype, rdf_graph) if obj.datatype else "None"
153
+ datatype_counts[datatype_label] = datatype_counts.get(datatype_label, 0) + 1
154
+ language_label = obj.language or "None"
155
+ language_counts[language_label] = language_counts.get(language_label, 0) + 1
156
+ if obj.datatype is None and obj.language is None:
157
+ untyped_literal_count += 1
158
+ if str(obj) == "":
159
+ empty_literal_count += 1
160
+ continue
161
+
162
+ resource_nodes.add(obj)
163
+ out_degree[subject] = out_degree.get(subject, 0) + 1
164
+ in_degree[obj] = in_degree.get(obj, 0) + 1
165
+ adjacency.setdefault(subject, set()).add(obj)
166
+ adjacency.setdefault(obj, set()).add(subject)
167
+
168
+ seen = set()
169
+ component_sizes = []
170
+ for node in resource_nodes:
171
+ if node in seen:
172
+ continue
173
+ stack = [node]
174
+ seen.add(node)
175
+ size = 0
176
+ while stack:
177
+ current = stack.pop()
178
+ size += 1
179
+ for neighbor in adjacency.get(current, set()):
180
+ if neighbor not in seen:
181
+ seen.add(neighbor)
182
+ stack.append(neighbor)
183
+ component_sizes.append(size)
184
+
185
+ resource_count = len(resource_nodes)
186
+ largest_distance = None
187
+ largest_distance_computed = compute_distances and resource_count <= distance_node_limit
188
+ if largest_distance_computed:
189
+ largest_distance = 0
190
+ for start in resource_nodes:
191
+ distances = {start: 0}
192
+ queue = [start]
193
+ for current in queue:
194
+ for neighbor in adjacency.get(current, set()):
195
+ if neighbor not in distances:
196
+ distances[neighbor] = distances[current] + 1
197
+ queue.append(neighbor)
198
+ if distances:
199
+ largest_distance = max(largest_distance, max(distances.values()))
200
+
201
+ subjects_without_type = len(subjects - typed_subjects)
202
+ subjects_with_labels = len(labels)
203
+ subjects_missing_labels = len(subjects - labels)
204
+ duplicate_triples = len(triples) - len(set(triples))
205
+ subjects_with_one_triple = sum(1 for count in subject_triple_counts.values() if count == 1)
206
+ weakly_connected_nodes = sum(
207
+ 1 for node in resource_nodes
208
+ if in_degree.get(node, 0) + out_degree.get(node, 0) <= 1
209
+ )
210
+ class_counts = {label: len(instances) for label, instances in class_instances.items()}
211
+
212
+ return {
213
+ "triples": len(triples),
214
+ "subjects": len(subjects),
215
+ "predicates": len(predicates),
216
+ "objects": len(objects),
217
+ "iri_count": len(iris),
218
+ "blank_nodes": len(blank_nodes),
219
+ "literals": literal_count,
220
+ "avg_triples_per_subject": len(triples) / len(subjects) if subjects else 0.0,
221
+ "classes": len(class_counts),
222
+ "subjects_without_type": subjects_without_type,
223
+ "resource_nodes": resource_count,
224
+ "avg_out_degree": sum(out_degree.values()) / resource_count if resource_count else 0.0,
225
+ "avg_in_degree": sum(in_degree.values()) / resource_count if resource_count else 0.0,
226
+ "weakly_connected_nodes": weakly_connected_nodes,
227
+ "components": len(component_sizes),
228
+ "largest_component": max(component_sizes, default=0),
229
+ "largest_distance": largest_distance,
230
+ "largest_distance_computed": largest_distance_computed,
231
+ "largest_distance_node_limit": distance_node_limit,
232
+ "datatype_distribution": sorted(datatype_counts.items(), key=lambda item: (-item[1], item[0])),
233
+ "language_distribution": sorted(language_counts.items(), key=lambda item: (-item[1], item[0])),
234
+ "untyped_literals": untyped_literal_count,
235
+ "empty_literals": empty_literal_count,
236
+ "subjects_with_labels": subjects_with_labels,
237
+ "subjects_missing_labels": subjects_missing_labels,
238
+ "label_coverage": _percent(subjects_with_labels, len(subjects)),
239
+ "duplicate_triples": duplicate_triples,
240
+ "subjects_with_one_triple": subjects_with_one_triple,
241
+ "blank_node_percentage": _percent(len(blank_nodes), resource_count),
242
+ "same_as_count": same_as_count,
243
+ "external_iri_count": sum(external_iri_counts.values()),
244
+ "top_external_namespaces": sorted(external_iri_counts.items(), key=lambda item: (-item[1], item[0]))[:10],
245
+ "top_predicates": sorted(predicate_counts.items(), key=lambda item: (-item[1], item[0]))[:10],
246
+ "rare_predicates": sorted(predicate_counts.items(), key=lambda item: (item[1], item[0]))[:10],
247
+ "predicate_distribution": sorted(predicate_counts.items(), key=lambda item: (-item[1], item[0])),
248
+ "top_classes": sorted(class_counts.items(), key=lambda item: (-item[1], item[0]))[:10],
249
+ "top_out_degree": [
250
+ (graph_label(node, rdf_graph), count)
251
+ for node, count in sorted(out_degree.items(), key=lambda item: (-item[1], graph_label(item[0], rdf_graph)))[:10]
252
+ ],
253
+ "top_in_degree": [
254
+ (graph_label(node, rdf_graph), count)
255
+ for node, count in sorted(in_degree.items(), key=lambda item: (-item[1], graph_label(item[0], rdf_graph)))[:10]
256
+ ],
257
+ }
258
+
259
+
260
+ def compute_metrics(
261
+ hdf_filename: Union[str, pathlib.Path],
262
+ structural: bool = True,
263
+ contextual: bool = True,
264
+ file_uri: Optional[str] = None,
265
+ skipND: Optional[int] = 1,
266
+ context: Optional[Dict] = None,
267
+ rdf_mappings: Optional[Dict] = None,
268
+ ) -> Dict[str, object]:
269
+ """Compute RDF knowledge graph metrics for an HDF5 file."""
270
+ graph = get_ld(
271
+ hdf_filename,
272
+ structural=structural,
273
+ contextual=contextual,
274
+ file_uri=file_uri,
275
+ skipND=skipND,
276
+ context=context,
277
+ rdf_mappings=rdf_mappings,
278
+ )
279
+ return compute_graph_metrics(graph, base_namespace=file_uri)
@@ -0,0 +1,15 @@
1
+ """LLM-based chat support for HDF5 metadata graphs."""
2
+
3
+ from .chat import chat
4
+ from .models import ChatResponse, ChatSession, ChatSessionState, QueryAttempt
5
+ from .providers.openai_adapter import OpenAIChatClient
6
+
7
+ __all__ = [
8
+ "chat",
9
+ "ChatResponse",
10
+ "ChatSession",
11
+ "ChatSessionState",
12
+ "QueryAttempt",
13
+ "OpenAIChatClient",
14
+ ]
15
+