h5pack 1.1.0__py3-none-any.whl
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.
- h5pack/.DS_Store +0 -0
- h5pack/__init__.py +0 -0
- h5pack/cli/__init__.py +0 -0
- h5pack/cli/checksum.py +126 -0
- h5pack/cli/info.py +83 -0
- h5pack/cli/main.py +234 -0
- h5pack/cli/pack.py +408 -0
- h5pack/cli/unpack.py +123 -0
- h5pack/cli/utils.py +230 -0
- h5pack/cli/virtual.py +127 -0
- h5pack/core/.DS_Store +0 -0
- h5pack/core/__init__.py +0 -0
- h5pack/core/config.py +98 -0
- h5pack/core/display.py +130 -0
- h5pack/core/exceptions.py +18 -0
- h5pack/core/guards.py +122 -0
- h5pack/core/io.py +211 -0
- h5pack/core/utils.py +308 -0
- h5pack/data/__init__.py +133 -0
- h5pack/data/extractors.py +498 -0
- h5pack/data/parsers.py +531 -0
- h5pack/data/validators.py +182 -0
- h5pack-1.1.0.dist-info/METADATA +495 -0
- h5pack-1.1.0.dist-info/RECORD +26 -0
- h5pack-1.1.0.dist-info/WHEEL +4 -0
- h5pack-1.1.0.dist-info/entry_points.txt +3 -0
h5pack/.DS_Store
ADDED
|
Binary file
|
h5pack/__init__.py
ADDED
|
File without changes
|
h5pack/cli/__init__.py
ADDED
|
File without changes
|
h5pack/cli/checksum.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from time import perf_counter
|
|
3
|
+
from argparse import Namespace
|
|
4
|
+
from ..core.io import (
|
|
5
|
+
add_extension,
|
|
6
|
+
get_dir_files
|
|
7
|
+
)
|
|
8
|
+
from ..core.guards import is_file_with_ext
|
|
9
|
+
from ..core.display import (
|
|
10
|
+
exit_error,
|
|
11
|
+
exit_warning,
|
|
12
|
+
print_warning,
|
|
13
|
+
print_error,
|
|
14
|
+
)
|
|
15
|
+
from ..core.utils import (
|
|
16
|
+
get_file_checksum,
|
|
17
|
+
time_to_str
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def cmd_checksum(args: Namespace) -> None:
|
|
22
|
+
"""Calculates or verifies checksums associated with `.h5` files.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
args (Namespace): User input arguments provided through the console.
|
|
26
|
+
"""
|
|
27
|
+
# Check input type
|
|
28
|
+
if is_file_with_ext(file=args.input, ext=".sha256"): # Verify
|
|
29
|
+
if args.save:
|
|
30
|
+
print_warning("--save ignored for .sha256 input")
|
|
31
|
+
|
|
32
|
+
# Read lines and check they contain only two elements
|
|
33
|
+
root_dir = os.path.dirname(args.input)
|
|
34
|
+
print(f"Using root folder '{os.path.abspath(root_dir)}'")
|
|
35
|
+
print(f"Verifying checksum in '{args.input}' ...")
|
|
36
|
+
|
|
37
|
+
start_time = perf_counter()
|
|
38
|
+
|
|
39
|
+
with open(args.input, "r") as f:
|
|
40
|
+
for line_idx, line in enumerate(f):
|
|
41
|
+
h5_filename, saved_checksum = line.split("\t")
|
|
42
|
+
h5_file = os.path.join(root_dir, h5_filename)
|
|
43
|
+
saved_checksum = saved_checksum.rstrip("\n")
|
|
44
|
+
|
|
45
|
+
if not is_file_with_ext(h5_file, ext=".h5"):
|
|
46
|
+
exit_error(
|
|
47
|
+
f"Invalid file '{h5_file}' reference in '{args.input}'"
|
|
48
|
+
f" (line {line_idx + 1})"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
checksum = get_file_checksum(h5_file, hash="sha256")
|
|
52
|
+
|
|
53
|
+
if saved_checksum == checksum:
|
|
54
|
+
print(
|
|
55
|
+
f"{h5_filename}\t{saved_checksum} [OK]"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
else:
|
|
59
|
+
print_error(
|
|
60
|
+
f"{h5_filename} [MISMATCH]"
|
|
61
|
+
f"\n - Saved: {saved_checksum}"
|
|
62
|
+
f"\n - Calculated: {checksum}"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
end_time = perf_counter()
|
|
66
|
+
elapsed_time_repr = time_to_str(end_time - start_time, abbrev=False)
|
|
67
|
+
print(f"Checksum verification completed in {elapsed_time_repr}")
|
|
68
|
+
|
|
69
|
+
else: # Calculate
|
|
70
|
+
if is_file_with_ext(args.input, ext=".h5"):
|
|
71
|
+
all_files = [args.input]
|
|
72
|
+
|
|
73
|
+
elif os.path.isdir(args.input):
|
|
74
|
+
all_files = get_dir_files(
|
|
75
|
+
args.input,
|
|
76
|
+
ext=".h5",
|
|
77
|
+
recursive=args.recursive
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
else:
|
|
81
|
+
exit_error(
|
|
82
|
+
"Input must be an .h5 file or a folder containing .h5 files"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if len(all_files) == 0:
|
|
86
|
+
if not args.recursive:
|
|
87
|
+
exit_warning(
|
|
88
|
+
f"0 .h5 files found in in '{args.input}'. Use "
|
|
89
|
+
"--recursive/-r if you intended to perform a recursive "
|
|
90
|
+
"search"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
else:
|
|
94
|
+
exit_warning(f"0 .h5 files found in '{args.input}'")
|
|
95
|
+
|
|
96
|
+
print(f"Calculating checksum for .h5 files in '{args.input}' ...")
|
|
97
|
+
|
|
98
|
+
if args.save:
|
|
99
|
+
checksum_file = add_extension(args.save, ext=".sha256")
|
|
100
|
+
|
|
101
|
+
with open(add_extension(args.save, ext=".sha256"), "w") as f:
|
|
102
|
+
start_time = perf_counter()
|
|
103
|
+
|
|
104
|
+
for file in all_files:
|
|
105
|
+
checksum = get_file_checksum(file, hash="sha256")
|
|
106
|
+
checksum_repr = f"{os.path.basename(file)}\t{checksum}"
|
|
107
|
+
f.write(f"{checksum_repr}\n")
|
|
108
|
+
print(checksum_repr)
|
|
109
|
+
|
|
110
|
+
end_time = perf_counter()
|
|
111
|
+
elapsed_time_repr = time_to_str(end_time - start_time)
|
|
112
|
+
print(
|
|
113
|
+
f"Checksum calculation completed in {elapsed_time_repr} "
|
|
114
|
+
f"and saved to '{checksum_file}'"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
else:
|
|
118
|
+
start_time = perf_counter()
|
|
119
|
+
|
|
120
|
+
for file in all_files:
|
|
121
|
+
checksum = get_file_checksum(file, hash="sha256")
|
|
122
|
+
print(f"{os.path.basename(file)}\t{checksum}")
|
|
123
|
+
|
|
124
|
+
end_time = perf_counter()
|
|
125
|
+
elapsed_time_repr = time_to_str(end_time - start_time)
|
|
126
|
+
print(f"Checksum calculation completed in {elapsed_time_repr}")
|
h5pack/cli/info.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import h5py
|
|
3
|
+
from argparse import Namespace
|
|
4
|
+
from ..core.guards import is_file_with_ext
|
|
5
|
+
from ..core.display import (
|
|
6
|
+
exit_error,
|
|
7
|
+
print_warning
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def cmd_info(args: Namespace) -> None:
|
|
12
|
+
"""Inspects a `.h5` file generated with `h5pack`.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
args (Namespace): Input user arguments provided through the console.
|
|
16
|
+
"""
|
|
17
|
+
# Check file exists
|
|
18
|
+
if not is_file_with_ext(args.input, ext=".h5"):
|
|
19
|
+
exit_error(f"Invalid input file '{args.input}'")
|
|
20
|
+
|
|
21
|
+
# Print info
|
|
22
|
+
print(f"Input file: '{args.input}'" )
|
|
23
|
+
|
|
24
|
+
with h5py.File(args.input, "r") as h5_file:
|
|
25
|
+
# Check if producer is h5pack, otherwise will not be correctly parsed
|
|
26
|
+
if not h5_file.attrs.get("producer", "").startswith("h5pack"):
|
|
27
|
+
exit_error(
|
|
28
|
+
"This file was not created using h5pack, so it may not be "
|
|
29
|
+
"formatted as expected and cannot be reliably parsed"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if len(h5_file.attrs) > 0:
|
|
33
|
+
print("File attribute(s):")
|
|
34
|
+
key_ljust = max([len(k) for k in h5_file.attrs]) + 6
|
|
35
|
+
|
|
36
|
+
for k, v in h5_file.attrs.items():
|
|
37
|
+
print(f" - {k}:".ljust(key_ljust) + f"{v}")
|
|
38
|
+
|
|
39
|
+
# Get data group level attributes
|
|
40
|
+
for data_group_name, data_group_data in h5_file.items():
|
|
41
|
+
print(f"Data group '{data_group_name}':")
|
|
42
|
+
|
|
43
|
+
if len(data_group_data.attrs) > 0:
|
|
44
|
+
key_ljust = max([len(k) for k in data_group_data.attrs]) + 6
|
|
45
|
+
|
|
46
|
+
print(f"'{data_group_name}' attribute(s):")
|
|
47
|
+
|
|
48
|
+
for k, v in data_group_data.items():
|
|
49
|
+
print(f" - {k}:".ljust(key_ljust) + f"{v}")
|
|
50
|
+
|
|
51
|
+
# Get dataset level info
|
|
52
|
+
for dataset_name, dataset_data in data_group_data.items():
|
|
53
|
+
if len(dataset_data.attrs) > 0:
|
|
54
|
+
key_ljust = max([len(k) for k in dataset_data.attrs]) + 8
|
|
55
|
+
print(f" - '{dataset_name}' attribute(s):")
|
|
56
|
+
|
|
57
|
+
for k, v in dataset_data.attrs.items():
|
|
58
|
+
print(f" - {k}:".ljust(key_ljust) + f"{v}")
|
|
59
|
+
|
|
60
|
+
print(f" - '{dataset_name}' data attribute(s):")
|
|
61
|
+
print(f" - shape: {dataset_data.shape}")
|
|
62
|
+
print(f" - dtype: {dataset_data.dtype}")
|
|
63
|
+
|
|
64
|
+
# If virtual, check paths are accesible and report broken paths
|
|
65
|
+
if h5_file.attrs.get("is_virtual") is not None:
|
|
66
|
+
print("Virtual dataset sources:")
|
|
67
|
+
|
|
68
|
+
for data_group_name, data_group_data in h5_file.items():
|
|
69
|
+
for dataset_name, dataset_data in data_group_data.items():
|
|
70
|
+
plist = dataset_data.id.get_create_plist()
|
|
71
|
+
|
|
72
|
+
print(f" - '{dataset_name}' source(s):")
|
|
73
|
+
|
|
74
|
+
for file_idx in range(plist.get_virtual_count()):
|
|
75
|
+
file = plist.get_virtual_filename(file_idx)
|
|
76
|
+
|
|
77
|
+
if not os.path.isfile(file):
|
|
78
|
+
print_warning(
|
|
79
|
+
f" - {file_idx}: {file} [NOT FOUND]"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
print(f" - {file_idx}: {file} [OK]")
|
h5pack/cli/main.py
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import argparse
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
from .checksum import cmd_checksum
|
|
6
|
+
from .info import cmd_info
|
|
7
|
+
from .pack import cmd_pack
|
|
8
|
+
from .unpack import cmd_unpack
|
|
9
|
+
from .virtual import cmd_virtual
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_parser() -> argparse.ArgumentParser:
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
description="pack/unpack/inspect hierarchical data format datasets",
|
|
15
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
16
|
+
allow_abbrev=False
|
|
17
|
+
)
|
|
18
|
+
subparser = parser.add_subparsers(dest="action")
|
|
19
|
+
|
|
20
|
+
# Pack parser
|
|
21
|
+
pack_parser = subparser.add_parser(
|
|
22
|
+
"pack",
|
|
23
|
+
description="pack data into HDF5 dataset files",
|
|
24
|
+
help="pack data into HDF5 dataset files",
|
|
25
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
26
|
+
allow_abbrev=False
|
|
27
|
+
)
|
|
28
|
+
pack_parser.add_argument(
|
|
29
|
+
"-c", "--config",
|
|
30
|
+
type=str,
|
|
31
|
+
default="h5pack.yaml",
|
|
32
|
+
help=".yaml configuration file containing dataset specifications"
|
|
33
|
+
)
|
|
34
|
+
pack_parser.add_argument(
|
|
35
|
+
"-o", "--output",
|
|
36
|
+
type=str,
|
|
37
|
+
required=True,
|
|
38
|
+
help="output HDF5 partition file(s) with .h5 extension"
|
|
39
|
+
)
|
|
40
|
+
pack_partitions_parser = pack_parser.add_mutually_exclusive_group()
|
|
41
|
+
pack_partitions_parser.add_argument(
|
|
42
|
+
"-p", "--partitions",
|
|
43
|
+
type=int,
|
|
44
|
+
default=1,
|
|
45
|
+
help="number of partitions to create"
|
|
46
|
+
)
|
|
47
|
+
pack_parser.add_argument(
|
|
48
|
+
"-f", "--files-per-partition",
|
|
49
|
+
type=int,
|
|
50
|
+
help="number of files per partition"
|
|
51
|
+
)
|
|
52
|
+
pack_parser.add_argument(
|
|
53
|
+
"-d", "--dataset",
|
|
54
|
+
type=str,
|
|
55
|
+
required=True,
|
|
56
|
+
help="name of the dataset to generate"
|
|
57
|
+
)
|
|
58
|
+
pack_parser.add_argument(
|
|
59
|
+
"--create-virtual",
|
|
60
|
+
action="store_true",
|
|
61
|
+
help="create a virtual layout when two or more partitions are created"
|
|
62
|
+
)
|
|
63
|
+
pack_parser.add_argument(
|
|
64
|
+
"--skip-validation",
|
|
65
|
+
action="store_true",
|
|
66
|
+
help="skip validating files before generating the partition(s)"
|
|
67
|
+
)
|
|
68
|
+
pack_parser.add_argument(
|
|
69
|
+
"--skip-checksum",
|
|
70
|
+
action="store_true",
|
|
71
|
+
help="skip generating the checksum file"
|
|
72
|
+
)
|
|
73
|
+
pack_parser.add_argument(
|
|
74
|
+
"--overwrite",
|
|
75
|
+
action="store_true",
|
|
76
|
+
help="allow overwriting existing files"
|
|
77
|
+
)
|
|
78
|
+
pack_parser.add_argument(
|
|
79
|
+
"-w", "--workers",
|
|
80
|
+
type=int,
|
|
81
|
+
default=1,
|
|
82
|
+
help="number of workers (0 means 1 worker per core)"
|
|
83
|
+
)
|
|
84
|
+
pack_parser.add_argument(
|
|
85
|
+
"-u", "--unattended",
|
|
86
|
+
action="store_true",
|
|
87
|
+
help="unattended mode (no user prompts)"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Unpack parser
|
|
91
|
+
unpack_parser = subparser.add_parser(
|
|
92
|
+
"unpack",
|
|
93
|
+
description="unpack HDF5 datasets into individual files",
|
|
94
|
+
help="unpack HDF5 datasets datasets into individual files",
|
|
95
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
96
|
+
allow_abbrev=False
|
|
97
|
+
)
|
|
98
|
+
unpack_parser.add_argument(
|
|
99
|
+
"input",
|
|
100
|
+
help="input .h5 file"
|
|
101
|
+
)
|
|
102
|
+
unpack_parser.add_argument(
|
|
103
|
+
"-o", "--output",
|
|
104
|
+
type=str,
|
|
105
|
+
help="output folder"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Virtual parser
|
|
109
|
+
virtual_parser = subparser.add_parser(
|
|
110
|
+
"virtual",
|
|
111
|
+
description="create virtual HDF5 datasets",
|
|
112
|
+
help="create virtual HDF5 datasets",
|
|
113
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
114
|
+
allow_abbrev=False
|
|
115
|
+
)
|
|
116
|
+
virtual_parser.add_argument(
|
|
117
|
+
"input",
|
|
118
|
+
type=str,
|
|
119
|
+
nargs="+",
|
|
120
|
+
help="input .h5 file(s) or folder(s) containing .h5 file(s)"
|
|
121
|
+
)
|
|
122
|
+
virtual_parser.add_argument(
|
|
123
|
+
"-o", "--output",
|
|
124
|
+
type=str,
|
|
125
|
+
required=True,
|
|
126
|
+
help="output HDF5 file(s) with .h5 extension"
|
|
127
|
+
)
|
|
128
|
+
virtual_parser.add_argument(
|
|
129
|
+
"-r", "--recursive",
|
|
130
|
+
action="store_true",
|
|
131
|
+
help="search folders recursively"
|
|
132
|
+
)
|
|
133
|
+
virtual_parser.add_argument(
|
|
134
|
+
"-a", "--attrs",
|
|
135
|
+
type=str,
|
|
136
|
+
nargs="+",
|
|
137
|
+
metavar="KEY VALUE",
|
|
138
|
+
help="top level attributes to write as a list of 'key' 'value' pairs"
|
|
139
|
+
)
|
|
140
|
+
virtual_pattr_parser = virtual_parser.add_mutually_exclusive_group()
|
|
141
|
+
virtual_pattr_parser.add_argument(
|
|
142
|
+
"-s", "--select",
|
|
143
|
+
type=str,
|
|
144
|
+
metavar="PATTERN",
|
|
145
|
+
help="select pattern include matching elements from --input"
|
|
146
|
+
)
|
|
147
|
+
virtual_pattr_parser.add_argument(
|
|
148
|
+
"-f", "--filter",
|
|
149
|
+
type=str,
|
|
150
|
+
metavar="PATTERN",
|
|
151
|
+
help="filter pattern to remove matching elements from --input"
|
|
152
|
+
)
|
|
153
|
+
virtual_parser.add_argument(
|
|
154
|
+
"--force-abspath",
|
|
155
|
+
action="store_true",
|
|
156
|
+
help="force all embedded paths to be absolute paths"
|
|
157
|
+
)
|
|
158
|
+
virtual_parser.add_argument(
|
|
159
|
+
"-u", "--unattended",
|
|
160
|
+
action="store_true",
|
|
161
|
+
help="unattended mode (no user prompts)"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Info parser
|
|
165
|
+
info_parser = subparser.add_parser(
|
|
166
|
+
"info",
|
|
167
|
+
description="inspect HDF5 datasets",
|
|
168
|
+
help="inspect HDF5 datasets",
|
|
169
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
170
|
+
allow_abbrev=False
|
|
171
|
+
)
|
|
172
|
+
info_parser.add_argument(
|
|
173
|
+
"input",
|
|
174
|
+
help="input .h5 file"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Checksum parser
|
|
178
|
+
checksum_parser = subparser.add_parser(
|
|
179
|
+
"checksum",
|
|
180
|
+
help="create/verify virtual HDF5 datasets checksum",
|
|
181
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
182
|
+
allow_abbrev=False
|
|
183
|
+
)
|
|
184
|
+
checksum_parser.add_argument(
|
|
185
|
+
"input",
|
|
186
|
+
type=str,
|
|
187
|
+
help=".sha256 file (to verify) or file or folder (to calculate)"
|
|
188
|
+
)
|
|
189
|
+
checksum_parser.add_argument(
|
|
190
|
+
"--save",
|
|
191
|
+
type=str,
|
|
192
|
+
help="save calculated checksum to a .sha256 file"
|
|
193
|
+
)
|
|
194
|
+
checksum_parser.add_argument(
|
|
195
|
+
"-r", "--recursive",
|
|
196
|
+
action="store_true",
|
|
197
|
+
help="search folders recursively if input is a folder"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return parser
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def main() -> int:
|
|
204
|
+
if (
|
|
205
|
+
len(sys.argv) == 1
|
|
206
|
+
or (len(sys.argv) == 2 and sys.argv[1] in ("--version"))
|
|
207
|
+
):
|
|
208
|
+
print(
|
|
209
|
+
f"h5pack version {version('h5pack')} 2024-{datetime.now().year} "
|
|
210
|
+
"developed by Esteban Gómez (Speech Interaction Technology, Aalto "
|
|
211
|
+
"University)"
|
|
212
|
+
)
|
|
213
|
+
sys.exit(0)
|
|
214
|
+
|
|
215
|
+
parser = get_parser()
|
|
216
|
+
args = parser.parse_args()
|
|
217
|
+
|
|
218
|
+
if args.action == "pack":
|
|
219
|
+
cmd_pack(args)
|
|
220
|
+
|
|
221
|
+
elif args.action == "virtual":
|
|
222
|
+
cmd_virtual(args)
|
|
223
|
+
|
|
224
|
+
elif args.action == "checksum":
|
|
225
|
+
cmd_checksum(args)
|
|
226
|
+
|
|
227
|
+
elif args.action == "info":
|
|
228
|
+
cmd_info(args)
|
|
229
|
+
|
|
230
|
+
elif args.action == "unpack":
|
|
231
|
+
cmd_unpack(args)
|
|
232
|
+
|
|
233
|
+
else:
|
|
234
|
+
raise AssertionError
|