mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
python-3.6.zip added from Github
README.cosmo contains the necessary links.
This commit is contained in:
parent
75fc601ff5
commit
0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions
228
third_party/python/Lib/test/test_iterlen.py
vendored
Normal file
228
third_party/python/Lib/test/test_iterlen.py
vendored
Normal file
|
@ -0,0 +1,228 @@
|
|||
""" Test Iterator Length Transparency
|
||||
|
||||
Some functions or methods which accept general iterable arguments have
|
||||
optional, more efficient code paths if they know how many items to expect.
|
||||
For instance, map(func, iterable), will pre-allocate the exact amount of
|
||||
space required whenever the iterable can report its length.
|
||||
|
||||
The desired invariant is: len(it)==len(list(it)).
|
||||
|
||||
A complication is that an iterable and iterator can be the same object. To
|
||||
maintain the invariant, an iterator needs to dynamically update its length.
|
||||
For instance, an iterable such as range(10) always reports its length as ten,
|
||||
but it=iter(range(10)) starts at ten, and then goes to nine after next(it).
|
||||
Having this capability means that map() can ignore the distinction between
|
||||
map(func, iterable) and map(func, iter(iterable)).
|
||||
|
||||
When the iterable is immutable, the implementation can straight-forwardly
|
||||
report the original length minus the cumulative number of calls to next().
|
||||
This is the case for tuples, range objects, and itertools.repeat().
|
||||
|
||||
Some containers become temporarily immutable during iteration. This includes
|
||||
dicts, sets, and collections.deque. Their implementation is equally simple
|
||||
though they need to permanently set their length to zero whenever there is
|
||||
an attempt to iterate after a length mutation.
|
||||
|
||||
The situation slightly more involved whenever an object allows length mutation
|
||||
during iteration. Lists and sequence iterators are dynamically updatable.
|
||||
So, if a list is extended during iteration, the iterator will continue through
|
||||
the new items. If it shrinks to a point before the most recent iteration,
|
||||
then no further items are available and the length is reported at zero.
|
||||
|
||||
Reversed objects can also be wrapped around mutable objects; however, any
|
||||
appends after the current position are ignored. Any other approach leads
|
||||
to confusion and possibly returning the same item more than once.
|
||||
|
||||
The iterators not listed above, such as enumerate and the other itertools,
|
||||
are not length transparent because they have no way to distinguish between
|
||||
iterables that report static length and iterators whose length changes with
|
||||
each call (i.e. the difference between enumerate('abc') and
|
||||
enumerate(iter('abc')).
|
||||
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from itertools import repeat
|
||||
from collections import deque
|
||||
from operator import length_hint
|
||||
|
||||
n = 10
|
||||
|
||||
|
||||
class TestInvariantWithoutMutations:
|
||||
|
||||
def test_invariant(self):
|
||||
it = self.it
|
||||
for i in reversed(range(1, n+1)):
|
||||
self.assertEqual(length_hint(it), i)
|
||||
next(it)
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
self.assertRaises(StopIteration, next, it)
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
|
||||
class TestTemporarilyImmutable(TestInvariantWithoutMutations):
|
||||
|
||||
def test_immutable_during_iteration(self):
|
||||
# objects such as deques, sets, and dictionaries enforce
|
||||
# length immutability during iteration
|
||||
|
||||
it = self.it
|
||||
self.assertEqual(length_hint(it), n)
|
||||
next(it)
|
||||
self.assertEqual(length_hint(it), n-1)
|
||||
self.mutate()
|
||||
self.assertRaises(RuntimeError, next, it)
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
|
||||
## ------- Concrete Type Tests -------
|
||||
|
||||
class TestRepeat(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = repeat(None, n)
|
||||
|
||||
class TestXrange(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = iter(range(n))
|
||||
|
||||
class TestXrangeCustomReversed(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = reversed(range(n))
|
||||
|
||||
class TestTuple(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = iter(tuple(range(n)))
|
||||
|
||||
## ------- Types that should not be mutated during iteration -------
|
||||
|
||||
class TestDeque(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = deque(range(n))
|
||||
self.it = iter(d)
|
||||
self.mutate = d.pop
|
||||
|
||||
class TestDequeReversed(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = deque(range(n))
|
||||
self.it = reversed(d)
|
||||
self.mutate = d.pop
|
||||
|
||||
class TestDictKeys(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = dict.fromkeys(range(n))
|
||||
self.it = iter(d)
|
||||
self.mutate = d.popitem
|
||||
|
||||
class TestDictItems(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = dict.fromkeys(range(n))
|
||||
self.it = iter(d.items())
|
||||
self.mutate = d.popitem
|
||||
|
||||
class TestDictValues(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = dict.fromkeys(range(n))
|
||||
self.it = iter(d.values())
|
||||
self.mutate = d.popitem
|
||||
|
||||
class TestSet(TestTemporarilyImmutable, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
d = set(range(n))
|
||||
self.it = iter(d)
|
||||
self.mutate = d.pop
|
||||
|
||||
## ------- Types that can mutate during iteration -------
|
||||
|
||||
class TestList(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = iter(range(n))
|
||||
|
||||
def test_mutation(self):
|
||||
d = list(range(n))
|
||||
it = iter(d)
|
||||
next(it)
|
||||
next(it)
|
||||
self.assertEqual(length_hint(it), n - 2)
|
||||
d.append(n)
|
||||
self.assertEqual(length_hint(it), n - 1) # grow with append
|
||||
d[1:] = []
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
self.assertEqual(list(it), [])
|
||||
d.extend(range(20))
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
|
||||
|
||||
class TestListReversed(TestInvariantWithoutMutations, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.it = reversed(range(n))
|
||||
|
||||
def test_mutation(self):
|
||||
d = list(range(n))
|
||||
it = reversed(d)
|
||||
next(it)
|
||||
next(it)
|
||||
self.assertEqual(length_hint(it), n - 2)
|
||||
d.append(n)
|
||||
self.assertEqual(length_hint(it), n - 2) # ignore append
|
||||
d[1:] = []
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
self.assertEqual(list(it), []) # confirm invariant
|
||||
d.extend(range(20))
|
||||
self.assertEqual(length_hint(it), 0)
|
||||
|
||||
## -- Check to make sure exceptions are not suppressed by __length_hint__()
|
||||
|
||||
|
||||
class BadLen(object):
|
||||
def __iter__(self):
|
||||
return iter(range(10))
|
||||
|
||||
def __len__(self):
|
||||
raise RuntimeError('hello')
|
||||
|
||||
|
||||
class BadLengthHint(object):
|
||||
def __iter__(self):
|
||||
return iter(range(10))
|
||||
|
||||
def __length_hint__(self):
|
||||
raise RuntimeError('hello')
|
||||
|
||||
|
||||
class NoneLengthHint(object):
|
||||
def __iter__(self):
|
||||
return iter(range(10))
|
||||
|
||||
def __length_hint__(self):
|
||||
return NotImplemented
|
||||
|
||||
|
||||
class TestLengthHintExceptions(unittest.TestCase):
|
||||
|
||||
def test_issue1242657(self):
|
||||
self.assertRaises(RuntimeError, list, BadLen())
|
||||
self.assertRaises(RuntimeError, list, BadLengthHint())
|
||||
self.assertRaises(RuntimeError, [].extend, BadLen())
|
||||
self.assertRaises(RuntimeError, [].extend, BadLengthHint())
|
||||
b = bytearray(range(10))
|
||||
self.assertRaises(RuntimeError, b.extend, BadLen())
|
||||
self.assertRaises(RuntimeError, b.extend, BadLengthHint())
|
||||
|
||||
def test_invalid_hint(self):
|
||||
# Make sure an invalid result doesn't muck-up the works
|
||||
self.assertEqual(list(NoneLengthHint()), list(range(10)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Add table
Add a link
Reference in a new issue