Skip to content

Commit 02ad833

Browse files
committed
Fix setting Model.module
Ensure `Model.module` gets set during `Model.clone()`. So far, this was only set during `model_module.get_model`. Fixes unpickling of cloned Models. Also implement `ModelPtr.__reduce__` in addition to `Model.__reduce__` (#2985).
1 parent 901c851 commit 02ad833

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ See also our [versioning policy](https://amici.readthedocs.io/en/latest/versioni
6464
This is a wrapper for both `amici.run_simulation` and
6565
`amici.run_simulations`, depending on the type of the `edata` argument.
6666
It also supports passing some `Solver` options as keyword arguments.
67-
* Improved `pickle` support for `amici.{ModelPtr,Solver,ExpData`.
67+
* Improved `pickle` support for `amici.{Model,ModelPtr,Solver,ExpData`.
6868
Note that AMICI's pickling support is only intended for short-term storage
6969
or inter-process communication.
7070
Reading pickled objects after updating AMICI or the model code will almost
7171
certainly fail.
72-
* `amici.ModelPtr` now supports sufficient pickling for use in
73-
multi-processing contexts. This works only if the amici-generated model
72+
* `amici.Model`and `amici.ModelPtr` now support sufficient pickling for use
73+
in multi-processing contexts. This works only if the amici-generated model
7474
package exists in the same file system location and does not change until
7575
unpickling.
7676
* `amici.Solver` is now picklable if amici was built with HDF5 support.

python/tests/test_swig_interface.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,10 @@ def test_pickle_model(sbml_example_presimulation_module):
698698
!= model_pickled.get_steady_state_sensitivity_mode()
699699
)
700700

701+
# ensure we can pickle after clone()
702+
model_clone = model.clone()
703+
pickle.loads(pickle.dumps(model_clone))
704+
701705

702706
def test_pickle_edata():
703707
ny = 2

swig/model.i

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,38 @@ using namespace amici;
108108
%newobject amici::Model::clone;
109109

110110
%rename(create_solver) amici::Model::get_solver;
111+
%rename(_cpp_model_clone) amici::Model::clone;
111112

112113
%extend amici::Model {
113114
%pythoncode %{
115+
def clone(self):
116+
"""Clone the model instance."""
117+
clone = self._cpp_model_clone()
118+
try:
119+
# copy module reference if present
120+
clone.module = self.module
121+
except Exception:
122+
pass
123+
124+
return clone
125+
114126
def __deepcopy__(self, memo):
115127
return self.clone()
116128

129+
def __reduce__(self):
130+
from amici.swig_wrappers import restore_model, get_model_settings, file_checksum
131+
132+
return (
133+
restore_model,
134+
(
135+
self.get_name(),
136+
Path(self.module.__spec__.origin).parent,
137+
get_model_settings(self),
138+
file_checksum(self.module.extension_path),
139+
),
140+
{}
141+
)
142+
117143
@overload
118144
def simulate(
119145
self: AmiciModel,
@@ -192,6 +218,17 @@ def simulate(
192218

193219
%extend std::unique_ptr<amici::Model> {
194220
%pythoncode %{
221+
def clone(self):
222+
"""Clone the model instance."""
223+
clone = self._cpp_model_clone()
224+
try:
225+
# copy module reference if present
226+
clone.module = self.module
227+
except Exception:
228+
pass
229+
230+
return clone
231+
195232
def __deepcopy__(self, memo):
196233
return self.clone()
197234

0 commit comments

Comments
 (0)