@@ -194,11 +194,8 @@ def _iter_with(iterable, context_manager):
194194
195195 with context_manager :
196196 next_item = next (iterator )
197- # You may notice that we are not `except`ing a `StopIteration`
198- # here; If we get one, it'll just get propagated and end *this*
199- # iterator. todo: I just realized this will probably cause a bug
200- # where `__exit__` will get the `StopIteration`! Make failing tests
201- # and fix.
197+ # Recycling `StopIteration` exception. (Assuming the context
198+ # manager doesn't have special treatment for it.)
202199
203200 yield next_item
204201
@@ -218,12 +215,15 @@ def get_items(iterable, n, container_type=tuple):
218215
219216def double_filter (filter_function , iterable , lazy_tuple = False ):
220217 '''
221- Filter an `iterable` into two lists according to a `filter_function`.
218+ Filter an `iterable` into two iterables according to a `filter_function`.
222219
223220 This is similar to the builtin `filter`, except it returns a tuple of two
224221 iterators, the first iterating on items that passed the filter function,
225222 and the second iterating on items that didn't.
226223
224+ Note that this function is not thread-safe. (You may not consume the two
225+ iterators on two separate threads.)
226+
227227 If `lazy_tuple=True`, returns a `LazyTuple` rather than an iterator.
228228 '''
229229 iterator = iter (iterable )
@@ -408,6 +408,24 @@ def _fill(iterable, fill_value, fill_value_maker, length):
408408 yield fill_value_maker ()
409409
410410
411+ def call_until_exception (function , exception , lazy_tuple = False ):
412+ '''Iterate on values returned from `function` until getting `exception`.'''
413+ iterator = _call_until_exception (function , exception )
414+ if lazy_tuple :
415+ from python_toolbox import nifty_collections # Avoiding circular import.
416+ return nifty_collections .LazyTuple (iterator )
417+ else :
418+ return iterator
419+
420+
421+ def _call_until_exception (function , exception ):
422+ from python_toolbox import sequence_tools
423+ exceptions = sequence_tools .to_tuple (exception , item_type = BaseException )
424+ try :
425+ yield function ()
426+ except exceptions :
427+ raise StopIteration
428+
411429def get_single_if_any (iterable ,
412430 exception_on_multiple = Exception ('More than one value '
413431 'not allowed.' )):
0 commit comments