[Jython-checkins] jython: Run all itertools tests, removing Jython-specific skips
jim.baker
jython-checkins at python.org
Tue Dec 9 01:08:38 CET 2014
https://hg.python.org/jython/rev/5ee9b24f3d9d
changeset: 7436:5ee9b24f3d9d
user: Jim Baker <jim.baker at rackspace.com>
date: Mon Dec 08 17:08:17 2014 -0700
summary:
Run all itertools tests, removing Jython-specific skips
Updated count, repeat, and tee in itertools to support various corner
cases seen in usage.
files:
Lib/test/test_itertools.py | 112 ++++-----
src/org/python/core/__builtin__.java | 2 +-
src/org/python/modules/itertools/PyTeeIterator.java | 2 +-
src/org/python/modules/itertools/count.java | 92 ++++++-
src/org/python/modules/itertools/repeat.java | 5 +
5 files changed, 132 insertions(+), 81 deletions(-)
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1,5 +1,6 @@
import unittest
from test import test_support
+from test.test_weakref import extra_collect
from itertools import *
from weakref import proxy
from decimal import Decimal
@@ -336,11 +337,8 @@
self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)])
self.assertRaises(TypeError, count, 2, 3, 4)
self.assertRaises(TypeError, count, 'a')
-
- #FIXME: not working in Jython
- #self.assertEqual(list(islice(count(maxsize-5), 10)), range(maxsize-5, maxsize+5))
- #self.assertEqual(list(islice(count(-maxsize-5), 10)), range(-maxsize-5, -maxsize+5))
-
+ self.assertEqual(list(islice(count(maxsize-5), 10)), range(maxsize-5, maxsize+5))
+ self.assertEqual(list(islice(count(-maxsize-5), 10)), range(-maxsize-5, -maxsize+5))
c = count(3)
self.assertEqual(repr(c), 'count(3)')
c.next()
@@ -348,27 +346,20 @@
c = count(-9)
self.assertEqual(repr(c), 'count(-9)')
c.next()
+ self.assertEqual(repr(count(10.25)), 'count(10.25)')
+ self.assertEqual(c.next(), -8)
+ for i in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 10, sys.maxint-5, sys.maxint+5):
+ # Test repr (ignoring the L in longs)
+ r1 = repr(count(i)).replace('L', '')
+ r2 = 'count(%r)'.__mod__(i).replace('L', '')
+ self.assertEqual(r1, r2)
- #FIXME: not working in Jython
- #self.assertEqual(repr(count(10.25)), 'count(10.25)')
- self.assertEqual(c.next(), -8)
-
- #FIXME: not working in Jython
- if not test_support.is_jython:
- for i in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 10, sys.maxint-5, sys.maxint+5):
- # Test repr (ignoring the L in longs)
- r1 = repr(count(i)).replace('L', '')
- r2 = 'count(%r)'.__mod__(i).replace('L', '')
- self.assertEqual(r1, r2)
-
- #FIXME: not working in Jython
# check copy, deepcopy, pickle
- if not test_support.is_jython:
- for value in -3, 3, sys.maxint-5, sys.maxint+5:
- c = count(value)
- self.assertEqual(next(copy.copy(c)), value)
- self.assertEqual(next(copy.deepcopy(c)), value)
- self.assertEqual(next(pickle.loads(pickle.dumps(c))), value)
+ for value in -3, 3, sys.maxint-5, sys.maxint+5:
+ c = count(value)
+ self.assertEqual(next(copy.copy(c)), value)
+ self.assertEqual(next(copy.deepcopy(c)), value)
+ self.assertEqual(next(pickle.loads(pickle.dumps(c))), value)
def test_count_with_stride(self):
self.assertEqual(zip('abc',count(2,3)), [('a', 2), ('b', 5), ('c', 8)])
@@ -378,17 +369,14 @@
[('a', 0), ('b', -1), ('c', -2)])
self.assertEqual(zip('abc',count(2,0)), [('a', 2), ('b', 2), ('c', 2)])
self.assertEqual(zip('abc',count(2,1)), [('a', 2), ('b', 3), ('c', 4)])
-
- #FIXME: not working in Jython
- #self.assertEqual(take(20, count(maxsize-15, 3)), take(20, range(maxsize-15, maxsize+100, 3)))
- #self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3)))
- #self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j])
- #self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))),
- # [Decimal('1.1'), Decimal('1.2'), Decimal('1.3')])
- #self.assertEqual(take(3, count(Fraction(2,3), Fraction(1,7))),
- # [Fraction(2,3), Fraction(17,21), Fraction(20,21)])
- #self.assertEqual(repr(take(3, count(10, 2.5))), repr([10, 12.5, 15.0]))
-
+ self.assertEqual(take(20, count(maxsize-15, 3)), take(20, range(maxsize-15, maxsize+100, 3)))
+ self.assertEqual(take(20, count(-maxsize-15, 3)), take(20, range(-maxsize-15,-maxsize+100, 3)))
+ self.assertEqual(take(3, count(2, 3.25-4j)), [2, 5.25-4j, 8.5-8j])
+ self.assertEqual(take(3, count(Decimal('1.1'), Decimal('.1'))),
+ [Decimal('1.1'), Decimal('1.2'), Decimal('1.3')])
+ self.assertEqual(take(3, count(Fraction(2,3), Fraction(1,7))),
+ [Fraction(2,3), Fraction(17,21), Fraction(20,21)])
+ self.assertEqual(repr(take(3, count(10, 2.5))), repr([10, 12.5, 15.0]))
c = count(3, 5)
self.assertEqual(repr(c), 'count(3, 5)')
c.next()
@@ -402,23 +390,18 @@
c.next()
self.assertEqual(repr(c), 'count(-12, -3)')
self.assertEqual(repr(c), 'count(-12, -3)')
-
- #FIXME: not working in Jython
- #self.assertEqual(repr(count(10.5, 1.25)), 'count(10.5, 1.25)')
- #self.assertEqual(repr(count(10.5, 1)), 'count(10.5)') # suppress step=1 when it's an int
- #self.assertEqual(repr(count(10.5, 1.00)), 'count(10.5, 1.0)') # do show float values lilke 1.0
-
- #FIXME: not working in Jython
- if not test_support.is_jython:
- for i in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 10, sys.maxint-5, sys.maxint+5):
- for j in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 1, 10, sys.maxint-5, sys.maxint+5):
- # Test repr (ignoring the L in longs)
- r1 = repr(count(i, j)).replace('L', '')
- if j == 1:
- r2 = ('count(%r)' % i).replace('L', '')
- else:
- r2 = ('count(%r, %r)' % (i, j)).replace('L', '')
- self.assertEqual(r1, r2)
+ self.assertEqual(repr(count(10.5, 1.25)), 'count(10.5, 1.25)')
+ self.assertEqual(repr(count(10.5, 1)), 'count(10.5)') # suppress step=1 when it's an int
+ self.assertEqual(repr(count(10.5, 1.00)), 'count(10.5, 1.0)') # do show float values lilke 1.0
+ for i in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 10, sys.maxint-5, sys.maxint+5):
+ for j in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 1, 10, sys.maxint-5, sys.maxint+5):
+ # Test repr (ignoring the L in longs)
+ r1 = repr(count(i, j)).replace('L', '')
+ if j == 1:
+ r2 = ('count(%r)' % i).replace('L', '')
+ else:
+ r2 = ('count(%r, %r)' % (i, j)).replace('L', '')
+ self.assertEqual(r1, r2)
def test_cycle(self):
self.assertEqual(take(10, cycle('abc')), list('abcabcabca'))
@@ -918,14 +901,25 @@
self.assertTrue(list(t1) == list(t2) == list(t3) == list('abc'))
# test that tee objects are weak referencable
- a, b = tee(xrange(10))
- p = proxy(a)
- self.assertEqual(getattr(p, '__class__'), type(b))
- del a
+ def delocalize():
+ # local variables in Jython cannot be deleted to see
+ # objects go out of scope immediately. Except for tests
+ # like this however this is not going to be observed!
+ a, b = tee(xrange(10))
+ return dict(a=a, b=b)
- #FIXME: not working in Jython
- if not test_support.is_jython:
- self.assertRaises(ReferenceError, getattr, p, '__class__')
+ d = delocalize()
+ p = proxy(d['a'])
+ self.assertEqual(getattr(p, '__class__'), type(d['b']))
+ del d['a']
+ extra_collect() # necessary for Jython to ensure ref queue is cleared out
+ self.assertRaises(ReferenceError, getattr, p, '__class__')
+
+ # Issue 13454: Crash when deleting backward iterator from tee()
+ def test_tee_del_backward(self):
+ forward, backward = tee(repeat(None, 20000000))
+ any(forward) # exhaust the iterator
+ del backward
def test_StopIteration(self):
self.assertRaises(StopIteration, izip().next)
diff --git a/src/org/python/core/__builtin__.java b/src/org/python/core/__builtin__.java
--- a/src/org/python/core/__builtin__.java
+++ b/src/org/python/core/__builtin__.java
@@ -972,7 +972,7 @@
}
try {
// See PyXRange.getLenOfRange for the primitive version
- PyObject diff = hi.__sub__(lo).__sub__(Py.One);
+ PyObject diff = hi._sub(lo)._sub(Py.One);
PyObject n = diff.__floordiv__(step).__add__(Py.One);
return n.asInt();
} catch (PyException pye) {
diff --git a/src/org/python/modules/itertools/PyTeeIterator.java b/src/org/python/modules/itertools/PyTeeIterator.java
--- a/src/org/python/modules/itertools/PyTeeIterator.java
+++ b/src/org/python/modules/itertools/PyTeeIterator.java
@@ -94,7 +94,7 @@
throw Py.ValueError("n must be >= 0");
}
- PyObject[] tees = new PyTeeIterator[n];
+ PyObject[] tees = new PyObject[n];
if (n == 0) {
return tees;
diff --git a/src/org/python/modules/itertools/count.java b/src/org/python/modules/itertools/count.java
--- a/src/org/python/modules/itertools/count.java
+++ b/src/org/python/modules/itertools/count.java
@@ -3,12 +3,14 @@
import org.python.core.ArgParser;
import org.python.core.Py;
+import org.python.core.PyException;
import org.python.core.PyInteger;
import org.python.core.PyIterator;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PyTuple;
import org.python.core.PyType;
+import org.python.core.__builtin__;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedType;
@@ -18,8 +20,16 @@
public static final PyType TYPE = PyType.fromClass(count.class);
private PyIterator iter;
- private int counter;
- private int stepper;
+ private PyObject counter;
+ private PyObject stepper;
+
+ private static PyObject NumberClass;
+ private static synchronized PyObject getNumberClass() {
+ if (NumberClass == null) {
+ NumberClass = __builtin__.__import__("numbers").__getattr__("Number");
+ }
+ return NumberClass;
+ }
public static final String count_doc =
"count(start=0, step=1) --> count object\n\n" +
@@ -37,62 +47,104 @@
}
/**
- * Creates an iterator that returns consecutive integers starting at 0.
+ * Creates an iterator that returns consecutive numbers starting at 0.
*/
public count() {
super();
- count___init__(0, 1);
+ count___init__(Py.Zero, Py.One);
}
/**
- * Creates an iterator that returns consecutive integers starting at <code>start</code>.
+ * Creates an iterator that returns consecutive numbers starting at <code>start</code>.
*/
- public count(final int start) {
+ public count(final PyObject start) {
super();
- count___init__(start, 1);
+ count___init__(start, Py.One);
}
/**
- * Creates an iterator that returns consecutive integers starting at <code>start</code> with <code>step</code> step.
+ * Creates an iterator that returns consecutive numbers starting at <code>start</code> with <code>step</code> step.
*/
- public count(final int start, final int step) {
+ public count(final PyObject start, final PyObject step) {
super();
count___init__(start, step);
}
+ // TODO: move into Py, although NumberClass import time resolution becomes
+ // TODO: a bit trickier
+ private static PyObject getNumber(PyObject obj) {
+ if (Py.isInstance(obj, getNumberClass())) {
+ return obj;
+ }
+ try {
+ PyObject intObj = obj.__int__();
+ if (Py.isInstance(obj, getNumberClass())) {
+ return intObj;
+ }
+ throw Py.TypeError("a number is required");
+ } catch (PyException exc) {
+ if (exc.match(Py.ValueError)) {
+ throw Py.TypeError("a number is required");
+ }
+ throw exc;
+ }
+ }
+
@ExposedNew
@ExposedMethod
final void count___init__(final PyObject[] args, String[] kwds) {
ArgParser ap = new ArgParser("count", args, kwds, new String[] {"start", "step"}, 0);
-
- int start = ap.getInt(0, 0);
- int step = ap.getInt(1, 1);
+ PyObject start = getNumber(ap.getPyObject(0, Py.Zero));
+ PyObject step = getNumber(ap.getPyObject(1, Py.One));
count___init__(start, step);
}
- private void count___init__(final int start, final int step) {
+ private void count___init__(final PyObject start, final PyObject step) {
counter = start;
stepper = step;
iter = new PyIterator() {
public PyObject __iternext__() {
- int result = counter;
- counter += stepper;
- return new PyInteger(result);
+ PyObject result = counter;
+ counter = counter._add(stepper);
+ return result;
}
};
}
@ExposedMethod
+ public PyObject count___copy__() {
+ return new count(counter, stepper);
+ }
+
+ @ExposedMethod
+ final PyObject count___reduce_ex__(PyObject protocol) {
+ return __reduce_ex__(protocol);
+ }
+
+ @ExposedMethod
+ final PyObject count___reduce__() {
+ return __reduce_ex__(Py.Zero);
+ }
+
+
+ public PyObject __reduce_ex__(PyObject protocol) {
+ if (stepper == Py.One) {
+ return new PyTuple(getType(), new PyTuple(counter));
+ } else {
+ return new PyTuple(getType(), new PyTuple(counter, stepper));
+ }
+ }
+
+ @ExposedMethod
public PyString __repr__() {
- if (stepper == 1) {
- return (PyString)(Py.newString("count(%d)").__mod__(Py.newInteger(counter)));
+ if (stepper instanceof PyInteger && stepper._cmp(Py.One) == 0) {
+ return Py.newString(String.format("count(%s)", counter));
}
else {
- return (PyString)(Py.newString("count(%d, %d)").__mod__(new PyTuple(
- Py.newInteger(counter), Py.newInteger(stepper))));
+ return Py.newString(String.format("count(%s, %s)", counter, stepper));
}
}
diff --git a/src/org/python/modules/itertools/repeat.java b/src/org/python/modules/itertools/repeat.java
--- a/src/org/python/modules/itertools/repeat.java
+++ b/src/org/python/modules/itertools/repeat.java
@@ -97,6 +97,11 @@
}
@ExposedMethod
+ final PyObject __copy__() {
+ return new repeat(object, counter);
+ }
+
+ @ExposedMethod
public int __len__() {
if (counter < 0) {
throw Py.TypeError("object of type 'itertools.repeat' has no len()");
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list