Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit181cb70

Browse files
committed
Rework backend loading.
This is preliminary work towards fixing the runtime detection of defaultbackend problem (the first step being to make it easier to check whethera backend *can* be loaded). No publically visible API is changed.Backend loading now defines default versions of `backend_version`,`draw_if_interactive`, and `show` using the same inheritance strategy asbuiltin backends do.For non-interactive backends (which don't override `mainloop`), restorethe default implementation of `show()` that prints a warning when runfrom a console (the backend refactor accidentally removed this errormessage as it provided a silent default `show()`).The `_Backend` class had to be moved to the end of the module as`FigureManagerBase` needs to be defined first. The `ShowBase` class hadto be moved even after that as it depends on the `_Backend` class.
1 parent1f3699c commit181cb70

File tree

5 files changed

+158
-168
lines changed

5 files changed

+158
-168
lines changed

‎lib/matplotlib/backend_bases.py

Lines changed: 127 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
fromcontextlibimportcontextmanager
4242
fromfunctoolsimportpartial
4343
importimportlib
44+
importinspect
4445
importio
4546
importos
4647
importsys
@@ -126,120 +127,6 @@ def get_registered_canvas_class(format):
126127
returnbackend_class
127128

128129

129-
class_Backend(object):
130-
# A backend can be defined by using the following pattern:
131-
#
132-
# @_Backend.export
133-
# class FooBackend(_Backend):
134-
# # override the attributes and methods documented below.
135-
136-
# The following attributes and methods must be overridden by subclasses.
137-
138-
# The `FigureCanvas` and `FigureManager` classes must be defined.
139-
FigureCanvas=None
140-
FigureManager=None
141-
142-
# The following methods must be left as None for non-interactive backends.
143-
# For interactive backends, `trigger_manager_draw` should be a function
144-
# taking a manager as argument and triggering a canvas draw, and `mainloop`
145-
# should be a function taking no argument and starting the backend main
146-
# loop.
147-
trigger_manager_draw=None
148-
mainloop=None
149-
150-
# The following methods will be automatically defined and exported, but
151-
# can be overridden.
152-
153-
@classmethod
154-
defnew_figure_manager(cls,num,*args,**kwargs):
155-
"""Create a new figure manager instance.
156-
"""
157-
# This import needs to happen here due to circular imports.
158-
frommatplotlib.figureimportFigure
159-
fig_cls=kwargs.pop('FigureClass',Figure)
160-
fig=fig_cls(*args,**kwargs)
161-
returncls.new_figure_manager_given_figure(num,fig)
162-
163-
@classmethod
164-
defnew_figure_manager_given_figure(cls,num,figure):
165-
"""Create a new figure manager instance for the given figure.
166-
"""
167-
canvas=cls.FigureCanvas(figure)
168-
manager=cls.FigureManager(canvas,num)
169-
returnmanager
170-
171-
@classmethod
172-
defdraw_if_interactive(cls):
173-
ifcls.trigger_manager_drawisnotNoneandis_interactive():
174-
manager=Gcf.get_active()
175-
ifmanager:
176-
cls.trigger_manager_draw(manager)
177-
178-
@classmethod
179-
defshow(cls,block=None):
180-
"""Show all figures.
181-
182-
`show` blocks by calling `mainloop` if *block* is ``True``, or if it
183-
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in
184-
`interactive` mode.
185-
"""
186-
ifcls.mainloopisNone:
187-
return
188-
managers=Gcf.get_all_fig_managers()
189-
ifnotmanagers:
190-
return
191-
formanagerinmanagers:
192-
manager.show()
193-
ifblockisNone:
194-
# Hack: Are we in IPython's pylab mode?
195-
frommatplotlibimportpyplot
196-
try:
197-
# IPython versions >= 0.10 tack the _needmain attribute onto
198-
# pyplot.show, and always set it to False, when in %pylab mode.
199-
ipython_pylab=notpyplot.show._needmain
200-
exceptAttributeError:
201-
ipython_pylab=False
202-
block=notipython_pylabandnotis_interactive()
203-
# TODO: The above is a hack to get the WebAgg backend working with
204-
# ipython's `%pylab` mode until proper integration is implemented.
205-
ifget_backend()=="WebAgg":
206-
block=True
207-
ifblock:
208-
cls.mainloop()
209-
210-
# This method is the one actually exporting the required methods.
211-
212-
@staticmethod
213-
defexport(cls):
214-
fornamein ["FigureCanvas",
215-
"FigureManager",
216-
"new_figure_manager",
217-
"new_figure_manager_given_figure",
218-
"draw_if_interactive",
219-
"show"]:
220-
setattr(sys.modules[cls.__module__],name,getattr(cls,name))
221-
222-
# For back-compatibility, generate a shim `Show` class.
223-
224-
classShow(ShowBase):
225-
defmainloop(self):
226-
returncls.mainloop()
227-
228-
setattr(sys.modules[cls.__module__],"Show",Show)
229-
returncls
230-
231-
232-
classShowBase(_Backend):
233-
"""
234-
Simple base class to generate a show() callable in backends.
235-
236-
Subclass must override mainloop() method.
237-
"""
238-
239-
def__call__(self,block=None):
240-
returnself.show(block=block)
241-
242-
243130
classRendererBase(object):
244131
"""An abstract base class to handle drawing/rendering operations.
245132
@@ -3366,3 +3253,129 @@ def set_message(self, s):
33663253
Message text
33673254
"""
33683255
pass
3256+
3257+
3258+
class_Backend(object):
3259+
# A backend can be defined by using the following pattern:
3260+
#
3261+
# @_Backend.export
3262+
# class FooBackend(_Backend):
3263+
# # override the attributes and methods documented below.
3264+
3265+
# May be overridden by the subclass.
3266+
backend_version="unknown"
3267+
# The `FigureCanvas` class must be overridden.
3268+
FigureCanvas=None
3269+
# For interactive backends, the `FigureManager` class must be overridden.
3270+
FigureManager=FigureManagerBase
3271+
# The following methods must be left as None for non-interactive backends.
3272+
# For interactive backends, `trigger_manager_draw` should be a function
3273+
# taking a manager as argument and triggering a canvas draw, and `mainloop`
3274+
# should be a function taking no argument and starting the backend main
3275+
# loop.
3276+
trigger_manager_draw=None
3277+
mainloop=None
3278+
3279+
# The following methods will be automatically defined and exported, but
3280+
# can be overridden.
3281+
3282+
@classmethod
3283+
defnew_figure_manager(cls,num,*args,**kwargs):
3284+
"""Create a new figure manager instance.
3285+
"""
3286+
# This import needs to happen here due to circular imports.
3287+
frommatplotlib.figureimportFigure
3288+
fig_cls=kwargs.pop('FigureClass',Figure)
3289+
fig=fig_cls(*args,**kwargs)
3290+
returncls.new_figure_manager_given_figure(num,fig)
3291+
3292+
@classmethod
3293+
defnew_figure_manager_given_figure(cls,num,figure):
3294+
"""Create a new figure manager instance for the given figure.
3295+
"""
3296+
canvas=cls.FigureCanvas(figure)
3297+
manager=cls.FigureManager(canvas,num)
3298+
returnmanager
3299+
3300+
@classmethod
3301+
defdraw_if_interactive(cls):
3302+
ifcls.trigger_manager_drawisnotNoneandis_interactive():
3303+
manager=Gcf.get_active()
3304+
ifmanager:
3305+
cls.trigger_manager_draw(manager)
3306+
3307+
@classmethod
3308+
defshow(cls,block=None):
3309+
"""Show all figures.
3310+
3311+
`show` blocks by calling `mainloop` if *block* is ``True``, or if it
3312+
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in
3313+
`interactive` mode.
3314+
"""
3315+
ifcls.mainloopisNone:
3316+
frame=inspect.currentframe()
3317+
whileframe:
3318+
ifframe.f_code.co_filenamein [
3319+
"<stdin>","<ipython console>"]:
3320+
warnings.warn("""\
3321+
Your currently selected backend does not support show().
3322+
Please select a GUI backend in your matplotlibrc file ('{}')
3323+
or with matplotlib.use()""".format(matplotlib.matplotlib_fname()))
3324+
break
3325+
else:
3326+
frame=frame.f_back
3327+
return
3328+
managers=Gcf.get_all_fig_managers()
3329+
ifnotmanagers:
3330+
return
3331+
formanagerinmanagers:
3332+
manager.show()
3333+
ifblockisNone:
3334+
# Hack: Are we in IPython's pylab mode?
3335+
frommatplotlibimportpyplot
3336+
try:
3337+
# IPython versions >= 0.10 tack the _needmain attribute onto
3338+
# pyplot.show, and always set it to False, when in %pylab mode.
3339+
ipython_pylab=notpyplot.show._needmain
3340+
exceptAttributeError:
3341+
ipython_pylab=False
3342+
block=notipython_pylabandnotis_interactive()
3343+
# TODO: The above is a hack to get the WebAgg backend working with
3344+
# ipython's `%pylab` mode until proper integration is implemented.
3345+
ifget_backend()=="WebAgg":
3346+
block=True
3347+
ifblock:
3348+
cls.mainloop()
3349+
3350+
# This method is the one actually exporting the required methods.
3351+
3352+
@staticmethod
3353+
defexport(cls):
3354+
fornamein ["backend_version",
3355+
"FigureCanvas",
3356+
"FigureManager",
3357+
"new_figure_manager",
3358+
"new_figure_manager_given_figure",
3359+
"draw_if_interactive",
3360+
"show"]:
3361+
setattr(sys.modules[cls.__module__],name,getattr(cls,name))
3362+
3363+
# For back-compatibility, generate a shim `Show` class.
3364+
3365+
classShow(ShowBase):
3366+
defmainloop(self):
3367+
returncls.mainloop()
3368+
3369+
setattr(sys.modules[cls.__module__],"Show",Show)
3370+
returncls
3371+
3372+
3373+
classShowBase(_Backend):
3374+
"""
3375+
Simple base class to generate a show() callable in backends.
3376+
3377+
Subclass must override mainloop() method.
3378+
"""
3379+
3380+
def__call__(self,block=None):
3381+
returnself.show(block=block)

‎lib/matplotlib/backends/__init__.py

Lines changed: 27 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33

44
importsix
55

6-
importmatplotlib
7-
importinspect
8-
importtraceback
9-
importwarnings
6+
importimportlib
107
importlogging
8+
importtraceback
9+
10+
importmatplotlib
11+
frommatplotlib.backend_basesimport_Backend
12+
1113

1214
_log=logging.getLogger(__name__)
1315

@@ -47,50 +49,30 @@ def pylab_setup(name=None):
4749
'''
4850
# Import the requested backend into a generic module object
4951
ifnameisNone:
50-
# validates, to match all_backends
5152
name=matplotlib.get_backend()
52-
ifname.startswith('module://'):
53-
backend_name=name[9:]
54-
else:
55-
backend_name='backend_'+name
56-
backend_name=backend_name.lower()# until we banish mixed case
57-
backend_name='matplotlib.backends.%s'%backend_name.lower()
58-
59-
# the last argument is specifies whether to use absolute or relative
60-
# imports. 0 means only perform absolute imports.
61-
backend_mod=__import__(backend_name,globals(),locals(),
62-
[backend_name],0)
63-
64-
# Things we pull in from all backends
65-
new_figure_manager=backend_mod.new_figure_manager
66-
67-
# image backends like pdf, agg or svg do not need to do anything
68-
# for "show" or "draw_if_interactive", so if they are not defined
69-
# by the backend, just do nothing
70-
defdo_nothing_show(*args,**kwargs):
71-
frame=inspect.currentframe()
72-
fname=frame.f_back.f_code.co_filename
73-
iffnamein ('<stdin>','<ipython console>'):
74-
warnings.warn("""
75-
Your currently selected backend, '%s' does not support show().
76-
Please select a GUI backend in your matplotlibrc file ('%s')
77-
or with matplotlib.use()"""%
78-
(name,matplotlib.matplotlib_fname()))
79-
80-
defdo_nothing(*args,**kwargs):
81-
pass
82-
83-
backend_version=getattr(backend_mod,'backend_version','unknown')
84-
85-
show=getattr(backend_mod,'show',do_nothing_show)
86-
87-
draw_if_interactive=getattr(backend_mod,'draw_if_interactive',
88-
do_nothing)
89-
90-
_log.info('backend %s version %s'% (name,backend_version))
53+
backend_name= (name[9:]ifname.startswith("module://")
54+
else"matplotlib.backends.backend_{}".format(name.lower()))
55+
56+
backend_mod=importlib.import_module(backend_name)
57+
Backend=type(str("Backend"), (_Backend,),vars(backend_mod))
58+
_log.info('backend %s version %s',name,Backend.backend_version)
9159

9260
# need to keep a global reference to the backend for compatibility
9361
# reasons. See https://github.com/matplotlib/matplotlib/issues/6092
9462
globalbackend
9563
backend=name
96-
returnbackend_mod,new_figure_manager,draw_if_interactive,show
64+
65+
# We want to get functions out of a class namespace and call them *without
66+
# the first argument being an instance of the class*. This works directly
67+
# on Py3. On Py2, we need to remove the check that the first argument be
68+
# an instance of the class. The only relevant case is if `.im_self` is
69+
# None, in which case we need to use `.im_func` (if we have a bound method
70+
# (e.g. a classmethod), everything is fine).
71+
def_dont_check_first_arg(func):
72+
return (func.im_funcifgetattr(func,"im_self",0)isNone
73+
elsefunc)
74+
75+
return (backend_mod,
76+
_dont_check_first_arg(Backend.new_figure_manager),
77+
_dont_check_first_arg(Backend.draw_if_interactive),
78+
_dont_check_first_arg(Backend.show))

‎lib/matplotlib/backends/backend_pdf.py

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

25962596

2597-
classFigureManagerPdf(FigureManagerBase):
2598-
pass
2597+
FigureManagerPdf=FigureManagerBase
25992598

26002599

26012600
@_Backend.export
26022601
class_BackendPdf(_Backend):
26032602
FigureCanvas=FigureCanvasPdf
2604-
FigureManager=FigureManagerPdf

‎lib/matplotlib/backends/backend_ps.py

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

17251725

1726-
classFigureManagerPS(FigureManagerBase):
1727-
pass
1726+
FigureManagerPS=FigureManagerBase
17281727

17291728

17301729
# The following Python dictionary psDefs contains the entries for the
@@ -1770,4 +1769,3 @@ class FigureManagerPS(FigureManagerBase):
17701769
@_Backend.export
17711770
class_BackendPS(_Backend):
17721771
FigureCanvas=FigureCanvasPS
1773-
FigureManager=FigureManagerPS

‎lib/matplotlib/backends/backend_svg.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,8 +1252,8 @@ def _print_svg(self, filename, svgwriter, **kwargs):
12521252
defget_default_filetype(self):
12531253
return'svg'
12541254

1255-
classFigureManagerSVG(FigureManagerBase):
1256-
pass
1255+
1256+
FigureManagerSVG=FigureManagerBase
12571257

12581258

12591259
svgProlog="""\
@@ -1267,4 +1267,3 @@ class FigureManagerSVG(FigureManagerBase):
12671267
@_Backend.export
12681268
class_BackendSVG(_Backend):
12691269
FigureCanvas=FigureCanvasSVG
1270-
FigureManager=FigureManagerSVG

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp