From a556b3996b9de74134963265834937979f57ca41 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Thu, 18 Jan 2024 20:41:22 +0100 Subject: [PATCH 1/4] backward compatability fix fix in case user is using model.agents --- mesa/agent.py | 6 +++--- mesa/model.py | 29 +++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/mesa/agent.py b/mesa/agent.py index 8688dc702a4..fcf643d3289 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -50,10 +50,10 @@ def __init__(self, unique_id: int, model: Model) -> None: # register agent try: - self.model._agents[type(self)][self] = None + self.model.agents_[type(self)][self] = None except AttributeError: # model super has not been called - self.model._agents = defaultdict(dict) + self.model.agents_ = defaultdict(dict) self.model.agentset_experimental_warning_given = False warnings.warn( @@ -65,7 +65,7 @@ def __init__(self, unique_id: int, model: Model) -> None: def remove(self) -> None: """Remove and delete the agent from the model.""" with contextlib.suppress(KeyError): - self.model._agents[type(self)].pop(self) + self.model.agents_[type(self)].pop(self) def step(self) -> None: """A single step of the agent.""" diff --git a/mesa/model.py b/mesa/model.py index ca0c653cd30..fa67743379a 100644 --- a/mesa/model.py +++ b/mesa/model.py @@ -9,6 +9,7 @@ import itertools import random +import warnings from collections import defaultdict # mypy @@ -29,7 +30,7 @@ class Model: running: A boolean indicating if the model should continue running. schedule: An object to manage the order and execution of agent steps. current_id: A counter for assigning unique IDs to agents. - _agents: A defaultdict mapping each agent type to a dict of its instances. + agents_: A defaultdict mapping each agent type to a dict of its instances. This private attribute is used internally to manage agents. Properties: @@ -65,7 +66,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.running = True self.schedule = None self.current_id = 0 - self._agents: defaultdict[type, dict] = defaultdict(dict) + self.agents_: defaultdict[type, dict] = defaultdict(dict) # Warning flags for current experimental features. These make sure a warning is only printed once per model. self.agentset_experimental_warning_given = False @@ -73,19 +74,31 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: @property def agents(self) -> AgentSet: """Provides an AgentSet of all agents in the model, combining agents from all types.""" - all_agents = itertools.chain( - *(agents_by_type.keys() for agents_by_type in self._agents.values()) - ) - return AgentSet(all_agents, self) + + if hasattr(self, "_agents"): + return self._agents + else: + + all_agents = itertools.chain( + *(agents_by_type.keys() for agents_by_type in self.agents_.values()) + ) + return AgentSet(all_agents, self) + + @agents.setter + def agents(self, agents: Any) -> None: + warnings.warn("You are trying to set model.agents. In a next release, this attribute is used " + "by MESA itself so you cannot use it directly anymore.", UserWarning) + + self._agents = agents @property def agent_types(self) -> list[type]: """Return a list of different agent types.""" - return list(self._agents.keys()) + return list(self.agents_.keys()) def get_agents_of_type(self, agenttype: type[Agent]) -> AgentSet: """Retrieves an AgentSet containing all agents of the specified type.""" - return AgentSet(self._agents[agenttype].keys(), self) + return AgentSet(self.agents_[agenttype].keys(), self) def run_model(self) -> None: """Run the model until the end condition is reached. Overload as From 6fd91d205a950933f5dc8d8d2da654155d57ede7 Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Thu, 18 Jan 2024 21:39:44 +0100 Subject: [PATCH 2/4] processed feedback --- mesa/model.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mesa/model.py b/mesa/model.py index fa67743379a..5903ec2f6c3 100644 --- a/mesa/model.py +++ b/mesa/model.py @@ -79,7 +79,7 @@ def agents(self) -> AgentSet: return self._agents else: - all_agents = itertools.chain( + all_agents = itertools.chain.from_iterable( *(agents_by_type.keys() for agents_by_type in self.agents_.values()) ) return AgentSet(all_agents, self) @@ -87,7 +87,9 @@ def agents(self) -> AgentSet: @agents.setter def agents(self, agents: Any) -> None: warnings.warn("You are trying to set model.agents. In a next release, this attribute is used " - "by MESA itself so you cannot use it directly anymore.", UserWarning) + "by MESA itself so you cannot use it directly anymore." + "Please adjust your code to use a different attribute name for custom agent storage" + , UserWarning, stacklevel=2) self._agents = agents From c14e492db5a852c3e311cdc95f41483154cb6ddb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:42:20 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/model.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mesa/model.py b/mesa/model.py index 5903ec2f6c3..9023e076af5 100644 --- a/mesa/model.py +++ b/mesa/model.py @@ -78,7 +78,6 @@ def agents(self) -> AgentSet: if hasattr(self, "_agents"): return self._agents else: - all_agents = itertools.chain.from_iterable( *(agents_by_type.keys() for agents_by_type in self.agents_.values()) ) @@ -86,10 +85,13 @@ def agents(self) -> AgentSet: @agents.setter def agents(self, agents: Any) -> None: - warnings.warn("You are trying to set model.agents. In a next release, this attribute is used " - "by MESA itself so you cannot use it directly anymore." - "Please adjust your code to use a different attribute name for custom agent storage" - , UserWarning, stacklevel=2) + warnings.warn( + "You are trying to set model.agents. In a next release, this attribute is used " + "by MESA itself so you cannot use it directly anymore." + "Please adjust your code to use a different attribute name for custom agent storage", + UserWarning, + stacklevel=2, + ) self._agents = agents From 12fe8521b3cfdb6d97dd4a66eda60f0aef5a7d8d Mon Sep 17 00:00:00 2001 From: Jan Kwakkel Date: Thu, 18 Jan 2024 21:50:46 +0100 Subject: [PATCH 4/4] Update model.py me being stupid --- mesa/model.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mesa/model.py b/mesa/model.py index 9023e076af5..1bd9b3a7548 100644 --- a/mesa/model.py +++ b/mesa/model.py @@ -78,9 +78,7 @@ def agents(self) -> AgentSet: if hasattr(self, "_agents"): return self._agents else: - all_agents = itertools.chain.from_iterable( - *(agents_by_type.keys() for agents_by_type in self.agents_.values()) - ) + all_agents = itertools.chain.from_iterable(self.agents_.values()) return AgentSet(all_agents, self) @agents.setter