1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
1 ##############################################################################
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
2 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
4 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
5 # This software is subject to the provisions of the Zope Public License,
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
6 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
10 # FOR A PARTICULAR PURPOSE
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
11 #
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
12 ##############################################################################
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
13 __doc__='''Iterator class
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
14
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
15 Unlike the builtin iterators of Python 2.2+, these classes are
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
16 designed to maintain information about the state of an iteration.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
17 The Iterator() function accepts either a sequence or a Python
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
18 iterator. The next() method fetches the next item, and returns
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
19 true if it succeeds.
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
20
|
|
2005
|
21 $Id: Iterator.py,v 1.3 2004-02-11 23:55:09 richard Exp $'''
|
|
|
22 __docformat__ = 'restructuredtext'
|
|
|
23 __version__='$Revision: 1.3 $'[11:-2]
|
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
24
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
25 import string
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
26
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
27 class Iterator:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
28 '''Simple Iterator class'''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
29
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
30 __allow_access_to_unprotected_subobjects__ = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
31
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
32 nextIndex = 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
33 def __init__(self, seq):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
34 self.seq = seq
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
35 for inner in seqInner, iterInner:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
36 if inner._supports(seq):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
37 self._inner = inner
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
38 self._prep_next = inner.prep_next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
39 return
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
40 raise TypeError, "Iterator does not support %s" % `seq`
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
41
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
42 def __getattr__(self, name):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
43 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
44 inner = getattr(self._inner, 'it_' + name)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
45 except AttributeError:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
46 raise AttributeError, name
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
47 return inner(self)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
48
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
49 def next(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
50 if not (hasattr(self, '_next') or self._prep_next(self)):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
51 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
52 self.index = i = self.nextIndex
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
53 self.nextIndex = i+1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
54 self._advance(self)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
55 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
56
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
57 def _advance(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
58 self.item = self._next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
59 del self._next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
60 del self.end
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
61 self._advance = self._inner.advance
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
62 self.start = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
63
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
64 def number(self): return self.nextIndex
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
65
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
66 def even(self): return not self.index % 2
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
67
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
68 def odd(self): return self.index % 2
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
69
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
70 def letter(self, base=ord('a'), radix=26):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
71 index = self.index
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
72 s = ''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
73 while 1:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
74 index, off = divmod(index, radix)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
75 s = chr(base + off) + s
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
76 if not index: return s
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
77
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
78 def Letter(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
79 return self.letter(base=ord('A'))
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
80
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
81 def Roman(self, rnvalues=(
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
82 (1000,'M'),(900,'CM'),(500,'D'),(400,'CD'),
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
83 (100,'C'),(90,'XC'),(50,'L'),(40,'XL'),
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
84 (10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
85 n = self.index + 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
86 s = ''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
87 for v, r in rnvalues:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
88 rct, n = divmod(n, v)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
89 s = s + r * rct
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
90 return s
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
91
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
92 def roman(self, lower=string.lower):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
93 return lower(self.Roman())
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
94
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
95 def first(self, name=None):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
96 if self.start: return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
97 return not self.same_part(name, self._last, self.item)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
98
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
99 def last(self, name=None):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
100 if self.end: return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
101 return not self.same_part(name, self.item, self._next)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
102
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
103 def same_part(self, name, ob1, ob2):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
104 if name is None:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
105 return ob1 == ob2
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
106 no = []
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
107 return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
108
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
109 def __iter__(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
110 return IterIter(self)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
111
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
112 class InnerBase:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
113 '''Base Inner class for Iterators'''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
114 # Prep sets up ._next and .end
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
115 def prep_next(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
116 it.next = self.no_next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
117 it.end = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
118 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
119
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
120 # Advance knocks them down
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
121 def advance(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
122 it._last = it.item
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
123 it.item = it._next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
124 del it._next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
125 del it.end
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
126 it.start = 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
127
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
128 def no_next(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
129 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
130
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
131 def it_end(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
132 if hasattr(it, '_next'):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
133 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
134 return not self.prep_next(it)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
135
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
136 class SeqInner(InnerBase):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
137 '''Inner class for sequence Iterators'''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
138
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
139 def _supports(self, ob):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
140 try: ob[0]
|
|
1233
|
141 except (TypeError, AttributeError): return 0
|
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
142 except: pass
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
143 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
144
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
145 def prep_next(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
146 i = it.nextIndex
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
147 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
148 it._next = it.seq[i]
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
149 except IndexError:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
150 it._prep_next = self.no_next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
151 it.end = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
152 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
153 it.end = 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
154 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
155
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
156 def it_length(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
157 it.length = l = len(it.seq)
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
158 return l
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
159
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
160 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
161 StopIteration=StopIteration
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
162 except NameError:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
163 StopIteration="StopIteration"
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
164
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
165 class IterInner(InnerBase):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
166 '''Iterator inner class for Python iterators'''
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
167
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
168 def _supports(self, ob):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
169 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
170 if hasattr(ob, 'next') and (ob is iter(ob)):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
171 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
172 except:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
173 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
174
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
175 def prep_next(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
176 try:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
177 it._next = it.seq.next()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
178 except StopIteration:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
179 it._prep_next = self.no_next
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
180 it.end = 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
181 return 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
182 it.end = 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
183 return 1
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
184
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
185 class IterIter:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
186 def __init__(self, it):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
187 self.it = it
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
188 self.skip = it.nextIndex > 0 and not it.end
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
189 def next(self):
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
190 it = self.it
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
191 if self.skip:
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
192 self.skip = 0
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
193 return it.item
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
194 if it.next():
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
195 return it.item
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
196 raise StopIteration
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
197
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
198 seqInner = SeqInner()
|
Richard Jones <richard@users.sourceforge.net>
parents:
diff
changeset
|
199 iterInner = IterInner()
|