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

Update migration_guide.md #2347

Merged
merged 5 commits into from
Oct 17, 2024
Merged

Update migration_guide.md #2347

merged 5 commits into from
Oct 17, 2024

Conversation

quaquel
Copy link
Member

@quaquel quaquel commented Oct 12, 2024

This is a minor expansion to using super in Model. I explicate how to handle the seed keyword argument, and briefly state something about how to handle arguments and keyword arguments via super.

@quaquel quaquel added the docs Release notes label label Oct 12, 2024
@quaquel quaquel requested a review from EwoutH October 12, 2024 10:27
def __init__(self, *args, **kwargs):
super().__init__() # This is now required!
def __init__(self, some_arg_I_need, *args, seed=None, my_init_kwarg=True, **kwargs):
super().__init__(*args, seed=seed, **kwargs) # This is now required!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the *args, **kwargs here essential for the Model class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not for the class itself but for proper use of super. See my remark above the code on this.

@EwoutH
Copy link
Member

EwoutH commented Oct 14, 2024

I found the super().__init__(*args, seed=seed, **kwargs) so ugly I started to find some creative ways around it.

One problem, why we have to call super().__init__() at all, is that we advise users to override the Model __init__ method, and then fix that by calling super().__init__().

Maybe that doesn't have to be that way. What is if we recommend users to put their setup code into a differently named method, so the Model.__init__ does get overridden?

In our model, we now call a new setup (or initialize) function in the init by default:

class Model:
    def __init__(self, seed: Optional[float] = None, **kwargs: Any) -> None:
        self.running = True
        self.steps: int = 0
        self._seed = seed if seed is not None else random.random()
        self.random = random.Random(self._seed)
        self._setup_agent_registration()
        
        # Remove 'seed' from kwargs before passing to setup
        kwargs.pop('seed', None)
        # Call user-defined setup
        self.setup(**kwargs)

    def setup(self, **kwargs: Any) -> None:
        """
        User-defined setup method.
        Subclasses should override this method instead of __init__.
        """
        pass

We request users to override setup instead of __init__. Their model then looks something like this:

class MyModel(Model):
    def setup(self, param1: int, param2: str):
        self.param1 = param1
        self.param2 = param2
        # Additional setup logic...

    def step(self):
        # Model step logic...
        pass

# Usage
model = MyModel(seed=42, param1=10, param2="example")

Which I find to look extremely clean.

As an additional advantage, we can now more easily modify the order of Model arguments, rename ones or add new ones without breaking user models, because we can handle all that (and throw warnings if necessary, etc.

We never have to be afraid an user doesn't call the super().__init__() incorrectly, because we simply don't allow overriding it anymore.

This is the most breaking change of changes, but I think it allows for so much flexibility in the future that it might be worth it.

@quaquel
Copy link
Member Author

quaquel commented Oct 14, 2024

I am not against shifting to having a model setup method, but that probably deserves its own discussion rather than discuss it here in this PR. This PR really is about making sure seed is handled correctly in the migration guide.

@quaquel
Copy link
Member Author

quaquel commented Oct 17, 2024

@EwoutH in line with our conversation, I simplified the migration guide and not bother with the *args and *kwargs and just explicitly only pass seed to super. This is what 95% of users needs. The *args, **kwargs stuff is only relevant when having a class hierarchy that includes other super classes next to Model. Users that do this should be well equipped to understand how to make that work themselves.

Copy link
Member

@EwoutH EwoutH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for cleaning it up!

@quaquel quaquel merged commit 42880ac into projectmesa:main Oct 17, 2024
1 of 2 checks passed
@quaquel quaquel deleted the migration_super branch October 25, 2024 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Release notes label
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants