Skip to content

Conversation

@heinrich5991
Copy link
Contributor

@heinrich5991 heinrich5991 commented Oct 17, 2025

On Arch Linux, automatic backend selection fails when at-spi2-core is installed but
python-gobject is not. Detect this by importing gi.require_version directly.

>>> import matplotlib.pyplot as plt
>>> plt.plot([0, 1], [0, 1])
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    plt.plot([0, 1], [0, 1])
    ~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 3838, in plot
    return gca().plot(
           ~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 2785, in gca
    return gcf().gca()
           ~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 1108, in gcf
    return figure()
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 1042, in figure
    manager = new_figure_manager(
        num, figsize=figsize, dpi=dpi,
        facecolor=facecolor, edgecolor=edgecolor, frameon=frameon,
        FigureClass=FigureClass, **kwargs)
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 551, in new_figure_manager
    _warn_if_gui_out_of_main_thread()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 528, in _warn_if_gui_out_of_main_thread
    canvas_class = cast(type[FigureCanvasBase], _get_backend_mod().FigureCanvas)
                                                ~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 369, in _get_backend_mod
    switch_backend(rcParams._get("backend"))
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 411, in switch_backend
    switch_backend(candidate)
    ~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 425, in switch_backend
    module = backend_registry.load_backend_module(newbackend)
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/registry.py", line 317, in load_backend_module
    return importlib.import_module(module_name)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/usr/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/backend_gtk4agg.py", line 4, in <module>
    from . import backend_agg, backend_gtk4
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/backend_gtk4.py", line 19, in <module>
    gi.require_version("Gtk", "4.0")
    ^^^^^^^^^^^^^^^^^^
AttributeError: module 'gi' has no attribute 'require_version'

Fixes #30654.

PR checklist

@heinrich5991
Copy link
Contributor Author

How can I add tests for this?

@tacaswell I took the liberty and deviated from what I've originally proposed to lower the amount of code that gets executed in a try: […] except AttributeError: […] block, so that fewer exceptions get accidentally silenced. Please let me know if I should PR my originally proposed change instead.

@heinrich5991
Copy link
Contributor Author

I'm not sure if the ubuntu-24.04-arm test failure is related to my PR. Can someone help me?

@rcomer
Copy link
Member

rcomer commented Oct 17, 2025

That failure is happening on various PRs. Since it's a timeout error, I re-started the job to see if it passes on second attempt.

try:
gi.require_version
except AttributeError as err:
raise ImportError("The GTK3 backends require PyGObject") from err
Copy link
Member

@tacaswell tacaswell Oct 17, 2025

Choose a reason for hiding this comment

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

Does the error message above need to be corrected then? I do not fully understand how PyGObject / gobject introspection splits itself up in either and upstream sense or the downstream packaging sense (which I assume different packagers make different choices?).

"No, this is the right error message in both cases" is perfectly good answer, but if we can make this a bit more precise that would be good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does the error message above need to be corrected then?

I think it's the correct error as the remediation is (on Arch Linux) to install python-gobject. import gi doesn't fail because other packages populate the /usr/lib/python3.13/site-packages/gi/ path, e.g. with /usr/lib/python3.13/site-packages/gi/overrides/Atspi.py.

Copy link
Member

Choose a reason for hiding this comment

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

This is likely a consequence of Python's new(ish) implicit namespace packages.

Copy link
Member

@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

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

On the "does the machinery do what it should" front, 👍

I left one comment making the human facing error message more precise, but approving the PR so if the answer is "this is the best we can do", then we only need one more review.

@tacaswell tacaswell added this to the v3.10.8 milestone Oct 17, 2025
@tacaswell
Copy link
Member

This is something where I'm ok with not adding an explicit test. We know that we can get an attribute error raised and have other tests that the machinery that catches the ImportError works correctly. The work to construct a test case with a half-installed pygobject and then maintain it going forward is in my judgement not worth the opportunity cost of spending that effort else where.

@WeatherGod
Copy link
Member

WeatherGod commented Oct 17, 2025 via email

@heinrich5991
Copy link
Contributor Author

One little nitpick. Should the ImportError be raised from None or err?

I'd think from err because the AttributeError is the cause.

@heinrich5991
Copy link
Contributor Author

I have a different suggestion, maybe we could instead use

from gi import require_version as gi_require_version

Then we don't have to catch the AttributeError.

@heinrich5991
Copy link
Contributor Author

If you like the other approach, I can squash the commits. :)

@tacaswell
Copy link
Member

I like the import-as approach better, more lines of change, but simplifies the logic.

On Arch Linux, automatic backend selection fails when
[`at-spi2-core`](https://archlinux.org/packages/extra/x86_64/at-spi2-core/files/)
is installed but
[`python-gobject`](https://archlinux.org/packages/extra/x86_64/python-gobject/files/)
is not. Detect this by importign `gi.require_version` directly.

```python
>>> import matplotlib.pyplot as plt
>>> plt.plot([0, 1], [0, 1])
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    plt.plot([0, 1], [0, 1])
    ~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 3838, in plot
    return gca().plot(
           ~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 2785, in gca
    return gcf().gca()
           ~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 1108, in gcf
    return figure()
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 1042, in figure
    manager = new_figure_manager(
        num, figsize=figsize, dpi=dpi,
        facecolor=facecolor, edgecolor=edgecolor, frameon=frameon,
        FigureClass=FigureClass, **kwargs)
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 551, in new_figure_manager
    _warn_if_gui_out_of_main_thread()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 528, in _warn_if_gui_out_of_main_thread
    canvas_class = cast(type[FigureCanvasBase], _get_backend_mod().FigureCanvas)
                                                ~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 369, in _get_backend_mod
    switch_backend(rcParams._get("backend"))
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 411, in switch_backend
    switch_backend(candidate)
    ~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/usr/lib/python3.13/site-packages/matplotlib/pyplot.py", line 425, in switch_backend
    module = backend_registry.load_backend_module(newbackend)
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/registry.py", line 317, in load_backend_module
    return importlib.import_module(module_name)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/usr/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/backend_gtk4agg.py", line 4, in <module>
    from . import backend_agg, backend_gtk4
  File "/usr/lib/python3.13/site-packages/matplotlib/backends/backend_gtk4.py", line 19, in <module>
    gi.require_version("Gtk", "4.0")
    ^^^^^^^^^^^^^^^^^^
AttributeError: module 'gi' has no attribute 'require_version'
```

Fixes matplotlib#30654.
@heinrich5991 heinrich5991 force-pushed the pr_attributeerror_gi_require_version branch from 7c07889 to 3ecf087 Compare October 20, 2025 15:17
@heinrich5991
Copy link
Contributor Author

Squashed the commits.

@heinrich5991
Copy link
Contributor Author

Could someone retry the failed pipeline? I'm not sure if it's related to this PR, I'd guess "no".

Copy link
Member

@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

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

Still approve of simplified version.

@tacaswell
Copy link
Member

Thanks! This still needs a second reviewer to merge it.

@QuLogic QuLogic merged commit ea40d72 into matplotlib:main Oct 21, 2025
49 of 50 checks passed
@QuLogic
Copy link
Member

QuLogic commented Oct 21, 2025

Thanks @heinrich5991! Congratulations on your first PR to Matplotlib 🎉 We hope to hear from you again.

@lumberbot-app
Copy link

lumberbot-app bot commented Oct 21, 2025

Owee, I'm MrMeeseeks, Look at me.

There seem to be a conflict, please backport manually. Here are approximate instructions:

  1. Checkout backport branch and update it.
git checkout v3.10.x
git pull
  1. Cherry pick the first parent branch of the this PR on top of the older branch:
git cherry-pick -x -m1 ea40d72fb0b5da047ffb02e9d6322531334354ae
  1. You will likely have some merge/cherry-pick conflict here, fix them and commit:
git commit -am "Backport PR #30657: Fix `AttributeError: module 'gi' has no attribute 'require_version'`"
  1. Push to a named branch:
git push YOURFORK v3.10.x:auto-backport-of-pr-30657-on-v3.10.x
  1. Create a PR against branch v3.10.x, I would have named this PR:

"Backport PR #30657 on branch v3.10.x (Fix AttributeError: module 'gi' has no attribute 'require_version')"

And apply the correct labels and milestones.

Congratulations — you did some good work! Hopefully your backport PR will be tested by the continuous integration and merged soon!

Remember to remove the Still Needs Manual Backport label once the PR gets merged.

If these instructions are inaccurate, feel free to suggest an improvement.

QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Oct 23, 2025
timhoffm added a commit that referenced this pull request Oct 23, 2025
…3.10.x

Backport PR #30657 on branch v3.10.x (Fix AttributeError: module 'gi' has no attribute 'require_version')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: error plotting: AttributeError: module 'gi' has no attribute 'require_version'

5 participants