Skip to content

Commit d0e94c7

Browse files
committed
Move required_interactive_framework to canvas class.
In mpl 3.0, the required_interactive_framework attribute was added to backend modules. However, it is sometimes required to access it from a canvas *instance* (e.g. in _fix_ipython_backend2gui), but the pattern `sys.modules[cls.__module__].required_interactive_framework` is brittle (e.g. it is broken by third-party subclasses). Instead it makes more sense to put the attribute on the canvas class; one can easily and robustly go from the backend module to the canvas class by accessing the FigureCanvas attribute.
1 parent bccdf2e commit d0e94c7

11 files changed

+43
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
API changes
2+
```````````
3+
4+
The ``required_interactive_framework`` attribute of backend modules introduced
5+
in Matplotlib 3.0 has been moved to the FigureCanvas class, in order to let it
6+
be inherited by third-party canvas subclasses and to make it easier to know
7+
what interactive framework is required by a canvas class.

lib/matplotlib/backend_bases.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -1560,8 +1560,12 @@ class FigureCanvasBase:
15601560
----------
15611561
figure : `matplotlib.figure.Figure`
15621562
A high-level figure instance
1563-
15641563
"""
1564+
1565+
# Set to one of {"qt5", "qt4", "gtk3", "wx", "tk", "macosx"} if an
1566+
# interactive framework is required, or None otherwise.
1567+
required_interactive_framework = None
1568+
15651569
events = [
15661570
'resize_event',
15671571
'draw_event',
@@ -1633,8 +1637,7 @@ def _fix_ipython_backend2gui(cls):
16331637
# In case we ever move the patch to IPython and remove these APIs,
16341638
# don't break on our side.
16351639
return
1636-
backend_mod = sys.modules[cls.__module__]
1637-
rif = getattr(backend_mod, "required_interactive_framework", None)
1640+
rif = getattr(cls, "required_interactive_framework", None)
16381641
backend2gui_rif = {"qt5": "qt", "qt4": "qt", "gtk3": "gtk3",
16391642
"wx": "wx", "macosx": "osx"}.get(rif)
16401643
if backend2gui_rif:
@@ -3255,10 +3258,6 @@ class _Backend:
32553258
# class FooBackend(_Backend):
32563259
# # override the attributes and methods documented below.
32573260

3258-
# Set to one of {"qt5", "qt4", "gtk3", "wx", "tk", "macosx"} if an
3259-
# interactive framework is required, or None otherwise.
3260-
required_interactive_framework = None
3261-
32623261
# `backend_version` may be overridden by the subclass.
32633262
backend_version = "unknown"
32643263

@@ -3341,14 +3340,15 @@ def show(cls, block=None):
33413340

33423341
@staticmethod
33433342
def export(cls):
3344-
for name in ["required_interactive_framework",
3345-
"backend_version",
3346-
"FigureCanvas",
3347-
"FigureManager",
3348-
"new_figure_manager",
3349-
"new_figure_manager_given_figure",
3350-
"draw_if_interactive",
3351-
"show"]:
3343+
for name in [
3344+
"backend_version",
3345+
"FigureCanvas",
3346+
"FigureManager",
3347+
"new_figure_manager",
3348+
"new_figure_manager_given_figure",
3349+
"draw_if_interactive",
3350+
"show",
3351+
]:
33523352
setattr(sys.modules[cls.__module__], name, getattr(cls, name))
33533353

33543354
# For back-compatibility, generate a shim `Show` class.

lib/matplotlib/backends/_backend_tk.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ def _on_timer(self):
124124

125125

126126
class FigureCanvasTk(FigureCanvasBase):
127+
required_interactive_framework = "tk"
128+
127129
keyvald = {65507: 'control',
128130
65505: 'shift',
129131
65513: 'alt',
@@ -868,7 +870,6 @@ def trigger(self, *args):
868870

869871
@_Backend.export
870872
class _BackendTk(_Backend):
871-
required_interactive_framework = "tk"
872873
FigureManager = FigureManagerTk
873874

874875
@classmethod

lib/matplotlib/backends/backend_gtk3.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ def _on_timer(self):
9797

9898

9999
class FigureCanvasGTK3(Gtk.DrawingArea, FigureCanvasBase):
100+
required_interactive_framework = "gtk3"
101+
100102
keyvald = {65507: 'control',
101103
65505: 'shift',
102104
65513: 'alt',
@@ -978,7 +980,6 @@ def error_msg_gtk(msg, parent=None):
978980

979981
@_Backend.export
980982
class _BackendGTK3(_Backend):
981-
required_interactive_framework = "gtk3"
982983
FigureCanvas = FigureCanvasGTK3
983984
FigureManager = FigureManagerGTK3
984985

lib/matplotlib/backends/backend_macosx.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ class FigureCanvasMac(_macosx.FigureCanvas, FigureCanvasAgg):
5353
----------
5454
figure : `matplotlib.figure.Figure`
5555
A high-level Figure instance
56-
5756
"""
5857

58+
required_interactive_framework = "macosx"
59+
5960
def __init__(self, figure):
6061
FigureCanvasBase.__init__(self, figure)
6162
width, height = self.get_width_height()
@@ -172,7 +173,6 @@ def set_message(self, message):
172173

173174
@_Backend.export
174175
class _BackendMac(_Backend):
175-
required_interactive_framework = "macosx"
176176
FigureCanvas = FigureCanvasMac
177177
FigureManager = FigureManagerMac
178178

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from .backend_qt5 import (
22
backend_version, SPECIAL_KEYS, SUPER, ALT, CTRL, SHIFT, MODIFIER_KEYS,
3-
cursord, _create_qApp, _BackendQT5, TimerQT, MainWindow, FigureManagerQT,
4-
NavigationToolbar2QT, SubplotToolQt, error_msg_qt, exception_handler)
5-
from .backend_qt5 import FigureCanvasQT as FigureCanvasQT5
3+
cursord, _create_qApp, _BackendQT5, TimerQT, MainWindow, FigureCanvasQT,
4+
FigureManagerQT, NavigationToolbar2QT, SubplotToolQt, error_msg_qt,
5+
exception_handler)
66

77

88
@_BackendQT5.export
99
class _BackendQT4(_BackendQT5):
10-
required_interactive_framework = "qt4"
10+
class FigureCanvas(FigureCanvasQT5):
11+
required_interactive_framework = "qt4"

lib/matplotlib/backends/backend_qt4agg.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88

99
@_BackendQT5Agg.export
1010
class _BackendQT4Agg(_BackendQT5Agg):
11-
required_interactive_framework = "qt4"
11+
class FigureCanvas(FigureCanvasQTAgg):
12+
required_interactive_framework = "qt4"
+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from .backend_qt5cairo import _BackendQT5Cairo
1+
from .backend_qt5cairo import _BackendQT5Cairo, FigureCanvasQTCairo
22

33

44
@_BackendQT5Cairo.export
55
class _BackendQT4Cairo(_BackendQT5Cairo):
6-
required_interactive_framework = "qt4"
6+
class FigureCanvas(FigureCanvasQTCairo):
7+
required_interactive_framework = "qt4"

lib/matplotlib/backends/backend_qt5.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ def _timer_stop(self):
211211

212212

213213
class FigureCanvasQT(QtWidgets.QWidget, FigureCanvasBase):
214+
required_interactive_framework = "qt5"
214215

215216
# map Qt button codes to MouseEvent's ones:
216217
buttond = {QtCore.Qt.LeftButton: MouseButton.LEFT,
@@ -1029,7 +1030,6 @@ def trigger(self, *args, **kwargs):
10291030

10301031
@_Backend.export
10311032
class _BackendQT5(_Backend):
1032-
required_interactive_framework = "qt5"
10331033
FigureCanvas = FigureCanvasQT
10341034
FigureManager = FigureManagerQT
10351035

lib/matplotlib/backends/backend_wx.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ class _FigureCanvasWxBase(FigureCanvasBase, wx.Panel):
519519
we give a hint as to our preferred minimum size.
520520
"""
521521

522+
required_interactive_framework = "wx"
523+
522524
keyvald = {
523525
wx.WXK_CONTROL: 'control',
524526
wx.WXK_SHIFT: 'shift',
@@ -1933,7 +1935,6 @@ def OnPrintPage(self, page):
19331935

19341936
@_Backend.export
19351937
class _BackendWx(_Backend):
1936-
required_interactive_framework = "wx"
19371938
FigureCanvas = FigureCanvasWx
19381939
FigureManager = FigureManagerWx
19391940
_frame_class = FigureFrameWx

lib/matplotlib/pyplot.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ def switch_backend(newbackend):
224224
_log.debug("Loaded backend %s version %s.",
225225
newbackend, Backend.backend_version)
226226

227-
required_framework = Backend.required_interactive_framework
227+
required_framework = getattr(
228+
Backend.FigureCanvas, "required_interactive_framework", None)
228229
if required_framework is not None:
229230
current_framework = \
230231
matplotlib.backends._get_running_interactive_framework()

0 commit comments

Comments
 (0)