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

Commit439338d

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 (i.e., `FigureManager ==FigureManagerBase`), restore the default implementation of `show()`that prints a warning when run from a console (the backend refactoraccidentally removed this error message 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 parentc280700 commit439338d

File tree

5 files changed

+156
-166
lines changed

5 files changed

+156
-166
lines changed

‎lib/matplotlib/backend_bases.py

Lines changed: 128 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@
4141
fromcontextlibimportcontextmanager
4242
fromfunctoolsimportpartial
4343
importimportlib
44+
importinspect
4445
importio
4546
importos
4647
importsys
4748
importtime
4849
importwarnings
4950

5051
importnumpyasnp
52+
importmatplotlib
5153
importmatplotlib.cbookascbook
5254
importmatplotlib.colorsascolors
5355
importmatplotlib.transformsastransforms
@@ -135,120 +137,6 @@ def get_registered_canvas_class(format):
135137
returnbackend_class
136138

137139

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

‎lib/matplotlib/backends/__init__.py

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
importsix
55

6-
importmatplotlib
7-
importinspect
6+
importimportlib
87
importtraceback
9-
importwarnings
8+
9+
importmatplotlib
10+
frommatplotlib.backend_basesimport_Backend
1011

1112

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

53+
backend_mod=importlib.import_module(backend_name)
54+
Backend=type(str("Backend"), (_Backend,),vars(backend_mod))
8855
matplotlib.verbose.report('backend %s version %s'%
89-
(name,backend_version))
56+
(name,Backend.backend_version))
9057

9158
# need to keep a global reference to the backend for compatibility
9259
# reasons. See https://github.com/matplotlib/matplotlib/issues/6092
9360
globalbackend
9461
backend=name
95-
returnbackend_mod,new_figure_manager,draw_if_interactive,show
62+
63+
# We want to get functions out of a class namespace and call them *without
64+
# the first argument being an instance of the class*. This works directly
65+
# on Py3. On Py2, we need to remove the check that the first argument be
66+
# an instance of the class. The only relevant case is if `.im_self` is
67+
# None, in which case we need to use `.im_func` (if we have a bound method
68+
# (e.g. a classmethod), everything is fine).
69+
def_dont_check_first_arg(func):
70+
return (func.im_funcifgetattr(func,"im_self",0)isNone
71+
elsefunc)
72+
73+
return (backend_mod,
74+
_dont_check_first_arg(Backend.new_figure_manager),
75+
_dont_check_first_arg(Backend.draw_if_interactive),
76+
_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
@@ -2599,11 +2599,9 @@ def print_pdf(self, filename, **kwargs):
25992599
file.close()
26002600

26012601

2602-
classFigureManagerPdf(FigureManagerBase):
2603-
pass
2602+
FigureManagerPdf=FigureManagerBase
26042603

26052604

26062605
@_Backend.export
26072606
class_BackendPdf(_Backend):
26082607
FigureCanvas=FigureCanvasPdf
2609-
FigureManager=FigureManagerPdf

‎lib/matplotlib/backends/backend_ps.py

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

17301730

1731-
classFigureManagerPS(FigureManagerBase):
1732-
pass
1731+
FigureManagerPS=FigureManagerBase
17331732

17341733

17351734
# The following Python dictionary psDefs contains the entries for the
@@ -1775,4 +1774,3 @@ class FigureManagerPS(FigureManagerBase):
17751774
@_Backend.export
17761775
class_BackendPS(_Backend):
17771776
FigureCanvas=FigureCanvasPS
1778-
FigureManager=FigureManagerPS

‎lib/matplotlib/backends/backend_svg.py

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

1254-
classFigureManagerSVG(FigureManagerBase):
1255-
pass
1254+
1255+
FigureManagerSVG=FigureManagerBase
12561256

12571257

12581258
svgProlog="""\
@@ -1266,4 +1266,3 @@ class FigureManagerSVG(FigureManagerBase):
12661266
@_Backend.export
12671267
class_BackendSVG(_Backend):
12681268
FigureCanvas=FigureCanvasSVG
1269-
FigureManager=FigureManagerSVG

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp