10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
13 __docformat__ = 'restructuredtext' |
13 __docformat__ = 'restructuredtext' |
14 |
14 |
15 |
15 from itertools import filterfalse, tee |
16 # import standard library |
|
17 from itertools import filterfalse |
|
18 from random import random, shuffle |
16 from random import random, shuffle |
19 |
17 |
20 # import interfaces |
18 from zope.interface import Interface |
21 |
19 |
22 # import packages |
20 from pyams_utils.adapter import ContextRequestViewAdapter, adapter_config |
|
21 from pyams_utils.interfaces.tales import ITALESExtension |
23 |
22 |
24 |
23 |
25 def unique(seq, key=None): |
24 def unique(seq, key=None): |
26 """Extract unique values from list, preserving order |
25 """Extract unique values from list, preserving order |
27 |
26 |
121 selected_index = int(random() * (index+1)) |
120 selected_index = int(random() * (index+1)) |
122 if selected_index < limit: |
121 if selected_index < limit: |
123 selected[selected_index] = item |
122 selected[selected_index] = item |
124 shuffle(selected) |
123 shuffle(selected) |
125 return iter(selected) |
124 return iter(selected) |
|
125 |
|
126 |
|
127 def boolean_iter(iterable): |
|
128 """Check if an iterable returns at least one value, without consuming it. |
|
129 |
|
130 The function returns a tuple containing a boolean flag indicating if the original iterator |
|
131 is empty or not, and the original un-consumed iterator. |
|
132 |
|
133 >>> from pyams_utils.list import boolean_iter |
|
134 >>> def empty(input): |
|
135 ... yield from input |
|
136 >>> mylist = empty(()) |
|
137 >>> check, myiter = boolean_iter(mylist) |
|
138 >>> check |
|
139 False |
|
140 >>> list(myiter) |
|
141 [] |
|
142 >>> mylist = empty((1,2,3)) |
|
143 >>> check, myiter = boolean_iter(mylist) |
|
144 >>> check |
|
145 True |
|
146 >>> list(myiter) |
|
147 [1, 2, 3] |
|
148 >>> list(myiter) |
|
149 [] |
|
150 """ |
|
151 |
|
152 def inner_check(): |
|
153 check, items = tee(iterable) |
|
154 try: |
|
155 next(check) |
|
156 except StopIteration: |
|
157 yield False |
|
158 else: |
|
159 yield True |
|
160 yield from items |
|
161 |
|
162 values = inner_check() |
|
163 return next(values), values |
|
164 |
|
165 |
|
166 @adapter_config(name='boolean_iter', context=(Interface, Interface, Interface), provides=ITALESExtension) |
|
167 class IterValuesCheckerExpression(ContextRequestViewAdapter): |
|
168 """TALES expression used to handle iterators |
|
169 |
|
170 The expression returns a tuple containing a boolean flag indicating if the original iterator |
|
171 is empty or not, and the original un-consumed iterator. |
|
172 """ |
|
173 |
|
174 def render(self, context=None): |
|
175 if context is None: |
|
176 context = self.context |
|
177 return boolean_iter(context) |