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

Skip to content

Commit 1174e4a

Browse files
committed
setattr context manager.
1 parent 74b6913 commit 1174e4a

12 files changed

+152
-213
lines changed

lib/matplotlib/artist.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -881,13 +881,8 @@ def _update_property(self, k, v):
881881
raise AttributeError('Unknown property %s' % k)
882882
return func(v)
883883

884-
store = self.eventson
885-
self.eventson = False
886-
try:
887-
ret = [_update_property(self, k, v)
888-
for k, v in props.items()]
889-
finally:
890-
self.eventson = store
884+
with cbook._setattr_cm(self, eventson=False):
885+
ret = [_update_property(self, k, v) for k, v in props.items()]
891886

892887
if len(ret):
893888
self.pchanged()

lib/matplotlib/backend_bases.py

Lines changed: 92 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,17 +2145,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21452145
tight bbox is calculated.
21462146
21472147
"""
2148-
self._is_saving = True
2149-
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2150-
# Having *no* manager and a *None* manager are currently different (see
2151-
# Figure.show); should probably be normalized to None at some point.
2152-
_no_manager = object()
2153-
if hasattr(self, 'manager'):
2154-
manager = self.manager
2155-
del self.manager
2156-
else:
2157-
manager = _no_manager
2158-
21592148
if format is None:
21602149
# get format from filename, or from backend's default filetype
21612150
if isinstance(filename, six.string_types):
@@ -2172,104 +2161,107 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21722161

21732162
if dpi is None:
21742163
dpi = rcParams['savefig.dpi']
2175-
21762164
if dpi == 'figure':
21772165
dpi = getattr(self.figure, '_original_dpi', self.figure.dpi)
21782166

2179-
if facecolor is None:
2180-
facecolor = rcParams['savefig.facecolor']
2181-
if edgecolor is None:
2182-
edgecolor = rcParams['savefig.edgecolor']
2183-
2184-
origDPI = self.figure.dpi
2185-
origfacecolor = self.figure.get_facecolor()
2186-
origedgecolor = self.figure.get_edgecolor()
2187-
2188-
self.figure.dpi = dpi
2189-
self.figure.set_facecolor(facecolor)
2190-
self.figure.set_edgecolor(edgecolor)
2191-
2192-
bbox_inches = kwargs.pop("bbox_inches", None)
2193-
if bbox_inches is None:
2194-
bbox_inches = rcParams['savefig.bbox']
2195-
2196-
if bbox_inches:
2197-
# call adjust_bbox to save only the given area
2198-
if bbox_inches == "tight":
2199-
# When bbox_inches == "tight", it saves the figure twice. The
2200-
# first save command (to a BytesIO) is just to estimate the
2201-
# bounding box of the figure.
2167+
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2168+
# Some code (e.g. Figure.show) differentiates between having *no*
2169+
# manager and a *None* manager, which should be fixed at some point,
2170+
# but this should be fine.
2171+
with cbook._setattr_cm(self, _is_saving=True, manager=None), \
2172+
cbook._setattr_cm(self.figure, dpi=dpi):
2173+
2174+
if facecolor is None:
2175+
facecolor = rcParams['savefig.facecolor']
2176+
if edgecolor is None:
2177+
edgecolor = rcParams['savefig.edgecolor']
2178+
2179+
origfacecolor = self.figure.get_facecolor()
2180+
origedgecolor = self.figure.get_edgecolor()
2181+
2182+
self.figure.dpi = dpi
2183+
self.figure.set_facecolor(facecolor)
2184+
self.figure.set_edgecolor(edgecolor)
2185+
2186+
bbox_inches = kwargs.pop("bbox_inches", None)
2187+
if bbox_inches is None:
2188+
bbox_inches = rcParams['savefig.bbox']
2189+
2190+
if bbox_inches:
2191+
# call adjust_bbox to save only the given area
2192+
if bbox_inches == "tight":
2193+
# When bbox_inches == "tight", it saves the figure twice.
2194+
# The first save command (to a BytesIO) is just to estimate
2195+
# the bounding box of the figure.
2196+
result = print_method(
2197+
io.BytesIO(),
2198+
dpi=dpi,
2199+
facecolor=facecolor,
2200+
edgecolor=edgecolor,
2201+
orientation=orientation,
2202+
dryrun=True,
2203+
**kwargs)
2204+
renderer = self.figure._cachedRenderer
2205+
bbox_inches = self.figure.get_tightbbox(renderer)
2206+
2207+
bbox_artists = kwargs.pop("bbox_extra_artists", None)
2208+
if bbox_artists is None:
2209+
bbox_artists = \
2210+
self.figure.get_default_bbox_extra_artists()
2211+
2212+
bbox_filtered = []
2213+
for a in bbox_artists:
2214+
bbox = a.get_window_extent(renderer)
2215+
if a.get_clip_on():
2216+
clip_box = a.get_clip_box()
2217+
if clip_box is not None:
2218+
bbox = Bbox.intersection(bbox, clip_box)
2219+
clip_path = a.get_clip_path()
2220+
if clip_path is not None and bbox is not None:
2221+
clip_path = \
2222+
clip_path.get_fully_transformed_path()
2223+
bbox = Bbox.intersection(
2224+
bbox, clip_path.get_extents())
2225+
if bbox is not None and (
2226+
bbox.width != 0 or bbox.height != 0):
2227+
bbox_filtered.append(bbox)
2228+
2229+
if bbox_filtered:
2230+
_bbox = Bbox.union(bbox_filtered)
2231+
trans = Affine2D().scale(1.0 / self.figure.dpi)
2232+
bbox_extra = TransformedBbox(_bbox, trans)
2233+
bbox_inches = Bbox.union([bbox_inches, bbox_extra])
2234+
2235+
pad = kwargs.pop("pad_inches", None)
2236+
if pad is None:
2237+
pad = rcParams['savefig.pad_inches']
2238+
2239+
bbox_inches = bbox_inches.padded(pad)
2240+
2241+
restore_bbox = tight_bbox.adjust_bbox(self.figure, bbox_inches,
2242+
canvas.fixed_dpi)
2243+
2244+
_bbox_inches_restore = (bbox_inches, restore_bbox)
2245+
else:
2246+
_bbox_inches_restore = None
2247+
2248+
try:
22022249
result = print_method(
2203-
io.BytesIO(),
2250+
filename,
22042251
dpi=dpi,
22052252
facecolor=facecolor,
22062253
edgecolor=edgecolor,
22072254
orientation=orientation,
2208-
dryrun=True,
2255+
bbox_inches_restore=_bbox_inches_restore,
22092256
**kwargs)
2210-
renderer = self.figure._cachedRenderer
2211-
bbox_inches = self.figure.get_tightbbox(renderer)
2212-
2213-
bbox_artists = kwargs.pop("bbox_extra_artists", None)
2214-
if bbox_artists is None:
2215-
bbox_artists = self.figure.get_default_bbox_extra_artists()
2216-
2217-
bbox_filtered = []
2218-
for a in bbox_artists:
2219-
bbox = a.get_window_extent(renderer)
2220-
if a.get_clip_on():
2221-
clip_box = a.get_clip_box()
2222-
if clip_box is not None:
2223-
bbox = Bbox.intersection(bbox, clip_box)
2224-
clip_path = a.get_clip_path()
2225-
if clip_path is not None and bbox is not None:
2226-
clip_path = clip_path.get_fully_transformed_path()
2227-
bbox = Bbox.intersection(bbox,
2228-
clip_path.get_extents())
2229-
if bbox is not None and (bbox.width != 0 or
2230-
bbox.height != 0):
2231-
bbox_filtered.append(bbox)
2232-
2233-
if bbox_filtered:
2234-
_bbox = Bbox.union(bbox_filtered)
2235-
trans = Affine2D().scale(1.0 / self.figure.dpi)
2236-
bbox_extra = TransformedBbox(_bbox, trans)
2237-
bbox_inches = Bbox.union([bbox_inches, bbox_extra])
2238-
2239-
pad = kwargs.pop("pad_inches", None)
2240-
if pad is None:
2241-
pad = rcParams['savefig.pad_inches']
2242-
2243-
bbox_inches = bbox_inches.padded(pad)
2244-
2245-
restore_bbox = tight_bbox.adjust_bbox(self.figure, bbox_inches,
2246-
canvas.fixed_dpi)
2247-
2248-
_bbox_inches_restore = (bbox_inches, restore_bbox)
2249-
else:
2250-
_bbox_inches_restore = None
2251-
2252-
try:
2253-
result = print_method(
2254-
filename,
2255-
dpi=dpi,
2256-
facecolor=facecolor,
2257-
edgecolor=edgecolor,
2258-
orientation=orientation,
2259-
bbox_inches_restore=_bbox_inches_restore,
2260-
**kwargs)
2261-
finally:
2262-
if bbox_inches and restore_bbox:
2263-
restore_bbox()
2264-
2265-
self.figure.dpi = origDPI
2266-
self.figure.set_facecolor(origfacecolor)
2267-
self.figure.set_edgecolor(origedgecolor)
2268-
self.figure.set_canvas(self)
2269-
if manager is not _no_manager:
2270-
self.manager = manager
2271-
self._is_saving = False
2272-
return result
2257+
finally:
2258+
if bbox_inches and restore_bbox:
2259+
restore_bbox()
2260+
2261+
self.figure.set_facecolor(origfacecolor)
2262+
self.figure.set_edgecolor(origedgecolor)
2263+
self.figure.set_canvas(self)
2264+
return result
22732265

22742266
@classmethod
22752267
def get_default_filetype(cls):

lib/matplotlib/backends/backend_agg.py

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -491,53 +491,33 @@ def buffer_rgba(self):
491491
def print_raw(self, filename_or_obj, *args, **kwargs):
492492
FigureCanvasAgg.draw(self)
493493
renderer = self.get_renderer()
494-
original_dpi = renderer.dpi
495-
renderer.dpi = self.figure.dpi
496-
if isinstance(filename_or_obj, six.string_types):
497-
fileobj = open(filename_or_obj, 'wb')
498-
close = True
499-
else:
500-
fileobj = filename_or_obj
501-
close = False
502-
try:
503-
fileobj.write(renderer._renderer.buffer_rgba())
504-
finally:
505-
if close:
506-
fileobj.close()
507-
renderer.dpi = original_dpi
494+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
495+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
496+
fh.write(renderer._renderer.buffer_rgba())
508497
print_rgba = print_raw
509498

510499
def print_png(self, filename_or_obj, *args, **kwargs):
511500
FigureCanvasAgg.draw(self)
512501
renderer = self.get_renderer()
513-
original_dpi = renderer.dpi
514-
renderer.dpi = self.figure.dpi
515502

516-
version_str = 'matplotlib version ' + __version__ + \
517-
', http://matplotlib.org/'
503+
version_str = (
504+
'matplotlib version ' + __version__ + ', http://matplotlib.org/')
518505
metadata = OrderedDict({'Software': version_str})
519506
user_metadata = kwargs.pop("metadata", None)
520507
if user_metadata is not None:
521508
metadata.update(user_metadata)
522509

523-
try:
524-
with cbook.open_file_cm(filename_or_obj, "wb") as fh:
525-
_png.write_png(renderer._renderer, fh,
526-
self.figure.dpi, metadata=metadata)
527-
finally:
528-
renderer.dpi = original_dpi
510+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
511+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
512+
_png.write_png(renderer._renderer, fh,
513+
self.figure.dpi, metadata=metadata)
529514

530515
def print_to_buffer(self):
531516
FigureCanvasAgg.draw(self)
532517
renderer = self.get_renderer()
533-
original_dpi = renderer.dpi
534-
renderer.dpi = self.figure.dpi
535-
try:
536-
result = (renderer._renderer.buffer_rgba(),
537-
(int(renderer.width), int(renderer.height)))
538-
finally:
539-
renderer.dpi = original_dpi
540-
return result
518+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi):
519+
return (renderer._renderer.buffer_rgba(),
520+
(int(renderer.width), int(renderer.height)))
541521

542522
if _has_pil:
543523
# add JPEG support

lib/matplotlib/backends/backend_qt5.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import matplotlib
1414

15+
from matplotlib import backend_tools, cbook
1516
from matplotlib._pylab_helpers import Gcf
1617
from matplotlib.backend_bases import (
1718
_Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2,
@@ -20,7 +21,6 @@
2021
from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool
2122
from matplotlib.figure import Figure
2223
from matplotlib.backend_managers import ToolManager
23-
from matplotlib import backend_tools
2424

2525
from .qt_compat import (
2626
QtCore, QtGui, QtWidgets, _getSaveFileName, is_pyqt5, __version__, QT_API)
@@ -169,12 +169,9 @@ def cooperative_qwidget_init(self, *args, **kwargs):
169169

170170
@functools.wraps(__init__)
171171
def wrapper(self, **kwargs):
172-
try:
173-
QtWidgets.QWidget.__init__ = cooperative_qwidget_init
172+
with cbook._setattr_cm(QtWidgets.QWidget,
173+
__init__=cooperative_qwidget_init):
174174
__init__(self, **kwargs)
175-
finally:
176-
# Restore __init__
177-
QtWidgets.QWidget.__init__ = qwidget_init
178175

179176
return wrapper
180177

@@ -490,11 +487,8 @@ def draw(self):
490487
# that uses the result of the draw() to update plot elements.
491488
if self._is_drawing:
492489
return
493-
self._is_drawing = True
494-
try:
490+
with cbook._setattr_cm(self, _is_drawing=True):
495491
super().draw()
496-
finally:
497-
self._is_drawing = False
498492
self.update()
499493

500494
def draw_idle(self):

lib/matplotlib/backends/backend_webagg_core.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,11 @@ def show(self):
151151

152152
def draw(self):
153153
renderer = self.get_renderer(cleared=True)
154-
155154
self._png_is_old = True
156-
157-
backend_agg.RendererAgg.lock.acquire()
158155
try:
159-
self.figure.draw(renderer)
156+
with backend_agg.RendererAgg.lock:
157+
self.figure.draw(renderer)
160158
finally:
161-
backend_agg.RendererAgg.lock.release()
162159
# Swap the frames
163160
self.manager.refresh_all()
164161

lib/matplotlib/cbook/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,3 +2572,21 @@ def _str_lower_equal(obj, s):
25722572
cannot be used in a boolean context.
25732573
"""
25742574
return isinstance(obj, six.string_types) and obj.lower() == s
2575+
2576+
2577+
@contextlib.contextmanager
2578+
def _setattr_cm(obj, **kwargs):
2579+
"""Temporarily set some attributes; restore original state at context exit.
2580+
"""
2581+
sentinel = object()
2582+
origs = [(attr, getattr(obj, attr, sentinel)) for attr in kwargs]
2583+
try:
2584+
for attr, val in kwargs.items():
2585+
setattr(obj, attr, val)
2586+
yield
2587+
finally:
2588+
for attr, orig in origs:
2589+
if orig is sentinel:
2590+
delattr(obj, attr)
2591+
else:
2592+
setattr(obj, attr, orig)

0 commit comments

Comments
 (0)