-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Shorten various offsetbox implementations #21699
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
Conversation
3512233
to
00b5604
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO this change would make get_offset()
basically unusable because users can't know whether they have to pass any parameters. We can't have that on public API.
@@ -272,23 +272,15 @@ def offset(width, height, xdescent, ydescent, renderer) \ | |||
self._offset = xy | |||
self.stale = True | |||
|
|||
def get_offset(self, width, height, xdescent, ydescent, renderer): | |||
def get_offset(self, *args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is deeply confusing. It's almost impossible for the user to figure out whether he has to pass anything and if so what. We can't have that on public API. At the very least, you should make the parameters explicit
def get_offset(self, *args, **kwargs): | |
def get_offset(self, width=None, height=None, xdescent=None, ydescent=None, renderer=None): |
But even with that I'm very concerned with the API. "The method needs arguments depending on the subclass and/or some configurable state." is not a contract you can program against. It's bad enough that we currently have the inconsistency that some subclasses do not take arguments. But at least that's explicit and when you know the class, you know what to pass. This change here would make that more implicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still propose to leave the parameters explicit until they are removed completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way the API currently is is just as bad though. In some cases you have to pass arguments .... just for us to drop them on the floor!
I think that this is going the right direction (no inputs anywhere), but I think I agree we need more steps to get there.
00b5604
to
3fd822c
Compare
I agree the API is pretty confusing, but that's what it was before. Still, it can be improved (last commit now) by making the callables passed to set_offset take no arguments whatsoever (they can call get_extent themselves), and therefore make get_offset also take no arguments. For backcompat I maintained the ability to pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing all parameters from get_offset() seems like a good way forward. Maybe we should even deprecate right now to give more direction and not have to word ourselves through what can or should be passed.
@@ -272,23 +272,15 @@ def offset(width, height, xdescent, ydescent, renderer) \ | |||
self._offset = xy | |||
self.stale = True | |||
|
|||
def get_offset(self, width, height, xdescent, ydescent, renderer): | |||
def get_offset(self, *args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still propose to leave the parameters explicit until they are removed completely.
Making args to get_offset explicit makes everything much more complicated, because now I need to check the signature of self._offset (if it is a callable) to decide whether to pass args or not (even if you make the signature |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having get_offset callables without parameters might be an improvement. - I'm not even too sure whether these changes are worth it.
But the API is getting really messy and we need to thoroughly document it if we want to go that direction.
Done (with minor rewordings on top of the proposed docs). |
4af7bb0
to
6045113
Compare
@tacaswell has told me that the message makes sense from the contents, but that last commit message is a bit inscrutable at first glance. |
By making the parameters of OffsetBox.get_offset optional (which matches the fact that there are currently subclasses for which get_offset does *not* take any parameters), and adjusting OffsetBox.get_window_extent to use get_extent (which is typically redefined in subclasses) instead of get_extent_offsets (which is not), we can inherit the implementation of OffsetBox.get_window_extent across most subclasses instead of having to copy-paste it again and again.
It is only called in `get_window_extent` -- and in `draw`, but *that* call is immediately followed by a call to `get_window_extent`, so it is redundant.
Agreed, is the new title better? :) |
@@ -263,32 +263,35 @@ def set_offset(self, xy): | |||
xy : (float, float) or callable | |||
The (x, y) coordinates of the offset in display units. These can | |||
either be given explicitly as a tuple (x, y), or by providing a | |||
function that converts the extent into the offset. This function | |||
must have the signature:: | |||
function that dynamically computes an offset (taking the arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs an API change note.
@@ -357,7 +362,7 @@ def draw(self, renderer): | |||
to the given *renderer*. | |||
""" | |||
w, h, xdescent, ydescent, offsets = self.get_extent_offsets(renderer) | |||
px, py = self.get_offset(w, h, xdescent, ydescent, renderer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any user who has used set_offset
with a callable will be broken by this (as they no longer get the inputs they expect).
This behavior / signature goes back to 3ae9221 which is related to mouse-draggable artists. I do not feel I understand why it was there to begin with to be confident ripping it out. |
Moved to draft. Seems to at least need an Api note, and response to comments above |
PR Summary
1st commit: Inherit OffsetBox.{get_offset,get_window_extent}.
By making the parameters of OffsetBox.get_offset optional (which matches
the fact that there are currently subclasses for which get_offset does
not take any parameters), and adjusting OffsetBox.get_window_extent to
use get_extent (which is typically redefined in subclasses) instead of
get_extent_offsets (which is not), we can inherit the implementation of
OffsetBox.get_window_extent across most subclasses instead of having to
copy-paste it again and again.
2nd commit: Inline AnchoredOffsetBox._update_offset_func.
It is only called in
get_window_extent
-- and indraw
, but thatcall is immediately followed by a call to
get_window_extent
, so it isredundant.
PR Checklist
Tests and Styling
pytest
passes).flake8-docstrings
and runflake8 --docstring-convention=all
).Documentation
doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).