Skip to content

Commit 6f167ca

Browse files
committed
Merge pull request #6275 from WeatherGod/fix_cycler_validation
Fix cycler validation
2 parents 997029b + 2128c96 commit 6f167ca

File tree

4 files changed

+46
-15
lines changed

4 files changed

+46
-15
lines changed

lib/matplotlib/rcsetup.py

+28-9
Original file line numberDiff line numberDiff line change
@@ -726,15 +726,7 @@ def cycler(*args, **kwargs):
726726
if not isinstance(args[0], Cycler):
727727
raise TypeError("If only one positional argument given, it must "
728728
" be a Cycler instance.")
729-
730-
c = args[0]
731-
unknowns = c.keys - (set(_prop_validators.keys()) |
732-
set(_prop_aliases.keys()))
733-
if unknowns:
734-
# This is about as much validation I can do
735-
raise TypeError("Unknown artist properties: %s" % unknowns)
736-
else:
737-
return Cycler(c)
729+
return validate_cycler(args[0])
738730
elif len(args) == 2:
739731
pairs = [(args[0], args[1])]
740732
elif len(args) > 2:
@@ -789,6 +781,33 @@ def validate_cycler(s):
789781
else:
790782
raise ValueError("object was not a string or Cycler instance: %s" % s)
791783

784+
unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases))
785+
if unknowns:
786+
raise ValueError("Unknown artist properties: %s" % unknowns)
787+
788+
# Not a full validation, but it'll at least normalize property names
789+
# A fuller validation would require v0.10 of cycler.
790+
checker = set()
791+
for prop in cycler_inst.keys:
792+
norm_prop = _prop_aliases.get(prop, prop)
793+
if norm_prop != prop and norm_prop in cycler_inst.keys:
794+
raise ValueError("Cannot specify both '{0}' and alias '{1}'"
795+
" in the same prop_cycle".format(norm_prop, prop))
796+
if norm_prop in checker:
797+
raise ValueError("Another property was already aliased to '{0}'."
798+
" Collision normalizing '{1}'.".format(norm_prop,
799+
prop))
800+
checker.update([norm_prop])
801+
802+
# This is just an extra-careful check, just in case there is some
803+
# edge-case I haven't thought of.
804+
assert len(checker) == len(cycler_inst.keys)
805+
806+
# Now, it should be safe to mutate this cycler
807+
for prop in cycler_inst.keys:
808+
norm_prop = _prop_aliases.get(prop, prop)
809+
cycler_inst.change_key(prop, norm_prop)
810+
792811
return cycler_inst
793812

794813

lib/matplotlib/tests/test_cycles.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_colorcycle_basic():
3232
def test_marker_cycle():
3333
fig = plt.figure()
3434
ax = fig.add_subplot(111)
35-
ax.set_prop_cycle(cycler('color', ['r', 'g', 'y']) +
35+
ax.set_prop_cycle(cycler('c', ['r', 'g', 'y']) +
3636
cycler('marker', ['.', '*', 'x']))
3737
xs = np.arange(10)
3838
ys = 0.25 * xs + 2
@@ -48,7 +48,7 @@ def test_marker_cycle():
4848
fig = plt.figure()
4949
ax = fig.add_subplot(111)
5050
# Test keyword arguments, numpy arrays, and generic iterators
51-
ax.set_prop_cycle(color=np.array(['r', 'g', 'y']),
51+
ax.set_prop_cycle(c=np.array(['r', 'g', 'y']),
5252
marker=iter(['.', '*', 'x']))
5353
xs = np.arange(10)
5454
ys = 0.25 * xs + 2
@@ -67,7 +67,7 @@ def test_marker_cycle():
6767
def test_linestylecycle_basic():
6868
fig = plt.figure()
6969
ax = fig.add_subplot(111)
70-
ax.set_prop_cycle(cycler('linestyle', ['-', '--', ':']))
70+
ax.set_prop_cycle(cycler('ls', ['-', '--', ':']))
7171
xs = np.arange(10)
7272
ys = 0.25 * xs + 2
7373
ax.plot(xs, ys, label='solid', lw=4)
@@ -85,7 +85,7 @@ def test_linestylecycle_basic():
8585
def test_fillcycle_basic():
8686
fig = plt.figure()
8787
ax = fig.add_subplot(111)
88-
ax.set_prop_cycle(cycler('color', ['r', 'g', 'y']) +
88+
ax.set_prop_cycle(cycler('c', ['r', 'g', 'y']) +
8989
cycler('hatch', ['xx', 'O', '|-']) +
9090
cycler('linestyle', ['-', '--', ':']))
9191
xs = np.arange(10)
@@ -131,7 +131,7 @@ def test_valid_input_forms():
131131
ax.set_prop_cycle(None)
132132
ax.set_prop_cycle(cycler('linewidth', [1, 2]))
133133
ax.set_prop_cycle('color', 'rgywkbcm')
134-
ax.set_prop_cycle('linewidth', (1, 2))
134+
ax.set_prop_cycle('lw', (1, 2))
135135
ax.set_prop_cycle('linewidth', [1, 2])
136136
ax.set_prop_cycle('linewidth', iter([1, 2]))
137137
ax.set_prop_cycle('linewidth', np.array([1, 2]))
@@ -181,6 +181,13 @@ def test_invalid_input_forms():
181181
'linewidth', {'1': 1, '2': 2})
182182
assert_raises((TypeError, ValueError), ax.set_prop_cycle,
183183
linewidth=1, color='r')
184+
assert_raises((TypeError, ValueError), ax.set_prop_cycle, 'foobar', [1, 2])
185+
assert_raises((TypeError, ValueError), ax.set_prop_cycle,
186+
foobar=[1, 2])
187+
assert_raises((TypeError, ValueError), ax.set_prop_cycle,
188+
cycler(foobar=[1, 2]))
189+
assert_raises(ValueError, ax.set_prop_cycle,
190+
cycler(color='rgb', c='cmy'))
184191

185192

186193
if __name__ == '__main__':

lib/matplotlib/tests/test_rcparams.py

+5
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ def test_validators():
322322
("cycler('c', 'rgb') * cycler('linestyle', ['-', '--'])",
323323
(cycler('color', 'rgb') *
324324
cycler('linestyle', ['-', '--']))),
325+
(cycler('ls', ['-', '--']),
326+
cycler('linestyle', ['-', '--'])),
327+
(cycler(mew=[2, 5]),
328+
cycler('markeredgewidth', [2, 5])),
325329
),
326330
# This is *so* incredibly important: validate_cycler() eval's
327331
# an arbitrary string! I think I have it locked down enough,
@@ -343,6 +347,7 @@ def test_validators():
343347
('cycler("waka", [1, 2, 3])', ValueError), # not a property
344348
('cycler(c=[1, 2, 3])', ValueError), # invalid values
345349
("cycler(lw=['a', 'b', 'c'])", ValueError), # invalid values
350+
(cycler('waka', [1, 3, 5]), ValueError), # not a property
346351
)
347352
},
348353
{'validator': validate_hatch,

setupext.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,7 @@ def check(self):
13841384
return "using cycler version %s" % cycler.__version__
13851385

13861386
def get_install_requires(self):
1387-
return ['cycler']
1387+
return ['cycler>=0.9']
13881388

13891389

13901390
class Dateutil(SetupPackage):

0 commit comments

Comments
 (0)