Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement empty iterable handling and its corresponding tests in batchrunner.py file. #2522

15 changes: 14 additions & 1 deletion mesa/batchrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,14 @@ def _make_model_kwargs(
Parameters
----------
parameters : Mapping[str, Union[Any, Iterable[Any]]]
Single or multiple values for each model parameter name
Single or multiple values for each model parameter name.

Allowed values for each parameter:
- A single value (e.g., `32`, `"relu"`).
- A non-empty iterable (e.g., `[0.01, 0.1]`, `["relu", "sigmoid"]`).

Not allowed:
- Empty lists or empty iterables (e.g., `[]`, `()`, etc.). These should be removed manually.

Returns:
-------
Expand All @@ -118,6 +125,12 @@ def _make_model_kwargs(
if isinstance(values, str):
# The values is a single string, so we shouldn't iterate over it.
all_values = [(param, values)]
elif isinstance(values, list | tuple | set) and len(values) == 0:
# If it's an empty iterable, raise an error
raise ValueError(
f"Parameter '{param}' contains an empty iterable, which is not allowed."
)

else:
try:
all_values = [(param, value) for value in values]
Expand Down
23 changes: 17 additions & 6 deletions mesa/examples/basic/schelling/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

def __init__(self, model, agent_type: int) -> None:
"""Create a new Schelling agent.

Args:
model: The model instance the agent belongs to
agent_type: Indicator for the agent's type (minority=1, majority=0)
Expand All @@ -20,11 +19,23 @@
self.pos, moore=True, radius=self.model.radius
)

# Count similar neighbors
similar = sum(neighbor.type == self.type for neighbor in neighbors)
valid_neighbors = 0
similar_neighbors = 0

for neighbor in neighbors:
if hasattr(neighbor, "type"): # Exclude empty cells
valid_neighbors += 1
if neighbor.type == self.type: # Count similar neighbors
similar_neighbors += 1

# Calculate the fraction of similar neighbors
if valid_neighbors > 0:
similarity_fraction = similar_neighbors / valid_neighbors

# If unhappy, move to a random empty cell:
if similar < self.model.homophily:
self.model.grid.move_to_empty(self)
# If unhappy, move to a random empty cell
if similarity_fraction < self.model.homophily:
self.model.grid.move_to_empty(self)
else:
self.model.happy += 1

Check warning on line 39 in mesa/examples/basic/schelling/agents.py

View check run for this annotation

Codecov / codecov/patch

mesa/examples/basic/schelling/agents.py#L39

Added line #L39 was not covered by tests
else:
self.model.happy += 1
2 changes: 1 addition & 1 deletion mesa/examples/basic/schelling/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def agent_portrayal(agent):
},
"density": Slider("Agent density", 0.8, 0.1, 1.0, 0.1),
"minority_pc": Slider("Fraction minority", 0.2, 0.0, 1.0, 0.05),
"homophily": Slider("Homophily", 3, 0, 8, 1),
"homophily": Slider("Homophily", 0.3, 0.0, 0.8, 0.1),
"width": 20,
"height": 20,
}
Expand Down
31 changes: 31 additions & 0 deletions tests/test_batch_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,37 @@ def test_make_model_kwargs(): # noqa: D103
assert _make_model_kwargs({"a": "value"}) == [{"a": "value"}]


def test_batch_run_with_params_with_empty_content():
"""Test handling of empty iterables in model kwargs."""
# If "a" is a single value and "b" is an empty list (should raise error for the empty list)
parameters_with_empty_list = {
"a": 3,
"b": [],
}

try:
_make_model_kwargs(parameters_with_empty_list)
raise AssertionError(
"Expected ValueError for empty iterable but no error was raised."
)
except ValueError as e:
assert "contains an empty iterable" in str(e)

# If "a" is a iterable and "b" is an empty list (should still raise error)
parameters_with_empty_b = {
"a": [1, 2],
"b": [],
}

try:
_make_model_kwargs(parameters_with_empty_b)
raise AssertionError(
"Expected ValueError for empty iterable but no error was raised."
)
except ValueError as e:
assert "contains an empty iterable" in str(e)


class MockAgent(Agent):
"""Minimalistic agent implementation for testing purposes."""

Expand Down
Loading