From 6542a70709938d633acc0af4967e037507dc3dab Mon Sep 17 00:00:00 2001 From: Floze <88098863+floze-the-genius@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:08:47 +0400 Subject: [PATCH] fix(agents): preserve string filter names --- abses/agents/sequences.py | 11 ++++++----- tests/api/test_human.py | 10 ++++++++++ tests/api/test_sequence.py | 17 +++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/abses/agents/sequences.py b/abses/agents/sequences.py index 3015fd4e..43d6bc17 100644 --- a/abses/agents/sequences.py +++ b/abses/agents/sequences.py @@ -213,7 +213,7 @@ def to_dict(self) -> Dict[str, ActorsList[A]]: def select( self, - filter_func: Callable[[A], bool] | None = None, + filter_func: Callable[[A], bool] | dict[str, Any] | str | None = None, at_most: int | float = float("inf"), inplace: bool = False, agent_type: Agent | None = None, @@ -253,16 +253,17 @@ def select( ``` """ if isinstance(filter_func, dict): - key_value_paris = filter_func + key_value_pairs = filter_func def filter_func(agent: Agent) -> bool: - return all(getattr(agent, k) == v for k, v in key_value_paris.items()) + return all(getattr(agent, k) == v for k, v in key_value_pairs.items()) if isinstance(filter_func, str): + attr_name = filter_func def filter_func(agent: Agent) -> bool: - # 如果 filter_func 是字符串,则使用该字符串作为过滤条件 - return getattr(agent, filter_func) + # Preserve the name before rebinding filter_func to this closure. + return getattr(agent, attr_name) objects = super().select(filter_func, at_most, inplace, agent_type) return ActorsList(self._model, objects) diff --git a/tests/api/test_human.py b/tests/api/test_human.py index 5ed66a3c..12610a6d 100644 --- a/tests/api/test_human.py +++ b/tests/api/test_human.py @@ -22,6 +22,16 @@ def test_human_attributes(self, human, farmer_cls, admin_cls): assert len(human.agents) == 10 +def test_human_module_actors(farmer_cls, cell_0_0): + """HumanModule.actors returns only its actors placed on earth.""" + model = cell_0_0.model + on_earth = cell_0_0.agents.new(farmer_cls, 2) + model.agents.new(farmer_cls, 1) + module = model.human.create_module("farmers", agent_type=farmer_cls) + + assert list(module.actors) == list(on_earth) + + def test_human_define(model, farmer_cls, admin_cls): """测试人口的定义""" human = model.human diff --git a/tests/api/test_sequence.py b/tests/api/test_sequence.py index 5be26bbf..57c23e34 100644 --- a/tests/api/test_sequence.py +++ b/tests/api/test_sequence.py @@ -18,6 +18,23 @@ class TestSequences: """Test Sequence""" + @pytest.mark.parametrize( + "selection", + [ + pytest.param("enabled", id="string"), + pytest.param({"enabled": True}, id="dict"), + pytest.param(lambda actor: actor.enabled, id="callable"), + ], + ) + def test_select_filter_forms(self, model: MainModel, selection): + """Select actors with every documented filter form.""" + actors = model.agents.new(Actor, 3) + actors.update("enabled", [True, False, True]) + + selected = actors.select(selection) + + assert list(selected) == [actors[0], actors[2]] + def test_sequences_attributes(self, model, farmer_cls): """测试容器的属性""" # arrange