Mesa 3.0.3__py3-none-any.whl → 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Mesa might be problematic. Click here for more details.

Files changed (50) hide show
  1. mesa/__init__.py +4 -6
  2. mesa/agent.py +48 -25
  3. mesa/batchrunner.py +14 -1
  4. mesa/datacollection.py +1 -6
  5. mesa/examples/__init__.py +2 -2
  6. mesa/examples/advanced/epstein_civil_violence/app.py +5 -0
  7. mesa/examples/advanced/pd_grid/app.py +5 -0
  8. mesa/examples/advanced/sugarscape_g1mt/app.py +7 -2
  9. mesa/examples/basic/boid_flockers/app.py +5 -0
  10. mesa/examples/basic/boltzmann_wealth_model/app.py +8 -5
  11. mesa/examples/basic/boltzmann_wealth_model/st_app.py +1 -1
  12. mesa/examples/basic/conways_game_of_life/app.py +5 -0
  13. mesa/examples/basic/conways_game_of_life/st_app.py +2 -2
  14. mesa/examples/basic/schelling/app.py +5 -0
  15. mesa/examples/basic/virus_on_network/app.py +5 -0
  16. mesa/experimental/__init__.py +17 -10
  17. mesa/experimental/cell_space/__init__.py +19 -7
  18. mesa/experimental/cell_space/cell.py +22 -37
  19. mesa/experimental/cell_space/cell_agent.py +12 -1
  20. mesa/experimental/cell_space/cell_collection.py +14 -1
  21. mesa/experimental/cell_space/discrete_space.py +15 -64
  22. mesa/experimental/cell_space/grid.py +74 -4
  23. mesa/experimental/cell_space/network.py +13 -1
  24. mesa/experimental/cell_space/property_layer.py +444 -0
  25. mesa/experimental/cell_space/voronoi.py +13 -1
  26. mesa/experimental/devs/__init__.py +20 -2
  27. mesa/experimental/devs/eventlist.py +19 -1
  28. mesa/experimental/devs/simulator.py +24 -8
  29. mesa/experimental/mesa_signals/__init__.py +23 -0
  30. mesa/experimental/mesa_signals/mesa_signal.py +485 -0
  31. mesa/experimental/mesa_signals/observable_collections.py +133 -0
  32. mesa/experimental/mesa_signals/signals_util.py +52 -0
  33. mesa/mesa_logging.py +190 -0
  34. mesa/model.py +17 -74
  35. mesa/visualization/__init__.py +2 -2
  36. mesa/visualization/mpl_space_drawing.py +2 -2
  37. mesa/visualization/solara_viz.py +12 -0
  38. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/METADATA +3 -4
  39. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/RECORD +43 -44
  40. mesa/experimental/UserParam.py +0 -67
  41. mesa/experimental/components/altair.py +0 -81
  42. mesa/experimental/components/matplotlib.py +0 -242
  43. mesa/experimental/devs/examples/epstein_civil_violence.py +0 -305
  44. mesa/experimental/devs/examples/wolf_sheep.py +0 -250
  45. mesa/experimental/solara_viz.py +0 -453
  46. mesa/time.py +0 -391
  47. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/WHEEL +0 -0
  48. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/entry_points.txt +0 -0
  49. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/LICENSE +0 -0
  50. {mesa-3.0.3.dist-info → mesa-3.1.0.dist-info}/licenses/NOTICE +0 -0
mesa/__init__.py CHANGED
@@ -7,24 +7,22 @@ import datetime
7
7
 
8
8
  import mesa.experimental as experimental
9
9
  import mesa.space as space
10
- import mesa.time as time
11
10
  from mesa.agent import Agent
12
11
  from mesa.batchrunner import batch_run
13
12
  from mesa.datacollection import DataCollector
14
13
  from mesa.model import Model
15
14
 
16
15
  __all__ = [
17
- "Model",
18
16
  "Agent",
19
- "time",
20
- "space",
21
17
  "DataCollector",
18
+ "Model",
22
19
  "batch_run",
23
20
  "experimental",
21
+ "space",
24
22
  ]
25
23
 
26
24
  __title__ = "mesa"
27
- __version__ = "3.0.3"
25
+ __version__ = "3.1.0"
28
26
  __license__ = "Apache 2.0"
29
- _this_year = datetime.datetime.now(tz=datetime.timezone.utc).date().year
27
+ _this_year = datetime.datetime.now(tz=datetime.UTC).date().year
30
28
  __copyright__ = f"Copyright {_this_year} Project Mesa Team"
mesa/agent.py CHANGED
@@ -85,6 +85,54 @@ class Agent:
85
85
  def advance(self) -> None: # noqa: D102
86
86
  pass
87
87
 
88
+ @classmethod
89
+ def create_agents(cls, model: Model, n: int, *args, **kwargs) -> AgentSet[Agent]:
90
+ """Create N agents.
91
+
92
+ Args:
93
+ model: the model to which the agents belong
94
+ args: arguments to pass onto agent instances
95
+ each arg is either a single object or a sequence of length n
96
+ n: the number of agents to create
97
+ kwargs: keyword arguments to pass onto agent instances
98
+ each keyword arg is either a single object or a sequence of length n
99
+
100
+ Returns:
101
+ AgentSet containing the agents created.
102
+
103
+ """
104
+
105
+ class ListLike:
106
+ """Helper class to make default arguments act as if they are in a list of length N."""
107
+
108
+ def __init__(self, value):
109
+ self.value = value
110
+
111
+ def __getitem__(self, i):
112
+ return self.value
113
+
114
+ listlike_args = []
115
+ for arg in args:
116
+ if isinstance(arg, (list | np.ndarray | tuple)) and len(arg) == n:
117
+ listlike_args.append(arg)
118
+ else:
119
+ listlike_args.append(ListLike(arg))
120
+
121
+ listlike_kwargs = {}
122
+ for k, v in kwargs.items():
123
+ if isinstance(v, (list | np.ndarray | tuple)) and len(v) == n:
124
+ listlike_kwargs[k] = v
125
+ else:
126
+ listlike_kwargs[k] = ListLike(v)
127
+
128
+ agents = []
129
+ for i in range(n):
130
+ instance_args = [arg[i] for arg in listlike_args]
131
+ instance_kwargs = {k: v[i] for k, v in listlike_kwargs.items()}
132
+ agent = cls(model, *instance_args, **instance_kwargs)
133
+ agents.append(agent)
134
+ return AgentSet(agents, random=model.random)
135
+
88
136
  @property
89
137
  def random(self) -> Random:
90
138
  """Return a seeded stdlib rng."""
@@ -155,7 +203,6 @@ class AgentSet(MutableSet, Sequence):
155
203
  at_most: int | float = float("inf"),
156
204
  inplace: bool = False,
157
205
  agent_type: type[Agent] | None = None,
158
- n: int | None = None,
159
206
  ) -> AgentSet:
160
207
  """Select a subset of agents from the AgentSet based on a filter function and/or quantity limit.
161
208
 
@@ -167,7 +214,6 @@ class AgentSet(MutableSet, Sequence):
167
214
  - If a float between 0 and 1, at most that fraction of original the agents are selected.
168
215
  inplace (bool, optional): If True, modifies the current AgentSet; otherwise, returns a new AgentSet. Defaults to False.
169
216
  agent_type (type[Agent], optional): The class type of the agents to select. Defaults to None, meaning no type filtering is applied.
170
- n (int): deprecated, use at_most instead
171
217
 
172
218
  Returns:
173
219
  AgentSet: A new AgentSet containing the selected agents, unless inplace is True, in which case the current AgentSet is updated.
@@ -176,14 +222,6 @@ class AgentSet(MutableSet, Sequence):
176
222
  - at_most just return the first n or fraction of agents. To take a random sample, shuffle() beforehand.
177
223
  - at_most is an upper limit. When specifying other criteria, the number of agents returned can be smaller.
178
224
  """
179
- if n is not None:
180
- warnings.warn(
181
- "The parameter 'n' is deprecated and will be removed in Mesa 3.1. Use 'at_most' instead.",
182
- DeprecationWarning,
183
- stacklevel=2,
184
- )
185
- at_most = n
186
-
187
225
  inf = float("inf")
188
226
  if filter_func is None and agent_type is None and at_most == inf:
189
227
  return self if inplace else copy.copy(self)
@@ -281,21 +319,6 @@ class AgentSet(MutableSet, Sequence):
281
319
  Returns:
282
320
  AgentSet | list[Any]: The results of the callable calls if return_results is True, otherwise the AgentSet itself.
283
321
  """
284
- try:
285
- return_results = kwargs.pop("return_results")
286
- except KeyError:
287
- return_results = False
288
- else:
289
- warnings.warn(
290
- "Using return_results is deprecated and will be removed in Mesa 3.1."
291
- "Use AgenSet.do in case of return_results=False, and AgentSet.map in case of return_results=True",
292
- DeprecationWarning,
293
- stacklevel=2,
294
- )
295
-
296
- if return_results:
297
- return self.map(method, *args, **kwargs)
298
-
299
322
  # we iterate over the actual weakref keys and check if weakref is alive before calling the method
300
323
  if isinstance(method, str):
301
324
  for agentref in self._agents.keyrefs():
mesa/batchrunner.py CHANGED
@@ -106,7 +106,14 @@ def _make_model_kwargs(
106
106
  Parameters
107
107
  ----------
108
108
  parameters : Mapping[str, Union[Any, Iterable[Any]]]
109
- Single or multiple values for each model parameter name
109
+ Single or multiple values for each model parameter name.
110
+
111
+ Allowed values for each parameter:
112
+ - A single value (e.g., `32`, `"relu"`).
113
+ - A non-empty iterable (e.g., `[0.01, 0.1]`, `["relu", "sigmoid"]`).
114
+
115
+ Not allowed:
116
+ - Empty lists or empty iterables (e.g., `[]`, `()`, etc.). These should be removed manually.
110
117
 
111
118
  Returns:
112
119
  -------
@@ -118,6 +125,12 @@ def _make_model_kwargs(
118
125
  if isinstance(values, str):
119
126
  # The values is a single string, so we shouldn't iterate over it.
120
127
  all_values = [(param, values)]
128
+ elif isinstance(values, list | tuple | set) and len(values) == 0:
129
+ # If it's an empty iterable, raise an error
130
+ raise ValueError(
131
+ f"Parameter '{param}' contains an empty iterable, which is not allowed."
132
+ )
133
+
121
134
  else:
122
135
  try:
123
136
  all_values = [(param, value) for value in values]
mesa/datacollection.py CHANGED
@@ -228,12 +228,7 @@ class DataCollector:
228
228
  reports = tuple(rep(agent) for rep in rep_funcs)
229
229
  return _prefix + reports
230
230
 
231
- agent_records = map(
232
- get_reports,
233
- model.schedule.agents
234
- if hasattr(model, "schedule") and model.schedule is not None
235
- else model.agents,
236
- )
231
+ agent_records = map(get_reports, model.agents)
237
232
  return agent_records
238
233
 
239
234
  def _record_agenttype(self, model, agent_type):
mesa/examples/__init__.py CHANGED
@@ -12,10 +12,10 @@ __all__ = [
12
12
  "BoidFlockers",
13
13
  "BoltzmannWealth",
14
14
  "ConwaysGameOfLife",
15
- "Schelling",
16
- "VirusOnNetwork",
17
15
  "EpsteinCivilViolence",
18
16
  "PdGrid",
17
+ "Schelling",
19
18
  "SugarscapeG1mt",
19
+ "VirusOnNetwork",
20
20
  "WolfSheep",
21
21
  ]
@@ -44,6 +44,11 @@ def post_process(ax):
44
44
 
45
45
 
46
46
  model_params = {
47
+ "seed": {
48
+ "type": "InputText",
49
+ "value": 42,
50
+ "label": "Random Seed",
51
+ },
47
52
  "height": 40,
48
53
  "width": 40,
49
54
  "citizen_density": Slider("Initial Agent Density", 0.7, 0.0, 0.9, 0.1),
@@ -24,6 +24,11 @@ def pd_agent_portrayal(agent):
24
24
 
25
25
  # Model parameters
26
26
  model_params = {
27
+ "seed": {
28
+ "type": "InputText",
29
+ "value": 42,
30
+ "label": "Random Seed",
31
+ },
27
32
  "width": Slider("Grid Width", value=50, min=10, max=100, step=1),
28
33
  "height": Slider("Grid Height", value=50, min=10, max=100, step=1),
29
34
  "activation_order": {
@@ -47,6 +47,11 @@ def SpaceDrawer(model):
47
47
 
48
48
 
49
49
  model_params = {
50
+ "seed": {
51
+ "type": "InputText",
52
+ "value": 42,
53
+ "label": "Random Seed",
54
+ },
50
55
  "width": 50,
51
56
  "height": 50,
52
57
  # Population parameters
@@ -66,10 +71,10 @@ model_params = {
66
71
  "enable_trade": {"type": "Checkbox", "value": True, "label": "Enable Trading"},
67
72
  }
68
73
 
69
- model1 = SugarscapeG1mt()
74
+ model = SugarscapeG1mt()
70
75
 
71
76
  page = SolaraViz(
72
- model1,
77
+ model,
73
78
  components=[SpaceDrawer, make_plot_component(["Trader", "Price"])],
74
79
  model_params=model_params,
75
80
  name="Sugarscape {G1, M, T}",
@@ -12,6 +12,11 @@ def boid_draw(agent):
12
12
 
13
13
 
14
14
  model_params = {
15
+ "seed": {
16
+ "type": "InputText",
17
+ "value": 42,
18
+ "label": "Random Seed",
19
+ },
15
20
  "population": Slider(
16
21
  label="Number of boids",
17
22
  value=100,
@@ -1,10 +1,13 @@
1
1
  from mesa.examples.basic.boltzmann_wealth_model.model import BoltzmannWealth
2
+ from mesa.mesa_logging import DEBUG, log_to_stderr
2
3
  from mesa.visualization import (
3
4
  SolaraViz,
4
5
  make_plot_component,
5
6
  make_space_component,
6
7
  )
7
8
 
9
+ log_to_stderr(DEBUG)
10
+
8
11
 
9
12
  def agent_portrayal(agent):
10
13
  color = agent.wealth # we are using a colormap to translate wealth to color
@@ -12,6 +15,11 @@ def agent_portrayal(agent):
12
15
 
13
16
 
14
17
  model_params = {
18
+ "seed": {
19
+ "type": "InputText",
20
+ "value": 42,
21
+ "label": "Random Seed",
22
+ },
15
23
  "n": {
16
24
  "type": "SliderInt",
17
25
  "value": 50,
@@ -20,11 +28,6 @@ model_params = {
20
28
  "max": 100,
21
29
  "step": 1,
22
30
  },
23
- "seed": {
24
- "type": "InputText",
25
- "value": 42,
26
- "label": "Random Seed",
27
- },
28
31
  "width": 10,
29
32
  "height": 10,
30
33
  }
@@ -68,7 +68,7 @@ if run:
68
68
  for i in range(num_ticks):
69
69
  model.step()
70
70
  my_bar.progress((i / num_ticks), text="Simulation progress")
71
- placeholder.text("Step = %d" % i)
71
+ placeholder.text(f"Step = {i}")
72
72
  for cell in model.grid.coord_iter():
73
73
  cell_content, (x, y) = cell
74
74
  agent_count = len(cell_content)
@@ -20,6 +20,11 @@ def post_process(ax):
20
20
 
21
21
 
22
22
  model_params = {
23
+ "seed": {
24
+ "type": "InputText",
25
+ "value": 42,
26
+ "label": "Random Seed",
27
+ },
23
28
  "width": {
24
29
  "type": "SliderInt",
25
30
  "value": 50,
@@ -49,9 +49,9 @@ if run:
49
49
  for i in range(num_ticks):
50
50
  model.step()
51
51
  my_bar.progress((i / num_ticks), text="Simulation progress")
52
- placeholder.text("Step = %d" % i)
52
+ placeholder.text(f"Step = {i}")
53
53
  for contents, (x, y) in model.grid.coord_iter():
54
- # print('x:',x,'y:',y, 'state:',contents)
54
+ # print(f"x: {x}, y: {y}, state: {contents}")
55
55
  selected_row = df_grid[(df_grid["x"] == x) & (df_grid["y"] == y)]
56
56
  df_grid.loc[selected_row.index, "state"] = (
57
57
  contents.state
@@ -19,6 +19,11 @@ def agent_portrayal(agent):
19
19
 
20
20
 
21
21
  model_params = {
22
+ "seed": {
23
+ "type": "InputText",
24
+ "value": 42,
25
+ "label": "Random Seed",
26
+ },
22
27
  "density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
23
28
  "minority_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
24
29
  "homophily": Slider("Homophily", 3, 0, 8, 1),
@@ -35,6 +35,11 @@ def get_resistant_susceptible_ratio(model):
35
35
 
36
36
 
37
37
  model_params = {
38
+ "seed": {
39
+ "type": "InputText",
40
+ "value": 42,
41
+ "label": "Random Seed",
42
+ },
38
43
  "num_nodes": Slider(
39
44
  label="Number of agents",
40
45
  value=10,
@@ -1,13 +1,20 @@
1
- """Experimental init."""
1
+ """Experimental features package for Mesa.
2
2
 
3
- from mesa.experimental import cell_space
3
+ This package contains modules that are under active development and testing. These
4
+ features are provided to allow early access and feedback from the Mesa community, but
5
+ their APIs may change between releases without following semantic versioning.
4
6
 
5
- try:
6
- from .solara_viz import JupyterViz, Slider, SolaraViz, make_text
7
+ Current experimental modules:
8
+ cell_space: Alternative API for discrete spaces with cell-centric functionality
9
+ devs: Discrete event simulation system for scheduling events at arbitrary times
10
+ mesa_signals: Reactive programming capabilities for tracking state changes
7
11
 
8
- __all__ = ["cell_space", "JupyterViz", "Slider", "SolaraViz", "make_text"]
9
- except ImportError:
10
- print(
11
- "Could not import SolaraViz. If you need it, install with 'pip install --pre mesa[viz]'"
12
- )
13
- __all__ = ["cell_space"]
12
+ Notes:
13
+ - Features in this package may be changed or removed without notice
14
+ - APIs are not guaranteed to be stable between releases
15
+ - Features graduate from experimental status once their APIs are stabilized
16
+ """
17
+
18
+ from mesa.experimental import cell_space, devs, mesa_signals
19
+
20
+ __all__ = ["cell_space", "devs", "mesa_signals"]
@@ -1,8 +1,18 @@
1
- """Cell spaces.
1
+ """Cell spaces for active, property-rich spatial modeling in Mesa.
2
2
 
3
- Cell spaces offer an alternative API for discrete spaces. It is experimental and under development. The API is more
4
- expressive that the default grids available in `mesa.space`.
3
+ Cell spaces extend Mesa's spatial modeling capabilities by making the space itself active -
4
+ each position (cell) can have properties and behaviors rather than just containing agents.
5
+ This enables more sophisticated environmental modeling and agent-environment interactions.
5
6
 
7
+ Key components:
8
+ - Cells: Active positions that can have properties and contain agents
9
+ - CellAgents: Agents that understand how to interact with cells
10
+ - Spaces: Different cell organization patterns (grids, networks, etc.)
11
+ - PropertyLayers: Efficient property storage and manipulation
12
+
13
+ This is particularly useful for models where the environment plays an active role,
14
+ like resource growth, pollution diffusion, or infrastructure networks. The cell
15
+ space system is experimental and under active development.
6
16
  """
7
17
 
8
18
  from mesa.experimental.cell_space.cell import Cell
@@ -20,19 +30,21 @@ from mesa.experimental.cell_space.grid import (
20
30
  OrthogonalVonNeumannGrid,
21
31
  )
22
32
  from mesa.experimental.cell_space.network import Network
33
+ from mesa.experimental.cell_space.property_layer import PropertyLayer
23
34
  from mesa.experimental.cell_space.voronoi import VoronoiGrid
24
35
 
25
36
  __all__ = [
26
- "CellCollection",
27
37
  "Cell",
28
38
  "CellAgent",
29
- "Grid2DMovingAgent",
30
- "FixedAgent",
39
+ "CellCollection",
31
40
  "DiscreteSpace",
41
+ "FixedAgent",
32
42
  "Grid",
43
+ "Grid2DMovingAgent",
33
44
  "HexGrid",
45
+ "Network",
34
46
  "OrthogonalMooreGrid",
35
47
  "OrthogonalVonNeumannGrid",
36
- "Network",
48
+ "PropertyLayer",
37
49
  "VoronoiGrid",
38
50
  ]
@@ -1,15 +1,25 @@
1
- """The Cell in a cell space."""
1
+ """Cells are positions in space that can have properties and contain agents.
2
+
3
+ A cell represents a location that can:
4
+ - Have properties (like temperature or resources)
5
+ - Track and limit the agents it contains
6
+ - Connect to neighboring cells
7
+ - Provide neighborhood information
8
+
9
+ Cells form the foundation of the cell space system, enabling rich spatial
10
+ environments where both location properties and agent behaviors matter. They're
11
+ useful for modeling things like varying terrain, infrastructure capacity, or
12
+ environmental conditions.
13
+ """
2
14
 
3
15
  from __future__ import annotations
4
16
 
5
- from collections.abc import Callable
6
17
  from functools import cache, cached_property
7
18
  from random import Random
8
- from typing import TYPE_CHECKING, Any
19
+ from typing import TYPE_CHECKING
9
20
 
10
21
  from mesa.experimental.cell_space.cell_agent import CellAgent
11
22
  from mesa.experimental.cell_space.cell_collection import CellCollection
12
- from mesa.space import PropertyLayer
13
23
 
14
24
  if TYPE_CHECKING:
15
25
  from mesa.agent import Agent
@@ -24,31 +34,20 @@ class Cell:
24
34
  coordinate (Tuple[int, int]) : the position of the cell in the discrete space
25
35
  agents (List[Agent]): the agents occupying the cell
26
36
  capacity (int): the maximum number of agents that can simultaneously occupy the cell
27
- properties (dict[str, Any]): the properties of the cell
28
37
  random (Random): the random number generator
29
38
 
30
39
  """
31
40
 
32
41
  __slots__ = [
33
- "coordinate",
34
- "connections",
42
+ "__dict__",
35
43
  "agents",
36
44
  "capacity",
45
+ "connections",
46
+ "coordinate",
37
47
  "properties",
38
48
  "random",
39
- "_mesa_property_layers",
40
- "__dict__",
41
49
  ]
42
50
 
43
- # def __new__(cls,
44
- # coordinate: tuple[int, ...],
45
- # capacity: float | None = None,
46
- # random: Random | None = None,):
47
- # if capacity != 1:
48
- # return object.__new__(cls)
49
- # else:
50
- # return object.__new__(SingleAgentCell)
51
-
52
51
  def __init__(
53
52
  self,
54
53
  coordinate: Coordinate,
@@ -70,9 +69,10 @@ class Cell:
70
69
  Agent
71
70
  ] = [] # TODO:: change to AgentSet or weakrefs? (neither is very performant, )
72
71
  self.capacity: int | None = capacity
73
- self.properties: dict[Coordinate, object] = {}
72
+ self.properties: dict[
73
+ Coordinate, object
74
+ ] = {} # fixme still used by voronoi mesh
74
75
  self.random = random
75
- self._mesa_property_layers: dict[str, PropertyLayer] = {}
76
76
 
77
77
  def connect(self, other: Cell, key: Coordinate | None = None) -> None:
78
78
  """Connects this cell to another cell.
@@ -105,6 +105,7 @@ class Cell:
105
105
 
106
106
  """
107
107
  n = len(self.agents)
108
+ self.empty = False
108
109
 
109
110
  if self.capacity and n >= self.capacity:
110
111
  raise Exception(
@@ -121,6 +122,7 @@ class Cell:
121
122
 
122
123
  """
123
124
  self.agents.remove(agent)
125
+ self.empty = self.is_empty
124
126
 
125
127
  @property
126
128
  def is_empty(self) -> bool:
@@ -195,23 +197,6 @@ class Cell:
195
197
  neighborhood.pop(self, None)
196
198
  return neighborhood
197
199
 
198
- # PropertyLayer methods
199
- def get_property(self, property_name: str) -> Any:
200
- """Get the value of a property."""
201
- return self._mesa_property_layers[property_name].data[self.coordinate]
202
-
203
- def set_property(self, property_name: str, value: Any):
204
- """Set the value of a property."""
205
- self._mesa_property_layers[property_name].set_cell(self.coordinate, value)
206
-
207
- def modify_property(
208
- self, property_name: str, operation: Callable, value: Any = None
209
- ):
210
- """Modify the value of a property."""
211
- self._mesa_property_layers[property_name].modify_cell(
212
- self.coordinate, operation, value
213
- )
214
-
215
200
  def __getstate__(self):
216
201
  """Return state of the Cell with connections set to empty."""
217
202
  # fixme, once we shift to 3.11, replace this with super. __getstate__
@@ -1,4 +1,15 @@
1
- """An agent with movement methods for cell spaces."""
1
+ """Agents that understand how to exist in and move through cell spaces.
2
+
3
+ Provides specialized agent classes that handle cell occupation, movement, and
4
+ proper registration:
5
+ - CellAgent: Mobile agents that can move between cells
6
+ - FixedAgent: Immobile agents permanently fixed to cells
7
+ - Grid2DMovingAgent: Agents with grid-specific movement capabilities
8
+
9
+ These classes ensure consistent agent-cell relationships and proper state management
10
+ as agents move through the space. They can be used directly or as examples for
11
+ creating custom cell-aware agents.
12
+ """
2
13
 
3
14
  from __future__ import annotations
4
15
 
@@ -1,4 +1,17 @@
1
- """CellCollection class."""
1
+ """Collection class for managing and querying groups of cells.
2
+
3
+ The CellCollection class provides a consistent interface for operating on multiple
4
+ cells, supporting:
5
+ - Filtering and selecting cells based on conditions
6
+ - Random cell and agent selection
7
+ - Access to contained agents
8
+ - Group operations
9
+
10
+ This is useful for implementing area effects, zones, or any operation that needs
11
+ to work with multiple cells as a unit. The collection handles efficient iteration
12
+ and agent access across cells. The class is used throughout the cell space
13
+ implementation to represent neighborhoods, selections, and other cell groupings.
14
+ """
2
15
 
3
16
  from __future__ import annotations
4
17