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

Alternative handling for close fixes #9770

Closed
wants to merge 2 commits into from

Conversation

mikeshardmind
Copy link
Contributor

Summary

See #9769 And discussion https://discord.com/channels/336642139381301249/1222571653272309842/1222915657046167687

Presented for comparison and testability of options.

Checklist

  • If code changes were made then they have been tested.
    • I have updated the documentation to reflect the changes.
  • This PR fixes an issue.
  • This PR adds something new (e.g. new method or parameters).
  • This PR is a breaking change (e.g. methods or parameters removed/renamed)
  • This PR is not a code change (e.g. documentation, README, ...)

Comment on lines 760 to 769
def __init_subclass__(cls):
"""
This exists to ensure we retain internal wrapping around close such
that it only runs once when called directly
"""
if cls.close is not Client.close:
# This is a bound method in __init_subclass__
# There's no way to type this properly currently,
cls._user_close_method = cls.close # type: ignore
cls.close = Client.close
Copy link
Owner

Choose a reason for hiding this comment

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

Why not just do this at __init__ instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doing it here, _user_close_method ends up a bound method (note: the comment is wrong there, sorry, that should state that it results in it being a bound method, and how, I'll update the PR with that in a moment.) and the reassignment only happens at subclass definition. In __init__, it would be unbound methods and require additional wrapping with types.MethodType or passing an instance where used.

For context, this is how I would go about it if you want it done in __init__:

def __init__(self, ...):
    selftype = type(self)
    if selftype.close is not Client.close:
        self._user_close_method = types.MethodType(selftype.close, self)
        self.close = types.MethodType(Client.close, self)

There are a few reasons I'd prefer the way with __init_subclass__

__init_subclass__ is documented for this kind of modification in the python data model.

By contrast, types.MethodType is documented under a header that states:

If you instantiate any of these types, note that signatures may vary between Python versions.

I don't think the signature of it ever has been different than it is, but it's specifically left open to change, and the faster-cpython stuff was looking at method and bound method lookup costs as a place to improve performance, so I wouldn't be surprised if it does in the future.

It ends up playing nicer with the language server in VSC this way, not sure about other language servers, and should play nicer with typing after stabilization of some in-progress specification work.

It ends up putting the only part of __init__ / __subclass_init__ that's wrapping around something a user did near what relies on it in the code. It's minor, but I find that locating things that are related nearby when reasonable helps when reading code that does something strange.


Not a reason here:

The performance costs of doing this in __init__ instead are currently negligible even in a case where this would be called somewhat repeatedly across multiple instances. In the case expected here, it should remain negligible no matter what happens with faster-cpython work and is not a major reason to prefer one over the other.

@mikeshardmind mikeshardmind marked this pull request as draft March 28, 2024 21:10
@mikeshardmind
Copy link
Contributor Author

This doesn't work as-is and would need other changes which would make it more complex, closing for now, can follow up in discord later.

@mikeshardmind mikeshardmind deleted the closing-fixes2 branch March 28, 2024 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants