h5yaml 0.0.4__tar.gz → 0.1.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.
@@ -0,0 +1,11 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.12.8
4
+ hooks:
5
+ - id: ruff-check
6
+ args: [ --fix ]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v6.0.0
10
+ hooks:
11
+ - id: check-yaml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: h5yaml
3
- Version: 0.0.4
3
+ Version: 0.1.0
4
4
  Summary: Use YAML configuration file to generate HDF5/netCDF4 formated files.
5
5
  Project-URL: Homepage, https://github.com/rmvanhees/h5_yaml
6
6
  Project-URL: Source, https://github.com/rmvanhees/h5_yaml
@@ -9,18 +9,18 @@ Author-email: Richard van Hees <r.m.van.hees@sron.nl>
9
9
  License-Expression: BSD-3-Clause
10
10
  License-File: LICENSE
11
11
  Keywords: HDF5,YAML,netCDF4
12
- Classifier: Development Status :: 4 - Beta
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Science/Research
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
22
  Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
23
- Requires-Python: >=3.9
23
+ Requires-Python: >=3.10
24
24
  Requires-Dist: h5py>=3.13
25
25
  Requires-Dist: netcdf4>=1.7
26
26
  Requires-Dist: numpy>=2.2
@@ -133,10 +133,11 @@ The YAML file should be structured as follows:
133
133
  Alternatively, provide a list with names of YAML files which contain the definitions
134
134
  of the compounds.
135
135
 
136
+ ```
136
137
  compounds:
137
138
  - h5_nomhk_tm.yaml
138
139
  - h5_science_hk.yaml
139
-
140
+ ```
140
141
  * The 'variables' are defined by their data-type ('_dtype') and dimensions ('_dims'),
141
142
  and optionally chunk sizes ('_chunks'), compression ('_compression'), variable length
142
143
  ('_vlen'). In addition, each variable can have as many attributes as you like,
@@ -104,10 +104,11 @@ The YAML file should be structured as follows:
104
104
  Alternatively, provide a list with names of YAML files which contain the definitions
105
105
  of the compounds.
106
106
 
107
+ ```
107
108
  compounds:
108
109
  - h5_nomhk_tm.yaml
109
110
  - h5_science_hk.yaml
110
-
111
+ ```
111
112
  * The 'variables' are defined by their data-type ('_dtype') and dimensions ('_dims'),
112
113
  and optionally chunk sizes ('_chunks'), compression ('_compression'), variable length
113
114
  ('_vlen'). In addition, each variable can have as many attributes as you like,
@@ -14,18 +14,18 @@ license = "BSD-3-Clause"
14
14
  authors = [
15
15
  {name = "Richard van Hees", email = "r.m.van.hees@sron.nl"}
16
16
  ]
17
- requires-python = ">=3.9"
17
+ requires-python = ">=3.10"
18
18
  classifiers = [
19
- "Development Status :: 4 - Beta",
19
+ "Development Status :: 5 - Production/Stable",
20
20
  "Intended Audience :: Developers",
21
21
  "Intended Audience :: Science/Research",
22
22
  "Operating System :: OS Independent",
23
23
  "Programming Language :: Python :: 3 :: Only",
24
- "Programming Language :: Python :: 3.9",
25
24
  "Programming Language :: Python :: 3.10",
26
25
  "Programming Language :: Python :: 3.11",
27
26
  "Programming Language :: Python :: 3.12",
28
27
  "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
29
  "Topic :: Scientific/Engineering :: Atmospheric Science",
30
30
  ]
31
31
  keywords = [
@@ -0,0 +1,106 @@
1
+ # YAML
2
+ #
3
+ # Configuration file to test the implementation of classes H5Yaml and NcYaml
4
+ #
5
+ # This file is part of h5_yaml:
6
+ # https://github.com/rmvanhees/h5_yaml.git
7
+ #
8
+ # Copyright (c) 2025 SRON
9
+ # All Rights Reserved
10
+ #
11
+ # License: BSD-3-Clause
12
+ #
13
+ # Define groups
14
+ groups:
15
+ - group_00
16
+ - group_01
17
+ - group_02
18
+
19
+ # Define dimensions
20
+ # Note dimensions with an attribute 'long_name' will also be generated as variable
21
+ dimensions:
22
+ number_of_images:
23
+ _dtype: u2
24
+ _size: 0
25
+ samples_per_image:
26
+ _dtype: u4
27
+ _size: 203500
28
+ column:
29
+ _dtype: u2
30
+ _size: 640
31
+ row:
32
+ _dtype: u2
33
+ _size: 512
34
+ time:
35
+ _dtype: f8
36
+ _size: 0
37
+ _FillValue: -32767
38
+ long_name: Attitude sample time (seconds of day)
39
+ calendar: proleptic_gregorian
40
+ units: seconds since %Y-%m-%d %H:%M:%S
41
+ valid_min: 0
42
+ valid_max: 92400
43
+
44
+ # Define compound types
45
+ # - compound elements must have a data-type, and can have a unit and long_name
46
+ compounds:
47
+ stats_dtype:
48
+ time:
49
+ - u8
50
+ - seconds since 1970-01-01T00:00:00
51
+ - timestamp
52
+ index: [u2, '1', index]
53
+ tbl_id: [u1, '1', binning id]
54
+ saa: [u1, '1', saa-flag]
55
+ coad: [u1, '1', co-addings]
56
+ texp: [f4, ms, exposure time]
57
+ lat: [f4, degree, latitude]
58
+ lon: [f4, degree, longitude]
59
+ avg: [f4, '1', '$S - S_{ref}$']
60
+ unc: [f4, '1', '\u03c3($S - S_{ref}$)']
61
+ dark_offs: [f4, '1', dark-offset]
62
+
63
+ geo_dtype:
64
+ lat: [f4, latitude]
65
+ lon: [f4, longitude]
66
+
67
+ # Define variables
68
+ variables:
69
+ /group_00/detector_images:
70
+ _dtype: u2
71
+ _dims: [number_of_images, column, row]
72
+ _FillValue: 65535
73
+ long_name: Detector pixel values
74
+ comment: unbinned full-frame data
75
+ units: '1'
76
+ valid_min: 0
77
+ valid_max: 65534
78
+ /group_01/detector_images:
79
+ _dtype: u2
80
+ _dims: [number_of_images, samples_per_image]
81
+ _FillValue: 65535
82
+ _compression: 1
83
+ long_name: Detector pixel values
84
+ comment: variable binned data (filled to the largest samples_per_image)
85
+ units: '1'
86
+ valid_min: 0
87
+ valid_max: 65534
88
+ /group_01/stats:
89
+ _dtype: stats_dtype
90
+ _dims: [time]
91
+ comment: detector map statistics
92
+ /group_02/detector_images:
93
+ _dtype: u2
94
+ _dims: [number_of_images]
95
+ _vlen: True
96
+ _FillValue: 65535
97
+ long_name: Detector pixel values
98
+ comment: variable binned (vlen) data
99
+ units: '1'
100
+ valid_min: 0
101
+ valid_max: 65534
102
+ /group_02/stats:
103
+ _dtype: stats_dtype
104
+ _vlen: True
105
+ _dims: [time]
106
+ comment: detector map statistics (vlen)
@@ -45,7 +45,10 @@ dimensions:
45
45
  # - compound elements must have a data-type, and can have a unit and long_name
46
46
  compounds:
47
47
  stats_dtype:
48
- time: [u8, seconds since 1970-01-01T00:00:00, timestamp]
48
+ time:
49
+ - u8
50
+ - seconds since 1970-01-01T00:00:00
51
+ - timestamp
49
52
  index: [u2, '1', index]
50
53
  tbl_id: [u1, '1', binning id]
51
54
  saa: [u1, '1', saa-flag]
@@ -57,10 +60,6 @@ compounds:
57
60
  unc: [f4, '1', '\u03c3($S - S_{ref}$)']
58
61
  dark_offs: [f4, '1', dark-offset]
59
62
 
60
- geo_dtype:
61
- lat: [f4, latitude]
62
- lon: [f4, longitude]
63
-
64
63
  # Define variables
65
64
  variables:
66
65
  /group_00/detector_images:
@@ -84,7 +83,6 @@ variables:
84
83
  valid_max: 65534
85
84
  /group_01/stats:
86
85
  _dtype: stats_dtype
87
- _vlen: True
88
86
  _dims: [time]
89
87
  comment: detector map statistics
90
88
  /group_02/detector_images:
@@ -23,7 +23,43 @@ import numpy as np
23
23
  from h5yaml.conf_from_yaml import conf_from_yaml
24
24
  from h5yaml.lib.chunksizes import guess_chunks
25
25
 
26
+
26
27
  # - helper function ------------------------------------
28
+ def adjust_attr(attr_key: str, attr_val: np.ndarray, attr_dtype: str) -> np.ndarray:
29
+ """..."""
30
+ if attr_key in ("valid_min", "valid_max", "valid_range"):
31
+ match attr_dtype:
32
+ case "i1":
33
+ res = np.int8(attr_val)
34
+ case "i2":
35
+ res = np.int16(attr_val)
36
+ case "i4":
37
+ res = np.int32(attr_val)
38
+ case "i8":
39
+ res = np.int64(attr_val)
40
+ case "u1":
41
+ res = np.uint8(attr_val)
42
+ case "u2":
43
+ res = np.uint16(attr_val)
44
+ case "u4":
45
+ res = np.uint32(attr_val)
46
+ case "u8":
47
+ res = np.uint64(attr_val)
48
+ case "f2":
49
+ res = np.float16(attr_val)
50
+ case "f4":
51
+ res = np.float32(attr_val)
52
+ case "f8":
53
+ res = np.float64(attr_val)
54
+ case _:
55
+ res = attr_val
56
+
57
+ return res
58
+
59
+ if attr_key == "flag_values":
60
+ return np.array(attr_val, dtype="u1")
61
+
62
+ return attr_val
27
63
 
28
64
 
29
65
  # - class definition -----------------------------------
@@ -82,6 +118,8 @@ class H5Yaml:
82
118
  )
83
119
  if "_values" in val:
84
120
  dset[:] = val["_values"]
121
+ elif "_range" in val:
122
+ dset[:] = np.arange(*val["_range"], dtype=val["_dtype"])
85
123
 
86
124
  dset.make_scale(
87
125
  Path(key).name
@@ -89,36 +127,8 @@ class H5Yaml:
89
127
  else "This is a netCDF dimension but not a netCDF variable."
90
128
  )
91
129
  for attr, attr_val in val.items():
92
- if attr.startswith("_"):
93
- continue
94
- if attr in ("valid_min", "valid_max"):
95
- match val["_dtype"]:
96
- case "i1":
97
- dset.attrs[attr] = np.int8(attr_val)
98
- case "i2":
99
- dset.attrs[attr] = np.int16(attr_val)
100
- case "i4":
101
- dset.attrs[attr] = np.int32(attr_val)
102
- case "i8":
103
- dset.attrs[attr] = np.int64(attr_val)
104
- case "u1":
105
- dset.attrs[attr] = np.uint8(attr_val)
106
- case "u2":
107
- dset.attrs[attr] = np.uint16(attr_val)
108
- case "u4":
109
- dset.attrs[attr] = np.uint32(attr_val)
110
- case "u8":
111
- dset.attrs[attr] = np.uint64(attr_val)
112
- case "f2":
113
- dset.attrs[attr] = np.float16(attr_val)
114
- case "f4":
115
- dset.attrs[attr] = np.float32(attr_val)
116
- case "f8":
117
- dset.attrs[attr] = np.float64(attr_val)
118
- case _:
119
- dset.attrs[attr] = attr_val
120
- else:
121
- dset.attrs[attr] = attr_val
130
+ if not attr.startswith("_"):
131
+ dset.attrs[attr] = adjust_attr(attr, attr_val, val["_dtype"])
122
132
 
123
133
  def __compounds(self: H5Yaml, fid: h5py.File) -> dict[str, str | int | float]:
124
134
  """Add compound datatypes to HDF5 product."""
@@ -192,9 +202,8 @@ class H5Yaml:
192
202
  fillvalue=fillvalue,
193
203
  )
194
204
  for attr, attr_val in val.items():
195
- if attr.startswith("_"):
196
- continue
197
- dset.attrs[attr] = attr_val
205
+ if not attr.startswith("_"):
206
+ dset.attrs[attr] = adjust_attr(attr, attr_val, val["_dtype"])
198
207
  continue
199
208
 
200
209
  n_udim = 0
@@ -236,7 +245,14 @@ class H5Yaml:
236
245
  shuffle = True
237
246
 
238
247
  if val.get("_vlen"):
239
- ds_dtype = h5py.vlen_dtype(ds_dtype)
248
+ ds_name = (
249
+ val["_dtype"].split("_")[0]
250
+ if "_" in val["_dtype"]
251
+ else val["_dtype"]
252
+ ) + "_vlen"
253
+ if ds_name not in fid:
254
+ fid[ds_name] = h5py.vlen_dtype(ds_dtype)
255
+ ds_dtype = fid[ds_name]
240
256
  fillvalue = None
241
257
  if ds_maxshape == (None,):
242
258
  ds_chunk = (16,)
@@ -256,38 +272,8 @@ class H5Yaml:
256
272
  dset.dims[ii].attach_scale(fid[coord])
257
273
 
258
274
  for attr, attr_val in val.items():
259
- if attr.startswith("_"):
260
- continue
261
- if attr in ("valid_min", "valid_max"):
262
- match val["_dtype"]:
263
- case "i1":
264
- dset.attrs[attr] = np.int8(attr_val)
265
- case "i2":
266
- dset.attrs[attr] = np.int16(attr_val)
267
- case "i4":
268
- dset.attrs[attr] = np.int32(attr_val)
269
- case "i8":
270
- dset.attrs[attr] = np.int64(attr_val)
271
- case "u1":
272
- dset.attrs[attr] = np.uint8(attr_val)
273
- case "u2":
274
- dset.attrs[attr] = np.uint16(attr_val)
275
- case "u4":
276
- dset.attrs[attr] = np.uint32(attr_val)
277
- case "u8":
278
- dset.attrs[attr] = np.uint64(attr_val)
279
- case "f2":
280
- dset.attrs[attr] = np.float16(attr_val)
281
- case "f4":
282
- dset.attrs[attr] = np.float32(attr_val)
283
- case "f8":
284
- dset.attrs[attr] = np.float64(attr_val)
285
- case _:
286
- dset.attrs[attr] = attr_val
287
- elif attr == "flag_values":
288
- dset.attrs[attr] = np.array(attr_val, dtype="u1")
289
- else:
290
- dset.attrs[attr] = attr_val
275
+ if not attr.startswith("_"):
276
+ dset.attrs[attr] = adjust_attr(attr, attr_val, val["_dtype"])
291
277
 
292
278
  if compounds is not None and val["_dtype"] in compounds:
293
279
  if compounds[val["_dtype"]]["units"]:
@@ -311,7 +297,8 @@ class H5Yaml:
311
297
  """
312
298
  try:
313
299
  with h5py.File(l1a_name, "w") as fid:
314
- self.__groups(fid)
300
+ if "groups" in self.h5_def:
301
+ self.__groups(fid)
315
302
  self.__dimensions(fid)
316
303
  self.__variables(fid, self.__compounds(fid))
317
304
  except PermissionError as exc:
@@ -258,7 +258,7 @@ class NcYaml:
258
258
  def tests() -> None:
259
259
  """..."""
260
260
  print("Calling NcYaml")
261
- NcYaml(files("h5yaml.Data") / "h5_testing.yaml").create("test_yaml.nc")
261
+ NcYaml(files("h5yaml.Data") / "nc_testing.yaml").create("test_yaml.nc")
262
262
 
263
263
 
264
264
  if __name__ == "__main__":
File without changes
File without changes
File without changes