From 6ee37470a151c8e245a14d8eb0504b269233b603 Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Sat, 17 Aug 2024 14:34:39 +0200 Subject: [PATCH 1/4] Require Mesa models to be initialized with super.__init__() Remove the workaround for when the model super has not been called, and thereby require Mesa models to be initialized with `super.__init__()`. This warning was present since 2.3.0, so there has been some time to update for existing users. --- mesa/agent.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/mesa/agent.py b/mesa/agent.py index 2f0e842d382..df435163d1e 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -11,9 +11,7 @@ import contextlib import copy import operator -import warnings import weakref -from collections import defaultdict from collections.abc import Callable, Iterable, Iterator, MutableSet, Sequence from random import Random @@ -50,19 +48,7 @@ def __init__(self, unique_id: int, model: Model) -> None: self.pos: Position | None = None # register agent - try: - self.model.agents_[type(self)][self] = None - except AttributeError: - # model super has not been called - self.model.agents_ = defaultdict(dict) - self.model.agents_[type(self)][self] = None - self.model.agentset_experimental_warning_given = False - - warnings.warn( - "The Mesa Model class was not initialized. In the future, you need to explicitly initialize the Model by calling super().__init__() on initialization.", - FutureWarning, - stacklevel=2, - ) + self.model.agents_[type(self)][self] = None def remove(self) -> None: """Remove and delete the agent from the model.""" @@ -100,8 +86,6 @@ class AgentSet(MutableSet, Sequence): which means that agents not referenced elsewhere in the program may be automatically removed from the AgentSet. """ - agentset_experimental_warning_given = False - def __init__(self, agents: Iterable[Agent], model: Model): """ Initializes the AgentSet with a collection of agents and a reference to the model. From b90eeb0c7207c9ed39993bdc660d9d53864b7453 Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Sat, 17 Aug 2024 14:35:57 +0200 Subject: [PATCH 2/4] Name experimental warning in PropertyLayer correctly The experimental_warning_given variable in PropertyLayer was named incorrectly, probably while copying from the AgentSet. This commit fixes that. --- mesa/space.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesa/space.py b/mesa/space.py index a6d070f0291..39433cb3fad 100644 --- a/mesa/space.py +++ b/mesa/space.py @@ -586,7 +586,7 @@ class PropertyLayer: aggregate_property(operation): Performs an aggregate operation over all cells. """ - agentset_experimental_warning_given = False + propertylayer_experimental_warning_given = False def __init__( self, name: str, width: int, height: int, default_value, dtype=np.float64 @@ -633,14 +633,14 @@ def __init__( self.data = np.full((width, height), default_value, dtype=dtype) - if not self.__class__.agentset_experimental_warning_given: + if not self.__class__.propertylayer_experimental_warning_given: warnings.warn( "The new PropertyLayer and _PropertyGrid classes experimental. It may be changed or removed in any and all future releases, including patch releases.\n" "We would love to hear what you think about this new feature. If you have any thoughts, share them with us here: https://github.com/projectmesa/mesa/discussions/1932", FutureWarning, stacklevel=2, ) - self.__class__.agentset_experimental_warning_given = True + self.__class__.propertylayer_experimental_warning_given = True def set_cell(self, position: Coordinate, value): """ From 288bfcf6aa8b87acb67f2405368a8cdb8d25424f Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Sun, 18 Aug 2024 09:55:35 +0200 Subject: [PATCH 3/4] Throw error if Model super class isn't initialized You should always run super().__init__() after initializing your model class that inherits from Mesa Model. --- mesa/agent.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mesa/agent.py b/mesa/agent.py index df435163d1e..b709207fc6b 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -48,7 +48,13 @@ def __init__(self, unique_id: int, model: Model) -> None: self.pos: Position | None = None # register agent - self.model.agents_[type(self)][self] = None + try: + self.model.agents_[type(self)][self] = None + except AttributeError: + # model super has not been called + raise RuntimeError( + "The Mesa Model class was not initialized. You must explicitly initialize the Model by calling super().__init__() on initialization." + ) def remove(self) -> None: """Remove and delete the agent from the model.""" From 4047dc6b2f18d0f6199c99c747731eb5196754fc Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Sun, 18 Aug 2024 10:00:16 +0200 Subject: [PATCH 4/4] Fix ruff error B904 Added `from err` to the `raise RuntimeError` line. This links the `RuntimeError` to the original `AttributeError`, making it clear that the new exception was raised because of the `AttributeError` caught in the `try` block. --- mesa/agent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesa/agent.py b/mesa/agent.py index b709207fc6b..91655784f79 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -50,11 +50,11 @@ def __init__(self, unique_id: int, model: Model) -> None: # register agent try: self.model.agents_[type(self)][self] = None - except AttributeError: + except AttributeError as err: # model super has not been called raise RuntimeError( "The Mesa Model class was not initialized. You must explicitly initialize the Model by calling super().__init__() on initialization." - ) + ) from err def remove(self) -> None: """Remove and delete the agent from the model."""