Skip to content

Commit d99eb86

Browse files
committed
Merge pull request #3196 from astrofrog/issue-3196
Issue with iterability of axes arguments [backport to 1.4.x]
1 parent 2d58094 commit d99eb86

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

lib/matplotlib/figure.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,14 @@ def fixitems(items):
780780
# to tuples for the key
781781
ret = []
782782
for k, v in items:
783-
if iterable(v):
783+
# some objects can define __getitem__ without being
784+
# iterable and in those cases the conversion to tuples
785+
# will fail. So instead of using the iterable(v) function
786+
# we simply try and convert to a tuple, and proceed if not.
787+
try:
784788
v = tuple(v)
789+
except Exception:
790+
pass
785791
ret.append((k, v))
786792
return tuple(ret)
787793

lib/matplotlib/tests/test_figure.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from nose.tools import assert_equal, assert_true, assert_raises
88
from matplotlib.testing.decorators import image_comparison, cleanup
9+
from matplotlib.axes import Axes
910
import matplotlib.pyplot as plt
1011

1112

@@ -110,6 +111,36 @@ def test_too_many_figures():
110111
assert len(w) == 1
111112

112113

114+
def test_iterability_axes_argument():
115+
116+
# This is a regression test for matplotlib/matplotlib#3196. If one of the
117+
# arguments returned by _as_mpl_axes defines __getitem__ but is not
118+
# iterable, this would raise an execption. This is because we check
119+
# whether the arguments are iterable, and if so we try and convert them
120+
# to a tuple. However, the ``iterable`` function returns True if
121+
# __getitem__ is present, but some classes can define __getitem__ without
122+
# being iterable. The tuple conversion is now done in a try...except in
123+
# case it fails.
124+
125+
class MyAxes(Axes):
126+
def __init__(self, *args, **kwargs):
127+
kwargs.pop('myclass', None)
128+
return Axes.__init__(self, *args, **kwargs)
129+
130+
class MyClass(object):
131+
132+
def __getitem__(self, item):
133+
if item != 'a':
134+
raise ValueError("item should be a")
135+
136+
def _as_mpl_axes(self):
137+
return MyAxes, {'myclass': self}
138+
139+
fig = plt.figure()
140+
ax = fig.add_subplot(1, 1, 1, projection=MyClass())
141+
plt.close(fig)
142+
143+
113144
if __name__ == "__main__":
114145
import nose
115146
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

0 commit comments

Comments
 (0)