ENH: Accept Scenario as class or instance in Model init#3450
ENH: Accept Scenario as class or instance in Model init#3450Nithurshen wants to merge 4 commits intomesa:mainfrom
Conversation
| if scenario is not None: | ||
| if rng is not None and (scenario.rng != rng): | ||
| # Handle scenario if it is a class, instance, or None | ||
| if isinstance(scenario, type) and issubclass(scenario, Scenario): |
There was a problem hiding this comment.
Did we not agree to raise probably a TypeError if scenario is not a subclass?
There was a problem hiding this comment.
At some point you said:
I don't want to force users to subclass Scenario to make any of this work.
It that still your current view?
There was a problem hiding this comment.
Both can be true: use the default Scenario class for just the rng and pass the rest as keyword arguments. But yes, it's a fair question. Looking at the open PRs on simplifying the examples, I like the cleaner code with scenario subclasses.
| # It's an instance, check if rng matches | ||
| if rng is not None and scenario.rng != rng: | ||
| raise ValueError("rng and scenario.rng must be the same") | ||
| else: | ||
| rng = scenario.rng | ||
| rng = scenario.rng |
There was a problem hiding this comment.
@quaquel how would you like to handle this long term? Always put rng in Scenario, keep it as something separate, something else?
There was a problem hiding this comment.
So we can deprecate/remove inputting rng directly? Only allow rng to be passed as part of a Scenario?
There was a problem hiding this comment.
yes, but keep that out of this PR. I hope to write up some stuff on replacing batchrunner soon and this will be included in that.
|
Thanks for the effort. @quaquel indicated that he wanted to give a stab to solve this more integrally, including resolving |
|
closing this in favor of #3493 |
Pre-PR Checklist
Approval Link
Closes #3435
Summary
This PR updates the
Modelclass initialization to accept aScenarioclass directly, automatically instantiating it with the appropriate default or providedrng. It maintains full backwards compatibility by continuing to support pre-instantiatedScenarioobjects orNone.Motive
The current pattern for wiring Scenarios into Models creates unnecessary boilerplate code in every model subclass (e.g., manually checking
if scenario is None:). By allowing aScenarioclass to be passed directly, developers can use the class as a default argument in their model's signature. This improves code readability, enables proper IDE autocomplete, and allows tools like SolaraViz orbatch_runto easily inspect default parameters.Implementation
mesa/model.py:Model.__init__type hints to accept a Scenario class (scenario: S | type[S] | None = None).scenariois a class (isinstance(scenario, type) and issubclass(scenario, Scenario)). If so, it instantiates the scenario using the resolvedrng.Scenarioinstances andNonefallbacks.tests/test_model.py: Added a new test,test_model_scenario_initialization, which verifies the behavior when passingNone, a pre-configuredScenarioinstance, and a customScenarioclass.Usage Examples
Before:
After:
Additional Notes
All existing tests and the newly added
test_model_scenario_initializationpass locally.