Mesa 3.0.0a4__py3-none-any.whl → 3.0.0a5__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 (40) hide show
  1. mesa/__init__.py +2 -3
  2. mesa/agent.py +106 -61
  3. mesa/batchrunner.py +15 -23
  4. mesa/cookiecutter-mesa/hooks/post_gen_project.py +2 -0
  5. mesa/cookiecutter-mesa/{{cookiecutter.snake}}/{{cookiecutter.snake}}/__init__.py +1 -0
  6. mesa/datacollection.py +138 -27
  7. mesa/experimental/UserParam.py +17 -6
  8. mesa/experimental/__init__.py +2 -0
  9. mesa/experimental/cell_space/__init__.py +7 -0
  10. mesa/experimental/cell_space/cell.py +61 -20
  11. mesa/experimental/cell_space/cell_agent.py +10 -5
  12. mesa/experimental/cell_space/cell_collection.py +54 -17
  13. mesa/experimental/cell_space/discrete_space.py +16 -5
  14. mesa/experimental/cell_space/grid.py +19 -8
  15. mesa/experimental/cell_space/network.py +9 -7
  16. mesa/experimental/cell_space/voronoi.py +26 -33
  17. mesa/experimental/components/altair.py +10 -0
  18. mesa/experimental/components/matplotlib.py +18 -0
  19. mesa/experimental/devs/__init__.py +2 -0
  20. mesa/experimental/devs/eventlist.py +36 -15
  21. mesa/experimental/devs/examples/epstein_civil_violence.py +65 -29
  22. mesa/experimental/devs/examples/wolf_sheep.py +38 -34
  23. mesa/experimental/devs/simulator.py +55 -15
  24. mesa/experimental/solara_viz.py +10 -19
  25. mesa/main.py +6 -4
  26. mesa/model.py +43 -45
  27. mesa/space.py +145 -120
  28. mesa/time.py +57 -67
  29. mesa/visualization/UserParam.py +19 -6
  30. mesa/visualization/__init__.py +3 -2
  31. mesa/visualization/components/altair.py +4 -2
  32. mesa/visualization/components/matplotlib.py +6 -4
  33. mesa/visualization/solara_viz.py +157 -83
  34. mesa/visualization/utils.py +3 -1
  35. {mesa-3.0.0a4.dist-info → mesa-3.0.0a5.dist-info}/METADATA +1 -1
  36. mesa-3.0.0a5.dist-info/RECORD +44 -0
  37. mesa-3.0.0a4.dist-info/RECORD +0 -44
  38. {mesa-3.0.0a4.dist-info → mesa-3.0.0a5.dist-info}/WHEEL +0 -0
  39. {mesa-3.0.0a4.dist-info → mesa-3.0.0a5.dist-info}/entry_points.txt +0 -0
  40. {mesa-3.0.0a4.dist-info → mesa-3.0.0a5.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,5 @@
1
+ """DiscreteSpace base class."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  from functools import cached_property
@@ -28,6 +30,13 @@ class DiscreteSpace(Generic[T]):
28
30
  cell_klass: type[T] = Cell,
29
31
  random: Random | None = None,
30
32
  ):
33
+ """Instantiate a DiscreteSpace.
34
+
35
+ Args:
36
+ capacity: capacity of cells
37
+ cell_klass: base class for all cells
38
+ random: random number generator
39
+ """
31
40
  super().__init__()
32
41
  self.capacity = capacity
33
42
  self._cells: dict[tuple[int, ...], T] = {}
@@ -40,25 +49,27 @@ class DiscreteSpace(Generic[T]):
40
49
  self._empties_initialized = False
41
50
 
42
51
  @property
43
- def cutoff_empties(self):
52
+ def cutoff_empties(self): # noqa
44
53
  return 7.953 * len(self._cells) ** 0.384
45
54
 
46
55
  def _connect_single_cell(self, cell: T): ...
47
56
 
48
57
  @cached_property
49
58
  def all_cells(self):
59
+ """Return all cells in space."""
50
60
  return CellCollection({cell: cell.agents for cell in self._cells.values()})
51
61
 
52
- def __iter__(self):
62
+ def __iter__(self): # noqa
53
63
  return iter(self._cells.values())
54
64
 
55
- def __getitem__(self, key):
65
+ def __getitem__(self, key: tuple[int, ...]) -> T: # noqa: D105
56
66
  return self._cells[key]
57
67
 
58
68
  @property
59
- def empties(self) -> CellCollection:
69
+ def empties(self) -> CellCollection[T]:
70
+ """Return all empty in spaces."""
60
71
  return self.all_cells.select(lambda cell: cell.is_empty)
61
72
 
62
73
  def select_random_empty_cell(self) -> T:
63
- """select random empty cell"""
74
+ """Select random empty cell."""
64
75
  return self.random.choice(list(self.empties))
@@ -1,3 +1,5 @@
1
+ """Various Grid Spaces."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  from collections.abc import Sequence
@@ -10,8 +12,8 @@ from mesa.experimental.cell_space import Cell, DiscreteSpace
10
12
  T = TypeVar("T", bound=Cell)
11
13
 
12
14
 
13
- class Grid(DiscreteSpace, Generic[T]):
14
- """Base class for all grid classes
15
+ class Grid(DiscreteSpace[T], Generic[T]):
16
+ """Base class for all grid classes.
15
17
 
16
18
  Attributes:
17
19
  dimensions (Sequence[int]): the dimensions of the grid
@@ -30,6 +32,15 @@ class Grid(DiscreteSpace, Generic[T]):
30
32
  random: Random | None = None,
31
33
  cell_klass: type[T] = Cell,
32
34
  ) -> None:
35
+ """Initialise the grid class.
36
+
37
+ Args:
38
+ dimensions: the dimensions of the space
39
+ torus: whether the space wraps
40
+ capacity: capacity of the grid cell
41
+ random: a random number generator
42
+ cell_klass: the base class to use for the cells
43
+ """
33
44
  super().__init__(capacity=capacity, random=random, cell_klass=cell_klass)
34
45
  self.torus = torus
35
46
  self.dimensions = dimensions
@@ -63,7 +74,7 @@ class Grid(DiscreteSpace, Generic[T]):
63
74
  if self.capacity is not None and not isinstance(self.capacity, float | int):
64
75
  raise ValueError("Capacity must be a number or None.")
65
76
 
66
- def select_random_empty_cell(self) -> T:
77
+ def select_random_empty_cell(self) -> T: # noqa
67
78
  # FIXME:: currently just a simple boolean to control behavior
68
79
  # FIXME:: basically if grid is close to 99% full, creating empty list can be faster
69
80
  # FIXME:: note however that the old results don't apply because in this implementation
@@ -89,7 +100,7 @@ class Grid(DiscreteSpace, Generic[T]):
89
100
  if self.torus:
90
101
  n_coord = tuple(nc % d for nc, d in zip(n_coord, self.dimensions))
91
102
  if all(0 <= nc < d for nc, d in zip(n_coord, self.dimensions)):
92
- cell.connect(self._cells[n_coord])
103
+ cell.connect(self._cells[n_coord], d_coord)
93
104
 
94
105
  def _connect_single_cell_2d(self, cell: T, offsets: list[tuple[int, int]]) -> None:
95
106
  i, j = cell.coordinate
@@ -100,7 +111,7 @@ class Grid(DiscreteSpace, Generic[T]):
100
111
  if self.torus:
101
112
  ni, nj = ni % height, nj % width
102
113
  if 0 <= ni < height and 0 <= nj < width:
103
- cell.connect(self._cells[ni, nj])
114
+ cell.connect(self._cells[ni, nj], (di, dj))
104
115
 
105
116
 
106
117
  class OrthogonalMooreGrid(Grid[T]):
@@ -122,7 +133,6 @@ class OrthogonalMooreGrid(Grid[T]):
122
133
  ( 1, -1), ( 1, 0), ( 1, 1),
123
134
  ]
124
135
  # fmt: on
125
- height, width = self.dimensions
126
136
 
127
137
  for cell in self.all_cells:
128
138
  self._connect_single_cell_2d(cell, offsets)
@@ -154,13 +164,12 @@ class OrthogonalVonNeumannGrid(Grid[T]):
154
164
  ( 1, 0),
155
165
  ]
156
166
  # fmt: on
157
- height, width = self.dimensions
158
167
 
159
168
  for cell in self.all_cells:
160
169
  self._connect_single_cell_2d(cell, offsets)
161
170
 
162
171
  def _connect_cells_nd(self) -> None:
163
- offsets = []
172
+ offsets: list[tuple[int, ...]] = []
164
173
  dimensions = len(self.dimensions)
165
174
  for dim in range(dimensions):
166
175
  for delta in [
@@ -176,6 +185,8 @@ class OrthogonalVonNeumannGrid(Grid[T]):
176
185
 
177
186
 
178
187
  class HexGrid(Grid[T]):
188
+ """A Grid with hexagonal tilling of the space."""
189
+
179
190
  def _connect_cells_2d(self) -> None:
180
191
  # fmt: off
181
192
  even_offsets = [
@@ -1,3 +1,5 @@
1
+ """A Network grid."""
2
+
1
3
  from random import Random
2
4
  from typing import Any
3
5
 
@@ -5,8 +7,8 @@ from mesa.experimental.cell_space.cell import Cell
5
7
  from mesa.experimental.cell_space.discrete_space import DiscreteSpace
6
8
 
7
9
 
8
- class Network(DiscreteSpace):
9
- """A networked discrete space"""
10
+ class Network(DiscreteSpace[Cell]):
11
+ """A networked discrete space."""
10
12
 
11
13
  def __init__(
12
14
  self,
@@ -15,13 +17,13 @@ class Network(DiscreteSpace):
15
17
  random: Random | None = None,
16
18
  cell_klass: type[Cell] = Cell,
17
19
  ) -> None:
18
- """A Networked grid
20
+ """A Networked grid.
19
21
 
20
22
  Args:
21
23
  G: a NetworkX Graph instance.
22
24
  capacity (int) : the capacity of the cell
23
- random (Random):
24
- CellKlass (type[Cell]): The base Cell class to use in the Network
25
+ random (Random): a random number generator
26
+ cell_klass (type[Cell]): The base Cell class to use in the Network
25
27
 
26
28
  """
27
29
  super().__init__(capacity=capacity, random=random, cell_klass=cell_klass)
@@ -35,6 +37,6 @@ class Network(DiscreteSpace):
35
37
  for cell in self.all_cells:
36
38
  self._connect_single_cell(cell)
37
39
 
38
- def _connect_single_cell(self, cell):
40
+ def _connect_single_cell(self, cell: Cell):
39
41
  for node_id in self.G.neighbors(cell.coordinate):
40
- cell.connect(self._cells[node_id])
42
+ cell.connect(self._cells[node_id], node_id)
@@ -1,3 +1,5 @@
1
+ """Support for Voronoi meshed grids."""
2
+
1
3
  from collections.abc import Sequence
2
4
  from itertools import combinations
3
5
  from random import Random
@@ -9,16 +11,17 @@ from mesa.experimental.cell_space.discrete_space import DiscreteSpace
9
11
 
10
12
 
11
13
  class Delaunay:
12
- """
13
- Class to compute a Delaunay triangulation in 2D
14
+ """Class to compute a Delaunay triangulation in 2D.
15
+
14
16
  ref: http://github.com/jmespadero/pyDelaunay2D
15
17
  """
16
18
 
17
19
  def __init__(self, center: tuple = (0, 0), radius: int = 9999) -> None:
18
- """
19
- Init and create a new frame to contain the triangulation
20
- center: Optional position for the center of the frame. Default (0,0)
21
- radius: Optional distance from corners to the center.
20
+ """Init and create a new frame to contain the triangulation.
21
+
22
+ Args:
23
+ center: Optional position for the center of the frame. Default (0,0)
24
+ radius: Optional distance from corners to the center.
22
25
  """
23
26
  center = np.asarray(center)
24
27
  # Create coordinates for the corners of the frame
@@ -44,9 +47,7 @@ class Delaunay:
44
47
  self.circles[t] = self._circumcenter(t)
45
48
 
46
49
  def _circumcenter(self, triangle: list) -> tuple:
47
- """
48
- Compute circumcenter and circumradius of a triangle in 2D.
49
- """
50
+ """Compute circumcenter and circumradius of a triangle in 2D."""
50
51
  points = np.asarray([self.coords[v] for v in triangle])
51
52
  points2 = np.dot(points, points.T)
52
53
  a = np.bmat([[2 * points2, [[1], [1], [1]]], [[[1, 1, 1, 0]]]])
@@ -60,16 +61,12 @@ class Delaunay:
60
61
  return (center, radius)
61
62
 
62
63
  def _in_circle(self, triangle: list, point: list) -> bool:
63
- """
64
- Check if point p is inside of precomputed circumcircle of triangle.
65
- """
64
+ """Check if point p is inside of precomputed circumcircle of triangle."""
66
65
  center, radius = self.circles[triangle]
67
66
  return np.sum(np.square(center - point)) <= radius
68
67
 
69
68
  def add_point(self, point: Sequence) -> None:
70
- """
71
- Add a point to the current DT, and refine it using Bowyer-Watson.
72
- """
69
+ """Add a point to the current DT, and refine it using Bowyer-Watson."""
73
70
  point_index = len(self.coords)
74
71
  self.coords.append(np.asarray(point))
75
72
 
@@ -121,9 +118,7 @@ class Delaunay:
121
118
  self.triangles[triangle][2] = new_triangles[(i - 1) % n] # previous
122
119
 
123
120
  def export_triangles(self) -> list:
124
- """
125
- Export the current list of Delaunay triangles
126
- """
121
+ """Export the current list of Delaunay triangles."""
127
122
  triangles_list = [
128
123
  (a - 4, b - 4, c - 4)
129
124
  for (a, b, c) in self.triangles
@@ -132,9 +127,7 @@ class Delaunay:
132
127
  return triangles_list
133
128
 
134
129
  def export_voronoi_regions(self):
135
- """
136
- Export coordinates and regions of Voronoi diagram as indexed data.
137
- """
130
+ """Export coordinates and regions of Voronoi diagram as indexed data."""
138
131
  use_vertex = {i: [] for i in range(len(self.coords))}
139
132
  vor_coors = []
140
133
  index = {}
@@ -163,11 +156,13 @@ class Delaunay:
163
156
  return vor_coors, regions
164
157
 
165
158
 
166
- def round_float(x: float) -> int:
159
+ def round_float(x: float) -> int: # noqa
167
160
  return int(x * 500)
168
161
 
169
162
 
170
163
  class VoronoiGrid(DiscreteSpace):
164
+ """Voronoi meshed GridSpace."""
165
+
171
166
  triangulation: Delaunay
172
167
  voronoi_coordinates: list
173
168
  regions: list
@@ -181,8 +176,7 @@ class VoronoiGrid(DiscreteSpace):
181
176
  capacity_function: callable = round_float,
182
177
  cell_coloring_property: str | None = None,
183
178
  ) -> None:
184
- """
185
- A Voronoi Tessellation Grid.
179
+ """A Voronoi Tessellation Grid.
186
180
 
187
181
  Given a set of points, this class creates a grid where a cell is centered in each point,
188
182
  its neighbors are given by Voronoi Tessellation cells neighbors
@@ -192,7 +186,7 @@ class VoronoiGrid(DiscreteSpace):
192
186
  centroids_coordinates: coordinates of centroids to build the tessellation space
193
187
  capacity (int) : capacity of the cells in the discrete space
194
188
  random (Random): random number generator
195
- CellKlass (type[Cell]): type of cell class
189
+ cell_klass (type[Cell]): type of cell class
196
190
  capacity_function (Callable): function to compute (int) capacity according to (float) area
197
191
  cell_coloring_property (str): voronoi visualization polygon fill property
198
192
  """
@@ -215,17 +209,15 @@ class VoronoiGrid(DiscreteSpace):
215
209
  self._build_cell_polygons()
216
210
 
217
211
  def _connect_cells(self) -> None:
218
- """
219
- Connect cells to neighbors based on given centroids and using Delaunay Triangulation
220
- """
212
+ """Connect cells to neighbors based on given centroids and using Delaunay Triangulation."""
221
213
  self.triangulation = Delaunay()
222
214
  for centroid in self.centroids_coordinates:
223
215
  self.triangulation.add_point(centroid)
224
216
 
225
217
  for point in self.triangulation.export_triangles():
226
218
  for i, j in combinations(point, 2):
227
- self._cells[i].connect(self._cells[j])
228
- self._cells[j].connect(self._cells[i])
219
+ self._cells[i].connect(self._cells[j], (i, j))
220
+ self._cells[j].connect(self._cells[i], (j, i))
229
221
 
230
222
  def _validate_parameters(self) -> None:
231
223
  if self.capacity is not None and not isinstance(self.capacity, float | int):
@@ -241,9 +233,10 @@ class VoronoiGrid(DiscreteSpace):
241
233
 
242
234
  def _get_voronoi_regions(self) -> tuple:
243
235
  if self.voronoi_coordinates is None or self.regions is None:
244
- self.voronoi_coordinates, self.regions = (
245
- self.triangulation.export_voronoi_regions()
246
- )
236
+ (
237
+ self.voronoi_coordinates,
238
+ self.regions,
239
+ ) = self.triangulation.export_voronoi_regions()
247
240
  return self.voronoi_coordinates, self.regions
248
241
 
249
242
  @staticmethod
@@ -1,3 +1,5 @@
1
+ """Altair components."""
2
+
1
3
  import contextlib
2
4
 
3
5
  import solara
@@ -8,6 +10,14 @@ with contextlib.suppress(ImportError):
8
10
 
9
11
  @solara.component
10
12
  def SpaceAltair(model, agent_portrayal, dependencies: list[any] | None = None):
13
+ """A component that renders a Space using Altair.
14
+
15
+ Args:
16
+ model: a model instance
17
+ agent_portrayal: agent portray specification
18
+ dependencies: optional list of dependencies (currently not used)
19
+
20
+ """
11
21
  space = getattr(model, "grid", None)
12
22
  if space is None:
13
23
  # Sometimes the space is defined as model.space instead of model.grid
@@ -1,3 +1,5 @@
1
+ """Support for using matplotlib to draw spaces."""
2
+
1
3
  from collections import defaultdict
2
4
 
3
5
  import networkx as nx
@@ -11,6 +13,14 @@ from mesa.experimental.cell_space import VoronoiGrid
11
13
 
12
14
  @solara.component
13
15
  def SpaceMatplotlib(model, agent_portrayal, dependencies: list[any] | None = None):
16
+ """A component for rendering a space using Matplotlib.
17
+
18
+ Args:
19
+ model: a model instance
20
+ agent_portrayal: a specification of how to portray an agent.
21
+ dependencies: list of dependencies.
22
+
23
+ """
14
24
  space_fig = Figure()
15
25
  space_ax = space_fig.subplots()
16
26
  space = getattr(model, "grid", None)
@@ -205,6 +215,14 @@ def _draw_voronoi(space, space_ax, agent_portrayal):
205
215
 
206
216
  @solara.component
207
217
  def PlotMatplotlib(model, measure, dependencies: list[any] | None = None):
218
+ """A solara component for creating a matplotlib figure.
219
+
220
+ Args:
221
+ model: Model instance
222
+ measure: measure to plot
223
+ dependencies: list of additional dependencies
224
+
225
+ """
208
226
  fig = Figure()
209
227
  ax = fig.subplots()
210
228
  df = model.datacollector.get_model_vars_dataframe()
@@ -1,3 +1,5 @@
1
+ """Support for event scheduling."""
2
+
1
3
  from .eventlist import Priority, SimulationEvent
2
4
  from .simulator import ABMSimulator, DEVSimulator
3
5
 
@@ -1,3 +1,5 @@
1
+ """Eventlist which is at the core of event scheduling."""
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import itertools
@@ -10,15 +12,17 @@ from weakref import WeakMethod, ref
10
12
 
11
13
 
12
14
  class Priority(IntEnum):
15
+ """Enumeration of priority levels."""
16
+
13
17
  LOW = 10
14
18
  DEFAULT = 5
15
19
  HIGH = 1
16
20
 
17
21
 
18
22
  class SimulationEvent:
19
- """A simulation event
23
+ """A simulation event.
20
24
 
21
- the callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
25
+ The callable is wrapped using weakref, so there is no need to explicitly cancel event if e.g., an agent
22
26
  is removed from the simulation.
23
27
 
24
28
  Attributes:
@@ -34,7 +38,7 @@ class SimulationEvent:
34
38
  _ids = itertools.count()
35
39
 
36
40
  @property
37
- def CANCELED(self) -> bool:
41
+ def CANCELED(self) -> bool: # noqa: D102
38
42
  return self._canceled
39
43
 
40
44
  def __init__(
@@ -45,6 +49,15 @@ class SimulationEvent:
45
49
  function_args: list[Any] | None = None,
46
50
  function_kwargs: dict[str, Any] | None = None,
47
51
  ) -> None:
52
+ """Initialize a simulation event.
53
+
54
+ Args:
55
+ time: the instant of time of the simulation event
56
+ function: the callable to invoke
57
+ priority: the priority of the event
58
+ function_args: arguments for callable
59
+ function_kwargs: keyword arguments for the callable
60
+ """
48
61
  super().__init__()
49
62
  if not callable(function):
50
63
  raise Exception()
@@ -64,20 +77,20 @@ class SimulationEvent:
64
77
  self.function_kwargs = function_kwargs if function_kwargs else {}
65
78
 
66
79
  def execute(self):
67
- """execute this event"""
80
+ """Execute this event."""
68
81
  if not self._canceled:
69
82
  fn = self.fn()
70
83
  if fn is not None:
71
84
  fn(*self.function_args, **self.function_kwargs)
72
85
 
73
86
  def cancel(self) -> None:
74
- """cancel this event"""
87
+ """Cancel this event."""
75
88
  self._canceled = True
76
89
  self.fn = None
77
90
  self.function_args = []
78
91
  self.function_kwargs = {}
79
92
 
80
- def __lt__(self, other):
93
+ def __lt__(self, other): # noqa
81
94
  # Define a total ordering for events to be used by the heapq
82
95
  return (self.time, self.priority, self.unique_id) < (
83
96
  other.time,
@@ -87,30 +100,31 @@ class SimulationEvent:
87
100
 
88
101
 
89
102
  class EventList:
90
- """An event list
103
+ """An event list.
91
104
 
92
105
  This is a heap queue sorted list of events. Events are always removed from the left, so heapq is a performant and
93
106
  appropriate data structure. Events are sorted based on their time stamp, their priority, and their unique_id
94
107
  as a tie-breaker, guaranteeing a complete ordering.
95
108
 
109
+
96
110
  """
97
111
 
98
112
  def __init__(self):
113
+ """Initialize an event list."""
99
114
  self._events: list[SimulationEvent] = []
100
115
  heapify(self._events)
101
116
 
102
117
  def add_event(self, event: SimulationEvent):
103
- """Add the event to the event list
118
+ """Add the event to the event list.
104
119
 
105
120
  Args:
106
121
  event (SimulationEvent): The event to be added
107
122
 
108
123
  """
109
-
110
124
  heappush(self._events, event)
111
125
 
112
126
  def peak_ahead(self, n: int = 1) -> list[SimulationEvent]:
113
- """Look at the first n non-canceled event in the event list
127
+ """Look at the first n non-canceled event in the event list.
114
128
 
115
129
  Args:
116
130
  n (int): The number of events to look ahead
@@ -139,7 +153,7 @@ class EventList:
139
153
  return peek
140
154
 
141
155
  def pop_event(self) -> SimulationEvent:
142
- """pop the first element from the event list"""
156
+ """Pop the first element from the event list."""
143
157
  while self._events:
144
158
  event = heappop(self._events)
145
159
  if not event.CANCELED:
@@ -147,16 +161,17 @@ class EventList:
147
161
  raise IndexError("Event list is empty")
148
162
 
149
163
  def is_empty(self) -> bool:
164
+ """Return whether the event list is empty."""
150
165
  return len(self) == 0
151
166
 
152
- def __contains__(self, event: SimulationEvent) -> bool:
167
+ def __contains__(self, event: SimulationEvent) -> bool: # noqa
153
168
  return event in self._events
154
169
 
155
- def __len__(self) -> int:
170
+ def __len__(self) -> int: # noqa
156
171
  return len(self._events)
157
172
 
158
173
  def __repr__(self) -> str:
159
- """Return a string representation of the event list"""
174
+ """Return a string representation of the event list."""
160
175
  events_str = ", ".join(
161
176
  [
162
177
  f"Event(time={e.time}, priority={e.priority}, id={e.unique_id})"
@@ -167,7 +182,12 @@ class EventList:
167
182
  return f"EventList([{events_str}])"
168
183
 
169
184
  def remove(self, event: SimulationEvent) -> None:
170
- """remove an event from the event list"""
185
+ """Remove an event from the event list.
186
+
187
+ Args:
188
+ event (SimulationEvent): The event to be removed
189
+
190
+ """
171
191
  # we cannot simply remove items from _eventlist because this breaks
172
192
  # heap structure invariant. So, we use a form of lazy deletion.
173
193
  # SimEvents have a CANCELED flag that we set to True, while popping and peak_ahead
@@ -175,4 +195,5 @@ class EventList:
175
195
  event.cancel()
176
196
 
177
197
  def clear(self):
198
+ """Clear the event list."""
178
199
  self._events.clear()