creek.util#
Iterator, cursor and function-composition utilities used across creek.
Main entry points:
iterize: turn anIn -> Outfunction into anIterator[In] -> Iterator[Out]onePipe: compose functions into one callableiterate_skipping_errors: iterate, skipping (and optionally reporting) exceptionsto_iterator, cursor_to_iterator, iterator_to_cursor: convert between iterables, iterators and argument-less “cursor” functions
>>> from creek.util import iterize
>>> list(iterize(str.upper)(['a', 'b']))
['A', 'B']
Functions
|
Wrap |
|
Get an iterator from a cursor function. |
Return |
|
|
Get a cursor function from an iterable. |
|
Return |
|
Iterate over a generator, skipping errors and calling an error callback if provided. |
|
Call |
|
Get a cursor function for the input iterator. |
|
From an In->Out function, makes a Iterator[In]->Itertor[Out] function. |
Return |
|
Get an iterator from an iterable or a cursor function |
Classes
|
An argument-less function returning an iterator's values |
|
An iterable type that can actually be used in singledispatch |
|
An iterator type that can actually be used in singledispatch |
|
Simple function composition. |
|
Namespace holding |
A namespace of small stream helpers. |
Exceptions
Raised when an iterator should quit being iterated on, signaling this event any process that cares to catch the signal. |
- class creek.util.CursorFunc(*args, **kwargs)[source]#
Bases:
ProtocolAn argument-less function returning an iterator’s values
- class creek.util.IterableType(*args, **kwargs)[source]#
Bases:
ProtocolAn iterable type that can actually be used in singledispatch
>>> assert isinstance([1, 2, 3], IterableType) >>> assert not isinstance(2, IterableType)
- exception creek.util.IteratorExit[source]#
Bases:
BaseExceptionRaised when an iterator should quit being iterated on, signaling this event any process that cares to catch the signal. We chose to inherit directly from
BaseExceptioninstead ofExceptionfor the same reason thatGeneratorExitdoes: Because it’s not technically an error.See: https://docs.python.org/3/library/exceptions.html#GeneratorExit
- class creek.util.IteratorType(*args, **kwargs)[source]#
Bases:
ProtocolAn iterator type that can actually be used in singledispatch
>>> assert isinstance(iter([1, 2, 3]), IteratorType) >>> assert not isinstance([1, 2, 3], IteratorType)
- class creek.util.Pipe(*funcs, **named_funcs)[source]#
Bases:
objectSimple function composition. That is, gives you a callable that implements input -> f_1 -> … -> f_n -> output.
>>> def foo(a, b=2): ... return a + b >>> f = Pipe(foo, lambda x: print(f"x: {x}")) >>> f(3) x: 5 >>> len(f) 2
You can name functions, but this would just be for documentation purposes. The names are completely ignored.
>>> g = Pipe( ... add_numbers = lambda x, y: x + y, ... multiply_by_2 = lambda x: x * 2, ... stringify = str ... ) >>> g(2, 3) '10' >>> len(g) 3
Notes
Pipe instances don’t have a __name__ etc. So some expectations of normal functions are not met.
Pipe instance are pickalable (as long as the functions that compose them are)
You can specify a single functions:
>>> Pipe(lambda x: x + 1)(2) 3
but
>>> Pipe() Traceback (most recent call last): ... ValueError: You need to specify at least one function!
You can specify an instance name and/or doc with the special (reserved) argument names
__name__and__doc__(which therefore can’t be used as function names):>>> f = Pipe(map, add_it=sum, __name__='map_and_sum', __doc__='Apply func and add') >>> f(lambda x: x * 10, [1, 2, 3]) 60 >>> f.__name__ 'map_and_sum' >>> f.__doc__ 'Apply func and add'
- class creek.util.PreIter[source]#
Bases:
objectNamespace holding
skip_items, apre_iterthat skips the firstnitems.
- creek.util.cls_wrap(cls, obj)[source]#
Wrap
objincls: a subclass wrapping instances at construction ifobjis a class, elsecls(obj).
- creek.util.cursor_to_iterator(cursor, sentinel=<creek.util.no_sentinel object>)[source]#
Get an iterator from a cursor function.
A cursor function is a callable that you call (without arguments) to get items of data one by one.
Sometimes, especially in live io contexts, that’s the kind interface you’re given to consume a stream.
- Return type:
>>> cursor = iter([1, 2, 3]).__next__ >>> assert not isinstance(cursor, Iterator) >>> assert not isinstance(cursor, Iterable) >>> assert callable(cursor)
If you want to consume your stream as an iterator instead, use
cursor_to_iterator.>>> iterator = cursor_to_iterator(cursor) >>> assert isinstance(iterator, Iterator) >>> list(iterator) [1, 2, 3]
If you want your iterator to stop (without a fuss) as soon as the cursor returns a particular element (called a sentinel), say it:
>>> cursor = iter([1, 2, None, None, 3]).__next__ >>> iterator = cursor_to_iterator(cursor, sentinel=None) >>> list(iterator) [1, 2]
- creek.util.iterable_to_cursor(iterable)[source]#
Get a cursor function from an iterable.
- Return type:
- creek.util.iterable_to_iterator(iterable, sentinel=<creek.util.no_sentinel object>)[source]#
Return
iter(iterable), or, given a sentinel, an iterator stopping just before that value.- Return type:
>>> iterable = [1, 2, 3] >>> iterator = iterable_to_iterator(iterable) >>> assert isinstance(iterator, Iterator) >>> assert list(iterator) == iterable
You can also specify a sentinel, which will result in the iterator stoping just before it encounters that sentinel value
>>> iterable = [1, 2, 3, 4, None, None, 7] >>> iterator = iterable_to_iterator(iterable, None) >>> assert isinstance(iterator, Iterator) >>> list(iterator) [1, 2, 3, 4]
- creek.util.iterate_skipping_errors(g, error_callback=None, caught_exceptions=(<class 'Exception'>, ))[source]#
Iterate over a generator, skipping errors and calling an error callback if provided.
- Parameters:
g (
Iterable) – The generator to iterate overerror_callback (
Callable[[BaseException],Any] |None) – A callback to call when an error is encountered.caught_exceptions (
tuple[BaseException]) – The exceptions to catch and skip.
- Return type:
- Returns:
A generator that yields the values of the original generator, skipping errors.
>>> list(iterate_skipping_errors(map(lambda x: 1 / x, [1, 0, 2]))) [1.0, 0.5] >>> list(iterate_skipping_errors(map(lambda x: 1 / x, [1, 0, 2]), print)) division by zero [1.0, 0.5]
See https://github.com/i2mint/creek/issues/6 for more info.
- creek.util.iterate_until_exception(iterator, interrupt_exceptions=(<class 'StopIteration'>, <class 'creek.util.IteratorExit'>, <class 'KeyboardInterrupt'>))[source]#
Call
nextoniteratoruntil one ofinterrupt_exceptionsis raised, then printending.
- creek.util.iterator_to_cursor(iterator, default=<creek.util.no_default object>)[source]#
Get a cursor function for the input iterator.
- Return type:
>>> iterator = iter([1, 2, 3]) >>> cursor = iterator_to_cursor(iterator) >>> assert callable(cursor) >>> assert cursor() == 1 >>> assert list(cursor_to_iterator(cursor)) == [2, 3]
Note how we consumed the cursor till the end; by using cursor_to_iterator. Indeed,
list(iter(cursor))wouldn’t have worked since a cursor isn’t a iterator, but a callable to get the items an the iterator would give you.You can specify a default. The default has the same role that it has for the
nextfunction: It makes the cursor function return that default when the iterator has been “consumed” (i.e. would raise aStopIteration).>>> iterator = iter([1, 2]) >>> cursor = iterator_to_cursor(iterator, None) >>> assert callable(cursor) >>> cursor() 1 >>> cursor() 2
And then…
>>> assert cursor() is None >>> assert cursor() is None
forever.
- creek.util.iterize(func, name=None)[source]#
From an In->Out function, makes a Iterator[In]->Itertor[Out] function.
>>> f = lambda x: x * 10 >>> f(2) 20 >>> iterized_f = iterize(f) >>> list(iterized_f(iter([1,2,3]))) [10, 20, 30]
- creek.util.static_identity_method(x)#
Return
xunchanged.
- creek.util.to_iterator(x, sentinel=<creek.util.no_sentinel object>)[source]#
- creek.util.to_iterator(x, sentinel=<creek.util.no_sentinel object>)
- creek.util.to_iterator(x, sentinel=<creek.util.no_sentinel object>)
Get an iterator from an iterable or a cursor function
>>> from typing import Iterator >>> it = to_iterator([1, 2, 3]) >>> assert isinstance(it, Iterator) >>> list(it) [1, 2, 3] >>> list(it) []
>>> cursor = iter([1, 2, 3]).__next__ >>> assert isinstance(cursor, CursorFunc) >>> it = to_iterator(cursor) >>> assert isinstance(it, Iterator) >>> list(it) [1, 2, 3] >>> list(it) []
You can use sentinels too
>>> list(to_iterator([1, 2, None, 4], sentinel=None)) [1, 2] >>> cursor = iter([1, 2, 3, 4, 5]).__next__ >>> list(to_iterator(cursor, sentinel=4)) [1, 2, 3]