Skip to content
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

Move IPython backend mapping to Matplotlib and support entry points #27948

Merged
merged 5 commits into from May 2, 2024

Conversation

ianthomas23
Copy link
Member

@ianthomas23 ianthomas23 commented Mar 19, 2024

This is WIP to move IPython's backend mapping into Matplotlib and extends it to allow backends to register themselves via entry points. It is a coordinated effort across Matplotlib, IPython, matplotlib-inline and ipympl. Closes #27663.

The only functional changes to pure (non-IPython) Matplotlib are:

  1. Backend names are now case-insensitive. Up to now IPython has used capitalised names. If you ask for QtAgg then get_backend() will now return qtagg.
  2. There is a new BackendRegistry.list_all() function to list all known (built-in and dynamically-loaded) backends as this is needed by IPython. This could be made more public by exposing it in pyplot or the top-level matplotlib.__init__.py if desired.
  3. Entry points allow backend modules to register themselves so they do not require explicit code to support them in Matplotlib or IPython. Example of how this is done: https://github.com/ipython/matplotlib-inline/blob/c5887eab4bf4b594be8f7cfd738bfff4d6fede88/pyproject.toml#L42-L43.

Functional improvements for IPython:

  1. Supports the full set of Matplotlib built-in backends, including svg, pdf, qtcairo, tkcairo, etc.
  2. Supports backends of the form module://some.backend such as module://mplcairo.qt.
  3. Supports entry-point backends, currently inline and widget/ipympl.
  4. The widget/jupyter backends behave like other non-interactive backends (e.g. agg) in pure IPython in that they can export to PNG, etc, but do not display an interactive window.

Jupyter inherits all these IPython benefits, displaying plots that use GUI frameworks in separate windows and the others within the notebook.

Because the four related projects are loosely coupled without direct dependencies on each other (except for ipython and matplotlib-inline), backward compatibility requires all possible combinations of projects before and after the new functionality (I will call these "old" and "new" from now on) to continue to work. I have tested these all locally, and the CI of this PR will test new Matplotlib against old IPython for example, but I need to add one or more new temporary CI runs to test new Matplotlib against new IPython etc. The identification of new versus old depends on version checks on the other libraries, so here is a table that I will update showing the current status of progress in the 4 projects:

Project Relevant PRs Possible release version
matplotlib-inline ipython/matplotlib-inline#34, ipython/matplotlib-inline#35 0.1.7 released
ipympl matplotlib/ipympl#549 0.9.4 released
Matplotlib #27948 (this) 3.9.0
IPython ipython/ipython#14371 8.24.0 released

The two widget projects can be released soon, once we are happy with the entry point approach. The other two projects' PRs will have to be synchronised as each includes version checks on each other.

Implementation details:

  1. cbook._backend_module_name has moved to BackendRegistry. It was private, but if there are concerns about downstream use of this function I can put a shim back in.
  2. For backward compatibility I have had to add synonyms notebook for nbagg, qt6agg for qtagg and qt6cairo for qtcairo. I am happy with notebook (it is a better name than nbagg anyway) but the qt6 ones are unfortunate as we are connecting a version-specific IPython GUI event loop (qt6) to a somewhat version-agnostic Matplotlib qtagg backend.
  3. Entry points are only read if they really need to be. If you ask for a built-in or module:// backend then the entry points are not needed. They are if you call list_all().
  4. Backend validation no longer has a list of valid string names, it checks if the supplied backend name is valid and only loads the entry points if necessary.
  5. You cannot have multiple entry points with the same name, and an entry point cannot use the same name as a built-in backend.
  6. There are a number of code blocks that do version checks on IPython, matplotlib-inline or ipympl for backward compatibility. These need to remain in place for 3+ years until the lowest version of Python supported by Matplotlib is higher than the highest versions of those libraries released before these changes. Probably I should add a specific comment to each code block stating the conditions required for it to be removed.

To do

  • Add temporary CI runs against the new PR branches of the other projects.
  • Support mac-specific backends (a0cac93).
  • Add comments for conditions required for backward-compatibility code blocks to be removed.
  • Update documentation on backends, for both users and developers.
  • Update Whats New docs.
  • Update version checks before merging.
  • Inform downstream backend libraries (e.g. mplcairo) about entry points and deprecation of IPythons backend2gui which is now performed in Matplotlib.

@ianthomas23
Copy link
Member Author

The macOS-specific backend works now. The name of the backend remains as "macosx" (case insensitive) and the GUI loop as "osx".

matplotlib.use("macosx")

works on all permutations of main and entry_point branches of Matplotlib and IPython.

In IPython,

%matplotlib osx

works of all the permutations. In addition

%matplotlib macosx

works if using both of the Matplotlib and IPython entry_point branches. This is consistent with other usage in IPython where the string argument to %matplotlib may be either a GUI framework or a backend name.

There is a "CocoaAgg" backend mentioned in IPython
https://github.com/ipython/ipython/blob/a3074b8cf3fbb20482732a5602c20cf7bac0a215/IPython/core/pylabtools.py#L51
but this was removed from Matplotlib in #6582 (June 2016). No extra code changes are required for this, anyone attempting to use such a backend will continue to get an "backend not recognised" error message.

The "macos" backend does not work in JupyterLab either before or after these changes. Fixing that, if it is desired, will be a different piece of work.

@ianthomas23 ianthomas23 force-pushed the entry_points branch 2 times, most recently from e8306d9 to 530fbbc Compare April 10, 2024 12:13
Carreau added a commit to ipython/ipython that referenced this pull request Apr 12, 2024
This is WIP to move IPython's backend mapping into Matplotlib and
extends it to allow backends to register themselves via [entry
points](https://setuptools.pypa.io/en/latest/userguide/entry_point.html#entry-points-for-plugins).
It is a coordinated effort across Matplotlib, IPython, matplotlib-inline
and ipympl. Closes #14311. Most of the work is in Matplotlib
(matplotlib/matplotlib#27948) but I will repeat the relevant points
here.

When using a Matplotlib magic command of the form `%matplotlib
something` the identification of the Matplotlib backend and GUI loop are
now performed in Matplotlib not IPython. This supports:

1. Matplotlib backends that IPython already supports such as `qtagg` and
`tkagg`.
2. Other built-in Matplotlib backends such as `qtcairo`.
3. Backends that use `module://something` syntax such as
`module://mplcairo.qt`.
4. Backends that self-register using entry points, currently `inline`
and `widget`/`ipympl`.

Implementation details:

1. The magic command is now explicitly `%matplotlib gui_or_backend`
rather than `%matplotlib gui`. This is already effectively the case as
e.g. `%matplotlib ipympl` is really a backend not GUI name. Within
Matplotlib the `gui_or_backend` is checked first to see if it is a GUI
name and then falls back to checking if it is a backend name.
2. If you select the `inline` backend the corresponding GUI is now
`None` not `inline`. All backends which do not have a GUI loop return
`None`, otherwise we have to keep explicit checks within IPython for
particular backends.
3. `backends` and `backend2gui` are now deprecated but are still
exposed, with a deprecation warning, if required. If using Matplotlib,
ipympl, etc releases that include the corresponding changes to this PR
then they are not needed as Matplotlib deals with it all. But for
backward compatibility they must still be available for a while along
with the remainder of the existing backend-handling code.
4. I haven't yet updated the documentation but we need to keep
information about valid GUI frameworks and I propose that we should
remove all lists of valid Matplotlib backends, replacing them with
instructions on how to obtain the current list (pointing to the
Matplotlib docs and using `%matplotlib --list`). If we keep any lists
then they will inevitably become out of date. This extends to the
`backend_keys` in IPython/core/shellapp.py.

Because the four related projects are loosely coupled without direct
dependencies on each other (except for `ipython` and
`matplotlib-inline`), backward compatibility requires all possible
combinations of projects before and after the new functionality (I will
call these "old" and "new" from now on) to continue to work. I have
tested these all locally, and the CI of this PR will test new IPython
against old Matplotlib for example, but I need to add one or more new
temporary CI runs to test new IPython against new Matplotlib etc. The
identification of new versus old depends on version checks on the other
libraries, so here is a table that I will update showing the current
status of progress in the 4 projects:

| Project | Relevant PRs | Possible release version |
| --- | --- | --- |
| matplotlib-inline | ipython/matplotlib-inline#34,
ipython/matplotlib-inline#35 | 0.1.7 |
| ipympl | matplotlib/ipympl#549 | 0.9.4 |
| Matplotlib | matplotlib/matplotlib#27948 | 3.9.1 |
| IPython | #14371 (this) | 8.24.0 |

The two widget projects can be released soon, once we are happy with the
entry point approach. The other two projects' PRs will have to be
synchronised as each includes version checks on each other.

To do

- [ ] Add CI runs against the new PR branches of the other projects.
- [ ] Add comments for conditions required for backward-compatibility
code blocks to be removed.
- [ ] Update documentation, including removal of lists of valid
backends.
- [ ] Update version checks before merging.
Carreau added a commit to ipython/ipython that referenced this pull request Apr 15, 2024
Fixes #14401 which has been a bug in the 8.22.x and 8.23.x releases.

When I removed the multiple initialisation of Matplotlib backends in
#14330 it broke use of the following:
```bash
ipython --matplotlib
ipython --matplotlib=auto
ipython --pylab
ipython --pylab=auto
```
by failing to display Matplotlib plot. If you specify a particular GUI
event loop such as using
```bash
ipython --pylab=qt
```
then it was and is fine. So for anyone finding this, the workaround
until the next release is to specify a GUI loop rather than relying on
the auto selection.

I didn't notice this as I've been concentrating on moving the Matplotlib
backend logic from IPython to Matplotlib, and with those changes
(matplotlib/matplotlib#27948) the above use cases all work OK.

The fix is to reintroduce the early import of `matplotlib-inline` but
only if both the gui loop is not specified and the Matplotlib version is
before the movement of the backend logic across to it.

There are no explicit tests for this. In the future I will try to think
of some tests for some of this IPython-Matplotlib functionality that
don't involve installing complicated backend dependencies or adding
image comparison tests.
@ianthomas23
Copy link
Member Author

This is now ready for review, barring a few CI tweaks.

matplotlib-inline 0.1.7 and ipympl 0.9.4 have both been released with entry_points defined in their pyproject.toml files. These will have no effect until this PR is merged to read the entry_points. The corresponding PR in ipython has been merged and will be released in version 8.24.0, expected at the end of this month. That will have no effect until this PR is merged and released as it checks for the existence of BackendRegistry.resolve_gui_or_backend

https://github.com/ipython/ipython/blob/8ff4109a184d242bbc8cdd08750d9a192b854784/IPython/core/pylabtools.py#L481

rather than checking the version of Matplotlib installed, hence avoiding hard-coding the check of a version that hasn't been decided yet.

Ideally this targets Matplotlib 3.9.1 rather than waiting for 3.10.0. It is adding to the BackendRegistry API, but that is effectively an internal API between Matplotlib and IPython.

@tacaswell
Copy link
Member

I think we should consider sneaking this is for 3.9.0 if we can get the reviews done ASAP.

@tacaswell tacaswell added this to the v3.9.0 milestone Apr 25, 2024
.github/workflows/tests.yml Outdated Show resolved Hide resolved
lib/matplotlib/__init__.py Outdated Show resolved Hide resolved
lib/matplotlib/backend_bases.py Outdated Show resolved Hide resolved
"headless": "agg",
"osx": "macosx",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change from macosx to osx? Actually, what would check that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it because IPython uses osx for the GUI framework and macosx for the backend. I thought this was fine for non-IPython Matplotlib but that isn't correct as FigureCanvasMac.required_interactive_framework = "macosx". I have been lucky to get away with these two different names for the same GUI framework; non-IPython Matplotlib never looks at this code, it only needs the required_interactive_framework to be consistent with cbook._get_running_interactive_framework. But it cannot stay like this, we can't have a declaration that the macOS GUI framework is osx when sometimes it isn't.

It would be possible to special case the osx GUI framework to mean macosx on input, but on output we have no way of knowing if the caller prefers osx to macosx. So I think the least bad solution here is to change this back to macosx and be entirely consistent within Matplotlib, and I will special case the osx <-> macosx in IPython.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I'll submit the IPython PR shortly.

lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
lib/matplotlib/testing/__init__.py Outdated Show resolved Hide resolved
},
{
"data": {
"image/png": "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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to commit this whole output?

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, I can clean the notebook to remove the outputs. I kept it in to be consistent with test_nbagg_01.ipynb, which is what this is based on. But neither actually compare the output image pixels.

As an aside it would be great to have some image-comparison testing of some combination of Matplotlib and IPython/Jupyter, but I cannot find a good place to put them. There is an excellent image-based testing framework used in Jupyter projects but it would bring in some complicated test dependencies so it is not appropriate here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best if this were removed on the initial commit instead of a later one, unless you intend for this entire PR to be squashed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll squash.

@ianthomas23
Copy link
Member Author

The macOS failures of

FAILED lib/matplotlib/tests/test_backend_macosx.py::test_ipython - subprocess...

are now expected when using latest IPython (8.24.0) but will not be errors when ipython/ipython#14420 is merged and released (I manually checked this now on my dev machine). I am already version-checking the result according to IPython < 8.24 or >= 8.24:

https://github.com/ianthomas23/matplotlib/blob/1078cab2e7cdc518dd0332af0a32c7eaa2d866ee/lib/matplotlib/testing/__init__.py#L182-L186

so I could just expand this and check for different results for IPython < 8.24, == 8.24 and > 8.24.

@ianthomas23
Copy link
Member Author

I have:

  • Disabled the IPython macos test if ipython == 8.24.0 as it is not possible to make it pass without a nasty hack in Matplotlib, and IPython 8.24.1 should be released shortly with the required fix at that end.
  • Squashed all the commits.
  • Disabled the IPython qt test on Windows as running it in a subprocess causes it to fail. It works fine for me locally in a Windows dev environment which is good enough for me.

I've restarted the AppVeyor run as it was failing to get freetype.

Copy link
Member

@ksunden ksunden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take or leave the comments about "headless"/extra if condition.

I do not particularly wish to block on either of these.

Summary of small action items if you wish:

  • remove extra condition is_valid_backend
  • remove reference to "headless" in docstrings for the return of both resolve_[gui_or_]backend methods.
  • make reg.resolve_gui_or_backend("headless") return ('agg', None) rather than ('agg', 'headless') (or potentially error if you do not want headless to be valid)

lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
lib/matplotlib/backends/registry.py Outdated Show resolved Hide resolved
@ianthomas23
Copy link
Member Author

Take or leave the comments about "headless"/extra if condition.

I do not particularly wish to block on either of these.

Summary of small action items if you wish:

  • remove extra condition is_valid_backend
  • remove reference to "headless" in docstrings for the return of both resolve_[gui_or_]backend methods.
  • make reg.resolve_gui_or_backend("headless") return ('agg', None) rather than ('agg', 'headless') (or potentially error if you do not want headless to be valid)

I've done all 3 of these.

@QuLogic QuLogic merged commit 2ba8545 into matplotlib:main May 2, 2024
43 of 44 checks passed
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request May 2, 2024
@ianthomas23 ianthomas23 deleted the entry_points branch May 2, 2024 19:06
ksunden added a commit that referenced this pull request May 3, 2024
…948-on-v3.9.x

Backport PR #27948 on branch v3.9.x (Move IPython backend mapping to Matplotlib and support entry points)
Carreau added a commit to ipython/ipython that referenced this pull request May 6, 2024
This is a correction to the code that moves backend handling to
Matplotlib, which came to light during the review of
matplotlib/matplotlib#27948. The GUI framework of macOSX is called `osx`
in IPython but `macosx` in Matplotlib.

It would be possible to allow passing a GUI framework of `osx` to
Matplotlib and internally converting it to `macosx`, but the reverse
direction is problematic as we would like the answer to be `osx` if we
are using IPython and `macosx` if using pure Matplotlib. Therefore the
simplest solution is to do the translation in IPython. It is not ideal
as we want to minimise such Matplotlib-related implementation details in
IPython, but the changes here are small and simple and hence I think
they are acceptable.

There are two new private functions `_convert_gui_to_matplotlib` and
`_convert_gui_from_matplotlib` to do the required checking and
conversion, and these are called whenever a GUI framework name is passed
to or from Matplotlib. There are only 3 places in the code where this is
currently required.

Inevitably this comes to light just after the release of IPython 8.24.0!
But it is not a problem for end users until the next Matplotlib release
which contains matplotlib/matplotlib#27948. If that occurs really
quickly (sometime in May?) perhaps we could release an IPython 8.24.1
just beforehand, otherwise the usual planned release at the end of next
month would be fine.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[MNT]: Move Matplotlib backend mapping from IPython and support backends self-registering
4 participants