-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
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
mesa/mesa/visualization/solara_viz.py
Line 188 in 1d98560
original_model.set(copy.deepcopy(model.value)) |
mesa/mesa/visualization/solara_viz.py
Line 212 in 1d98560
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?