Commit 53190b64 authored by Evan Simpson's avatar Evan Simpson

Handle Python 2.2 iterators, implement first() and last().

parent 661377e7
......@@ -12,8 +12,14 @@
##############################################################################
__doc__='''Iterator class
$Id: Iterator.py,v 1.3 2001/11/28 15:51:22 matt Exp $'''
__version__='$Revision: 1.3 $'[11:-2]
Unlike the builtin iterators of Python 2.2+, these classes are
designed to maintain information about the state of an iteration.
The Iterator() function accepts either a sequence or a Python
iterator. The next() method fetches the next item, and returns
true if it succeeds.
$Id: Iterator.py,v 1.4 2001/12/12 02:21:56 evan Exp $'''
__version__='$Revision: 1.4 $'[11:-2]
import string
......@@ -21,21 +27,39 @@ class Iterator:
'''Simple Iterator class'''
__allow_access_to_unprotected_subobjects__ = 1
nextIndex = 0
def __init__(self, seq):
self.seq = seq
self.nextIndex = 0
if hasattr(seq, 'next'):
inner = iterInner
else:
inner = seqInner
self._inner = inner
self._prep_next = inner.prep_next
def __getattr__(self, name):
try:
inner = getattr(self._inner, 'it_' + name)
except AttributeError:
raise AttributeError, name
return inner(self)
def next(self):
i = self.nextIndex
try:
self.seq[i]
except IndexError:
if not (hasattr(self, '_next') or self._prep_next(self)):
return 0
self.index = i
self.index = i = self.nextIndex
self.nextIndex = i+1
self._advance(self)
return 1
def _advance(self, it):
self.item = self._next
del self._next
del self.end
self._advance = self._inner.advance
self.start = 1
def number(self): return self.nextIndex
def even(self): return not self.index % 2
......@@ -67,16 +91,94 @@ class Iterator:
def roman(self, lower=string.lower):
return lower(self.Roman())
def start(self): return self.nextIndex == 1
def first(self, name=None):
if self.start: return 1
return not self.same_part(name, self._last, self.item)
def last(self, name=None):
if self.end: return 1
return not self.same_part(name, self.item, self._next)
def same_part(self, name, ob1, ob2):
if name is None:
return ob1 == ob2
no = []
return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
def __iter__(self):
return IterIter(self)
class InnerBase:
'''Base Inner class for Iterators'''
# Prep sets up ._next and .end
def prep_next(self, it):
it.next = self.no_next
it.end = 1
return 0
def end(self):
try: self.seq[self.nextIndex]
except IndexError: return 1
# Advance knocks them down
def advance(self, it):
it._last = it.item
it.item = it._next
del it._next
del it.end
it.start = 0
def no_next(self, it):
return 0
def item(self):
return self.seq[self.index]
def it_end(self, it):
if hasattr(it, '_next'):
return 0
return not self.prep_next(it)
def length(self):
return len(self.seq)
class SeqInner(InnerBase):
'''Inner class for sequence Iterators'''
def prep_next(self, it):
i = it.nextIndex
try:
it._next = it.seq[i]
except IndexError:
it._prep_next = self.no_next
it.end = 1
return 0
it.end = 0
return 1
def it_length(self, it):
it.length = l = len(it.seq)
return l
try:
StopIteration=StopIteration
except NameError:
StopIteration="StopIteration"
class IterInner(InnerBase):
'''Iterator inner class for Python iterators'''
def prep_next(self, it):
try:
it._next = it.seq.next()
except StopIteration:
it._prep_next = self.no_next
it.end = 1
return 0
it.end = 0
return 1
class IterIter:
def __init__(self, it):
self.it = it
self.skip = it.nextIndex > 0 and not it.end
def next(self):
it = self.it
if self.skip:
self.skip = 0
return it.item
if it.next():
return it.item
raise StopIteration
seqInner = SeqInner()
iterInner = IterInner()
......@@ -2,6 +2,12 @@ import os, sys, unittest
from ZTUtils import Iterator
try:
iter
do_piter_test = 1
except NameError:
do_piter_test = 0
class IteratorTests(unittest.TestCase):
def testIterator0(self):
......@@ -12,12 +18,98 @@ class IteratorTests(unittest.TestCase):
it = Iterator((1,))
assert it.next() and not it.next(), "Single-element iterator"
def testIterator2(self):
def testIteratorMany(self):
it = Iterator('text')
for c in 'text':
assert it.next(), "Multi-element iterator"
assert not it.next(), "Multi-element iterator"
def testStart(self):
for size in range(4):
it = Iterator(range(size+1))
it.next()
assert it.start, "Start true on element 1 of %s" % (size + 1)
el = 1
while it.next():
el = el + 1
assert not it.start, (
"Start false on element %s of %s" % (el, size+1))
def testEnd(self):
for size in range(4):
size = size + 1
it = Iterator(range(size))
el = 0
while it.next():
el = el + 1
if el == size:
assert it.end, "End true on element %s" % size
else:
assert not it.end, (
"End false on element %s of %s" % (el, size))
def testIndex(self):
it = Iterator(range(5))
for el in range(5):
assert it.next(), "Iterator stopped too soon"
assert it.index == el, "Incorrect index"
assert it.number() == el + 1, "Incorrect number"
assert it.item == el, "Incorrect item"
def testFirstLast(self):
it = Iterator([1])
it.next()
assert it.first() == it.last() == 1, "Bad first/last on singleton"
four = range(4)
for a in 2,3:
for b in four:
for c in four:
s = 'a' * a + 'b' * b + 'c' * c
it = Iterator(s)
it.next()
assert it.first(), "First element not first()"
last = s[0]
lastlast = it.last()
while it.next():
assert ((it.item != last) == it.first()), (
"first() error")
assert ((it.item != last) == lastlast), (
"last() error" % (it.item,
last, lastlast))
last = it.item
lastlast = it.last()
assert lastlast, "Last element not last()"
if do_piter_test:
def testIterOfIter(self):
for i in range(4):
r = range(i)
it1 = Iterator(r)
it2 = Iterator(iter(r))
while it1.next() and it2.next():
assert it1.item == it2.item, "Item mismatch with iter()"
assert it1.index == it2.index, (
"Index mismatch with iter()")
assert not (it1.next() or it2.next()), (
"Length mismatch with iter()")
def testIterIter(self):
wo_iter = map(lambda x:(x, x), range(4))
for i in range(4):
r = range(i)
w_iter = []
it = Iterator(r)
for x in it:
w_iter.append((x, it.index))
assert w_iter == wo_iter[:i], (
"for-loop failure on full iterator")
it = Iterator(range(4))
it.next(); it.next(); it.next()
w_iter = []
for x in it:
w_iter.append((x, it.index))
assert w_iter == wo_iter[2:], "for-loop failure on half iteration"
def test_suite():
return unittest.makeSuite(IteratorTests)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment