Skip to content

unable to start solara app when model cannot be pickled #2427

@wang-boyu

Description

@wang-boyu

Describe the bug

When a model or agents have attributes that cannot be pickled, Solara app won't start due to

TypeError: cannot pickle '_thread.lock' object

Expected behavior

Should be able to run model with Solara regardless it can be deep copied or not

To Reproduce

Take the Schelling model as an example, add the following into the __init__() method in model.py:

import threading
self.t = threading.Thread(target=print, args=("Hello"))
self.t.start()

Then run solara run app.py in the command line.

Additional context

It appears to be related to

original_model.set(copy.deepcopy(model.value))
and
model.value = copy.deepcopy(original_model.value)

where we try to create deep copies of the model object.

If we remove all usages related to deepcopy:

diff --git a/mesa/visualization/solara_viz.py b/mesa/visualization/solara_viz.py
index 4bca98d..c2d4960 100644
--- a/mesa/visualization/solara_viz.py
+++ b/mesa/visualization/solara_viz.py
@@ -183,14 +183,6 @@ def ModelController(model: solara.Reactive[Model], play_interval=100):
     running = solara.use_reactive(True)
     original_model = solara.use_reactive(None)
 
-    def save_initial_model():
-        """Save the initial model for comparison."""
-        original_model.set(copy.deepcopy(model.value))
-        playing.value = False
-        force_update()
-
-    solara.use_effect(save_initial_model, [model.value])
-
     async def step():
         while playing.value and running.value:
             await asyncio.sleep(play_interval / 1000)
@@ -205,18 +197,11 @@ def ModelController(model: solara.Reactive[Model], play_interval=100):
         model.value.step()
         running.value = model.value.running
 
-    def do_reset():
-        """Reset the model to its initial state."""
-        playing.value = False
-        running.value = True
-        model.value = copy.deepcopy(original_model.value)
-
     def do_play_pause():
         """Toggle play/pause."""
         playing.value = not playing.value
 
     with solara.Row(justify="space-between"):
-        solara.Button(label="Reset", color="primary", on_click=do_reset)
         solara.Button(
             label="▶" if not playing.value else "❚❚",
             color="primary",

Then the Solara app runs but without the Reset button.

Probably need a better way to create or save the initial model object?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugRelease notes label

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions