Skip to content

Commit 38893d2

Browse files
committed
[WIP] Changing how we save files
1 parent 08e510d commit 38893d2

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

gempy/modules/serialization/save_load.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from ...optional_dependencies import require_zlib
88
import pathlib
99
import os
10+
import io
11+
import zipfile
1012

1113

1214
def save_model(model: GeoModel, path: str | None = None, validate_serialization: bool = True):
@@ -44,10 +46,10 @@ def save_model(model: GeoModel, path: str | None = None, validate_serialization:
4446
# If no extension, add the valid extension
4547
path = str(path_obj) + VALID_EXTENSION
4648

47-
binary_file = model_to_binary(model)
49+
binary_file = model_to_bytes(model)
4850

4951
if validate_serialization:
50-
model_deserialized = _deserialize_binary_file(binary_file)
52+
model_deserialized = _load_model_from_bytes(binary_file)
5153
_validate_serialization(model, model_deserialized)
5254

5355
# Create directory if it doesn't exist
@@ -129,8 +131,62 @@ def load_model(path: str) -> GeoModel:
129131
with open(path, 'rb') as f:
130132
binary_file = f.read()
131133

132-
return _deserialize_binary_file(binary_file)
134+
return _load_model_from_bytes(binary_file)
133135

136+
def model_to_bytes(model: GeoModel) -> bytes:
137+
# 1) Make a fully deterministic JSON header
138+
# header_dict = model.model_dump(by_alias=True)
139+
# header_json = json.dumps(
140+
# header_dict,
141+
# sort_keys=True, # always sort object keys
142+
# separators=(",", ":"), # no extra whitespace
143+
# ).encode("utf-8")
144+
145+
header_json = model.model_dump_json(by_alias=True, indent=4)
146+
147+
# 2) Raw binary chunks (no additional zlib.compress here)
148+
input_raw = model.structural_frame.input_tables_binary
149+
grid_raw = model.grid.grid_binary
150+
151+
# 3) Pack into a ZIP archive in a fixed order:
152+
153+
buf = io.BytesIO()
154+
with zipfile.ZipFile(
155+
buf, mode="w",
156+
compression=zipfile.ZIP_DEFLATED,
157+
compresslevel=6
158+
) as zf:
159+
# Force a fixed timestamp (1980-01-01) so the file headers don't vary
160+
def make_info(name):
161+
zi = zipfile.ZipInfo(name, date_time=(1980,1,1,0,0,0))
162+
zi.external_attr = 0 # clear OS-specific file permissions
163+
return zi
164+
165+
zf.writestr(make_info("header.json"), header_json)
166+
zf.writestr(make_info("input.bin"), input_raw)
167+
zf.writestr(make_info("grid.bin"), grid_raw)
168+
169+
return buf.getvalue()
170+
171+
def _load_model_from_bytes(data: bytes) -> GeoModel:
172+
import json, zlib
173+
from ...core.data.encoders.converters import loading_model_from_binary
174+
175+
buf = io.BytesIO(data)
176+
with zipfile.ZipFile(buf, "r") as zf:
177+
header_json = zf.read("header.json").decode("utf-8")
178+
# header = json.loads(header_json)
179+
input_raw = zf.read("input.bin")
180+
grid_raw = zf.read("grid.bin")
181+
182+
# If you want to validate or decompress further, do it here…
183+
with loading_model_from_binary(
184+
input_binary=input_raw,
185+
grid_binary= grid_raw
186+
):
187+
model = GeoModel.model_validate_json(header_json)
188+
189+
return model
134190

135191
def _deserialize_binary_file(binary_file):
136192
import json

test/verify_helper.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
from approvaltests.reporters import GenericDiffReporter, GenericDiffReporterConfig
1212

1313
from gempy.core.data import GeoModel
14-
from gempy.modules.serialization.save_load import _to_binary, _deserialize_binary_file, model_to_binary
15-
from gempy.optional_dependencies import require_zlib
16-
14+
from gempy.modules.serialization.save_load import _load_model_from_bytes, model_to_bytes
1715

1816
class WSLWindowsDiffReporter(GenericDiffReporter):
1917
def get_command(self, received, approved):
@@ -120,7 +118,7 @@ def verify_model_serialization(model: GeoModel, verify_moment: Literal["before",
120118
Raises:
121119
ValueError: If `verify_moment` is not set to "before" or "after".
122120
"""
123-
binary_file = model_to_binary(model)
121+
binary_file = model_to_bytes(model)
124122

125123
original_model = model
126124
original_model.meta.creation_date = "<DATE_IGNORED>"
@@ -131,7 +129,7 @@ def verify_model_serialization(model: GeoModel, verify_moment: Literal["before",
131129
name=file_name
132130
)
133131
elif verify_moment == "after":
134-
model_deserialized = _deserialize_binary_file(binary_file)
132+
model_deserialized = _load_model_from_bytes(binary_file)
135133
model_deserialized.meta.creation_date = "<DATE_IGNORED>"
136134
verify_json(
137135
item=model_deserialized.model_dump_json(by_alias=True, indent=4),

0 commit comments

Comments
 (0)