@@ -622,6 +622,10 @@ class filter(Stream):
622622 predicate : function
623623 The predicate. Should return True or False, where
624624 True means that the predicate is satisfied.
625+ *args :
626+ The arguments to pass to the predicate.
627+ **kwargs:
628+ Keyword arguments to pass to predicate
625629
626630 Examples
627631 --------
@@ -633,15 +637,19 @@ class filter(Stream):
633637 2
634638 4
635639 """
636- def __init__ (self , upstream , predicate , ** kwargs ):
640+
641+ def __init__ (self , upstream , predicate , * args , ** kwargs ):
637642 if predicate is None :
638643 predicate = _truthy
639644 self .predicate = predicate
645+ stream_name = kwargs .pop ("stream_name" , None )
646+ self .kwargs = kwargs
647+ self .args = args
640648
641- Stream .__init__ (self , upstream , ** kwargs )
649+ Stream .__init__ (self , upstream , stream_name = stream_name )
642650
643651 def update (self , x , who = None ):
644- if self .predicate (x ):
652+ if self .predicate (x , * self . args , ** self . kwargs ):
645653 return self ._emit (x )
646654
647655
@@ -652,13 +660,19 @@ class accumulate(Stream):
652660 This performs running or cumulative reductions, applying the function
653661 to the previous total and the new element. The function should take
654662 two arguments, the previous accumulated state and the next element and
655- it should return a new accumulated state.
663+ it should return a new accumulated state,
664+ - ``state = func(previous_state, new_value)`` (returns_state=False)
665+ - ``state, result = func(previous_state, new_value)`` (returns_state=True)
666+
667+ where the new_state is passed to the next invocation. The state or result
668+ is emitted downstream for the two cases.
656669
657670 Parameters
658671 ----------
659672 func: callable
660673 start: object
661- Initial value. Defaults to the first submitted element
674+ Initial value, passed as the value of ``previous_state`` on the first
675+ invocation. Defaults to the first submitted element
662676 returns_state: boolean
663677 If true then func should return both the state and the value to emit
664678 If false then both values are the same, and func returns one value
@@ -667,14 +681,41 @@ class accumulate(Stream):
667681
668682 Examples
669683 --------
684+ A running total, producing triangular numbers
685+
670686 >>> source = Stream()
671687 >>> source.accumulate(lambda acc, x: acc + x).sink(print)
672688 >>> for i in range(5):
673689 ... source.emit(i)
690+ 0
674691 1
675692 3
676693 6
677694 10
695+
696+ A count of number of events (including the current one)
697+
698+ >>> source = Stream()
699+ >>> source.accumulate(lambda acc, x: acc + 1, start=0).sink(print)
700+ >>> for _ in range(5):
701+ ... source.emit(0)
702+ 1
703+ 2
704+ 3
705+ 4
706+ 5
707+
708+ Like the builtin "enumerate".
709+
710+ >>> source = Stream()
711+ >>> source.accumulate(lambda acc, x: ((acc[0] + 1, x), (acc[0], x)),
712+ ... start=(0, 0), returns_state=True
713+ ... ).sink(print)
714+ >>> for i in range(3):
715+ ... source.emit(0)
716+ (0, 0)
717+ (1, 0)
718+ (2, 0)
678719 """
679720 _graphviz_shape = 'box'
680721
@@ -706,6 +747,54 @@ def update(self, x, who=None):
706747 return self ._emit (result )
707748
708749
750+ @Stream .register_api ()
751+ class slice (Stream ):
752+ """
753+ Get only some events in a stream by position. Works like list[] syntax.
754+
755+ Parameters
756+ ----------
757+ start : int
758+ First event to use. If None, start from the beginnning
759+ end : int
760+ Last event to use (non-inclusive). If None, continue without stopping.
761+ Does not support negative indexing.
762+ step : int
763+ Pass on every Nth event. If None, pass every one.
764+
765+ Examples
766+ --------
767+ >>> source = Stream()
768+ >>> source.slice(2, 6, 2).sink(print)
769+ >>> for i in range(5):
770+ ... source.emit(0)
771+ 2
772+ 4
773+ """
774+
775+ def __init__ (self , upstream , start = None , end = None , step = None , ** kwargs ):
776+ self .state = 0
777+ self .star = start or 0
778+ self .end = end
779+ self .step = step or 1
780+ if any ((_ or 0 ) < 0 for _ in [start , end , step ]):
781+ raise ValueError ("Negative indices not supported by slice" )
782+ stream_name = kwargs .pop ('stream_name' , None )
783+ Stream .__init__ (self , upstream , stream_name = stream_name )
784+ self ._check_end ()
785+
786+ def update (self , x , who = None ):
787+ if self .state >= self .star and self .state % self .step == 0 :
788+ self .emit (x )
789+ self .state += 1
790+ self ._check_end ()
791+
792+ def _check_end (self ):
793+ if self .end and self .state >= self .end :
794+ # we're done
795+ self .upstream .downstreams .remove (self )
796+
797+
709798@Stream .register_api ()
710799class partition (Stream ):
711800 """ Partition stream into tuples of equal size
@@ -740,10 +829,17 @@ def update(self, x, who=None):
740829class sliding_window (Stream ):
741830 """ Produce overlapping tuples of size n
742831
832+ Parameters
833+ ----------
834+ return_partial : bool
835+ If True, yield tuples as soon as any events come in, each tuple being
836+ smaller or equal to the window size. If False, only start yielding
837+ tuples once a full window has accrued.
838+
743839 Examples
744840 --------
745841 >>> source = Stream()
746- >>> source.sliding_window(3).sink(print)
842+ >>> source.sliding_window(3, return_partial=False ).sink(print)
747843 >>> for i in range(8):
748844 ... source.emit(i)
749845 (0, 1, 2)
@@ -755,14 +851,15 @@ class sliding_window(Stream):
755851 """
756852 _graphviz_shape = 'diamond'
757853
758- def __init__ (self , upstream , n , ** kwargs ):
854+ def __init__ (self , upstream , n , return_partial = True , ** kwargs ):
759855 self .n = n
760856 self .buffer = deque (maxlen = n )
857+ self .partial = return_partial
761858 Stream .__init__ (self , upstream , ** kwargs )
762859
763860 def update (self , x , who = None ):
764861 self .buffer .append (x )
765- if len (self .buffer ) == self .n :
862+ if self . partial or len (self .buffer ) == self .n :
766863 return self ._emit (tuple (self .buffer ))
767864 else :
768865 return []
0 commit comments