Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad44a7e

Browse files
authored
Merge pull request #9551 from anntzer/backend-loading
Refactor backend loading
2 parents 5960887 + 617c5d6 commit ad44a7e

File tree

6 files changed

+154
-176
lines changed

6 files changed

+154
-176
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Non-interactive FigureManager classes are now aliases of FigureManagerBase
2+
``````````````````````````````````````````````````````````````````````````
3+
4+
The `FigureManagerPdf`, `FigureManagerPS`, and `FigureManagerSVG` classes,
5+
which were previously empty subclasses of `FigureManagerBase` (i.e., not
6+
adding or overriding any attribute or method), are now direct aliases for
7+
`FigureManagerBase`.

lib/matplotlib/backend_bases.py

Lines changed: 119 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -124,121 +124,6 @@ def get_registered_canvas_class(format):
124124
return backend_class
125125

126126

127-
class _Backend(object):
128-
# A backend can be defined by using the following pattern:
129-
#
130-
# @_Backend.export
131-
# class FooBackend(_Backend):
132-
# # override the attributes and methods documented below.
133-
134-
# The following attributes and methods must be overridden by subclasses.
135-
136-
# The `FigureCanvas` and `FigureManager` classes must be defined.
137-
FigureCanvas = None
138-
FigureManager = None
139-
140-
# The following methods must be left as None for non-interactive backends.
141-
# For interactive backends, `trigger_manager_draw` should be a function
142-
# taking a manager as argument and triggering a canvas draw, and `mainloop`
143-
# should be a function taking no argument and starting the backend main
144-
# loop.
145-
trigger_manager_draw = None
146-
mainloop = None
147-
148-
# The following methods will be automatically defined and exported, but
149-
# can be overridden.
150-
151-
@classmethod
152-
def new_figure_manager(cls, num, *args, **kwargs):
153-
"""Create a new figure manager instance.
154-
"""
155-
# This import needs to happen here due to circular imports.
156-
from matplotlib.figure import Figure
157-
fig_cls = kwargs.pop('FigureClass', Figure)
158-
fig = fig_cls(*args, **kwargs)
159-
return cls.new_figure_manager_given_figure(num, fig)
160-
161-
@classmethod
162-
def new_figure_manager_given_figure(cls, num, figure):
163-
"""Create a new figure manager instance for the given figure.
164-
"""
165-
canvas = cls.FigureCanvas(figure)
166-
manager = cls.FigureManager(canvas, num)
167-
return manager
168-
169-
@classmethod
170-
def draw_if_interactive(cls):
171-
if cls.trigger_manager_draw is not None and is_interactive():
172-
manager = Gcf.get_active()
173-
if manager:
174-
cls.trigger_manager_draw(manager)
175-
176-
@classmethod
177-
def show(cls, block=None):
178-
"""Show all figures.
179-
180-
`show` blocks by calling `mainloop` if *block* is ``True``, or if it
181-
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in
182-
`interactive` mode.
183-
"""
184-
managers = Gcf.get_all_fig_managers()
185-
if not managers:
186-
return
187-
for manager in managers:
188-
# Emits a warning if the backend is non-interactive.
189-
manager.canvas.figure.show()
190-
if cls.mainloop is None:
191-
return
192-
if block is None:
193-
# Hack: Are we in IPython's pylab mode?
194-
from matplotlib import pyplot
195-
try:
196-
# IPython versions >= 0.10 tack the _needmain attribute onto
197-
# pyplot.show, and always set it to False, when in %pylab mode.
198-
ipython_pylab = not pyplot.show._needmain
199-
except AttributeError:
200-
ipython_pylab = False
201-
block = not ipython_pylab and not is_interactive()
202-
# TODO: The above is a hack to get the WebAgg backend working with
203-
# ipython's `%pylab` mode until proper integration is implemented.
204-
if get_backend() == "WebAgg":
205-
block = True
206-
if block:
207-
cls.mainloop()
208-
209-
# This method is the one actually exporting the required methods.
210-
211-
@staticmethod
212-
def export(cls):
213-
for name in ["FigureCanvas",
214-
"FigureManager",
215-
"new_figure_manager",
216-
"new_figure_manager_given_figure",
217-
"draw_if_interactive",
218-
"show"]:
219-
setattr(sys.modules[cls.__module__], name, getattr(cls, name))
220-
221-
# For back-compatibility, generate a shim `Show` class.
222-
223-
class Show(ShowBase):
224-
def mainloop(self):
225-
return cls.mainloop()
226-
227-
setattr(sys.modules[cls.__module__], "Show", Show)
228-
return cls
229-
230-
231-
class ShowBase(_Backend):
232-
"""
233-
Simple base class to generate a show() callable in backends.
234-
235-
Subclass must override mainloop() method.
236-
"""
237-
238-
def __call__(self, block=None):
239-
return self.show(block=block)
240-
241-
242127
class RendererBase(object):
243128
"""An abstract base class to handle drawing/rendering operations.
244129
@@ -3328,3 +3213,122 @@ def set_message(self, s):
33283213
Message text
33293214
"""
33303215
pass
3216+
3217+
3218+
class _Backend(object):
3219+
# A backend can be defined by using the following pattern:
3220+
#
3221+
# @_Backend.export
3222+
# class FooBackend(_Backend):
3223+
# # override the attributes and methods documented below.
3224+
3225+
# `backend_version` may be overridden by the subclass.
3226+
backend_version = "unknown"
3227+
3228+
# The `FigureCanvas` class must be defined.
3229+
FigureCanvas = None
3230+
3231+
# For interactive backends, the `FigureManager` class must be overridden.
3232+
FigureManager = FigureManagerBase
3233+
3234+
# The following methods must be left as None for non-interactive backends.
3235+
# For interactive backends, `trigger_manager_draw` should be a function
3236+
# taking a manager as argument and triggering a canvas draw, and `mainloop`
3237+
# should be a function taking no argument and starting the backend main
3238+
# loop.
3239+
trigger_manager_draw = None
3240+
mainloop = None
3241+
3242+
# The following methods will be automatically defined and exported, but
3243+
# can be overridden.
3244+
3245+
@classmethod
3246+
def new_figure_manager(cls, num, *args, **kwargs):
3247+
"""Create a new figure manager instance.
3248+
"""
3249+
# This import needs to happen here due to circular imports.
3250+
from matplotlib.figure import Figure
3251+
fig_cls = kwargs.pop('FigureClass', Figure)
3252+
fig = fig_cls(*args, **kwargs)
3253+
return cls.new_figure_manager_given_figure(num, fig)
3254+
3255+
@classmethod
3256+
def new_figure_manager_given_figure(cls, num, figure):
3257+
"""Create a new figure manager instance for the given figure.
3258+
"""
3259+
canvas = cls.FigureCanvas(figure)
3260+
manager = cls.FigureManager(canvas, num)
3261+
return manager
3262+
3263+
@classmethod
3264+
def draw_if_interactive(cls):
3265+
if cls.trigger_manager_draw is not None and is_interactive():
3266+
manager = Gcf.get_active()
3267+
if manager:
3268+
cls.trigger_manager_draw(manager)
3269+
3270+
@classmethod
3271+
def show(cls, block=None):
3272+
"""Show all figures.
3273+
3274+
`show` blocks by calling `mainloop` if *block* is ``True``, or if it
3275+
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in
3276+
`interactive` mode.
3277+
"""
3278+
managers = Gcf.get_all_fig_managers()
3279+
if not managers:
3280+
return
3281+
for manager in managers:
3282+
# Emits a warning if the backend is non-interactive.
3283+
manager.canvas.figure.show()
3284+
if cls.mainloop is None:
3285+
return
3286+
if block is None:
3287+
# Hack: Are we in IPython's pylab mode?
3288+
from matplotlib import pyplot
3289+
try:
3290+
# IPython versions >= 0.10 tack the _needmain attribute onto
3291+
# pyplot.show, and always set it to False, when in %pylab mode.
3292+
ipython_pylab = not pyplot.show._needmain
3293+
except AttributeError:
3294+
ipython_pylab = False
3295+
block = not ipython_pylab and not is_interactive()
3296+
# TODO: The above is a hack to get the WebAgg backend working with
3297+
# ipython's `%pylab` mode until proper integration is implemented.
3298+
if get_backend() == "WebAgg":
3299+
block = True
3300+
if block:
3301+
cls.mainloop()
3302+
3303+
# This method is the one actually exporting the required methods.
3304+
3305+
@staticmethod
3306+
def export(cls):
3307+
for name in ["backend_version",
3308+
"FigureCanvas",
3309+
"FigureManager",
3310+
"new_figure_manager",
3311+
"new_figure_manager_given_figure",
3312+
"draw_if_interactive",
3313+
"show"]:
3314+
setattr(sys.modules[cls.__module__], name, getattr(cls, name))
3315+
3316+
# For back-compatibility, generate a shim `Show` class.
3317+
3318+
class Show(ShowBase):
3319+
def mainloop(self):
3320+
return cls.mainloop()
3321+
3322+
setattr(sys.modules[cls.__module__], "Show", Show)
3323+
return cls
3324+
3325+
3326+
class ShowBase(_Backend):
3327+
"""
3328+
Simple base class to generate a show() callable in backends.
3329+
3330+
Subclass must override mainloop() method.
3331+
"""
3332+
3333+
def __call__(self, block=None):
3334+
return self.show(block=block)

lib/matplotlib/backends/__init__.py

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import inspect
1+
import importlib
22
import logging
33
import traceback
4-
import warnings
54

65
import matplotlib
6+
from matplotlib.backend_bases import _Backend
77

88
_log = logging.getLogger(__name__)
99

@@ -15,10 +15,11 @@
1515

1616

1717
def pylab_setup(name=None):
18-
'''return new_figure_manager, draw_if_interactive and show for pyplot
18+
"""
19+
Return new_figure_manager, draw_if_interactive and show for pyplot.
1920
20-
This provides the backend-specific functions that are used by
21-
pyplot to abstract away the difference between interactive backends.
21+
This provides the backend-specific functions that are used by pyplot to
22+
abstract away the difference between backends.
2223
2324
Parameters
2425
----------
@@ -39,54 +40,25 @@ def pylab_setup(name=None):
3940
4041
show : function
4142
Show (and possibly block) any unshown figures.
42-
43-
'''
44-
# Import the requested backend into a generic module object
43+
"""
44+
# Import the requested backend into a generic module object.
4545
if name is None:
46-
# validates, to match all_backends
4746
name = matplotlib.get_backend()
48-
if name.startswith('module://'):
49-
backend_name = name[9:]
50-
else:
51-
backend_name = 'backend_' + name
52-
backend_name = backend_name.lower() # until we banish mixed case
53-
backend_name = 'matplotlib.backends.%s' % backend_name.lower()
54-
55-
# the last argument is specifies whether to use absolute or relative
56-
# imports. 0 means only perform absolute imports.
57-
backend_mod = __import__(backend_name, globals(), locals(),
58-
[backend_name], 0)
59-
60-
# Things we pull in from all backends
61-
new_figure_manager = backend_mod.new_figure_manager
62-
63-
# image backends like pdf, agg or svg do not need to do anything
64-
# for "show" or "draw_if_interactive", so if they are not defined
65-
# by the backend, just do nothing
66-
def do_nothing_show(*args, **kwargs):
67-
frame = inspect.currentframe()
68-
fname = frame.f_back.f_code.co_filename
69-
if fname in ('<stdin>', '<ipython console>'):
70-
warnings.warn("""
71-
Your currently selected backend, '%s' does not support show().
72-
Please select a GUI backend in your matplotlibrc file ('%s')
73-
or with matplotlib.use()""" %
74-
(name, matplotlib.matplotlib_fname()), stacklevel=2)
75-
76-
def do_nothing(*args, **kwargs):
77-
pass
78-
79-
backend_version = getattr(backend_mod, 'backend_version', 'unknown')
80-
81-
show = getattr(backend_mod, 'show', do_nothing_show)
82-
83-
draw_if_interactive = getattr(backend_mod, 'draw_if_interactive',
84-
do_nothing)
85-
86-
_log.debug('backend %s version %s', name, backend_version)
87-
88-
# need to keep a global reference to the backend for compatibility
89-
# reasons. See https://github.com/matplotlib/matplotlib/issues/6092
47+
backend_name = (name[9:] if name.startswith("module://")
48+
else "matplotlib.backends.backend_{}".format(name.lower()))
49+
backend_mod = importlib.import_module(backend_name)
50+
# Create a local Backend class whose body corresponds to the contents of
51+
# the backend module. This allows the Backend class to fill in the missing
52+
# methods through inheritance.
53+
Backend = type("Backend", (_Backend,), vars(backend_mod))
54+
55+
# Need to keep a global reference to the backend for compatibility reasons.
56+
# See https://github.com/matplotlib/matplotlib/issues/6092
9057
global backend
9158
backend = name
92-
return backend_mod, new_figure_manager, draw_if_interactive, show
59+
60+
_log.debug('backend %s version %s', name, Backend.backend_version)
61+
return (backend_mod,
62+
Backend.new_figure_manager,
63+
Backend.draw_if_interactive,
64+
Backend.show)

lib/matplotlib/backends/backend_pdf.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2575,11 +2575,9 @@ def print_pdf(self, filename, *,
25752575
file.close()
25762576

25772577

2578-
class FigureManagerPdf(FigureManagerBase):
2579-
pass
2578+
FigureManagerPdf = FigureManagerBase
25802579

25812580

25822581
@_Backend.export
25832582
class _BackendPdf(_Backend):
25842583
FigureCanvas = FigureCanvasPdf
2585-
FigureManager = FigureManagerPdf

lib/matplotlib/backends/backend_ps.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,8 +1695,7 @@ def pstoeps(tmpfile, bbox=None, rotated=False):
16951695
shutil.move(epsfile, tmpfile)
16961696

16971697

1698-
class FigureManagerPS(FigureManagerBase):
1699-
pass
1698+
FigureManagerPS = FigureManagerBase
17001699

17011700

17021701
# The following Python dictionary psDefs contains the entries for the
@@ -1742,4 +1741,3 @@ class FigureManagerPS(FigureManagerBase):
17421741
@_Backend.export
17431742
class _BackendPS(_Backend):
17441743
FigureCanvas = FigureCanvasPS
1745-
FigureManager = FigureManagerPS

lib/matplotlib/backends/backend_svg.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,8 +1213,8 @@ def _print_svg(
12131213
def get_default_filetype(self):
12141214
return 'svg'
12151215

1216-
class FigureManagerSVG(FigureManagerBase):
1217-
pass
1216+
1217+
FigureManagerSVG = FigureManagerBase
12181218

12191219

12201220
svgProlog = """\
@@ -1228,4 +1228,3 @@ class FigureManagerSVG(FigureManagerBase):
12281228
@_Backend.export
12291229
class _BackendSVG(_Backend):
12301230
FigureCanvas = FigureCanvasSVG
1231-
FigureManager = FigureManagerSVG

0 commit comments

Comments
 (0)