Skip to content

Commit 7a811d8

Browse files
committed
Implemented an expanded syntax for cycler()
1 parent ddc6e11 commit 7a811d8

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

cycler.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,61 @@ def simplify(self):
332332
return reduce(add, (cycler(k, v) for k, v in six.iteritems(trans)))
333333

334334

335-
def cycler(label, itr):
335+
def cycler(*args, **kwargs):
336+
"""
337+
Create a new `Cycler` object from the combination of
338+
positional arguments or keyword arguments.
339+
340+
cycler(arg)
341+
cycler(label1, itr1[, label2, iter2[, ...]])
342+
cycler(label1=itr1[, label2=iter2[, ...]])
343+
344+
Form 1 simply copies a given `Cycler` object.
345+
Form 2 composes a `Cycler` as an outer product of the
346+
pairs of label/iter.
347+
Form 3 composes a `Cycler` as an inner product of the
348+
pairs of keyword arguments.
349+
350+
Parameters
351+
----------
352+
label : str
353+
The property key.
354+
355+
itr : iterable
356+
Finite length iterable of the property values.
357+
358+
Returns
359+
-------
360+
cycler : Cycler
361+
New `Cycler` for the given property
362+
"""
363+
364+
if args and kwargs:
365+
raise TypeError("cyl() can only accept positional OR keyword "
366+
"arguments -- not both.")
367+
elif not args and not kwargs:
368+
raise TypeError("cyl() must have positional OR keyword arguments")
369+
370+
if len(args) == 1:
371+
if not isinstance(args[0], Cycler):
372+
raise TypeError("If only one positional argument given, it must "
373+
" be a Cycler instance.")
374+
return copy.copy(args[0])
375+
elif len(args) > 1:
376+
if (len(args) % 2) == 1:
377+
raise TypeError("Positional arguments must be in pairs. Odd "
378+
" number of arguments found: %d" % len(args))
379+
pairs = [(args[i], args[i+1]) for i in range(0, len(args), 2)]
380+
op = mul
381+
382+
if kwargs:
383+
pairs = six.iteritems(kwargs)
384+
op = add
385+
386+
return reduce(op, (_cycler(k, v) for k, v in pairs))
387+
388+
389+
def _cycler(label, itr):
336390
"""
337391
Create a new `Cycler` object from a property name and
338392
iterable of values.

test_cycler.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ def test_creation():
2828
yield _cycler_helper, c, 3, ['c'], [['r', 'g', 'b']]
2929
c = cycler('c', list('rgb'))
3030
yield _cycler_helper, c, 3, ['c'], [['r', 'g', 'b']]
31+
c = cycler(c='rgb')
32+
yield _cycler_helper, c, 3, ['c'], [['r', 'g', 'b']]
33+
c = cycler(cycler('c', 'rgb'))
34+
yield _cycler_helper, c, 3, ['c'], [['r', 'g', 'b']]
3135

3236

3337
def test_compose():
@@ -73,6 +77,33 @@ def test_constructor():
7377
c3 = cycler('c', c1)
7478
yield _cycler_helper, c3+c2, 3, ['c', 'ec'], [['r', 'g', 'b']]*2
7579

80+
# addition using cycler()
81+
yield (_cycler_helper, cycler(c='rgb', lw=range(3)),
82+
3, ['c', 'lw'], [list('rgb'), range(3)])
83+
yield (_cycler_helper, cycler(lw=range(3), c='rgb'),
84+
3, ['c', 'lw'], [list('rgb'), range(3)])
85+
# Purposely mixing them
86+
yield (_cycler_helper, cycler(c=range(3), lw=c1),
87+
3, ['c', 'lw'], [range(3), list('rgb')])
88+
89+
# multiplication with cycler()
90+
target = zip(*product(list('rgb'), range(3)))
91+
yield (_cycler_helper, cycler('c', 'rgb', 'lw', range(3)),
92+
9, ['c', 'lw'], target)
93+
94+
target = zip(*product(range(3), list('rgb')))
95+
yield (_cycler_helper, cycler('lw', range(3), 'c', 'rgb'),
96+
9, ['lw', 'c'], target)
97+
98+
target = zip(*product(range(15), list('rgb')))
99+
yield (_cycler_helper, cycler('lw', range(15), 'c', 'rgb'),
100+
45, ['lw', 'c'], target)
101+
102+
# Purposely mixing them
103+
target = zip(*product(list('rgb'), range(15)))
104+
yield (_cycler_helper, cycler('lw', c1, 'c', range(15)),
105+
45, ['lw', 'c'], target)
106+
76107

77108
def test_failures():
78109
c1 = cycler('c', 'rgb')

0 commit comments

Comments
 (0)