Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Generate pyplot wrappers at runtime#25422

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
QuLogic wants to merge2 commits intomatplotlib:main
base:main
Choose a base branch
Loading
fromQuLogic:runtime-pyplot

Conversation

QuLogic
Copy link
Member

PR Summary

When looking at#24976, I was wondering if we could dropblack for it, but that seemed to be fairly difficult. But then I wondered if we really needed to generate all this text that needed to passflake8 in the first place.

So this removes the need for a boilerplate and various templates that need to be generated and pass flake8. Now that module-level__getattr__ exists, we don't need to pay the full penalty of generating everything on import, and can amortize that over every function call.

As a downside, the wrappers no longer have explicit parameters, so argument errors are raised from the original
methods, which may be confusing. There is currently one test that fails because of this, but it could be fixed if we are okay with this.

This also includes#12743, in order to more explicitly define what's in the file. I didnot yet re-review everything in__all__, but I did need to addthese symbols to__dir__ in order to get tests to pass.

There's also a small oddity that I need to explicitly call__getattr__ inthe file itself. I'm not sure if there is a better way to fix that.

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (andpytest passes)
  • Documentation is sphinx and numpydoc compliant (the docs shouldbuild without error).
  • [n/a] New plotting related features are documented with examples.

Release Notes

  • New features are marked with a.. versionadded:: directive in the docstring and documented indoc/users/next_whats_new/
  • API changes are marked with a.. versionchanged:: directive in the docstring and documented indoc/api/next_api_changes/
  • Release notes conform with instructions innext_whats_new/README.rst ornext_api_changes/README.rst

timhoffmand others added2 commitsMarch 9, 2023 03:54
This removes the need for a boilerplate and various templates that needto be generated and pass flake8. As a downside, the wrappers no longerave explicit parameters, so argument errors are raised from the originalmethods, which may be confusing.
@tacaswell
Copy link
Member

When we talked about doing this before we rejected it because we wanted to be kind to static analysis so we would probably need to generate the pyi files still?

@anntzer
Copy link
Contributor

I don't think the pyi files necessarily need to follow pep8 (at least they may not need to be linewrapped)?

@QuLogic
Copy link
MemberAuthor

I thought we had an earlier discussion about this, but could not find it. I went through again and did a better search, and I believe the longterm goal was to get rid ofboilerplate.py. Reading through the issues I've found that:

  1. I lefta comment that@jklymak had an implementation for this, but the branch was deleted. But I don't actually know where I found the reference to that branch any more.
  2. Code generation improvements in Python 2.4 would enable droppingboilerplate.py, but 2.2 was still supported at the time:Pyplot update in setup.py #928 (comment)
  3. The previous major holdupwas the signature being*args, **kwargs

At this point, we are far and away from still supporting Python 2.2, and this implementation correctly creates the signature:

$ ipythonIn [1]: import matplotlib.pyplot as pltIn [2]: plt.acorr  # Axes wrapperOut[2]: <function matplotlib.pyplot.acorr(x, *, data=None, **kwargs)>In [3]: plt.Axes.acorrOut[3]: <function matplotlib.axes._axes.Axes.acorr(self, x, *, data=None, **kwargs)>In [4]: plt.figimage  # Figure wrapperOut[4]: <function matplotlib.pyplot.figimage(X, xo=0, yo=0, alpha=None, norm=None, cmap=None, vmin=None, vmax=None, origin=None, resize=False, **kwargs)>In [5]: plt.Figure.figimageOut[5]: <function matplotlib.figure.Figure.figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, vmin=None, vmax=None, origin=None, resize=False, **kwargs)>

The only inconsistency is the error raised for incorrect arguments as noted above, but we could fix that withinspect.bind also?

@QuLogic
Copy link
MemberAuthor

I also could've sworn that yesterday I could get ipython/python to display the type annotations in signature, and thus confirmed that the wrapped versions were correct, but today I can't seem to get it to display anything, even for the original functions.

But yes, it looks like runningmypy on an example that uses apyplot wrapper does fail now, so we'll have to do something about that.

@ksunden
Copy link
Member

This will not have type hints for the generated functions. Type hints from pyi stub files are not available at runtime, and thus the signatures for any dynamic generation will not have them until and unless we have inline type hints.

This behavior may also explain the "ipython sometimes has annotations". It will have them, I think, for pyplot in#24976, but not any of the underlying functions. I believe Ipython uses the runtime annotations.

Wecould make boilerplate generate the pyi file instead of the py file, which is arguably easier (though not by much, honestly) and could be less strict about flake8...

@timhoffm
Copy link
Member

timhoffm commentedMar 10, 2023
edited
Loading

I’m feeling very uneasy about this. Dynamically generated code can behave like static code, but it is different, which can show up in a number of ways:

  • Only the executed code will reveal the added functions. But there are tools that statically analyze files.
  • What happens when you step through this in a debugger?
  • Is this correctly picked up in Sphinx? (Didn’t check because CI is broken). Maybe yes, but then likely without source links.
  • Some types of structural errors in the generated functions would be caught by the parser (we at least know that we create syntactically valid functions). For dynamic functions, everything is deferred to call-time. (Which we might not cover systematically in our tests).
  • Related: I assume it’s not possible to have a test coverage report on the dynamic functions.
  • It’s harder to see that changes in our generating code will do the right thing: The static generator produces code that I can investigate. The dynamic generator produces runtime objects/ behavior that is much harder to reason about.
  • For new contributors / readers of the code , it is much harder to understand what is going on.

Overall, I think this will work well in 99% of the cases, but I expect several edge cases where we’ll run into trouble. This is an essential part of the library. The static generator has proven to work well. Changing that is risky.

On the other hand, I do not fully understand the motivation. What are the benefits of this? Is this only because of flake8? If so, there have to be better ways to cope with it.

tacaswell reacted with thumbs up emoji

@ksunden
Copy link
Member

My understanding is that this is in response tomy proposed change as part of the type hinting effort. See that discussion for my in depth reply.

The short version is that type hints made the auto generated code hit several edge cases on formatting that the existing naivetextwrap implementation did not handle well and so rather than playing whack-a-mole with those edge cases, I usedblack, a tool designed to autoformat python code, to apply formatting to the autogenerated portions ofpyplot.

I am not totally unwilling to rethink that, but the bar ispretty high, as outlined in my reply to the linked comment above.

@timhoffm
Copy link
Member

I'm fine with running black on the autogenerated code.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

5 participants
@QuLogic@tacaswell@anntzer@ksunden@timhoffm

[8]ページ先頭

©2009-2025 Movatter.jp