[Checkins] SVN: Sandbox/malthe/chameleon.core/ Made repeat-variable work with iterables which do not declare their length before execution.
Malthe Borch
mborch at gmail.com
Tue Nov 25 16:35:38 EST 2008
Log message for revision 93351:
Made repeat-variable work with iterables which do not declare their length before execution.
Changed:
U Sandbox/malthe/chameleon.core/CHANGES.txt
U Sandbox/malthe/chameleon.core/src/chameleon/core/clauses.py
U Sandbox/malthe/chameleon.core/src/chameleon/core/utils.py
-=-
Modified: Sandbox/malthe/chameleon.core/CHANGES.txt
===================================================================
--- Sandbox/malthe/chameleon.core/CHANGES.txt 2008-11-25 21:29:48 UTC (rev 93350)
+++ Sandbox/malthe/chameleon.core/CHANGES.txt 2008-11-25 21:35:37 UTC (rev 93351)
@@ -4,6 +4,9 @@
HEAD
~~~~
+- Made repeat-variable work with iterables which do not announce their
+ length before execution. [malthe]
+
- Added namespace attribute support. [malthe]
- Static attributes are now computed such that attributes are omitted
Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/clauses.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/clauses.py 2008-11-25 21:29:48 UTC (rev 93350)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/clauses.py 2008-11-25 21:35:37 UTC (rev 93351)
@@ -721,6 +721,25 @@
>>> _repeat.end(stream)
>>> exec stream.getvalue()
+ A repeat over an iterable which has no length, renders the generator.
+
+ >>> class iterator(object):
+ ... def __iter__(self):
+ ... yield 1; yield 2; yield 3
+
+ >>> _out, _write, stream = testing.setup_stream()
+ >>> _repeat = Repeat(types.declaration(("i",)), testing.pyexp("iterator()"))
+ >>> _repeat.begin(stream)
+ >>> stream.write("r = repeat['i']")
+ >>> stream.write(
+ ... "print (i, r.index, r.start, r.end, r.number(), r.odd(), r.even())")
+ >>> _repeat.end(stream)
+ >>> exec stream.getvalue()
+ (1, 0, True, False, 1, False, True)
+ (2, 1, False, False, 2, True, False)
+ (3, 2, False, True, 3, False, True)
+ >>> _repeat.end(stream)
+
A repeat over a non-iterable raises an exception.
>>> _out, _write, stream = testing.setup_stream()
Modified: Sandbox/malthe/chameleon.core/src/chameleon/core/utils.py
===================================================================
--- Sandbox/malthe/chameleon.core/src/chameleon/core/utils.py 2008-11-25 21:29:48 UTC (rev 93350)
+++ Sandbox/malthe/chameleon.core/src/chameleon/core/utils.py 2008-11-25 21:35:37 UTC (rev 93351)
@@ -187,12 +187,33 @@
class repeatdict(dict):
def insert(self, key, iterable):
try:
- length = len(iterable)
+ # this may seem convoluted, but in some cases, looking up
+ # the ``__len__`` attribute may raise an exception, in
+ # which case we'll pretend it isn't there; in this case, a
+ # safe way to get the length is to coerce the iterable
+ # into a tuple from which we can always get the length
+ __len__ = getattr(iterable, '__len__')
+ except AttributeError:
+ # some objects may provide a length but not possess a
+ # ``__len__`` in which case we'll try using the builtin
+ # method to obtain the length
+ try:
+ __len__ = length = len(iterable)
+ except TypeError:
+ # only if this results in a type-error, do we let is
+ # pass through; we do not want to mask any errors
+ # caused by actual code
+ __len__ = None
+ except (KeyboardInterrupt, SystemExit):
+ # these should never be caught; re-raise exception
+ raise
except:
- # we catch all exceptions here, because it's not required
- # for iteration
- length = None
-
+ __len__ = None
+ else:
+ # it should be safe to obtain the length from the
+ # ``__len__`` method; remove safety gloves.
+ length = __len__()
+
try:
# We used to do iterable.__iter__() but, e.g. BTreeItems
# objects are iterable (via __getitem__) but don't possess
@@ -203,8 +224,14 @@
raise TypeError(
"Can only repeat over an iterable object (%s)." % iterable)
- if length is not None:
- self[key] = (iterator, length)
+ # if no length was obtained, coerce iterable to a tuple first
+ if __len__ is None:
+ generated = tuple(iterator)
+ iterator = iter(generated)
+ length = len(generated)
+
+ # insert iterable into repeat structure
+ self[key] = (iterator, length)
return iterator
More information about the Checkins
mailing list