pyhdf5-handler 0.7__tar.gz → 0.9__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 (30) hide show
  1. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/backups/workspace.ini.bak +1 -1
  2. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/workspace.ini +1 -1
  3. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/PKG-INFO +1 -1
  4. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/Release_note.txt +10 -0
  5. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/__init__.py +1 -1
  6. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/src/hdf5_handler.py +156 -27
  7. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/src/object_handler.py +191 -80
  8. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/tutorial/hdf5_io_tests.py +87 -10
  9. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyproject.toml +1 -1
  10. pyhdf5_handler-0.9/test.hdf5 +0 -0
  11. pyhdf5_handler-0.7/hdf5_database_rejeu_202311211359_202311030000_202311031200.hdf5 +0 -0
  12. pyhdf5_handler-0.7/test.hdf5 +0 -0
  13. pyhdf5_handler-0.7/test_fichier_julie.py +0 -42
  14. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/backups/codestyle.ini.bak +0 -0
  15. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/backups/encoding.ini.bak +0 -0
  16. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/backups/vcs.ini.bak +0 -0
  17. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/codestyle.ini +0 -0
  18. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/defaults/defaults-codestyle-0.2.0.ini +0 -0
  19. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/defaults/defaults-encoding-0.2.0.ini +0 -0
  20. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/defaults/defaults-vcs-0.2.0.ini +0 -0
  21. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/defaults/defaults-workspace-0.2.0.ini +0 -0
  22. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/encoding.ini +0 -0
  23. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/.spyproject/config/vcs.ini +0 -0
  24. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/LICENSE +0 -0
  25. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/README.md +0 -0
  26. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/mycontrol.hdf5 +0 -0
  27. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/src/__init__.py +0 -0
  28. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/src/constant.py +0 -0
  29. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/tutorial/__init__.py +0 -0
  30. {pyhdf5_handler-0.7 → pyhdf5_handler-0.9}/pyhdf5_handler/tutorial/complementary_test.py +0 -0
@@ -4,7 +4,7 @@ save_data_on_exit = True
4
4
  save_history = True
5
5
  save_non_project_files = False
6
6
  project_type = 'empty-project-type'
7
- recent_files = ['pyhdf5_handler/src/hdf5_handler.py', 'pyhdf5_handler/src/object_handler.py', 'pyhdf5_handler/tutorial/hdf5_io_tests.py', 'pyhdf5_handler/tutorial/complementary_test.py', 'test_fichier_julie.py']
7
+ recent_files = ['pyhdf5_handler/src/hdf5_handler.py', 'pyhdf5_handler/src/object_handler.py', 'pyhdf5_handler/tutorial/hdf5_io_tests.py', 'pyhdf5_handler/tutorial/complementary_test.py']
8
8
 
9
9
  [main]
10
10
  version = 0.2.0
@@ -4,7 +4,7 @@ save_data_on_exit = True
4
4
  save_history = True
5
5
  save_non_project_files = False
6
6
  project_type = 'empty-project-type'
7
- recent_files = ['pyhdf5_handler/src/hdf5_handler.py', 'pyhdf5_handler/src/object_handler.py', 'pyhdf5_handler/tutorial/hdf5_io_tests.py', 'pyhdf5_handler/tutorial/complementary_test.py', 'test_fichier_julie.py']
7
+ recent_files = ['pyhdf5_handler/src/hdf5_handler.py', 'pyhdf5_handler/src/object_handler.py', 'pyhdf5_handler/tutorial/hdf5_io_tests.py', 'pyhdf5_handler/tutorial/complementary_test.py']
8
8
 
9
9
  [main]
10
10
  version = 0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyhdf5_handler
3
- Version: 0.7
3
+ Version: 0.9
4
4
  Summary: A Python library to read and write data to HDF5 format. This library is based on the h5py (https://docs.h5py.org/en/stable/index.html) and has been developed by Maxime Jay-Allemand at Hydris hydrologie (https://www.hydris-hydrologie.fr/)
5
5
  Project-URL: Homepage, https://codeberg.org/maximejay/pyhdf5_handler
6
6
  Project-URL: Issues, https://codeberg.org/maximejay/pyhdf5_handler/issues
@@ -1,3 +1,13 @@
1
+ v0.9 : 23-07-2026
2
+ - fix: handle dtype with panda dataframe: read/write
3
+
4
+ v0.8 : 19-06-2026
5
+ - relase 0.8
6
+ - Add support for pd.DataFrame()
7
+ - improve function map_dict_to_object
8
+ - Fix : return in hdf5_dataset_creator after parsing an unknown object
9
+ - Add function to map a dictionary to an object with a given structure
10
+
1
11
  v0.7 : 12-03-2026
2
12
  - Exclude some python object when parsing a dict or an object. For instance Geopandas and shapely are excluded, because pyhdf5_handler crash when handled these complex python object. Other module can be exclude using the global variable EXCLUDE_PYTHON_OBJ.
3
13
  - Fix: Max recursion counter was set to zeros at the begining of the recursive function.
@@ -4,6 +4,6 @@
4
4
 
5
5
  from .src.hdf5_handler import close_all_hdf5_file, open_hdf5, add_hdf5_sub_group, hdf5_dataset_creator, save_dict_to_hdf5, save_dict_to_hdf5file, save_object_to_hdf5file, read_hdf5file_as_dict, read_hdf5_as_dict, hdf5_read_dataset, get_hdf5file_attribute, get_hdf5file_dataset, get_hdf5file_item, get_hdf5_item, search_in_hdf5file, search_in_hdf5, hdf5file_view, hdf5file_ls, hdf5_ls, hdf5_view
6
6
 
7
- from .src.object_handler import generate_dict_structure, generate_object_structure, read_object_as_dict
7
+ from .src.object_handler import generate_dict_structure, generate_object_structure, read_object_as_dict, map_dict_to_object
8
8
 
9
9
  from .src.constant import EXCLUDE_PYTHON_OBJ
@@ -99,7 +99,9 @@ def open_hdf5(path, read_only=False, replace=False, wait_time=0):
99
99
  print(f"File {path} does not exist.")
100
100
  return f
101
101
  else:
102
- print(f"The file {path} is unvailable, waiting {wait}/{wait_time}s")
102
+ print(
103
+ f"The file {path} is unvailable, waiting {wait}/{wait_time}s"
104
+ )
103
105
 
104
106
  wait = wait + 1
105
107
 
@@ -216,13 +218,19 @@ def _dump_object_to_hdf5_from_dict_attribute(hdf5, instance, dict_attr):
216
218
  sub_instance = instance
217
219
 
218
220
  if isinstance(value, dict):
219
- _dump_object_to_hdf5_from_dict_attribute(hdf5[attr], sub_instance, value)
221
+ _dump_object_to_hdf5_from_dict_attribute(
222
+ hdf5[attr], sub_instance, value
223
+ )
220
224
 
221
225
  elif isinstance(value, list):
222
- _dump_object_to_hdf5_from_list_attribute(hdf5[attr], sub_instance, value)
226
+ _dump_object_to_hdf5_from_list_attribute(
227
+ hdf5[attr], sub_instance, value
228
+ )
223
229
 
224
230
  elif isinstance(value, str):
225
- _dump_object_to_hdf5_from_str_attribute(hdf5[attr], sub_instance, value)
231
+ _dump_object_to_hdf5_from_str_attribute(
232
+ hdf5[attr], sub_instance, value
233
+ )
226
234
 
227
235
  else:
228
236
 
@@ -392,6 +400,32 @@ def _hdf5_handle_DatetimeIndex(name: str, value: pd.DatetimeIndex):
392
400
  return dataset
393
401
 
394
402
 
403
+ def _hdf5_handle_PandaDataFrame(
404
+ hdf5: h5py.File, name: str, value: pd.DataFrame
405
+ ):
406
+
407
+ hdf5 = add_hdf5_sub_group(hdf5, subgroup=name)
408
+ hdf5_data = hdf5[name]
409
+
410
+ hdf5_data = add_hdf5_sub_group(hdf5_data, subgroup="pd_DataFrame")
411
+ hdf5_data = hdf5_data["pd_DataFrame"]
412
+
413
+ keys = _hdf5_handle_array("columns", np.array(list(value.columns)))
414
+ _hdf5_create_dataset(hdf5_data, keys)
415
+
416
+ dataset = _hdf5_handle_array("array", value.to_numpy())
417
+ _hdf5_create_dataset(hdf5_data, dataset)
418
+
419
+ dtype = []
420
+ for col in value.columns:
421
+ dtype.append(value[col].dtype.name)
422
+
423
+ dataset = _hdf5_handle_list("dtype", dtype)
424
+ _hdf5_create_dataset(hdf5_data, dataset)
425
+
426
+ return
427
+
428
+
395
429
  def _hdf5_handle_list(name: str, value: list | tuple):
396
430
 
397
431
  arr = np.array(value)
@@ -415,16 +449,18 @@ def _hdf5_handle_exclude_obj(name: str, value: list | tuple):
415
449
 
416
450
  return dataset
417
451
 
452
+
418
453
  def _hdf5_skip_cls(value):
419
-
454
+
420
455
  type_str = str(type(value))
421
- module_name = type_str.split("'")[1].split('.')[0]
422
-
456
+ module_name = type_str.split("'")[1].split(".")[0]
457
+
423
458
  if module_name in constant.EXCLUDE_PYTHON_OBJ:
424
459
  return True
425
460
  else:
426
461
  return False
427
462
 
463
+
428
464
  def _hdf5_handle_array(name: str, value: np.ndarray):
429
465
 
430
466
  dtype_attr = type(value)
@@ -503,10 +539,10 @@ def hdf5_dataset_creator(hdf5: h5py.File, name: str, value):
503
539
  value to write in the hdf5
504
540
 
505
541
  """
506
-
542
+
507
543
  if _hdf5_skip_cls(value):
508
544
  dataset = _hdf5_handle_exclude_obj(name, value)
509
-
545
+
510
546
  elif isinstance(value, str):
511
547
  dataset = _hdf5_handle_str(name, value)
512
548
 
@@ -522,6 +558,12 @@ def hdf5_dataset_creator(hdf5: h5py.File, name: str, value):
522
558
  elif isinstance(value, pd.DatetimeIndex):
523
559
  dataset = _hdf5_handle_DatetimeIndex(name, value)
524
560
 
561
+ # TODO : To be tested
562
+ elif isinstance(value, pd.DataFrame):
563
+
564
+ _hdf5_handle_PandaDataFrame(hdf5, name, value)
565
+ return
566
+
525
567
  elif isinstance(value, list):
526
568
  dataset = _hdf5_handle_list(name, value)
527
569
 
@@ -544,6 +586,8 @@ def hdf5_dataset_creator(hdf5: h5py.File, name: str, value):
544
586
 
545
587
  save_dict_to_hdf5(hdf5[name], newdict)
546
588
 
589
+ return
590
+
547
591
  _hdf5_create_dataset(hdf5, dataset)
548
592
 
549
593
 
@@ -601,6 +645,35 @@ def _dump_ndarray_to_hdf5(hdf5, value):
601
645
  )
602
646
 
603
647
 
648
+ def _read_pd_dataframe(hdf5):
649
+ """
650
+ read a pandas dataframe data structure from hdf5 file
651
+
652
+ Parameters
653
+ ----------
654
+
655
+ hdf5 : h5py.File
656
+ an hdf5 object at the roots of the ndarray datastructure
657
+
658
+ Return
659
+ ------
660
+
661
+ pd.DataFrame : the pandas dataframe
662
+
663
+ """
664
+
665
+ if "pd_DataFrame" in list(hdf5.keys()):
666
+ columns = hdf5["pd_DataFrame/columns"][:]
667
+ array = hdf5["pd_DataFrame/array"][:]
668
+ dtype = hdf5["pd_DataFrame/dtype"][:]
669
+
670
+ newdict = {}
671
+ for i, col in enumerate(columns):
672
+ newdict.update({col.decode(): array[:, i].astype(dtype[i])})
673
+
674
+ return pd.DataFrame(newdict)
675
+
676
+
604
677
  def _read_ndarray_datastructure(hdf5):
605
678
  """
606
679
  read a ndarray data structure from hdf5 file
@@ -855,7 +928,11 @@ def save_object_to_hdf5file(
855
928
 
856
929
 
857
930
  def read_hdf5file_as_dict(
858
- path_to_hdf5, location="./", wait_time=0, read_attrs=True, read_dataset_attrs=False
931
+ path_to_hdf5,
932
+ location="./",
933
+ wait_time=0,
934
+ read_attrs=True,
935
+ read_dataset_attrs=False,
859
936
  ):
860
937
  """
861
938
 
@@ -897,7 +974,9 @@ def read_hdf5file_as_dict(
897
974
  return None
898
975
 
899
976
  dictionary = read_hdf5_as_dict(
900
- hdf5[location], read_attrs=read_attrs, read_dataset_attrs=read_dataset_attrs
977
+ hdf5[location],
978
+ read_attrs=read_attrs,
979
+ read_dataset_attrs=read_dataset_attrs,
901
980
  )
902
981
 
903
982
  hdf5.close()
@@ -936,7 +1015,9 @@ def read_hdf5_as_dict(hdf5, read_attrs=True, read_dataset_attrs=False):
936
1015
 
937
1016
  """
938
1017
 
939
- if not isinstance(hdf5, (h5py.File, h5py.Group, h5py.Dataset, h5py.Datatype)):
1018
+ if not isinstance(
1019
+ hdf5, (h5py.File, h5py.Group, h5py.Dataset, h5py.Datatype)
1020
+ ):
940
1021
  print("Error: input arg is not an instance of hdf5.File()")
941
1022
  return {}
942
1023
 
@@ -949,7 +1030,12 @@ def read_hdf5_as_dict(hdf5, read_attrs=True, read_dataset_attrs=False):
949
1030
  if key == "ndarray_ds":
950
1031
 
951
1032
  # dictionary.update({key: _read_ndarray_datastructure(hdf5)})
952
- return _read_ndarray_datastructure(hdf5)
1033
+ values = _read_ndarray_datastructure(hdf5)
1034
+ dictionary.update({key: values})
1035
+
1036
+ elif key == "pd_DataFrame":
1037
+ values = _read_pd_dataframe(hdf5)
1038
+ dictionary.update({key: values})
953
1039
 
954
1040
  else:
955
1041
 
@@ -970,14 +1056,17 @@ def read_hdf5_as_dict(hdf5, read_attrs=True, read_dataset_attrs=False):
970
1056
  list_attribute = []
971
1057
  if read_attrs or read_dataset_attrs:
972
1058
  tmp_list_attribute = list(hdf5.attrs.keys())
973
- hdf5_item_matching_attributes = ["_" + element for element in list(hdf5.keys())]
1059
+ hdf5_item_matching_attributes = [
1060
+ "_" + element for element in list(hdf5.keys())
1061
+ ]
974
1062
 
975
1063
  if read_attrs:
976
1064
 
977
1065
  list_attribute.extend(
978
1066
  list(
979
1067
  filter(
980
- lambda l: l not in hdf5_item_matching_attributes, tmp_list_attribute
1068
+ lambda l: l not in hdf5_item_matching_attributes,
1069
+ tmp_list_attribute,
981
1070
  )
982
1071
  )
983
1072
  )
@@ -985,7 +1074,12 @@ def read_hdf5_as_dict(hdf5, read_attrs=True, read_dataset_attrs=False):
985
1074
  if read_dataset_attrs:
986
1075
 
987
1076
  list_attribute.extend(
988
- list(filter(lambda l: l in hdf5_item_matching_attributes, tmp_list_attribute))
1077
+ list(
1078
+ filter(
1079
+ lambda l: l in hdf5_item_matching_attributes,
1080
+ tmp_list_attribute,
1081
+ )
1082
+ )
989
1083
  )
990
1084
 
991
1085
  for key in list_attribute:
@@ -1094,7 +1188,11 @@ def hdf5_read_dataset(item, expected_type=None):
1094
1188
 
1095
1189
  values = None
1096
1190
 
1097
- elif expected_type in (str(pd.Timestamp), str(np.datetime64), str(datetime.datetime)):
1191
+ elif expected_type in (
1192
+ str(pd.Timestamp),
1193
+ str(np.datetime64),
1194
+ str(datetime.datetime),
1195
+ ):
1098
1196
 
1099
1197
  if expected_type == str(pd.Timestamp):
1100
1198
  values = pd.Timestamp(item[0].decode())
@@ -1178,7 +1276,9 @@ def get_hdf5file_attribute(
1178
1276
  return return_attribute
1179
1277
 
1180
1278
 
1181
- def get_hdf5file_dataset(path_to_hdf5=str(), location="./", dataset=None, wait_time=0):
1279
+ def get_hdf5file_dataset(
1280
+ path_to_hdf5=str(), location="./", dataset=None, wait_time=0
1281
+ ):
1182
1282
  """
1183
1283
  Get the value of an attribute in the hdf5file
1184
1284
 
@@ -1230,7 +1330,11 @@ def get_hdf5file_dataset(path_to_hdf5=str(), location="./", dataset=None, wait_t
1230
1330
 
1231
1331
 
1232
1332
  def get_hdf5file_item(
1233
- path_to_hdf5=str(), location="./", item=None, wait_time=0, search_attrs=False
1333
+ path_to_hdf5=str(),
1334
+ location="./",
1335
+ item=None,
1336
+ wait_time=0,
1337
+ search_attrs=False,
1234
1338
  ):
1235
1339
  """
1236
1340
 
@@ -1273,7 +1377,10 @@ def get_hdf5file_item(
1273
1377
  return None
1274
1378
 
1275
1379
  hdf5_item = get_hdf5_item(
1276
- hdf5_instance=hdf5, location=location, item=item, search_attrs=search_attrs
1380
+ hdf5_instance=hdf5,
1381
+ location=location,
1382
+ item=item,
1383
+ search_attrs=search_attrs,
1277
1384
  )
1278
1385
 
1279
1386
  hdf5.close()
@@ -1281,7 +1388,9 @@ def get_hdf5file_item(
1281
1388
  return hdf5_item
1282
1389
 
1283
1390
 
1284
- def get_hdf5_item(hdf5_instance=None, location="./", item=None, search_attrs=False):
1391
+ def get_hdf5_item(
1392
+ hdf5_instance=None, location="./", item=None, search_attrs=False
1393
+ ):
1285
1394
  """
1286
1395
 
1287
1396
  Get a custom item in an hdf5file
@@ -1349,6 +1458,10 @@ def get_hdf5_item(hdf5_instance=None, location="./", item=None, search_attrs=Fal
1349
1458
 
1350
1459
  return _read_ndarray_datastructure(hdf5)
1351
1460
 
1461
+ elif item == "pd_DataFrame":
1462
+
1463
+ return _read_pd_dataframe(hdf5)
1464
+
1352
1465
  else:
1353
1466
 
1354
1467
  returned_dict = read_hdf5_as_dict(hdf5_item)
@@ -1420,7 +1533,9 @@ def search_in_hdf5file(
1420
1533
  if hdf5 is None:
1421
1534
  return None
1422
1535
 
1423
- results = search_in_hdf5(hdf5, key, location=location, search_attrs=search_attrs)
1536
+ results = search_in_hdf5(
1537
+ hdf5, key, location=location, search_attrs=search_attrs
1538
+ )
1424
1539
 
1425
1540
  hdf5.close()
1426
1541
 
@@ -1542,7 +1657,12 @@ def search_in_hdf5(hdf5_base, key=None, location="./", search_attrs=False):
1542
1657
  values = item[:]
1543
1658
 
1544
1659
  result.append(
1545
- {"path": location, "key": key, "datatype": "dataset", "value": values}
1660
+ {
1661
+ "path": location,
1662
+ "key": key,
1663
+ "datatype": "dataset",
1664
+ "value": values,
1665
+ }
1546
1666
  )
1547
1667
 
1548
1668
  return result
@@ -1774,14 +1894,17 @@ def hdf5_view(
1774
1894
  list_attribute = []
1775
1895
  if list_attrs or list_dataset_attrs:
1776
1896
  tmp_list_attribute = list(hdf5.attrs.keys())
1777
- list_keys_matching_attributes = ["_" + element for element in list(hdf5.keys())]
1897
+ list_keys_matching_attributes = [
1898
+ "_" + element for element in list(hdf5.keys())
1899
+ ]
1778
1900
 
1779
1901
  if list_attrs:
1780
1902
 
1781
1903
  list_attribute.extend(
1782
1904
  list(
1783
1905
  filter(
1784
- lambda l: l not in list_keys_matching_attributes, tmp_list_attribute
1906
+ lambda l: l not in list_keys_matching_attributes,
1907
+ tmp_list_attribute,
1785
1908
  )
1786
1909
  )
1787
1910
  )
@@ -1789,14 +1912,20 @@ def hdf5_view(
1789
1912
  if list_dataset_attrs:
1790
1913
 
1791
1914
  list_attribute.extend(
1792
- list(filter(lambda l: l in list_keys_matching_attributes, tmp_list_attribute))
1915
+ list(
1916
+ filter(
1917
+ lambda l: l in list_keys_matching_attributes,
1918
+ tmp_list_attribute,
1919
+ )
1920
+ )
1793
1921
  )
1794
1922
 
1795
1923
  for key in list_attribute:
1796
1924
  values = hdf5.attrs[key]
1797
1925
  sub_location = os.path.join(location, key)
1798
1926
  if isinstance(
1799
- values, (int, float, np.int64, np.float64, np.int32, np.float32, np.bool)
1927
+ values,
1928
+ (int, float, np.int64, np.float64, np.int32, np.float32, np.bool),
1800
1929
  ):
1801
1930
  result.append(
1802
1931
  f"{level_base}| {sub_location}, attribute, type={type(hdf5.attrs[key])}, value={values}"
@@ -1,4 +1,3 @@
1
-
2
1
  from __future__ import annotations
3
2
 
4
3
  import numpy as np
@@ -9,44 +8,62 @@ from ..src import constant
9
8
 
10
9
 
11
10
  def _isinstance_pandas(value):
12
- pandas_classes = [getattr(pd, item) for item in dir(pd) if isinstance(getattr(pd, item), type)]
11
+ pandas_classes = [
12
+ getattr(pd, item)
13
+ for item in dir(pd)
14
+ if isinstance(getattr(pd, item), type)
15
+ ]
13
16
  for cls in pandas_classes:
14
17
  if isinstance(value, cls):
15
18
  return True
16
19
  return False
17
20
 
21
+
18
22
  def _isinstance_numpy(value):
19
- numpy_classes = [getattr(np, item) for item in dir(np) if isinstance(getattr(np, item), type)]
23
+ numpy_classes = [
24
+ getattr(np, item)
25
+ for item in dir(np)
26
+ if isinstance(getattr(np, item), type)
27
+ ]
20
28
  for cls in numpy_classes:
21
29
  if isinstance(value, cls):
22
30
  return True
23
31
  return False
24
32
 
33
+
25
34
  def _isinstance_datetime(value):
26
- datetime_classes = [getattr(datetime, item) for item in dir(datetime) if isinstance(getattr(datetime, item), type)]
35
+ datetime_classes = [
36
+ getattr(datetime, item)
37
+ for item in dir(datetime)
38
+ if isinstance(getattr(datetime, item), type)
39
+ ]
27
40
  for cls in datetime_classes:
28
41
  if isinstance(value, cls):
29
42
  return True
30
43
  return False
31
44
 
45
+
32
46
  def _isinstance_exclude_obj(value):
33
-
47
+
34
48
  type_str = str(type(value))
35
- module_name = type_str.split("'")[1].split('.')[0]
36
-
49
+ module_name = type_str.split("'")[1].split(".")[0]
50
+
37
51
  if module_name in constant.EXCLUDE_PYTHON_OBJ:
38
52
  return True
39
53
  else:
40
54
  return False
41
55
 
42
- def generate_dict_structure(dictionary,recursion_counter=0,recursion_limit=100,include_method=True):
56
+
57
+ def generate_dict_structure(
58
+ dictionary, recursion_counter=0, recursion_limit=100, include_method=True
59
+ ):
43
60
  """
44
-
61
+
45
62
  this function create a full dictionnary containing all the structure of an dictionnary in order to save it to an hdf5
46
63
 
47
64
  Parameters
48
65
  ----------
49
-
66
+
50
67
  instance : python dictionary
51
68
  a custom dictionary.
52
69
  recursion_limit : int
@@ -58,70 +75,148 @@ def generate_dict_structure(dictionary,recursion_counter=0,recursion_limit=100,i
58
75
 
59
76
  Returns
60
77
  -------
61
-
78
+
62
79
  list or dict :
63
80
  A list or dictionary matching the structure of the python object.
64
-
81
+
65
82
  """
66
- key_data={}
83
+ key_data = {}
67
84
  key_list = list()
68
- recursion_counter=0
69
- for attr,value in dictionary.items():
70
-
85
+ recursion_counter = 0
86
+ for attr, value in dictionary.items():
87
+
71
88
  try:
72
89
  if _isinstance_exclude_obj(value):
73
90
  next(attrs)
74
- elif isinstance(value,dict):
75
- subkey_data=generate_dict_structure(value)
76
- if len(subkey_data)>0:
77
- key_data.update({attr:subkey_data})
78
-
91
+ elif isinstance(value, dict):
92
+ subkey_data = generate_dict_structure(value)
93
+ if len(subkey_data) > 0:
94
+ key_data.update({attr: subkey_data})
95
+
79
96
  elif isinstance(value, (list, tuple, numbers.Number, str)):
80
97
  key_list.append(attr)
81
-
98
+
82
99
  elif _isinstance_pandas(value):
83
100
  key_list.append(attr)
84
-
101
+
85
102
  elif _isinstance_datetime(value):
86
103
  key_list.append(attr)
87
-
104
+
88
105
  elif _isinstance_numpy(value):
89
106
  key_list.append(attr)
90
-
107
+
91
108
  elif type(value) == "method":
92
109
  if include_method:
93
110
  key_list.append(attr)
94
111
  else:
95
112
  next(attr)
96
113
  else:
97
-
98
- recursion_counter = recursion_counter+1
99
-
114
+
115
+ recursion_counter = recursion_counter + 1
116
+
100
117
  if recursion_counter > recursion_limit:
101
- print(f"recursion counter exceed the limit of {recursion_limit}... return")
118
+ print(
119
+ f"recursion counter exceed the limit of {recursion_limit}... return"
120
+ )
102
121
  return
103
-
104
- subkey_data = generate_object_structure(value,recursion_counter=recursion_counter,recursion_limit=recursion_limit,include_method=include_method)
122
+
123
+ subkey_data = generate_object_structure(
124
+ value,
125
+ recursion_counter=recursion_counter,
126
+ recursion_limit=recursion_limit,
127
+ include_method=include_method,
128
+ )
105
129
  if len(subkey_data) > 0:
106
130
  key_data.update({attr: subkey_data})
107
131
 
108
132
  except:
109
133
  pass
110
-
134
+
111
135
  for attr, value in key_data.items():
112
136
  key_list.append({attr: value})
113
-
137
+
114
138
  return key_list
115
139
 
116
140
 
117
- def generate_object_structure(instance,recursion_counter=0,recursion_limit=100,include_method=True):
141
+ def generate_object_from_dictionary(dictionary):
142
+
143
+ class Object:
144
+ def __init__(self):
145
+ pass
146
+
147
+ obj = Object()
148
+
149
+ if isinstance(dictionary, dict):
150
+ for attr, value in dictionary.items():
151
+
152
+ if isinstance(value, (dict, list, tuple)):
153
+ setattr(obj, attr, generate_object_from_dictionary(value))
154
+ else:
155
+ setattr(obj, attr, value)
156
+ elif isinstance(dictionary, (list, tuple)):
157
+ return dictionary
158
+ # for attr in dictionary:
159
+ # setattr(obj, attr, None)
160
+
161
+ return obj
162
+
163
+
164
+ def map_dict_to_object(structure, dictionary, obj):
165
+ """
166
+ Map a dictionary to an object knowing its structure.
167
+ Structure must be generated with generate_dict_structure or generate_object_structure. If the object or an attribute of this object is
168
+ None, a empty object is created to be able to set new attribute.
118
169
  """
119
-
170
+
171
+ class Object:
172
+ def __init__(self):
173
+ pass
174
+
175
+ if obj is None:
176
+ obj = Object()
177
+
178
+ if isinstance(structure, dict):
179
+
180
+ for attr, value in structure.items():
181
+ if isinstance(value, (dict, list, tuple)):
182
+
183
+ if not hasattr(obj, attr):
184
+ setattr(obj, str(attr), Object())
185
+ else:
186
+ if getattr(obj, attr) is None:
187
+ setattr(obj, str(attr), Object())
188
+
189
+ map_dict_to_object(value, dictionary[attr], getattr(obj, attr))
190
+ else:
191
+ v = None
192
+ if attr in dictionary.keys():
193
+ v = dictionary[attr]
194
+
195
+ setattr(obj, str(attr), v)
196
+
197
+ elif isinstance(structure, (list, tuple)):
198
+
199
+ for attr in structure:
200
+ if isinstance(attr, (dict, list, tuple)):
201
+ map_dict_to_object(attr, dictionary, obj)
202
+ else:
203
+ v = None
204
+ if attr in dictionary.keys():
205
+ v = dictionary[attr]
206
+
207
+ setattr(obj, str(attr), v)
208
+
209
+
210
+ def generate_object_structure(
211
+ instance, recursion_counter=0, recursion_limit=100, include_method=True
212
+ ):
213
+ """
214
+
120
215
  this function create a full dictionnary containing all the structure of an object in order to save it to an hdf5
121
216
 
122
217
  Parameters
123
218
  ----------
124
-
219
+
125
220
  instance : object
126
221
  a custom python object.
127
222
  recursion_limit : int
@@ -133,36 +228,36 @@ def generate_object_structure(instance,recursion_counter=0,recursion_limit=100,i
133
228
 
134
229
  Returns
135
230
  -------
136
-
231
+
137
232
  list or dict :
138
233
  A list or dictionary matching the structure of the python object.
139
-
234
+
140
235
  """
141
236
  key_data = {}
142
237
  key_list = list()
143
238
  return_list = False
144
- #recursion_counter += 1
239
+ # recursion_counter += 1
145
240
  for attr in dir(instance):
146
-
241
+
147
242
  if not attr.startswith("_") and not attr in ["from_handle", "copy"]:
148
-
243
+
149
244
  try:
150
245
  value = getattr(instance, attr)
151
-
246
+
152
247
  if _isinstance_exclude_obj(value):
153
248
  next(attr)
154
-
249
+
155
250
  elif isinstance(value, (list, tuple)):
156
251
  key_list.append(attr)
157
252
  return_list = True
158
-
253
+
159
254
  elif _isinstance_numpy(value):
160
255
  key_list.append(attr)
161
256
  return_list = True
162
-
257
+
163
258
  elif isinstance(value, dict):
164
-
165
- depp_key_data=generate_dict_structure(value)
259
+
260
+ depp_key_data = generate_dict_structure(value)
166
261
  if len(depp_key_data) > 0:
167
262
  key_data.update({attr: depp_key_data})
168
263
 
@@ -180,24 +275,35 @@ def generate_object_structure(instance,recursion_counter=0,recursion_limit=100,i
180
275
  return_list = True
181
276
  else:
182
277
  next(attr)
183
-
278
+
184
279
  elif _isinstance_pandas(value):
185
280
  key_list.append(attr)
186
281
  return_list = True
187
-
282
+
188
283
  elif _isinstance_datetime(value):
189
284
  key_list.append(attr)
190
285
  return_list = True
191
-
286
+
287
+ # ~ elif value is None:
288
+ # ~ key_list.append(attr)
289
+ # ~ return_list = True
290
+
192
291
  else:
193
-
194
- recursion_counter = recursion_counter+1
195
-
292
+
293
+ recursion_counter = recursion_counter + 1
294
+
196
295
  if recursion_counter > recursion_limit:
197
- print(f"recursion counter exceed the limit of {recursion_limit}... return")
296
+ print(
297
+ f"recursion counter exceed the limit of {recursion_limit}... return"
298
+ )
198
299
  return
199
-
200
- depp_key_data = generate_object_structure(value, recursion_counter=recursion_counter,recursion_limit=recursion_limit,include_method=include_method)
300
+
301
+ depp_key_data = generate_object_structure(
302
+ value,
303
+ recursion_counter=recursion_counter,
304
+ recursion_limit=recursion_limit,
305
+ include_method=include_method,
306
+ )
201
307
 
202
308
  if len(depp_key_data) > 0:
203
309
  key_data.update({attr: depp_key_data})
@@ -217,14 +323,14 @@ def generate_object_structure(instance,recursion_counter=0,recursion_limit=100,i
217
323
  return key_data
218
324
 
219
325
 
220
- def read_object_as_dict(instance, recursion_counter=0,recursion_limit=100):
326
+ def read_object_as_dict(instance, recursion_counter=0, recursion_limit=100):
221
327
  """
222
-
328
+
223
329
  create a dictionary from a custom python object
224
330
 
225
331
  Parameters
226
332
  ----------
227
-
333
+
228
334
  instance : object
229
335
  an custom python object
230
336
  recursion_limit : int
@@ -234,35 +340,35 @@ def read_object_as_dict(instance, recursion_counter=0,recursion_limit=100):
234
340
 
235
341
  Return
236
342
  ------
237
-
343
+
238
344
  key_data: dict
239
345
  an dictionary containing all keys and atributes of the object
240
-
346
+
241
347
  """
242
348
  key_data = {}
243
- #recursion_counter = 0
349
+ # recursion_counter = 0
244
350
  for attr in dir(instance):
245
- #print(attr)
351
+ # print(attr)
246
352
  if not attr.startswith("_") and not attr in ["from_handle", "copy"]:
247
353
  try:
248
354
  value = getattr(instance, attr)
249
-
355
+
250
356
  if _isinstance_exclude_obj(value):
251
357
  next(attr)
252
-
358
+
253
359
  elif isinstance(value, (list, tuple)):
254
-
360
+
255
361
  if isinstance(value, list):
256
- value = np.array(value).astype('U')
362
+ value = np.array(value).astype("U")
257
363
 
258
364
  if value.dtype == "object" or value.dtype.char == "U":
259
365
  value = value.astype("U")
260
-
366
+
261
367
  key_data.update({attr: value})
262
-
368
+
263
369
  elif isinstance(value, dict):
264
370
  key_data.update({attr: value})
265
-
371
+
266
372
  elif isinstance(value, numbers.Number):
267
373
  key_data.update({attr: value})
268
374
 
@@ -271,33 +377,38 @@ def read_object_as_dict(instance, recursion_counter=0,recursion_limit=100):
271
377
 
272
378
  elif type(value) == "method":
273
379
  next(attr)
274
-
380
+
275
381
  elif _isinstance_pandas(value):
276
382
  if value.dtype == "object" or value.dtype.char == "U":
277
383
  value = value.astype("U")
278
384
  key_data.update({attr: value})
279
-
385
+
280
386
  elif _isinstance_datetime(value):
281
387
  if value.dtype == "object" or value.dtype.char == "U":
282
388
  value = value.astype("U")
283
389
  key_data.update({attr: value})
284
-
390
+
285
391
  elif _isinstance_numpy(value):
286
392
  if value.dtype == "object" or value.dtype.char == "U":
287
393
  value = value.astype("U")
288
394
  key_data.update({attr: value})
289
395
 
290
396
  else:
291
-
292
- recursion_counter = recursion_counter+1
293
-
397
+
398
+ recursion_counter = recursion_counter + 1
399
+
294
400
  if recursion_counter > recursion_limit:
295
- print(f"recursion counter exceed the limit of {recursion_limit}... return")
401
+ print(
402
+ f"recursion counter exceed the limit of {recursion_limit}... return"
403
+ )
296
404
  return
297
-
405
+
298
406
  depp_key_data = read_object_as_dict(
299
- value, recursion_counter=recursion_counter,recursion_limit=recursion_limit)
300
-
407
+ value,
408
+ recursion_counter=recursion_counter,
409
+ recursion_limit=recursion_limit,
410
+ )
411
+
301
412
  if len(depp_key_data) > 0:
302
413
  key_data.update({attr: depp_key_data})
303
414
 
@@ -22,7 +22,9 @@ if __name__ == "__main__":
22
22
  hdf5, "timestamp_numpy", np.datetime64("2019-09-22T17:38:30")
23
23
  )
24
24
  pyhdf5_handler.hdf5_dataset_creator(
25
- hdf5, "timestamp_datetime", datetime.datetime.fromisoformat("2019-09-22T17:38:30")
25
+ hdf5,
26
+ "timestamp_datetime",
27
+ datetime.datetime.fromisoformat("2019-09-22T17:38:30"),
26
28
  )
27
29
  pyhdf5_handler.hdf5_dataset_creator(
28
30
  hdf5, "timestamp_pandas", pd.Timestamp("2019-09-22T17:38:30")
@@ -33,7 +35,10 @@ if __name__ == "__main__":
33
35
  pyhdf5_handler.hdf5_dataset_creator(
34
36
  hdf5,
35
37
  "list_date_numpy",
36
- [np.datetime64("2019-09-22 17:38:30"), np.datetime64("2019-09-22 18:38:30")],
38
+ [
39
+ np.datetime64("2019-09-22 17:38:30"),
40
+ np.datetime64("2019-09-22 18:38:30"),
41
+ ],
37
42
  )
38
43
  pyhdf5_handler.hdf5_dataset_creator(
39
44
  hdf5,
@@ -46,10 +51,43 @@ if __name__ == "__main__":
46
51
  pyhdf5_handler.hdf5_dataset_creator(
47
52
  hdf5,
48
53
  "list_date_pandas",
49
- [pd.Timestamp("2019-09-22 17:38:30"), pd.Timestamp("2019-09-22 17:38:30")],
54
+ [
55
+ pd.Timestamp("2019-09-22 17:38:30"),
56
+ pd.Timestamp("2019-09-22 17:38:30"),
57
+ ],
50
58
  )
51
59
  pyhdf5_handler.hdf5_dataset_creator(
52
- hdf5, "list_date_range_pandas", pd.date_range(start="1/1/2018", end="1/08/2018")
60
+ hdf5,
61
+ "list_date_range_pandas",
62
+ pd.date_range(start="1/1/2018", end="1/08/2018"),
63
+ )
64
+
65
+ pyhdf5_handler.hdf5_dataset_creator(
66
+ hdf5,
67
+ "panda_dataframe_onecolumn",
68
+ pd.DataFrame({"column1": np.array([1, 2, 3])}),
69
+ )
70
+ pyhdf5_handler.hdf5_dataset_creator(
71
+ hdf5,
72
+ "panda_dataframe",
73
+ pd.DataFrame(
74
+ {"column1": np.array([1, 2, 3]), "column2": np.array([4, 5, 6])}
75
+ ),
76
+ )
77
+ pyhdf5_handler.hdf5_dataset_creator(
78
+ hdf5,
79
+ "mix_dtype_panda_dataframe",
80
+ pd.DataFrame(
81
+ {
82
+ "column1": np.array(["A", "B", "C"]),
83
+ "column2": np.array([4, 5, 6]),
84
+ }
85
+ ),
86
+ )
87
+ pyhdf5_handler.hdf5_dataset_creator(
88
+ hdf5,
89
+ "empty_dataframe",
90
+ pd.DataFrame({}),
53
91
  )
54
92
 
55
93
  # write a python dictionary in the hdf5 database
@@ -63,6 +101,12 @@ if __name__ == "__main__":
63
101
  "array": np.array([1, 2, 3, 4]),
64
102
  "date_range": pd.date_range(start="1/1/2018", end="1/08/2018"),
65
103
  "list_mixte": [1.0, np.datetime64("2019-09-22 17:38:30")],
104
+ "pandas_df": pd.DataFrame(
105
+ {
106
+ "column1": np.array([1, 2, 3]),
107
+ "column2": np.array([4, 5, 6]),
108
+ }
109
+ ),
66
110
  }
67
111
  }
68
112
 
@@ -88,7 +132,9 @@ if __name__ == "__main__":
88
132
  data = pyhdf5_handler.read_hdf5_as_dict(hdf5, read_attrs=True)
89
133
 
90
134
  # read a specific item
91
- pyhdf5_handler.hdf5_read_dataset(item=hdf5["str"], expected_type=hdf5.attrs["_str"])
135
+ pyhdf5_handler.hdf5_read_dataset(
136
+ item=hdf5["str"], expected_type=hdf5.attrs["_str"]
137
+ )
92
138
  pyhdf5_handler.hdf5_read_dataset(
93
139
  item=hdf5["numpy_numbers"], expected_type=hdf5.attrs["_numpy_numbers"]
94
140
  )
@@ -96,7 +142,22 @@ if __name__ == "__main__":
96
142
  item=hdf5["numbers"], expected_type=hdf5.attrs["_numbers"]
97
143
  )
98
144
  pyhdf5_handler.hdf5_read_dataset(
99
- item=hdf5["list_date_numpy"], expected_type=hdf5.attrs["_list_date_numpy"]
145
+ item=hdf5["list_date_numpy"],
146
+ expected_type=hdf5.attrs["_list_date_numpy"],
147
+ )
148
+
149
+ # getting specific item
150
+ pyhdf5_handler.get_hdf5_item(
151
+ hdf5_instance=hdf5,
152
+ location="./panda_dataframe",
153
+ )
154
+ pyhdf5_handler.get_hdf5_item(
155
+ hdf5_instance=hdf5,
156
+ location="./mix_dtype_panda_dataframe",
157
+ )
158
+ pyhdf5_handler.get_hdf5_item(
159
+ hdf5_instance=hdf5,
160
+ location="./structured_array",
100
161
  )
101
162
 
102
163
  # close the hdf5
@@ -106,7 +167,14 @@ if __name__ == "__main__":
106
167
  pyhdf5_handler.hdf5file_ls("./test.hdf5")
107
168
  pyhdf5_handler.hdf5file_ls("./test.hdf5", location="structured_array")
108
169
 
109
- data = pyhdf5_handler.read_hdf5file_as_dict("./test.hdf5", read_attrs=False)
170
+ data = pyhdf5_handler.read_hdf5file_as_dict(
171
+ "./test.hdf5", read_attrs=False
172
+ )
173
+
174
+ pyhdf5_handler.get_hdf5file_item(
175
+ path_to_hdf5="./test.hdf5",
176
+ location="./mix_dtype_panda_dataframe",
177
+ )
110
178
 
111
179
  pyhdf5_handler.save_dict_to_hdf5file("./test.hdf5", data)
112
180
 
@@ -154,15 +222,24 @@ if __name__ == "__main__":
154
222
  )
155
223
 
156
224
  pyhdf5_handler.get_hdf5file_item(
157
- path_to_hdf5="./test.hdf5", location="./", item="list_mixte", search_attrs=False
225
+ path_to_hdf5="./test.hdf5",
226
+ location="./",
227
+ item="list_mixte",
228
+ search_attrs=False,
158
229
  )
159
230
 
160
231
  pyhdf5_handler.get_hdf5file_item(
161
- path_to_hdf5="./test.hdf5", location="./", item="attribute", search_attrs=True
232
+ path_to_hdf5="./test.hdf5",
233
+ location="./",
234
+ item="attribute",
235
+ search_attrs=True,
162
236
  )
163
237
 
164
238
  pyhdf5_handler.get_hdf5file_attribute(
165
- path_to_hdf5="./test.hdf5", location="./", attribute="_list_num", wait_time=0
239
+ path_to_hdf5="./test.hdf5",
240
+ location="./",
241
+ attribute="_list_num",
242
+ wait_time=0,
166
243
  )
167
244
 
168
245
  pyhdf5_handler.get_hdf5file_attribute(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyhdf5_handler"
7
- version = "0.7"
7
+ version = "0.9"
8
8
  authors = [
9
9
  { name="Maxime Jay-Allemand", email="maxime.jay.allemand@hydris-hydrologie.fr" },
10
10
  ]
Binary file
Binary file
@@ -1,42 +0,0 @@
1
- import pyhdf5_handler
2
- import numpy as np
3
-
4
- #states
5
- pyhdf5_handler.hdf5file_view("202309010300_states.hdf5")
6
-
7
- res=pyhdf5_handler.read_hdf5file_as_dict("202309010300_states.hdf5")
8
- res.keys()
9
- res["202309010300"].keys()
10
- res["202309010300"]["keys"][0].decode()
11
- res["202309010300"]["keys"][:].astype("str")
12
-
13
- states=res["202309010300"]["values"]
14
-
15
- states=pyhdf5_handler.get_hdf5file_item("202309010300_states.hdf5",location="./202309010300",item="values")
16
-
17
- search=pyhdf5_handler.search_in_hdf5file("202309010300_states.hdf5","values")
18
- res=search[0]
19
- res.keys()
20
- res["path"]
21
- res["key"]
22
- res["datatype"]
23
- res["value"]
24
-
25
- #prévis ensemble:
26
- pyhdf5_handler.hdf5file_view("20230901030000_qens.hdf5")
27
-
28
- res=pyhdf5_handler.read_hdf5file_as_dict("20230901030000_qens.hdf5")
29
-
30
- res.keys()
31
- res["20230901030000"].keys()
32
- Q=res["20230901030000"]["member0"]
33
-
34
- Q=pyhdf5_handler.get_hdf5file_item("20230901030000_qens.hdf5",location="./20230901030000",item="member8")
35
-
36
- search=pyhdf5_handler.search_in_hdf5file("20230901030000_qens.hdf5","member8")
37
- res=search[0]
38
- res.keys()
39
- res["path"]
40
- res["key"]
41
- res["datatype"]
42
- res["value"]
File without changes
File without changes