Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Merged
merged 2 commits into from
Jul 7, 2021

Conversation

timhoffm
Copy link
Member

@timhoffm timhoffm commented Jul 3, 2021

PR Summary

First try at #19884.

@tacaswell tacaswell added this to the v3.5.0 milestone Jul 3, 2021
@timhoffm
Copy link
Member Author

timhoffm commented Jul 3, 2021

Slightly changed the implementation so that the mechanism can also rewrite Artist.set itself.


# We defer this to the end of them module, because it needs ArtistInspector
# to be defined.
Artist._update_set_signature_and_docstring()
Copy link
Contributor

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.)

Copy link
Member Author

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.)

Copy link
Contributor

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.

# docstring based on the subclasses' properties.

if 'set' in cls.__dict__:
return # don't overwrite set if the subclass defines set itself.
Copy link
Contributor

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)

Copy link
Member Author

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__.

Copy link
Contributor

@anntzer anntzer Jul 4, 2021

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?

Copy link
Member Author

@timhoffm timhoffm Jul 4, 2021

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 ...

Copy link
Contributor

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?

@timhoffm timhoffm force-pushed the axes-set branch 3 times, most recently from 6102de5 to 4ec064f Compare July 4, 2021 21:01
@anntzer
Copy link
Contributor

anntzer commented Jul 5, 2021

Doc failure seems real (arising from now-referenced setters which are themselves undocumented).

@timhoffm
Copy link
Member Author

timhoffm commented Jul 5, 2021

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.

@timhoffm timhoffm force-pushed the axes-set branch 2 times, most recently from d2654be to 73836ad Compare July 5, 2021 22:35
@anntzer
Copy link
Contributor

anntzer commented Jul 6, 2021

Now it's flake8 :)

Error: [flake8] reported by reviewdog 🐶
F401 '.docstring' imported but unused

Raw Output:
./lib/matplotlib/artist.py:14:1: F401 '.docstring' imported but unused
Error: [flake8] reported by reviewdog 🐶
F811 redefinition of unused 'docstring' from line 14

Raw Output:
./lib/matplotlib/artist.py:1372:9: F811 redefinition of unused 'docstring' from line 14
Error: Process completed with exit code 1.

@timhoffm
Copy link
Member Author

timhoffm commented Jul 6, 2021

Will fix that tonight.

🙄 If tests were faster, I'd run them locally. But currently I'm just pushing and doing something else.
@anntzer Thanks for for pointing out the reasons for the failures. I care for them as they come along, but turnaround times can be a couple of hours to a day because I'm only intermittently working on Matplotlib.

@anntzer
Copy link
Contributor

anntzer commented Jul 6, 2021

no worries, it's the same here and for most of us I guess...

@timhoffm
Copy link
Member Author

timhoffm commented Jul 6, 2021

I‘m afraid it‘s our own fault, because the figure creation is relatively slow.

@timhoffm timhoffm force-pushed the axes-set branch 2 times, most recently from c543574 to 8acf99b Compare July 6, 2021 19:04
@@ -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:
Copy link
Contributor

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.

Copy link
Member Author

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.

@tacaswell
Copy link
Member

pytest -n 8 makes the tests go faster!

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.
@timhoffm
Copy link
Member Author

timhoffm commented Jul 6, 2021

I don't get a gain beyond pytest -n 4 (@ 4core+hyperthreading), which is a bit more than 4min on my machine. That's actually better than I thought and still bearable. The docs build is a bigger pain point.

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.

@anntzer anntzer merged commit 92825fe into matplotlib:master Jul 7, 2021
@timhoffm timhoffm deleted the axes-set branch July 7, 2021 07:09
@timhoffm timhoffm mentioned this pull request Jul 13, 2021
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.

3 participants