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

Appearance settings

Commit 075523e

Browse filesBrowse files
committed
setattr context manager.
1 parent 3d3472c commit 075523e
Copy full SHA for 075523e

File tree

Expand file treeCollapse file tree

12 files changed

+144
-193
lines changed
Filter options
Expand file treeCollapse file tree

12 files changed

+144
-193
lines changed

‎lib/matplotlib/artist.py

Copy file name to clipboardExpand all lines: lib/matplotlib/artist.py
+2-7Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -897,13 +897,8 @@ def _update_property(self, k, v):
897897
raise AttributeError('Unknown property %s' % k)
898898
return func(v)
899899

900-
store = self.eventson
901-
self.eventson = False
902-
try:
903-
ret = [_update_property(self, k, v)
904-
for k, v in props.items()]
905-
finally:
906-
self.eventson = store
900+
with cbook._setattr_cm(self, eventson=False):
901+
ret = [_update_property(self, k, v) for k, v in props.items()]
907902

908903
if len(ret):
909904
self.pchanged()

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+98-107Lines changed: 98 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,17 +2148,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21482148
tight bbox is calculated.
21492149
21502150
"""
2151-
self._is_saving = True
2152-
# Remove the figure manager, if any, to avoid resizing the GUI widget.
2153-
# Having *no* manager and a *None* manager are currently different (see
2154-
# Figure.show); should probably be normalized to None at some point.
2155-
_no_manager = object()
2156-
if hasattr(self, 'manager'):
2157-
manager = self.manager
2158-
del self.manager
2159-
else:
2160-
manager = _no_manager
2161-
21622151
if format is None:
21632152
# get format from filename, or from backend's default filetype
21642153
if isinstance(filename, six.string_types):
@@ -2175,111 +2164,113 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21752164

21762165
if dpi is None:
21772166
dpi = rcParams['savefig.dpi']
2178-
21792167
if dpi == 'figure':
21802168
dpi = getattr(self.figure, '_original_dpi', self.figure.dpi)
21812169

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

22842275
@classmethod
22852276
def get_default_filetype(cls):

‎lib/matplotlib/backends/backend_agg.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_agg.py
+11-31Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -489,53 +489,33 @@ def buffer_rgba(self):
489489
def print_raw(self, filename_or_obj, *args, **kwargs):
490490
FigureCanvasAgg.draw(self)
491491
renderer = self.get_renderer()
492-
original_dpi = renderer.dpi
493-
renderer.dpi = self.figure.dpi
494-
if isinstance(filename_or_obj, six.string_types):
495-
fileobj = open(filename_or_obj, 'wb')
496-
close = True
497-
else:
498-
fileobj = filename_or_obj
499-
close = False
500-
try:
492+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
493+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
501494
fileobj.write(renderer._renderer.buffer_rgba())
502-
finally:
503-
if close:
504-
fileobj.close()
505-
renderer.dpi = original_dpi
506495
print_rgba = print_raw
507496

508497
def print_png(self, filename_or_obj, *args, **kwargs):
509498
FigureCanvasAgg.draw(self)
510499
renderer = self.get_renderer()
511-
original_dpi = renderer.dpi
512-
renderer.dpi = self.figure.dpi
513500

514-
version_str = 'matplotlib version ' + __version__ + \
515-
', http://matplotlib.org/'
501+
version_str = (
502+
'matplotlib version ' + __version__ + ', http://matplotlib.org/')
516503
metadata = OrderedDict({'Software': version_str})
517504
user_metadata = kwargs.pop("metadata", None)
518505
if user_metadata is not None:
519506
metadata.update(user_metadata)
520507

521-
try:
522-
with cbook.open_file_cm(filename_or_obj, "wb") as fh:
523-
_png.write_png(renderer._renderer, fh,
524-
self.figure.dpi, metadata=metadata)
525-
finally:
526-
renderer.dpi = original_dpi
508+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
509+
cbook.open_file_cm(filename_or_obj, "wb") as fh:
510+
_png.write_png(renderer._renderer, fh,
511+
self.figure.dpi, metadata=metadata)
527512

528513
def print_to_buffer(self):
529514
FigureCanvasAgg.draw(self)
530515
renderer = self.get_renderer()
531-
original_dpi = renderer.dpi
532-
renderer.dpi = self.figure.dpi
533-
try:
534-
result = (renderer._renderer.buffer_rgba(),
535-
(int(renderer.width), int(renderer.height)))
536-
finally:
537-
renderer.dpi = original_dpi
538-
return result
516+
with cbook._setattr_cm(renderer, dpi=self.figure.dpi):
517+
return (renderer._renderer.buffer_rgba(),
518+
(int(renderer.width), int(renderer.height)))
539519

540520
if _has_pil:
541521
# add JPEG support

‎lib/matplotlib/backends/backend_qt5.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_qt5.py
+2-5Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,9 @@ def cooperative_qwidget_init(self, *args, **kwargs):
166166

167167
@functools.wraps(__init__)
168168
def wrapper(self, **kwargs):
169-
try:
170-
QtWidgets.QWidget.__init__ = cooperative_qwidget_init
169+
with cbook._setattr_cm(QtWidgets.QWidget,
170+
__init__=cooperative_qwidget_init):
171171
__init__(self, **kwargs)
172-
finally:
173-
# Restore __init__
174-
QtWidgets.QWidget.__init__ = qwidget_init
175172

176173
return wrapper
177174

‎lib/matplotlib/backends/backend_qt5agg.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_qt5agg.py
+1-5Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,8 @@ def draw(self):
127127
# uses the result of the draw() to update plot elements.
128128
if self._agg_is_drawing:
129129
return
130-
131-
self._agg_is_drawing = True
132-
try:
130+
with cbook._setattr_cm(self, _agg_is_drawing=True):
133131
super(FigureCanvasQTAggBase, self).draw()
134-
finally:
135-
self._agg_is_drawing = False
136132
self.update()
137133

138134
def draw_idle(self):

‎lib/matplotlib/backends/backend_webagg_core.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_webagg_core.py
+2-5Lines 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

Copy file name to clipboardExpand all lines: lib/matplotlib/cbook/__init__.py
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,3 +2803,21 @@ def _str_lower_equal(obj, s):
28032803
cannot be used in a boolean context.
28042804
"""
28052805
return isinstance(obj, six.string_types) and obj.lower() == s
2806+
2807+
2808+
@contextlib.contextmanager
2809+
def _setattr_cm(obj, **kwargs):
2810+
"""Temporarily set some attributes; restore original state at context exit.
2811+
"""
2812+
sentinel = object()
2813+
origs = [(attr, getattr(obj, attr, sentinel)) for attr in kwargs]
2814+
try:
2815+
for attr, val in kwargs.items():
2816+
setattr(obj, attr, val)
2817+
yield
2818+
finally:
2819+
for attr, orig in origs:
2820+
if orig is sentinel:
2821+
delattr(obj, attr)
2822+
else:
2823+
setattr(obj, attr, orig)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.