From 32851c9820190782429676a092add6822453f8f8 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Mon, 3 Nov 2025 19:21:13 +0100 Subject: [PATCH 1/6] turn HasCell and FixedCell into descriptors --- mesa/discrete_space/cell_agent.py | 75 ++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index b45a0634043..60fde8c839d 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -28,26 +28,50 @@ class HasCellProtocol(Protocol): class HasCell: - """Descriptor for cell movement behavior.""" - _mesa_cell: Cell | None = None + def __get__(self, obj: Agent, type=None) -> Cell | None: + return getattr(obj,self._private_name) - @property - def cell(self) -> Cell | None: # noqa: D102 - return self._mesa_cell + def __set__(self, obj: Agent, value:Cell) -> None: + try: + current_cell = getattr(obj, self._private_name) + except AttributeError: + current_cell = None - @cell.setter - def cell(self, cell: Cell | None) -> None: # remove from current cell - if self.cell is not None: - self.cell.remove_agent(self) + if current_cell is not None: + current_cell.remove_agent(obj) - # update private attribute - self._mesa_cell = cell + setattr(obj, self._private_name, value) # add to new cell - if cell is not None: - cell.add_agent(self) + if value is not None: + value.add_agent(obj) + + def __set_name__(self, owner: Agent, name) -> None: + self._private_name = f"_{name}" + +# class HasCell: +# """Descriptor for cell movement behavior.""" +# +# _mesa_cell: Cell | None = None +# +# @property +# def cell(self) -> Cell | None: # noqa: D102 +# return self._mesa_cell +# +# @cell.setter +# def cell(self, cell: Cell | None) -> None: +# # remove from current cell +# if self.cell is not None: +# self.cell.remove_agent(self) +# +# # update private attribute +# self._mesa_cell = cell +# +# # add to new cell +# if cell is not None: +# cell.add_agent(self) class BasicMovement: @@ -71,27 +95,27 @@ def move_relative(self: HasCellProtocol, direction: tuple[int, ...]): class FixedCell(HasCell): - """Mixin for agents that are fixed to a cell.""" + """Descriptor for agents that are fixed to a cell.""" - @property - def cell(self) -> Cell | None: # noqa: D102 - return self._mesa_cell + def __set__(self, obj: Agent, value:Cell) -> None: + try: + current_cell = getattr(obj, self._private_name) + except AttributeError: + current_cell = None - @cell.setter - def cell(self, cell: Cell) -> None: - if self.cell is not None: + if current_cell is not None: raise ValueError("Cannot move agent in FixedCell") - self._mesa_cell = cell + setattr(obj, self._private_name, value) + value.add_agent(obj) - cell.add_agent(self) - -class CellAgent(Agent, HasCell, BasicMovement): +class CellAgent(Agent, BasicMovement): """Cell Agent is an extension of the Agent class and adds behavior for moving in discrete spaces. Attributes: cell (Cell): The cell the agent is currently in. """ + cell = HasCell() def remove(self): """Remove the agent from the model.""" @@ -99,8 +123,9 @@ def remove(self): self.cell = None # ensures that we are also removed from cell -class FixedAgent(Agent, FixedCell): +class FixedAgent(Agent): """A patch in a 2D grid.""" + cell = FixedCell() def remove(self): """Remove the agent from the model.""" From 1d7da42afad46ab2a0e42bd8dccc1a24f8043684 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:26:02 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/discrete_space/cell_agent.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index 60fde8c839d..b674898160d 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -28,11 +28,10 @@ class HasCellProtocol(Protocol): class HasCell: - def __get__(self, obj: Agent, type=None) -> Cell | None: - return getattr(obj,self._private_name) + return getattr(obj, self._private_name) - def __set__(self, obj: Agent, value:Cell) -> None: + def __set__(self, obj: Agent, value: Cell) -> None: try: current_cell = getattr(obj, self._private_name) except AttributeError: @@ -51,13 +50,14 @@ def __set__(self, obj: Agent, value:Cell) -> None: def __set_name__(self, owner: Agent, name) -> None: self._private_name = f"_{name}" + # class HasCell: # """Descriptor for cell movement behavior.""" # # _mesa_cell: Cell | None = None # # @property -# def cell(self) -> Cell | None: # noqa: D102 +# def cell(self) -> Cell | None: # return self._mesa_cell # # @cell.setter @@ -97,7 +97,7 @@ def move_relative(self: HasCellProtocol, direction: tuple[int, ...]): class FixedCell(HasCell): """Descriptor for agents that are fixed to a cell.""" - def __set__(self, obj: Agent, value:Cell) -> None: + def __set__(self, obj: Agent, value: Cell) -> None: try: current_cell = getattr(obj, self._private_name) except AttributeError: @@ -115,6 +115,7 @@ class CellAgent(Agent, BasicMovement): Attributes: cell (Cell): The cell the agent is currently in. """ + cell = HasCell() def remove(self): @@ -125,6 +126,7 @@ def remove(self): class FixedAgent(Agent): """A patch in a 2D grid.""" + cell = FixedCell() def remove(self): From 65548a876eebc41fa34dd7effc41387707551ee7 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Mon, 3 Nov 2025 19:31:05 +0100 Subject: [PATCH 3/6] Update cell_agent.py --- mesa/discrete_space/cell_agent.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index b674898160d..43c60d631c6 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -28,10 +28,13 @@ class HasCellProtocol(Protocol): class HasCell: - def __get__(self, obj: Agent, type=None) -> Cell | None: - return getattr(obj, self._private_name) + def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 + try: + return getattr(obj, self._private_name) + except AttributeError: + return None - def __set__(self, obj: Agent, value: Cell) -> None: + def __set__(self, obj: Agent, value:Cell) -> None: # noqa: D105 try: current_cell = getattr(obj, self._private_name) except AttributeError: @@ -47,7 +50,7 @@ def __set__(self, obj: Agent, value: Cell) -> None: if value is not None: value.add_agent(obj) - def __set_name__(self, owner: Agent, name) -> None: + def __set_name__(self, owner: Agent, name) -> None: # noqa: D105 self._private_name = f"_{name}" @@ -97,7 +100,7 @@ def move_relative(self: HasCellProtocol, direction: tuple[int, ...]): class FixedCell(HasCell): """Descriptor for agents that are fixed to a cell.""" - def __set__(self, obj: Agent, value: Cell) -> None: + def __set__(self, obj: Agent, value:Cell) -> None: # noqa: D105 try: current_cell = getattr(obj, self._private_name) except AttributeError: From 22e783b503dab57913ba79e16f279bfc6fb85ed1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:32:15 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/discrete_space/cell_agent.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index 43c60d631c6..5567fb4322f 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -28,13 +28,13 @@ class HasCellProtocol(Protocol): class HasCell: - def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 + def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 try: return getattr(obj, self._private_name) except AttributeError: return None - def __set__(self, obj: Agent, value:Cell) -> None: # noqa: D105 + def __set__(self, obj: Agent, value: Cell) -> None: # noqa: D105 try: current_cell = getattr(obj, self._private_name) except AttributeError: @@ -50,7 +50,7 @@ def __set__(self, obj: Agent, value:Cell) -> None: # noqa: D105 if value is not None: value.add_agent(obj) - def __set_name__(self, owner: Agent, name) -> None: # noqa: D105 + def __set_name__(self, owner: Agent, name) -> None: # noqa: D105 self._private_name = f"_{name}" @@ -100,7 +100,7 @@ def move_relative(self: HasCellProtocol, direction: tuple[int, ...]): class FixedCell(HasCell): """Descriptor for agents that are fixed to a cell.""" - def __set__(self, obj: Agent, value:Cell) -> None: # noqa: D105 + def __set__(self, obj: Agent, value: Cell) -> None: # noqa: D105 try: current_cell = getattr(obj, self._private_name) except AttributeError: From c4801ca4abfa5c6abfba10122b46e717b7c1aff5 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Mon, 3 Nov 2025 19:33:06 +0100 Subject: [PATCH 5/6] ruff related and test related fixes --- mesa/discrete_space/cell_agent.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index 5567fb4322f..5e2a9c65d41 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -28,7 +28,9 @@ class HasCellProtocol(Protocol): class HasCell: - def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 + """Descriptor for agents have a cell.""" + + def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 try: return getattr(obj, self._private_name) except AttributeError: From 2e264be0059a6db856dce35d5fa33a75636a57c8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:33:35 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/discrete_space/cell_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesa/discrete_space/cell_agent.py b/mesa/discrete_space/cell_agent.py index 5e2a9c65d41..a811174f726 100644 --- a/mesa/discrete_space/cell_agent.py +++ b/mesa/discrete_space/cell_agent.py @@ -30,7 +30,7 @@ class HasCellProtocol(Protocol): class HasCell: """Descriptor for agents have a cell.""" - def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 + def __get__(self, obj: Agent, type=None) -> Cell | None: # noqa: D105 try: return getattr(obj, self._private_name) except AttributeError: