6
6
import os
7
7
import zserio
8
8
import yaml
9
+ import zlib
10
+ import zstandard
11
+ import lz4 .frame
12
+ import brotli
13
+ from enum import Enum
9
14
10
15
# Cache to store loaded YAML/JSON files
11
16
_file_cache = {}
12
17
18
+ class CompressionType (Enum ):
19
+ NO_COMPRESSION = 0
20
+ ZLIB = 1
21
+ ZSTD = 2
22
+ LZ4 = 3
23
+ BROTLI = 4
24
+
25
+ @classmethod
26
+ def from_string (cls , value : str ):
27
+ """Convert string representation to enum value, case-insensitive"""
28
+ try :
29
+ return cls [value .upper ()]
30
+ except KeyError :
31
+ raise ValueError (f"Unknown compression type: { value } . Valid values are: { ', ' .join (cls .__members__ .keys ())} " )
32
+
13
33
def insert_yaml_as_extern (transformer , file , template_args = None ):
14
34
"""
15
35
Include external YAML by transforming it to JSON and using zserio.
@@ -121,34 +141,53 @@ def repeat_node(transformer, node, count):
121
141
return [copy .deepcopy (node ) for _ in range (count )]
122
142
123
143
124
- def extract_extern_as_yaml (transformer , buffer , bitSize , schema_module , schema_type , file_name ):
144
+ def extract_extern_as_yaml (transformer , buffer , bitSize , schema_module , schema_type , file_name , compression_type = 0 , remove_nulls = False ):
125
145
"""
126
146
Extract binary data and save as an external YAML file.
127
147
128
- Note: This function contains some redundancy with the bin_to_yaml function
129
- in zs_yaml.convert to avoid circular imports. If modifying this function,
130
- please consider updating bin_to_yaml as well, and vice versa.
131
-
132
148
Args:
133
149
transformer (YamlTransformer): The transformer instance.
134
150
buffer (bytes): The binary data to be extracted.
135
151
bitSize (int): The size of the binary data in bits.
136
152
schema_module (str): The name of the schema module.
137
153
schema_type (str): The name of the schema type.
138
154
file_name (str): The name of the file to save the extracted data.
155
+ compression_type (Union[CompressionType, str, int, None]): Type of compression used.
156
+ Can be a CompressionType enum, string (e.g., 'zstd'), or integer value.
157
+ Defaults to None (no compression).
158
+ remove_nulls (bool): Whether the extracted yaml should also contain fields with null values or not.
139
159
140
160
Returns:
141
161
dict: A reference to the extracted file.
142
162
"""
163
+ # Convert compression_type to enum if needed
164
+ if compression_type is not None :
165
+ if isinstance (compression_type , str ):
166
+ compression_type = CompressionType .from_string (compression_type )
167
+ elif isinstance (compression_type , int ):
168
+ compression_type = CompressionType (compression_type )
169
+ elif not isinstance (compression_type , CompressionType ):
170
+ raise ValueError ("compression_type must be a CompressionType enum, string, or integer value" )
171
+
143
172
# Ensure the output directory exists
144
173
output_dir = os .path .dirname (transformer .yaml_file_path )
145
174
os .makedirs (output_dir , exist_ok = True )
146
175
147
176
# Generate the full path for the new file
148
177
yaml_file_path = os .path .join (output_dir , file_name )
149
178
150
- # Extract binary data
179
+ # Extract and decompress binary data if needed
151
180
buffer = bytes (buffer )
181
+ if compression_type is not None :
182
+ if compression_type == CompressionType .ZLIB :
183
+ buffer = zlib .decompress (buffer )
184
+ elif compression_type == CompressionType .ZSTD :
185
+ dctx = zstandard .ZstdDecompressor ()
186
+ buffer = dctx .decompress (buffer )
187
+ elif compression_type == CompressionType .LZ4 :
188
+ buffer = lz4 .frame .decompress (buffer )
189
+ elif compression_type == CompressionType .BROTLI :
190
+ buffer = brotli .decompress (buffer )
152
191
153
192
# Import the module and get the type
154
193
module = importlib .import_module (schema_module )
@@ -169,7 +208,18 @@ def extract_extern_as_yaml(transformer, buffer, bitSize, schema_module, schema_t
169
208
** json_data
170
209
}
171
210
172
- # Save the extracted data to the new file
211
+ # Clean the data if remove_nulls is True
212
+ if remove_nulls :
213
+ def rm_nulls (data ):
214
+ """Remove null values from a dictionary recursively."""
215
+ if isinstance (data , dict ):
216
+ return {k : rm_nulls (v ) for k , v in data .items () if v is not None }
217
+ elif isinstance (data , list ):
218
+ return [rm_nulls (item ) for item in data if item is not None ]
219
+ return data
220
+
221
+ data_to_write = rm_nulls (data_to_write )
222
+
173
223
with open (yaml_file_path , 'w' ) as f :
174
224
yaml .dump (data_to_write , f , default_flow_style = False , sort_keys = False )
175
225
0 commit comments