-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
backend switching -- don't create a public fallback API #11600
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
"tkagg", "wxagg", "agg", "cairo"]: | ||
try: | ||
switch_backend(candidate) | ||
except ImportError: |
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.
Does this catch the 'no display' errors you get on a headless server?
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.
It should(?), because _get_running_interactive_framework will return "headless" which is different from what the backend declares. We need the backend import to correctly fail with an ImportError, but I took care of the cases I encountered in the previous PR.
Modulo fixing the mac tests... |
e8f0b22
to
77ba47c
Compare
@anntzer Thank you for considering my comments. It's good not to overload the semantics of However, I'm afraid I haven't made myself clear there:
Please see my comment #11581 (comment) (which was probably created in parallel to this PR.) |
Re: mac failures: @timhoffm I agree that the backend doesn't logically belong in the rcParams, but until python-syntax matplotlibrcs happen (if ever, yada yada), the only thing we can set from matplotlibrc is entries in rcParams, and we definitely want a way to set the backend from matplotlibrc. Once python-syntax matplotlibrc happen, we can always move it out and ask people to use Having the entry in the rcParams and the actual backend go out of sync is exactly what I don't want to happen. |
I agree, that we want to set the default backend from matplotlibrc. The current backend should not be part of the rcParams. There's no syncing involved if we make that distinction. |
I don't have a mac to test on....
for better or worse, the current backend being stashed in rcParams in the existing behavior. I think the weird side effects of setting one rcparam (at risk of setting a very poor precedent) is better than breaking that bit of existing behavior. |
I am aware that the current backend being stashed in rcParams is the existing behavior. So far, this is read-only (setting the rcParam when a current backend exists has no effect). This is not great, but both easy to cope with if we want to evolve the API, and likely not used very often. This PR adds setting-capability through rcParams. IMO it's a movement in the wrong direction. We make more users aware of this poor API. And the added functionality will make it harded to smoothly migrate to a better API later. I strongly suggest not to go down this road. There are better ways to bring in the backend-switching functionality. Unfortunately, I don't have the time to write the design out now, but I will do so tonight. Please wait with further decisions until then, if at all possible. |
@tacaswell You realize that Travis is my main OSX machine? :) Tried to push something, let's see whether it works. |
04a0de8
to
1d9d0ed
Compare
Cherry-picked #9993 into this PR as well because the current version of qt_compat fails with NameError (instead of ImportError) when qt bindings are not installed. |
93967ac
to
c0bae18
Compare
#11612 lays out an alternative API design. |
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 looks good to me. Not really parsing all the backend selection logic, but I assume this works, or will get fixed quickly if it breaks for someone.
lib/matplotlib/backends/qt_compat.py
Outdated
|
||
if 'PySide2' in sys.modules: | ||
# user has imported PySide before importing mpl | ||
# First, check if anything is already imported. |
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 assume we are prepared to do quick patch releases if this stuff doesn't work on everyone's setup....
Appveyor is of course failing for some reason.... |
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.
Fine modulo the active rcParams["backend"]
stuff.
Side remark: The cherry-pick of #9993 makes reviewing harder - I did not check that parts. Under normal circumstances, it should be reviewed and merged separately.
@@ -1,6 +1,9 @@ | |||
Changes to backend loading | |||
`````````````````````````` | |||
|
|||
Assignment to ``rcParams["backend"]`` now sets the backend. Backends can now |
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.
As discussed in #11612 I'm 👎 on making rcParams["backend"]
active. This is a new way of API behavior, which we don't want in the long run. There is no loss in functionality, if users still use matplotlib.use()
to set the backend.
Can we leave that part out in the PR?
The cherry-pick is due to #11629 (and the fact that this PR explicitly relies on unimportable backends to raise ImportError -- I believe that generically catching any exception is too wide and too likely to hide real bugs). Would be happy for #9993 to be merged in first, or otherwise for #11629 to be fixed separately. I'm fine with moving the switching logic to @timhoffm Do you want to give a try at implementing this? The pieces are basically all there, just a matter of moving things around. |
64a34ab
to
44eb749
Compare
See changes documented in the API changes file. I inlined pylab_setup into switch_backend (and deprecated the old version of pylab_setup) because otherwise the typical call stack would be `use()` -> `switch_backend()` -> `pylab_setup()`, which is a bit of a mess; at least we can get rid of one of the layers.
44eb749
to
d5576e2
Compare
To actually make it change backends. This change is required because I reverted some of the more aggressive changes to `mpl.use` (to effectively default to force=True).
It seems to have a bug where `plt.show` hangs when the window is closed.
b2087dd
to
0ccc19e
Compare
As noted on gitter, I can't really follow what this is doing, and it seems to need documentation. I won't block if core folks like @tacaswell, @dopplershift and @anntzer are happy with it, and are willing to maintain it. |
Basically, when I originally wrote the PR, there were two goals:
The second part has been removed after the additional PRs by @tacaswell due to disagreements about the API, which I can't say I'm that happy with (but still thanks for putting together that implementation to move things forward); on the other hand even just having the first part is clearly already an improvement (and not having the second part means that there is less API changes). Moreover, implementing something else in the spirit of the second part remains relatively easy to do now (again, it's mostly a discussion about the API that's needed). |
## If you omit this parameter, it will always default to "Agg", which is a | ||
## non-interactive backend. | ||
backend : $TEMPLATE_BACKEND | ||
## If you omit this parameter, the backend will be determined by fallback. |
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.
"...by fallback" is vague. What will actually happen if this parameter is omitted?
@@ -267,6 +267,39 @@ - (int)index; | |||
|
|||
/* ---------------------------- Python classes ---------------------------- */ |
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.
Not clear what these changes have to do w/ this PR...
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.
It defers creating the main loop until you actually create a figure. This means you should be able to import pyplot and the use switch_backend
as much as you want between any backend until you create a figure.
I added a whats new for the backend selection logic. Did not add one for the backend switching (despite that being the name of this branch!) because as @anntzer points out there is still disagreement of what that API should look like (and where it should live) so lets not advertise it widely (yet). |
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.
You might address one minor comment, but I think the critical thing is to get this merged so that it gets more testing, and so 3.0rc1 can get out the door. This PR doesn't have to be perfect; it just has to work, and constitute an improvement.
|
||
force : bool, optional | ||
If True, attempt to switch the backend. This defaults to | ||
false and using `.pyplot.switch_backend` is preferred. |
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 thought this docstring reference to 'switch_backend' was going to be deleted.
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.
Sorry, I missed that (but did remove it from warning message.
@@ -242,13 +243,14 @@ def validate_fonttype(s): | |||
|
|||
_validate_standard_backends = ValidateInStrings( | |||
'backend', all_backends, ignorecase=True) | |||
_auto_backend_sentinel = object() |
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'm curious as to why this used as the sentinel, instead of the more typical 'auto' or None.
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.
Because we don't want to expose this as a public API (... at this point yet, at least).
OK, well, four of the most senior devs approved or authored it, and I can't see anything bad in it, so I'm merging. Thanks for the "Whats New" that definitely helped. The documentation issue noted above can be handled post merge if a follow-up PR if deemed necessary before 3.0 is fully released. |
Thanks for taking this step by step and deferring the API discussion to 3.1. I've been on holidays and couldn't take part in the final discussion. However, I fully agree with the approach taken so far. 😄 |
Alternative version of #11581, following in particular @timhoffm's comments.
The difference is that instead of allowing assigning a list to
rcParams["backend"]
and having implicit fallback (an admittedly awkward API), we use a private, magic value as default that triggers the fallback. This should still be enough to fix most issues with downstream packagers.A public fallback API would come (or not) with python-syntax matplotlibrcs (
for backend in ...: try: use(backend); except ImportError: pass
).I think I prefer this version.
See changes documented in the API changes file.
Some followup cleanup (of the now unused old machinery) will come as a
separate PR (left some "FIXME: Remove." comments).
Changes to the build process (namely, getting rid of trying to detect
the default backend in setupext.py) will come as a separate PR.
I inlined pylab_setup into switch_backend (and deprecated the old
version of pylab_setup) because otherwise the typical call stack would
be
use()
->set rcParams['backend'] = ...
->switch_backend()
->pylab_setup()
, which is a bit of a mess; at least we can get rid ofone of the layers.
PR Summary
PR Checklist