Package osh :: Package command :: Module window
[frames] | no frames]

Source Code for Module osh.command.window

  1  # osh 
  2  # Copyright (C) Jack Orenstein <jao@geophile.com> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or 
  7  # (at your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 17   
 18  """C{window PREDICATE} 
 19   
 20  C{window -o WINDOW_SIZE} 
 21   
 22  C{window -d WINDOW_SIZE} 
 23       
 24  Groups of consecutive input objects are formed into tuples which are 
 25  passed to the output stream. The objects are grouped in one of two 
 26  mechanisms. 
 27   
 28  1) A new group is started on the first input object, and for any 
 29  subsequent object for which C{PREDICATE} returns true. For example, if 
 30  the input stream contains the integers C{1, 2, 3, ...}, then:: 
 31   
 32      window 'n: n % 3 == 2' 
 33   
 34  yields as output:: 
 35   
 36      ((1,),) 
 37      ((2,), (3,), (4,)) 
 38      ((5,), (6,), (7,)) 
 39      ((8,), (9,), (10,)) 
 40      ... 
 41   
 42  I.e., a new tuple is started for each integer n such that n % 3 = 2. 
 43   
 44  2) Groups have a fixed number of objects. The C{-o} and C{-d} flags 
 45  specify C{WINDOW_SIZE}, the number of objects in the groups.  C{-o} 
 46  specifies I{overlapping} windows, in which each input object begins a 
 47  new list containing C{WINDOW_SIZE} items. Groups may be padded with 
 48  C{None} values to ensure that the group's size is C{WINDOW_SIZE}. 
 49       
 50  B{Example}: For input C{0, 1, ..., 9}, C{window -o 3} yields these 
 51  tuples:: 
 52       
 53      ((0,), (1,), (2,)) 
 54      ((1,), (2,), (3,)) 
 55      ((2,), (3,), (4,)) 
 56      ((3,), (4,), (5,)) 
 57      ((4,), (5,), (6,)) 
 58      ((5,), (6,), (7,)) 
 59      ((6,), (7,), (8,)) 
 60      ((7,), (8,), (9,)) 
 61      ((8,), (9,), (None,)) 
 62      ((9,), (None,), (None,)) 
 63   
 64  C{-d} specifies I{disjoint} windows, in which each input object 
 65  appears in only one group. A new group is started every C{WINDOW_SIZE} 
 66  objects. The last window may be padded with (None,) to ensure that it 
 67  has C{WINDOW_SIZE} elements. 
 68       
 69  B{Example}: For input C{0, 1, ..., 9}, C{window -d 3} yields these 
 70  tuples:: 
 71       
 72      ((0,), (1,), (2,)) 
 73      ((3,), (4,), (5,)) 
 74      ((6,), (7,), (8,)) 
 75      ((9,), (None,), (None,)) 
 76  """ 
 77   
 78  import types 
 79   
 80  import osh.args 
 81  import osh.core 
 82   
 83  Option = osh.args.Option 
 84   
 85  # CLI 
86 -def _window():
87 return _Window()
88 89 # API
90 -def window(predicate = None, disjoint = None, overlap = None):
91 """Groups of consecutive input objects are formed into tuples which 92 are passed to the output stream. Only one of C{predicate}, 93 C{disjoint}, ant C{overlap} may be specified. If C{predicate}, a 94 function returning a boolean, is specified, then a new group of 95 objects is started for the first input, and subsequently for every 96 input object which causes C{predicate} to return true. If 97 C{disjoint}, an integer, is specified, then the input is broken 98 into disjoint groups of C{disjoint} objects each. If C{overlap}, 99 an int, is specified, then each input object begins a group of 100 C{overlap} objects. For both C{disjoint} and C{overlap}, groups 101 may be padded with C{None} values to form groups of the required 102 size. 103 """ 104 arg = predicate 105 if not arg and disjoint: 106 arg = Option('-d', disjoint) 107 if not arg and overlap: 108 arg = Option('-o', overlap) 109 return _Window().process_args(arg)
110
111 -class _Window(osh.core.Op):
112 113 _window_generator = None 114 115 116 # object interface 117
118 - def __init__(self):
119 osh.core.Op.__init__(self, 'o:d:', (0, 1))
120 121 122 # BaseOp interface 123
124 - def doc(self):
125 return __doc__
126
127 - def setup(self):
128 args = self.args() 129 overlap = args.int_arg('-o') 130 disjoint = args.int_arg('-d') 131 if overlap is not None and disjoint is not None: 132 self.usage() 133 elif overlap is not None: 134 self._window_generator = _OverlapWindow(overlap) 135 elif disjoint is not None: 136 self._window_generator = _DisjointWindow(disjoint) 137 else: 138 predicate = args.next_function() 139 self._window_generator = _PredicateWindow(predicate)
140
141 - def receive(self, object):
142 self._window_generator.process(object, self)
143
144 - def receive_complete(self):
145 self._window_generator.finish(self) 146 self.send_complete()
147
148 -class _OverlapWindow(object):
149 150 _window_size = None 151 _window = None 152
153 - def __init__(self, window_size):
154 self._window_size = window_size 155 self._window = []
156
157 - def process(self, object, op):
158 if len(self._window) == self._window_size: 159 self._window = self._window[1:] 160 self._window.append(object) 161 if len(self._window) == self._window_size: 162 op.send(self._window)
163
164 - def finish(self, op):
165 padding = (None,) 166 if len(self._window) < self._window_size: 167 while len(self._window) < self._window_size: 168 self._window.append(padding) 169 op.send(self._window) 170 else: 171 for i in xrange(self._window_size - 1): 172 self._window = self._window[1:] 173 self._window.append(padding) 174 op.send(self._window)
175
176 -class _DisjointWindow(object):
177 178 _window_size = None 179 _window = None 180
181 - def __init__(self, window_size):
182 self._window_size = window_size 183 self._window = []
184
185 - def process(self, object, op):
186 self._window.append(object) 187 if len(self._window) == self._window_size: 188 op.send(self._window) 189 self._window = []
190
191 - def finish(self, op):
192 if len(self._window) == 0: 193 # Last window was complete 194 pass 195 else: 196 padding = (None,) 197 while len(self._window) < self._window_size: 198 self._window.append(padding) 199 op.send(self._window)
200
201 -class _PredicateWindow(object):
202 203 _predicate = None 204 _window = None 205
206 - def __init__(self, predicate):
207 self._predicate = predicate 208 self._window = []
209
210 - def process(self, object, op):
211 if self._predicate(*object): 212 if len(self._window) > 0: 213 op.send(self._window) 214 self._window = [] 215 self._window.append(object)
216
217 - def finish(self, op):
218 op.send(self._window)
219