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

Skip to content

Commit cd82b2e

Browse files
committed
setattr context manager.
1 parent 8184e1f commit cd82b2e

12 files changed

+151
-209
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
@@ -2117,17 +2117,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21172117
tight bbox is calculated.
21182118
21192119
"""
2120-
self._is_saving = True
2121-
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2122-
# Having *no* manager and a *None* manager are currently different (see
2123-
# Figure.show); should probably be normalized to None at some point.
2124-
_no_manager = object()
2125-
if hasattr(self, 'manager'):
2126-
manager = self.manager
2127-
del self.manager
2128-
else:
2129-
manager = _no_manager
2130-
21312120
if format is None:
21322121
# get format from filename, or from backend's default filetype
21332122
if isinstance(filename, six.string_types):
@@ -2144,104 +2133,107 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21442133

21452134
if dpi is None:
21462135
dpi = rcParams['savefig.dpi']
2147-
21482136
if dpi == 'figure':
21492137
dpi = getattr(self.figure, '_original_dpi', self.figure.dpi)
21502138

2151-
if facecolor is None:
2152-
facecolor = rcParams['savefig.facecolor']
2153-
if edgecolor is None:
2154-
edgecolor = rcParams['savefig.edgecolor']
2155-
2156-
origDPI = self.figure.dpi
2157-
origfacecolor = self.figure.get_facecolor()
2158-
origedgecolor = self.figure.get_edgecolor()
2159-
2160-
self.figure.dpi = dpi
2161-
self.figure.set_facecolor(facecolor)
2162-
self.figure.set_edgecolor(edgecolor)
2163-
2164-
bbox_inches = kwargs.pop("bbox_inches", None)
2165-
if bbox_inches is None:
2166-
bbox_inches = rcParams['savefig.bbox']
2167-
2168-
if bbox_inches:
2169-
# call adjust_bbox to save only the given area
2170-
if bbox_inches == "tight":
2171-
# When bbox_inches == "tight", it saves the figure twice. The
2172-
# first save command (to a BytesIO) is just to estimate the
2173-
# bounding box of the figure.
2139+
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2140+
# Some code (e.g. Figure.show) differentiates between having *no*
2141+
# manager and a *None* manager, which should be fixed at some point,
2142+
# but this should be fine.
2143+
with cbook._setattr_cm(self, _is_saving=True, manager=None), \
2144+
cbook._setattr_cm(self.figure, dpi=dpi):
2145+
2146+
if facecolor is None:
2147+
facecolor = rcParams['savefig.facecolor']
2148+
if edgecolor is None:
2149+
edgecolor = rcParams['savefig.edgecolor']
2150+
2151+
origfacecolor = self.figure.get_facecolor()
2152+
origedgecolor = self.figure.get_edgecolor()
2153+
2154+
self.figure.dpi = dpi
2155+
self.figure.set_facecolor(facecolor)
2156+
self.figure.set_edgecolor(edgecolor)
2157+
2158+
bbox_inches = kwargs.pop("bbox_inches", None)
2159+
if bbox_inches is None:
2160+
bbox_inches = rcParams['savefig.bbox']
2161+
2162+
if bbox_inches:
2163+
# call adjust_bbox to save only the given area
2164+
if bbox_inches == "tight":
2165+
# When bbox_inches == "tight", it saves the figure twice.
2166+
# The first save command (to a BytesIO) is just to estimate
2167+
# the bounding box of the figure.
2168+
result = print_method(
2169+
io.BytesIO(),
2170+
dpi=dpi,
2171+
facecolor=facecolor,
2172+
edgecolor=edgecolor,
2173+
orientation=orientation,
2174+
dryrun=True,
2175+
**kwargs)
2176+
renderer = self.figure._cachedRenderer
2177+
bbox_inches = self.figure.get_tightbbox(renderer)
2178+
2179+
bbox_artists = kwargs.pop("bbox_extra_artists", None)
2180+
if bbox_artists is None:
2181+
bbox_artists = \
2182+
self.figure.get_default_bbox_extra_artists()
2183+
2184+
bbox_filtered = []
2185+
for a in bbox_artists:
2186+
bbox = a.get_window_extent(renderer)
2187+
if a.get_clip_on():
2188+
clip_box = a.get_clip_box()
2189+
if clip_box is not None:
2190+
bbox = Bbox.intersection(bbox, clip_box)
2191+
clip_path = a.get_clip_path()
2192+
if clip_path is not None and bbox is not None:
2193+
clip_path = \
2194+
clip_path.get_fully_transformed_path()
2195+
bbox = Bbox.intersection(
2196+
bbox, clip_path.get_extents())
2197+
if bbox is not None and (
2198+
bbox.width != 0 or bbox.height != 0):
2199+
bbox_filtered.append(bbox)
2200+
2201+
if bbox_filtered:
2202+
_bbox = Bbox.union(bbox_filtered)
2203+
trans = Affine2D().scale(1.0 / self.figure.dpi)
2204+
bbox_extra = TransformedBbox(_bbox, trans)
2205+
bbox_inches = Bbox.union([bbox_inches, bbox_extra])
2206+
2207+
pad = kwargs.pop("pad_inches", None)
2208+
if pad is None:
2209+
pad = rcParams['savefig.pad_inches']
2210+
2211+
bbox_inches = bbox_inches.padded(pad)
2212+
2213+
restore_bbox = tight_bbox.adjust_bbox(self.figure, bbox_inches,
2214+
canvas.fixed_dpi)
2215+
2216+
_bbox_inches_restore = (bbox_inches, restore_bbox)
2217+
else:
2218+
_bbox_inches_restore = None
2219+
2220+
try:
21742221
result = print_method(
2175-
io.BytesIO(),
2222+
filename,
21762223
dpi=dpi,
21772224
facecolor=facecolor,
21782225
edgecolor=edgecolor,
21792226
orientation=orientation,
2180-
dryrun=True,
2227+
bbox_inches_restore=_bbox_inches_restore,
21812228
**kwargs)
2182-
renderer = self.figure._cachedRenderer
2183-
bbox_inches = self.figure.get_tightbbox(renderer)
2184-
2185-
bbox_artists = kwargs.pop("bbox_extra_artists", None)
2186-
if bbox_artists is None:
2187-
bbox_artists = self.figure.get_default_bbox_extra_artists()
2188-
2189-
bbox_filtered = []
2190-
for a in bbox_artists:
2191-
bbox = a.get_window_extent(renderer)
2192-
if a.get_clip_on():
2193-
clip_box = a.get_clip_box()
2194-
if clip_box is not None:
2195-
bbox = Bbox.intersection(bbox, clip_box)
2196-
clip_path = a.get_clip_path()
2197-
if clip_path is not None and bbox is not None:
2198-
clip_path = clip_path.get_fully_transformed_path()
2199-
bbox = Bbox.intersection(bbox,
2200-
clip_path.get_extents())
2201-
if bbox is not None and (bbox.width != 0 or
2202-
bbox.height != 0):
2203-
bbox_filtered.append(bbox)
2204-
2205-
if bbox_filtered:
2206-
_bbox = Bbox.union(bbox_filtered)
2207-
trans = Affine2D().scale(1.0 / self.figure.dpi)
2208-
bbox_extra = TransformedBbox(_bbox, trans)
2209-
bbox_inches = Bbox.union([bbox_inches, bbox_extra])
2210-
2211-
pad = kwargs.pop("pad_inches", None)
2212-
if pad is None:
2213-
pad = rcParams['savefig.pad_inches']
2214-
2215-
bbox_inches = bbox_inches.padded(pad)
2216-
2217-
restore_bbox = tight_bbox.adjust_bbox(self.figure, bbox_inches,
2218-
canvas.fixed_dpi)
2219-
2220-
_bbox_inches_restore = (bbox_inches, restore_bbox)
2221-
else:
2222-
_bbox_inches_restore = None
2223-
2224-
try:
2225-
result = print_method(
2226-
filename,
2227-
dpi=dpi,
2228-
facecolor=facecolor,
2229-
edgecolor=edgecolor,
2230-
orientation=orientation,
2231-
bbox_inches_restore=_bbox_inches_restore,
2232-
**kwargs)
2233-
finally:
2234-
if bbox_inches and restore_bbox:
2235-
restore_bbox()
2236-
2237-
self.figure.dpi = origDPI
2238-
self.figure.set_facecolor(origfacecolor)
2239-
self.figure.set_edgecolor(origedgecolor)
2240-
self.figure.set_canvas(self)
2241-
if manager is not _no_manager:
2242-
self.manager = manager
2243-
self._is_saving = False
2244-
return result
2229+
finally:
2230+
if bbox_inches and restore_bbox:
2231+
restore_bbox()
2232+
2233+
self.figure.set_facecolor(origfacecolor)
2234+
self.figure.set_edgecolor(origedgecolor)
2235+
self.figure.set_canvas(self)
2236+
return result
22452237

22462238
@classmethod
22472239
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
@@ -486,53 +486,33 @@ def buffer_rgba(self):
486486
def print_raw(self, filename_or_obj, *args, **kwargs):
487487
FigureCanvasAgg.draw(self)
488488
renderer = self.get_renderer()
489-
original_dpi = renderer.dpi
490-
renderer.dpi = self.figure.dpi
491-
if isinstance(filename_or_obj, six.string_types):
492-
fileobj = open(filename_or_obj, 'wb')
493-
close = True
494-
else:
495-
fileobj = filename_or_obj
496-
close = False
497-
try:
498-
fileobj.write(renderer._renderer.buffer_rgba())
499-
finally:
500-
if close:
501-
fileobj.close()
502-
renderer.dpi = original_dpi
489+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
490+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
491+
fh.write(renderer._renderer.buffer_rgba())
503492
print_rgba = print_raw
504493

505494
def print_png(self, filename_or_obj, *args, **kwargs):
506495
FigureCanvasAgg.draw(self)
507496
renderer = self.get_renderer()
508-
original_dpi = renderer.dpi
509-
renderer.dpi = self.figure.dpi
510497

511-
version_str = 'matplotlib version ' + __version__ + \
512-
', http://matplotlib.org/'
498+
version_str = (
499+
'matplotlib version ' + __version__ + ', http://matplotlib.org/')
513500
metadata = OrderedDict({'Software': version_str})
514501
user_metadata = kwargs.pop("metadata", None)
515502
if user_metadata is not None:
516503
metadata.update(user_metadata)
517504

518-
try:
519-
with cbook.open_file_cm(filename_or_obj, "wb") as fh:
520-
_png.write_png(renderer._renderer, fh,
521-
self.figure.dpi, metadata=metadata)
522-
finally:
523-
renderer.dpi = original_dpi
505+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
506+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
507+
_png.write_png(renderer._renderer, fh,
508+
self.figure.dpi, metadata=metadata)
524509

525510
def print_to_buffer(self):
526511
FigureCanvasAgg.draw(self)
527512
renderer = self.get_renderer()
528-
original_dpi = renderer.dpi
529-
renderer.dpi = self.figure.dpi
530-
try:
531-
result = (renderer._renderer.buffer_rgba(),
532-
(int(renderer.width), int(renderer.height)))
533-
finally:
534-
renderer.dpi = original_dpi
535-
return result
513+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi):
514+
return (renderer._renderer.buffer_rgba(),
515+
(int(renderer.width), int(renderer.height)))
536516

537517
if _has_pil:
538518
# 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

@@ -492,11 +489,8 @@ def draw(self):
492489
# that uses the result of the draw() to update plot elements.
493490
if self._is_drawing:
494491
return
495-
self._is_drawing = True
496-
try:
492+
with cbook._setattr_cm(self, _is_drawing=True):
497493
super().draw()
498-
finally:
499-
self._is_drawing = False
500494
self.update()
501495

502496
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
@@ -2063,3 +2063,21 @@ def _str_lower_equal(obj, s):
20632063
cannot be used in a boolean context.
20642064
"""
20652065
return isinstance(obj, six.string_types) and obj.lower() == s
2066+
2067+
2068+
@contextlib.contextmanager
2069+
def _setattr_cm(obj, **kwargs):
2070+
"""Temporarily set some attributes; restore original state at context exit.
2071+
"""
2072+
sentinel = object()
2073+
origs = [(attr, getattr(obj, attr, sentinel)) for attr in kwargs]
2074+
try:
2075+
for attr, val in kwargs.items():
2076+
setattr(obj, attr, val)
2077+
yield
2078+
finally:
2079+
for attr, orig in origs:
2080+
if orig is sentinel:
2081+
delattr(obj, attr)
2082+
else:
2083+
setattr(obj, attr, orig)

0 commit comments

Comments
 (0)