-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Better signature and docstring for Artist.set #20569
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
Slightly changed the implementation so that the mechanism can also rewrite |
|
||
# We defer this to the end of them module, because it needs ArtistInspector | ||
# to be defined. | ||
Artist._update_set_signature_and_docstring() |
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.
Can you just move the definition of ArtistInspector above Artist and avoid this deferred call? (And then _update_set_signature_and_docstring can be inlined into init_subclass.)
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.
No strong opinion. But that's quite a bit moving of code, which makes digging in the history more complicated.
I don't think we can inline, because __init_subclass__
is not called by Artist
itself, but we want to adjust Artist.set
as well. (I wouldn't want to explicitly call __init_subclass__
on Artist
. That's more confusing than an extra function.)
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.
Let's leave things as they are for now.
lib/matplotlib/artist.py
Outdated
# docstring based on the subclasses' properties. | ||
|
||
if 'set' in cls.__dict__: | ||
return # don't overwrite set if the subclass defines set itself. |
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 think it's more if cls.set != Artist.set
(because cls could also be a subclass of a subclass that overrides set
)
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.
if cls.set != Artist.set: return
does not work:
Consider the class hierarchy Artist
-> A
-> B
. A
get's a new set
because there cls.set == Artist.set
. But B
will not get it's own set
because B.set == A.set != Artist.set
. Thus B.set will show only the properties of A
not the additional ones of B
.
We want to always define a new set
unless the class definition itself contains a set (which none of our Artists does, but some third party might have implemented a dedicated set in their derived Artists and we don't want to break that). And I think the correct way to check this is checking cls.__dict__
.
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.
which none of our Artists does, but some third party might have implemented a dedicated set in their derived Artists and we don't want to break that
My point was that if thirdpartylib defines both A and B (in your example above) where A overrides set
but B doesn't (and thus inherits A.set
), I think(?) that your current implementation will correctly leave A alone, but not B?
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.
Solved that via a flag on our autogenerated methods.
That said, I'm not 100% percent sure that this magic setter addition is what we want and downstream libraries expect. The alternative would be a class decorator, which we have to apply to all Artists; meaning adding this function would be opt-in. OTOH if nobody complains ...
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 think this is fine for now, AFAICT this will not really affect 3rd-parties now that you added the flag?
6102de5
to
4ec064f
Compare
Doc failure seems real (arising from now-referenced setters which are themselves undocumented). |
I've made docs available for a few of the offenders. There's still a more fundamental problem that private base classes are not documented. For now, I've created an explicit blacklist that will not try to link these, but instead only writes the property name as string literal. This should be good enough for the present PR. However we need a more fundamental solution for this in the long run. Probably getting rid of private base classes. |
d2654be
to
73836ad
Compare
Now it's flake8 :)
|
Will fix that tonight. 🙄 If tests were faster, I'd run them locally. But currently I'm just pushing and doing something else. |
no worries, it's the same here and for most of us I guess... |
I‘m afraid it‘s our own fault, because the figure creation is relatively slow. |
c543574
to
8acf99b
Compare
@@ -1394,6 +1488,10 @@ def aliased_name_rest(self, s, target): | |||
alias, return 'markerfacecolor or mfc' and for the transform | |||
property, which does not, return 'transform'. | |||
""" | |||
# workaround to prevent "reference target not found" | |||
if target in self._NOT_LINKABLE: |
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.
Are non-linkable targets basically the methods defined on a private parent? If so, perhaps you can just check whether the class name starts with an underscore, rather than hard coding the entire list.
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.
That's what I first thought (and checked with the print statement). Turns out it is more complicated than that.
As a general statement, a setter is not linkable if it has not doc entry. All non-private classes can (and now do) write documentation entries setters. We don't autodoc private classes, so there is no default place to document their setters. However, sublcasses may reimplement the setter and document that, or explicit entries can be created (e.g. for _AxesBase
setters).
I'm not even sure this is the whole story. Anyway, I've chosen to only explicitly backout for the properties that sphinx was complaining about. The other ones are found one way or the other.
But, point taken, we should add performance to the list of things we want to spend money on improving. |
This introduces a known blacklist of currently non-linkable items.
I don't get a gain beyond Nevertheless, 👍 spending some money on performance. This benefits tests, doc builds (I suspect a large part comes from the sphinx gallery figures), and not least also end users. |
PR Summary
First try at #19884.