1 ##############################################################################
2 #
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE
11 #
12 ##############################################################################
13 __doc__='''Batch class, for iterating over a sequence in batches
15 $Id: Batch.py,v 1.2 2002-09-11 23:54:26 richard Exp $'''
16 __version__='$Revision: 1.2 $'[11:-2]
18 class LazyPrevBatch:
19 def __of__(self, parent):
20 return Batch(parent._sequence, parent._size,
21 parent.first - parent._size + parent.overlap, 0,
22 parent.orphan, parent.overlap)
24 class LazyNextBatch:
25 def __of__(self, parent):
26 try: parent._sequence[parent.end]
27 except IndexError: return None
28 return Batch(parent._sequence, parent._size,
29 parent.end - parent.overlap, 0,
30 parent.orphan, parent.overlap)
32 class LazySequenceLength:
33 def __of__(self, parent):
34 parent.sequence_length = l = len(parent._sequence)
35 return l
37 class Batch:
38 """Create a sequence batch"""
39 __allow_access_to_unprotected_subobjects__ = 1
41 previous = LazyPrevBatch()
42 next = LazyNextBatch()
43 sequence_length = LazySequenceLength()
45 def __init__(self, sequence, size, start=0, end=0,
46 orphan=0, overlap=0):
47 '''Encapsulate "sequence" in batches of "size".
49 Arguments: "start" and "end" are 0-based indexes into the
50 sequence. If the next batch would contain no more than
51 "orphan" elements, it is combined with the current batch.
52 "overlap" is the number of elements shared by adjacent
53 batches. If "size" is not specified, it is computed from
54 "start" and "end". Failing that, it is 7.
56 Attributes: Note that the "start" attribute, unlike the
57 argument, is a 1-based index (I know, lame). "first" is the
58 0-based index. "length" is the actual number of elements in
59 the batch.
61 "sequence_length" is the length of the original, unbatched, sequence
62 '''
64 start = start + 1
66 start,end,sz = opt(start,end,size,orphan,sequence)
68 self._sequence = sequence
69 self.size = sz
70 self._size = size
71 self.start = start
72 self.end = end
73 self.orphan = orphan
74 self.overlap = overlap
75 self.first = max(start - 1, 0)
76 self.length = self.end - self.first
77 if self.first == 0:
78 self.previous = None
81 def __getitem__(self, index):
82 if index < 0:
83 if index + self.end < self.first: raise IndexError, index
84 return self._sequence[index + self.end]
86 if index >= self.length: raise IndexError, index
87 return self._sequence[index + self.first]
89 def __len__(self):
90 return self.length
92 def opt(start,end,size,orphan,sequence):
93 if size < 1:
94 if start > 0 and end > 0 and end >= start:
95 size=end+1-start
96 else: size=7
98 if start > 0:
100 try: sequence[start-1]
101 except IndexError: start=len(sequence)
103 if end > 0:
104 if end < start: end=start
105 else:
106 end=start+size-1
107 try: sequence[end+orphan-1]
108 except IndexError: end=len(sequence)
109 elif end > 0:
110 try: sequence[end-1]
111 except IndexError: end=len(sequence)
112 start=end+1-size
113 if start - 1 < orphan: start=1
114 else:
115 start=1
116 end=start+size-1
117 try: sequence[end+orphan-1]
118 except IndexError: end=len(sequence)
119 return start,end,size