diff --git a/.gitignore b/.gitignore index 9cba9c93ca2..21bb9083b00 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,6 @@ dmypy.json # JS dependencies mesa/visualization/templates/external/ mesa/visualization/templates/js/external/ +.venv312/ +.venv312/ +.venv312/ diff --git "a/_\357\201\274\357\201\274 true" "b/_\357\201\274\357\201\274 true" new file mode 100644 index 00000000000..1f0dff0a0f6 --- /dev/null +++ "b/_\357\201\274\357\201\274 true" @@ -0,0 +1,174 @@ +HISTORY.md:45:The major highlight of release 3.3.0 is the introduction of a new and improved visualization module. This effort was @Sahil-Chhoker's Google Summer of Code project . The new module is backwards compatible and continues to use Solara. It has several new and improved features to include: +HISTORY.md:122:The SolaraViz visualization system has received substantial upgrades: +HISTORY.md:126:- **Dark Mode** ([#2689](https://github.com/projectmesa/mesa/pull/2689)): Support for Solara Dark theme, automatically matching system preferences +HISTORY.md:129:- **PropertyLayer visualisation in Altair** ([#2643](https://github.com/projectmesa/mesa/pull/2643)): Support for visualising PropertyLayers using the Altair frontend in Solara. +HISTORY.md:292:Other improvements in this release include consistent visualization behavior across space types with the reimplementation of `draw_voronoi` [#2608](https://github.com/projectmesa/mesa/pull/2608), and a new render interval slider for controlling visualization update frequency in SolaraViz, which helps improve performance when working with complex visualizations [#2596](https://github.com/projectmesa/mesa/pull/2596). We've also fixed a bug affecting random number generation determinism when using `Model(seed=something)`, ensuring both `model.random` and `model.rng` now behave consistently when seeded with the same initial value [#2598](https://github.com/projectmesa/mesa/pull/2598). +HISTORY.md:367:Mesa now includes built-in support for logging using the standard Python `logging` module. This provides developers with a flexible and powerful way to add structured diagnostic and debug output to their simulations, without the need for custom logging solutions. The logging system is integrated throughout the library, including the new SolaraViz visualization system (#2506). +HISTORY.md:441:* Support simulators in SolaraViz by @quaquel in https://github.com/projectmesa/mesa/pull/2470 +HISTORY.md:482:### Modern Visualization with SolaraViz +HISTORY.md:483:Mesa 3.0's new experimental visualization system, SolaraViz, provides a modern, interactive interface for model exploration: +HISTORY.md:486:from mesa.visualization import SolaraViz, make_space_component, make_plot_component +HISTORY.md:488:visualization = SolaraViz( +HISTORY.md:508:*Note: SolaraViz is in active development. We might make API breaking changes between Mesa 3.0 and 3.1.* +HISTORY.md:576:- Old visualization system replaced by SolaraViz +HISTORY.md:602:We're still working very active on the visualisation, so we have marked that experimental for Mesa 3.0. We will stabilize SolaraViz in Mesa 3.1. +HISTORY.md:611:* Mark SolaraViz as experimental for Mesa 3.0 by @EwoutH in https://github.com/projectmesa/mesa/pull/2459 +HISTORY.md:710:* use GridDraggable instead of Column in SolaraViz by @wang-boyu in https://github.com/projectmesa/mesa/pull/2344 +HISTORY.md:715:* experimental init: Fix Solara import by making it lazy by @EwoutH in https://github.com/projectmesa/mesa/pull/2357 +HISTORY.md:797:Finally, SolaraViz received updates improving its interface and performance ([#2299](https://github.com/projectmesa/mesa/pull/2299), [#2304](https://github.com/projectmesa/mesa/pull/2304)). Cell connections in grids and networks are now public and named for more intuitive agent movements ([#2296](https://github.com/projectmesa/mesa/pull/2296)). The Model class initialization process was simplified by moving random seed and random object creation to `__init__` ([#1940](https://github.com/projectmesa/mesa/pull/1940)). Documentation has been extensively updated, including enforcing Google docstrings ([#2294](https://github.com/projectmesa/mesa/pull/2294)) and reorganizing the API documentation ([#2298](https://github.com/projectmesa/mesa/pull/2298)) for better clarity and navigation. +HISTORY.md:808:* SolaraViz Updates by @Corvince in https://github.com/projectmesa/mesa/pull/2299 +HISTORY.md:809:* Solara viz: use_task for non-threaded continuous play by @Corvince in https://github.com/projectmesa/mesa/pull/2304 +HISTORY.md:848: - The old SolaraViz API is still available at `mesa.experimental`, but might be removed in future releases. +HISTORY.md:860:* Implement new SolaraViz API by @Corvince in https://github.com/projectmesa/mesa/pull/2263 +HISTORY.md:863:* add default SolaraViz by @Corvince in https://github.com/projectmesa/mesa/pull/2280 +HISTORY.md:891:Furthermore, we improved the performance of accessing `Model.agents`, squashed a bug in SolaraViz, started testing on Python 3.13 and added a new benchmark model. +HISTORY.md:895:Finally, we have two brand new examples: An Ant Colony Optimization model using an Ant System approach to the Traveling Salesman problem, a Mesa NetworkGrid, and a custom visualisation with SolaraViz ([examples#157](https://github.com/projectmesa/mesa-examples/pull/157) by @zjost). The first example using the `PropertyLayer` was added, a very fast implementation of Conway's Game of Life ([examples#182](https://github.com/projectmesa/mesa-examples/pull/182)). +HISTORY.md:914:* SolaraViz: Reset components when params are changed by @rht in https://github.com/projectmesa/mesa/pull/2240 +HISTORY.md:931:In Mesa 3.0 alpha 2 (`v3.0.0a2`) we've done more clean-up in preparation for Mesa 3.0. We now [require](https://github.com/projectmesa/mesa/pull/2218) `super().__init__()` to run on initializing a Mesa model subclass, `Model.agents` is now fully reserved for the Model's internal AgentSet and we fixed a bug in our Solara space_drawer. +HISTORY.md:935:The new Solara visualisation now allows portraying agents in different shapes, checkout some examples in [#2214](https://github.com/projectmesa/mesa/pull/2214). +HISTORY.md:962:Mesa 3.0 alpha 1 (`v3.0.0a1`) is another step towards our next major version. This release introduces a name change from JupyterViz (jupyter_viz) to SolaraViz (solara_viz), to better represent the tech stack being used. It also includes two bugfixes also present in 2.3.2. +HISTORY.md:968:* Rename JupyterViz to SolaraViz by @rht in https://github.com/projectmesa/mesa/pull/2187 +HISTORY.md:988:- The old visualisation is removed, in favor of the new, Solara based, Jupyter Viz. This was already available in the 2.3.x release series, but is now stabilized. Checkout out our new [Visualization Tutorial](https://mesa.readthedocs.io/latest/tutorials/visualization_tutorial.html). More examples and a migration guide will follow later in the Mesa 3.0 development. +HISTORY.md:1072:* JupyterViz: {Convert make_plot & prepare ColorCard} to become Solara component by @rht in https://github.com/projectmesa/mesa/pull/2020 +HISTORY.md:1149:Mesa 2.2.3 is a small release with two improvements to the experimental Solara visualisation, on request of one of our contributors. No stable features have changed. +HISTORY.md:1194:* refactor: Move Matplotlib-specific Solara components to separate file by @rht in https://github.com/projectmesa/mesa/pull/1943 +HISTORY.md:1302:This release has some critical fixes to JupyterViz/Solara frontend to prevent +HISTORY.md:1322:**Solara/JupyterViz** +HISTORY.md:1325:- Convert make_space into Solara component (#1877) +HISTORY.md:1343:the JupyterViz/Solara frontend. It\'s a patch release instead of a minor +HISTORY.md:1366:**Solara/JupyterViz** +HISTORY.md:1368:- perf: increase speed of Solara render #1819 +HISTORY.md:1376:to the JupyterViz/Solara frontend. It\'s a patch release instead of a +HISTORY.md:1388:**Solara/JupyterViz** +HISTORY.md:1404:- Docker: Update to use Solara viz #1757 +HISTORY.md:1416:- fix: Allow multiple connections in Solara #1759 +HISTORY.md:1434: - Improve new/experimental Solara based visualization to ensure +docs/best-practices.md:13:- `app.py` should contain the Solara-based visualization code (optional). +docs/index.md:34:- Browser-based Solara visualization +docs/migration_guide.md:67:from mesa.visualization import SolaraViz, make_space_component +docs/migration_guide.md:69:SolaraViz(model, components=[make_space_component(agent_portrayal)]) +docs/migration_guide.md:72:from mesa.visualization import SolaraViz, SpaceRenderer +docs/migration_guide.md:79:SolaraViz( +docs/migration_guide.md:96:from mesa.visualization import SolaraViz, make_plot_component +docs/migration_guide.md:98:SolaraViz( +docs/migration_guide.md:354:Mesa has adopted a new API for our frontend. If you already migrated to the experimental new SolaraViz you can still use +docs/migration_guide.md:357:> **Note:** SolaraViz is experimental and still in active development for Mesa 3.0. While we attempt to minimize them, there might be API breaking changes between Mesa 3.0 and 3.1. There won't be breaking changes between Mesa 3.0.x patch releases. +docs/migration_guide.md:361:Previously SolaraViz was initialized by providing a `model_cls` and a `model_params`. This has changed to expect a model instance `model`. You can still provide (user-settable) `model_params`, but only if users should be able to change them. It is now also possible to pass in a "reactive model" by first calling `model = solara.reactive(model)`. This is useful for notebook environments. It allows you to pass the model to the SolaraViz Module, but continue to use the model. For example calling `model.value.step()` (notice the extra .value) will automatically update the plots. This currently only automatically works for the step method, you can force visualization updates by calling `model.value.force_update()`. +docs/migration_guide.md:365:With the introduction of SolaraViz in Mesa 3.0, models are now instantiated using `**model_parameters.value`. This means all inputs for initializing a new model must be keyword arguments. Ensure your model's `__init__` method accepts keyword arguments matching the keys in `model_params`. +docs/migration_guide.md:380:from mesa.experimental import SolaraViz +docs/migration_guide.md:382:SolaraViz(model_cls, model_params, agent_portrayal=agent_portrayal) +docs/migration_guide.md:385:from mesa.visualization import SolaraViz, make_space_component +docs/migration_guide.md:387:SolaraViz(model, components=[make_space_component(agent_portrayal)]) +docs/migration_guide.md:396:from mesa.experimental import SolaraViz +docs/migration_guide.md:403:SolaraViz(model_cls, model_params, measures=[make_plot, "foo", ["bar", "baz"]]) +docs/migration_guide.md:406:from mesa.visualization import SolaraViz, make_plot_component +docs/migration_guide.md:408:SolaraViz(model, components=[make_plot, make_plot_component("foo"), make_plot_component("bar", "baz")]) +docs/migration_guide.md:413:To plot model-dependent text the experimental SolaraViz provided a `make_text` function that wraps another functions that receives the model and turns its string return value into a solara text component. Again, this other function can now be passed directly to the new SolaraViz components array. It is okay if your function just returns a string. +docs/migration_guide.md:417:from mesa.experimental import SolaraViz, make_text +docs/migration_guide.md:422:SolaraViz(model_cls, model_params, measures=make_text(show_steps)) +docs/migration_guide.md:425:from mesa.visualisation import SolaraViz +docs/migration_guide.md:430:SolaraViz(model, components=[show_steps]) +docs/overview.md:250:Mesa now uses a new browser-based visualization system called SolaraViz. This allows for interactive, customizable visualizations of your models. +docs/overview.md:252:Note: SolaraViz is experimental and still in active development in Mesa 3.x. While we attempt to minimize them, there might be API breaking changes in minor releases. +docs/overview.md:253:> **Note:** SolaraViz instantiates new models using `**model_parameters.value`, so all model inputs must be keyword arguments. +docs/overview.md:268:from mesa.visualization import SolaraViz, make_space_component, make_plot_component +docs/overview.md:285:page = SolaraViz( +docs/tutorials/4_visualization_basic.ipynb:19: "Due to conflict with Colab and Solara there are no colab links for this tutorial\n", +docs/tutorials/4_visualization_basic.ipynb:63: "from mesa.visualization import SolaraViz, SpaceRenderer, make_plot_component\n", +docs/tutorials/4_visualization_basic.ipynb:182: "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." +docs/tutorials/4_visualization_basic.ipynb:257: "This is the Python object used to visualize the grid, agents, and property layers associated with the space and the model and is passed to the `SolaraViz`\n", +docs/tutorials/4_visualization_basic.ipynb:290: "In tutorial 8, you will learn how to create custom components for the Solara dashboard. If you want a custom component to appear on a specific page, you must pass it as a tuple containing the component and the page number.\n", +docs/tutorials/4_visualization_basic.ipynb:297: "page = SolaraViz(\n", +docs/tutorials/4_visualization_basic.ipynb:323: "page = SolaraViz(\n", +docs/tutorials/5_visualization_dynamic_agents.ipynb:19: "Due to conflict with Colab and Solara there are no colab links for this tutorial\n", +docs/tutorials/5_visualization_dynamic_agents.ipynb:63: "from mesa.visualization import SolaraViz, SpaceRenderer, make_plot_component\n", +docs/tutorials/5_visualization_dynamic_agents.ipynb:182: "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." +docs/tutorials/5_visualization_dynamic_agents.ipynb:284: "In tutorial 8, you will learn how to create custom components for the Solara dashboard. If you want a custom component to appear on a specific page, you must pass it as a tuple containing the component and the page number.\n", +docs/tutorials/5_visualization_dynamic_agents.ipynb:291: "page = SolaraViz(\n", +docs/tutorials/5_visualization_dynamic_agents.ipynb:316: "page = SolaraViz(\n", +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:19: "Due to conflict with Colab and Solara there are no colab links for this tutorial\n", +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:62: "from mesa.visualization import SolaraViz, SpaceRenderer, make_plot_component\n", +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:181: "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:268: "In tutorial 8, you will learn how to create custom components for the Solara dashboard. If you want a custom component to appear on a specific page, you must pass it as a tuple containing the component and the page number.\n", +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:275: "page = SolaraViz(\n", +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:494: "Now that we have the model, visual renderer, and plot components defined, we can bring everything together using `SolaraViz`:" +docs/tutorials/6_visualization_rendering_with_space_renderer.ipynb:503: "page = SolaraViz(\n", +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:19: "Due to conflict with Colab and Solara there are no colab links for this tutorial\n", +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:64: "from mesa.visualization import SolaraViz, SpaceRenderer, make_plot_component\n", +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:190: "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline." +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:277: "In the next tutorial, you will learn how to create custom components for the Solara dashboard. If you want a custom component to appear on a specific page, you must pass it as a tuple containing the component and the page number.\n", +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:284: "page = SolaraViz(\n", +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:458: "Now that we have the model, visual renderer, and plot components defined, we can bring everything together using `SolaraViz`:" +docs/tutorials/7_visualization_propertylayer_visualization.ipynb:467: "page = SolaraViz(\n", +docs/tutorials/8_visualization_custom.ipynb:19: "Due to conflict with Colab and Solara there are no colab links for this tutorial\n", +docs/tutorials/8_visualization_custom.ipynb:63: "from mesa.visualization import SolaraViz, make_plot_component, make_space_component" +docs/tutorials/8_visualization_custom.ipynb:181: "First, a quick explanation of how Mesa's interactive visualization works. The visualization is done in a browser window or Jupyter instance, using the [Solara](https://solara.dev/) framework, a pure Python, React-style web framework. Running `solara run app.py` will launch a web server, which runs the model, and displays model detail at each step via a plotting library. Alternatively, you can execute everything inside a Jupyter instance and display it inline.\n", +docs/tutorials/8_visualization_custom.ipynb:207: "In addition, due to the way Solara works we need to trigger an update whenever the underlying model changes. For this you need to register an update counter with every component." +docs/tutorials/8_visualization_custom.ipynb:284: "page = SolaraViz(\n", +docs/tutorials/8_visualization_custom.ipynb:347: "page = SolaraViz(\n", +mesa/examples/advanced/alliance_formation/Readme.md:42:- `app.py`: Contains the code for the interactive Solara visualization. +mesa/examples/advanced/alliance_formation/app.py:7:from mesa.visualization import SolaraViz +mesa/examples/advanced/alliance_formation/app.py:60:# Create the SolaraViz page. This will automatically create a server and display the +mesa/examples/advanced/alliance_formation/app.py:65:page = SolaraViz( +mesa/examples/advanced/epstein_civil_violence/app.py:9: SolaraViz, +mesa/examples/advanced/epstein_civil_violence/app.py:71:page = SolaraViz( +mesa/examples/advanced/pd_grid/app.py:2:Solara-based visualization for the Spatial Prisoner's Dilemma Model. +mesa/examples/advanced/pd_grid/app.py:8: SolaraViz, +mesa/examples/advanced/pd_grid/app.py:51:page = SolaraViz( +mesa/examples/advanced/sugarscape_g1mt/Readme.md:56:* `app.py`: Runs a visualization server via Solara (`solara run app.py`). +mesa/examples/advanced/sugarscape_g1mt/app.py:2:from mesa.visualization import Slider, SolaraViz, SpaceRenderer, make_plot_component +mesa/examples/advanced/sugarscape_g1mt/app.py:67:# on the Solara dashboard. +mesa/examples/advanced/sugarscape_g1mt/app.py:68:page = SolaraViz( +mesa/examples/advanced/wolf_sheep/app.py:7: SolaraViz, +mesa/examples/advanced/wolf_sheep/app.py:91:page = SolaraViz( +mesa/examples/basic/boid_flockers/Readme.md:22:* [app.py](app.py): Solara based Visualization code. +mesa/examples/basic/boid_flockers/app.py:4:from mesa.visualization import Slider, SolaraViz, SpaceRenderer +mesa/examples/basic/boid_flockers/app.py:78:page = SolaraViz( +mesa/examples/basic/boltzmann_wealth_model/app.py:6: SolaraViz, +mesa/examples/basic/boltzmann_wealth_model/app.py:75:# The SolaraViz page combines the model, renderer, and components into a web interface. +mesa/examples/basic/boltzmann_wealth_model/app.py:77:page = SolaraViz( +mesa/examples/basic/conways_game_of_life/app.py:3: SolaraViz, +mesa/examples/basic/conways_game_of_life/app.py:64:# Create the SolaraViz page. This will automatically create a server and display the +mesa/examples/basic/conways_game_of_life/app.py:69:page = SolaraViz( +mesa/examples/basic/schelling/app.py:8: SolaraViz, +mesa/examples/basic/schelling/app.py:85:page = SolaraViz( +mesa/examples/basic/virus_on_network/Readme.md:37:* ``app.py``: Contains the code for the interactive Solara visualization. +mesa/examples/basic/virus_on_network/app.py:12: SolaraViz, +mesa/examples/basic/virus_on_network/app.py:126:page = SolaraViz( +mesa/visualization/__init__.py:1:"""Solara based visualization for Mesa models. +mesa/visualization/__init__.py:4: SolaraViz is experimental and still in active development in Mesa 3.x. While we attempt to minimize them, there might be API breaking changes in minor releases. +mesa/visualization/__init__.py:15:from .solara_viz import JupyterViz, SolaraViz +mesa/visualization/__init__.py:23: "SolaraViz", +mesa/visualization/solara_viz.py:7: - SolaraViz: Main component for creating visualizations, supporting grid displays and plots +mesa/visualization/solara_viz.py:11:The module uses Solara for rendering in Jupyter notebooks or as standalone web applications. +mesa/visualization/solara_viz.py:18: 3. Create a SolaraViz instance with your model, parameters, and desired measures +mesa/visualization/solara_viz.py:19: 4. Display the visualization in a Jupyter notebook or run as a Solara app +mesa/visualization/solara_viz.py:58:def SolaraViz( +mesa/visualization/solara_viz.py:73: """Solara visualization component. +mesa/visualization/solara_viz.py:75: This component provides a visualization interface for a given model using Solara. +mesa/visualization/solara_viz.py:103: >>> SolaraViz(model, console_kwargs=console_kwargs) +mesa/visualization/solara_viz.py:106: solara.component: A Solara component that renders the visualization interface for the model. +mesa/visualization/solara_viz.py:110: >>> page = SolaraViz(model) +mesa/visualization/solara_viz.py:351: """Wrap a component in an auto-updated Solara component if needed.""" +mesa/visualization/solara_viz.py:449:JupyterViz = SolaraViz +mesa/visualization/solara_viz.py:741: """Solara component for creating and managing a model instance with user-defined parameters. +mesa/visualization/solara_viz.py:753: solara.component: A Solara component that renders the model creation and management interface. +mesa/visualization/solara_viz.py:818: "Mesa's visualization requires the use of keyword arguments to ensure the parameters are passed to Solara correctly. Please ensure all model parameters are of form param=value" +mesa/visualization/user_param.py:1:"""Solara visualization related helper classes.""" +mesa/visualization/utils.py:1:"""Solara related utils.""" +tests/test_solara_viz.py:1:"""Test Solara visualizations.""" +tests/test_solara_viz.py:19: SolaraViz, +tests/test_solara_viz.py:137: SolaraViz( +tests/test_solara_viz.py:149: solara.render(SolaraViz(model, components="default")) +tests/test_solara_viz.py:166: SolaraViz( +tests/test_solara_viz.py:200: solara.render(SolaraViz(model, components=[AltSpace.drawer])) +tests/test_solara_viz.py:209: SolaraViz(voronoi_model, components=[make_mpl_space_component(agent_portrayal)]) +tests/test_solara_viz.py:325: "Mesa's visualization requires the use of keyword arguments to ensure the parameters are passed to Solara correctly. Please ensure all model parameters are of form param=value" +tests/test_solara_viz_updated.py:1:"""Test Solara visualizations.""" +tests/test_solara_viz_updated.py:16: SolaraViz, +tests/test_solara_viz_updated.py:155: SolaraViz( +tests/test_solara_viz_updated.py:176: solara.render(SolaraViz(model)) +tests/test_solara_viz_updated.py:193: solara.render(SolaraViz(model, renderer, components=[])) +tests/test_solara_viz_updated.py:211: solara.render(SolaraViz(model)) +tests/test_solara_viz_updated.py:226: solara.render(SolaraViz(model, components=[AltSpace.drawer])) +tests/test_solara_viz_updated.py:342: "Mesa's visualization requires the use of keyword arguments to ensure the parameters are passed to Solara correctly. Please ensure all model parameters are of form param=value" diff --git a/mesa/agent.py b/mesa/agent.py index 93cd6287528..bec44940fa3 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -708,7 +708,12 @@ def agg(self, attr_name: str, func: Callable) -> dict[Hashable, Any]: for group_name, group in self.groups.items() } - def __iter__(self): # noqa: D105 + def __iter__(self) -> Iterator[tuple[Hashable, list | AgentSet]]: + """Iterate over (group_name, group) tuples. + + Yields: + tuple[Hashable, list | AgentSet]: pairs of group name and group. + """ return iter(self.groups.items()) def __len__(self): # noqa: D105 diff --git a/tests/test_iteration_fix.py b/tests/test_iteration_fix.py new file mode 100644 index 00000000000..ae69913d962 --- /dev/null +++ b/tests/test_iteration_fix.py @@ -0,0 +1,32 @@ +"""Test AgentSet iteration with garbage collection (Python 3.14 fix).""" + +import gc + +from mesa.agent import Agent, AgentSet +from mesa.model import Model + + +class TestAgent(Agent): + """Simple agent for testing.""" + + +def test_agentset_iteration_with_gc(): + """Test that AgentSet iteration doesn't fail when GC runs during iteration.""" + model = Model() + agents = [TestAgent(model) for _ in range(100)] + agentset = AgentSet(agents, random=model.random) + + # Test iteration with forced GC + collected_ids = [] + for i, agent in enumerate(agentset): + collected_ids.append(agent.unique_id) + if i % 10 == 0: + gc.collect() # Force GC during iteration + + assert len(collected_ids) == 100 + print("Test passed: Iteration with GC works!") + + +if __name__ == "__main__": + test_agentset_iteration_with_gc() + print("\nAll tests passed!")