2 Helper for looping over sequences, particular in templates.
4 Often in a loop in a template it's handy to know what's next up,
5 previously up, if this is the first or last item in the sequence, etc.
6 These can be awkward to manage in a normal Python loop, but using the
7 looper you can get a better sense of the context. Use like::
9 >>> for loop, item in looper(['a', 'b', 'c']):
10 ... print loop.number, item
22 from Cython
.Tempita
.compat3
import basestring_
29 Helper for looping (particularly in templates)
33 for loop, item in looper(seq):
38 def __init__(self
, seq
):
42 return looper_iter(self
.seq
)
45 return '<%s for %r>' % (
46 self
.__class
__.__name
__, self
.seq
)
49 class looper_iter(object):
51 def __init__(self
, seq
):
59 if self
.pos
>= len(self
.seq
):
61 result
= loop_pos(self
.seq
, self
.pos
), self
.seq
[self
.pos
]
69 class loop_pos(object):
71 def __init__(self
, seq
, pos
):
76 return '<loop pos=%r at %r>' % (
77 self
.seq
[self
.pos
], self
.pos
)
81 index
= property(index
)
85 number
= property(number
)
88 return self
.seq
[self
.pos
]
93 return self
.seq
[self
.pos
+ 1]
96 __next__
= property(__next__
)
104 return self
.seq
[self
.pos
- 1]
105 previous
= property(previous
)
108 return not self
.pos
% 2
113 even
= property(even
)
117 first
= property(first
)
120 return self
.pos
== len(self
.seq
) - 1
121 last
= property(last
)
125 length
= property(length
)
127 def first_group(self
, getter
=None):
129 Returns true if this item is the start of a new group,
130 where groups mean that some attribute has changed. The getter
131 can be None (the item itself changes), an attribute name like
132 ``'.attr'``, a function, or a dict key or list index.
136 return self
._compare
_group
(self
.item
, self
.previous
, getter
)
138 def last_group(self
, getter
=None):
140 Returns true if this item is the end of a new group,
141 where groups mean that some attribute has changed. The getter
142 can be None (the item itself changes), an attribute name like
143 ``'.attr'``, a function, or a dict key or list index.
147 return self
._compare
_group
(self
.item
, self
.__next
__, getter
)
149 def _compare_group(self
, item
, other
, getter
):
152 elif (isinstance(getter
, basestring_
)
153 and getter
.startswith('.')):
155 if getter
.endswith('()'):
157 return getattr(item
, getter
)() != getattr(other
, getter
)()
159 return getattr(item
, getter
) != getattr(other
, getter
)
160 elif hasattr(getter
, '__call__'):
161 return getter(item
) != getter(other
)
163 return item
[getter
] != other
[getter
]