From d057aeeb118a51b17d52b32698651998e220fd56 Mon Sep 17 00:00:00 2001 From: Amin Sadeghi Date: Sun, 26 Apr 2026 15:10:44 -0700 Subject: [PATCH] fix: route `param.*` keys from porespy dicts into network params `network.update(net)` bypasses `Network.__setitem__`, so any `param.*` entries in the porespy dict landed as raw items instead of being routed into `_params`. That broke project save/load round-trips. Pop them out first and assign individually so they go through the proper code path. --- src/openpnm/io/_porespy.py | 7 ++++++- tests/unit/io/PoreSpyTest.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/openpnm/io/_porespy.py b/src/openpnm/io/_porespy.py index 5ddc40a317..f4f341f8d3 100644 --- a/src/openpnm/io/_porespy.py +++ b/src/openpnm/io/_porespy.py @@ -22,13 +22,18 @@ def network_from_porespy(filename): """ # Parse the filename if isinstance(filename, dict): - net = filename + net = dict(filename) else: filename = _parse_filename(filename=filename) with open(filename, mode='rb') as f: net = pk.load(f) + # Pop param.* entries so they're routed via __setitem__ into _params + # rather than landing as raw dict items via update(). + params = {k: net.pop(k) for k in list(net) if k.startswith('param.')} network = Network() network.update(net) + for key, value in params.items(): + network[key] = value return network diff --git a/tests/unit/io/PoreSpyTest.py b/tests/unit/io/PoreSpyTest.py index cf481b9f3c..8c46b73d87 100644 --- a/tests/unit/io/PoreSpyTest.py +++ b/tests/unit/io/PoreSpyTest.py @@ -23,6 +23,26 @@ def test_load_PoreSpy_from_file(self): assert net.Np == 1637 assert net.Nt == 2785 + def test_param_keys_are_routed_to_params(self): + net_with_params = dict(self.net) + net_with_params['param.voxel_size'] = 1.5e-6 + net_with_params['param.ndim'] = 3 + proj = op.io.network_from_porespy(net_with_params) + net = proj.network + assert net['param.voxel_size'] == 1.5e-6 + assert net['param.ndim'] == 3 + # Ensure they survive a project save/load round-trip + import tempfile + with tempfile.TemporaryDirectory() as tmp: + fname = os.path.join(tmp, 'proj') + op.Workspace().save_project(project=net.project, filename=fname) + ws = op.Workspace() + ws.clear() + ws.load_project(filename=fname + '.pnm') + loaded = list(ws.values())[0][0] + assert loaded['param.voxel_size'] == 1.5e-6 + assert loaded['param.ndim'] == 3 + if __name__ == '__main__': # All the tests in this file can be run with 'playing' this file