Skip to content

Commit

Permalink
Implement Iterable in PyIterator. This means generators are usable in…
Browse files Browse the repository at this point in the history
… foreach loops. The

implementation could be moved up to PyObject, but I feel like implementing the interface says that
the object will be iterable, and not all PyObjects provide an __iter__.
  • Loading branch information
groves committed Jan 17, 2009
1 parent 010e27c commit 1f43040
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 65 deletions.
2 changes: 0 additions & 2 deletions Lib/test/test_java_visibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,6 @@ def simple_gen():
yield 2
yield 3
self.assertEquals(6, Coercions.takeIterable(simple_gen()))
self.assertEquals(True, Coercions.takeBoolIterable(simple_gen()))


def test_class_coercion(self):
c = Coercions()
Expand Down
2 changes: 1 addition & 1 deletion src/org/python/core/BytecodeLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.python.util.Generic;

/**
* Utility class for loading of compiled python modules and java classes defined in python modules.
* Utility class for loading compiled python modules and java classes defined in python modules.
*/
public class BytecodeLoader {

Expand Down
13 changes: 12 additions & 1 deletion src/org/python/core/PyIterator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2000 Finn Bock
package org.python.core;

import java.util.Iterator;

/**
* An abstract helper class useful when implementing an iterator object. This implementation supply
* a correct __iter__() and a next() method based on the __iternext__() implementation. The
Expand All @@ -9,7 +11,7 @@
* If the implementation raises a StopIteration exception, it should be stored in stopException so
* the correct exception can be thrown to preserve the line numbers in the traceback.
*/
public abstract class PyIterator extends PyObject {
public abstract class PyIterator extends PyObject implements Iterable<Object> {

protected PyException stopException;

Expand Down Expand Up @@ -51,4 +53,13 @@ protected final PyObject doNext(PyObject ret) {
}
return ret;
}

public Iterator<Object> iterator() {
return new WrappedIterIterator<Object>(this) {
@Override
public Object next() {
return getNext().__tojava__(Object.class);
}
};
}
}
4 changes: 2 additions & 2 deletions src/org/python/core/PyList.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
import org.python.expose.MethodType;
import org.python.util.Generic;

/**
* A builtin python list.
Expand Down Expand Up @@ -51,7 +51,7 @@ public PyList(PyObject o) {
}

private static List<PyObject> listify(Iterator<PyObject> iter) {
final List<PyObject> list = new LinkedList<PyObject>();
List<PyObject> list = Generic.list();
while (iter.hasNext()) {
list.add(iter.next());
}
Expand Down
36 changes: 4 additions & 32 deletions src/org/python/core/PyObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import org.python.expose.ExposedDelete;
import org.python.expose.ExposedGet;
import org.python.expose.ExposedMethod;
Expand Down Expand Up @@ -765,36 +763,10 @@ public PyObject __iter__() {
*/
public Iterable<PyObject> asIterable() {
return new Iterable<PyObject>() {

public Iterator<PyObject> iterator() {
return new Iterator<PyObject>() {

private PyObject iter = __iter__();

private PyObject next;

private boolean checkedForNext;

public boolean hasNext() {
if (!checkedForNext) {
next = iter.__iternext__();
checkedForNext = true;
}
return next != null;
}

return new WrappedIterIterator<PyObject>(__iter__()) {
public PyObject next() {
if (!hasNext()) {
throw new NoSuchElementException("End of the line, bub");
}
PyObject toReturn = next;
checkedForNext = false;
next = null;
return toReturn;
}

public void remove() {
throw new UnsupportedOperationException("Can't remove from a Python iterator");
return getNext();
}
};
}
Expand Down Expand Up @@ -1894,8 +1866,8 @@ private PyObject _binop_rule(PyType t1, PyObject o2, PyType t2,
where1 = where[0];
PyObject impl2 = t2.lookup_where(right, where);
where2 = where[0];
if (impl2 != null && impl1 != null && where1 != where2 &&
(t2.isSubType(t1) && !Py.isSubClass(where1, where2)
if (impl2 != null && impl1 != null && where1 != where2 &&
(t2.isSubType(t1) && !Py.isSubClass(where1, where2)
&& !Py.isSubClass(t1, where2) ||
isStrUnicodeSpecialCase(t1, t2, op))) {
PyObject tmp = o1;
Expand Down
3 changes: 0 additions & 3 deletions src/org/python/core/PySequence.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
*/
public abstract class PySequence extends PyObject {

/**
* This constructor is used by PyJavaClass.init()
*/
public PySequence() {}
public int gListAllocatedStatus = -1;

Expand Down
48 changes: 48 additions & 0 deletions src/org/python/core/WrappedIterIterator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.python.core;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* Exposes a Python iter as a Java Iterator.
*/
public abstract class WrappedIterIterator<E> implements Iterator<E> {

private final PyObject iter;

private PyObject next;

private boolean checkedForNext;

public WrappedIterIterator(PyObject iter) {
this.iter = iter;
}

public boolean hasNext() {
if (!checkedForNext) {
next = iter.__iternext__();
checkedForNext = true;
}
return next != null;
}

/**
* Subclasses must implement this to turn the type returned by the iter to the type expected by
* Java.
*/
public abstract E next();

public PyObject getNext() {
if (!hasNext()) {
throw new NoSuchElementException("End of the line, bub");
}
PyObject toReturn = next;
checkedForNext = false;
next = null;
return toReturn;
}

public void remove() {
throw new UnsupportedOperationException("Can't remove from a Python iterator");
}
}
25 changes: 11 additions & 14 deletions src/org/python/core/codecs.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,14 +245,14 @@ public static PyObject replace_errors(PyObject[] args, String[] kws) {
if (Py.isInstance(exc, Py.UnicodeDecodeError)) {
PyObject object = exc.__getattr__("object");
if (!Py.isInstance(object, PyString.TYPE) || Py.isInstance(object, PyUnicode.TYPE)) {
throw Py.TypeError("object attribute must be str");
throw Py.TypeError("object attribute must be str");
}
PyObject end = exc.__getattr__("end");
return new PyTuple(new PyUnicode(Py_UNICODE_REPLACEMENT_CHARACTER), end);
} else if (Py.isInstance(exc, Py.UnicodeEncodeError)) {
PyObject object = exc.__getattr__("object");
if (!Py.isInstance(object, PyUnicode.TYPE)) {
throw Py.TypeError("object attribute must be unicode");
throw Py.TypeError("object attribute must be unicode");
}
PyObject end = exc.__getattr__("end");
return new PyTuple(Py.java2py("?"), end);
Expand Down Expand Up @@ -388,9 +388,9 @@ private static void registry_init() {
XMLCHARREFREPLACE,
BACKSLASHREPLACE
};
for (int i = 0; i < builtinErrorHandlers.length; i++) {
register_error(builtinErrorHandlers[i], Py.newJavaFunc(codecs.class,
builtinErrorHandlers[i] + "_errors"));
for (String builtinErrorHandler : builtinErrorHandlers) {
register_error(builtinErrorHandler, Py.newJavaFunc(codecs.class,
builtinErrorHandler + "_errors"));
}
import_encodings();
}
Expand All @@ -414,9 +414,9 @@ private static void registry_init() {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 1, 1
,


};

private static boolean SPECIAL(char c, boolean encodeO, boolean encodeWS){
return (c>127 || utf7_special[(c)] == 1) ||
(encodeWS && (utf7_special[(c)] == 2)) ||
Expand Down Expand Up @@ -447,7 +447,6 @@ public static String PyUnicode_DecodeUTF7(String str,
int bitsInCharsleft = 0;
long charsleft = 0;
boolean surrogate = false;
char highOrderSurrogate = 0;
StringBuilder unicode = new StringBuilder(e);
while (s < e) {
// restart:
Expand All @@ -470,7 +469,6 @@ public static String PyUnicode_DecodeUTF7(String str,
surrogate = false;
} else if (0xDC00 <= outCh && outCh <= 0xDFFF) {
surrogate = true;
highOrderSurrogate = outCh;
} else {
unicode.append(outCh);
}
Expand Down Expand Up @@ -537,7 +535,6 @@ public static String PyUnicode_DecodeUTF7(String str,
"code pairs are not supported");
} else if (0xDC00 <= outCh && outCh <= 0xDFFF) {
surrogate = true;
highOrderSurrogate = outCh;
} else {
unicode.append(outCh);
}
Expand Down Expand Up @@ -631,7 +628,7 @@ public static String PyUnicode_EncodeUTF7(String str,
bitsleft -= 6;
}
/* If the next character is special then we dont' need to terminate
the shift sequence. If the next character is not a BASE64 character
the shift sequence. If the next character is not a BASE64 character
or '-' then the shift sequence will be terminated implicitly and we
don't have to insert a '-'. */

Expand Down Expand Up @@ -1280,7 +1277,7 @@ class StringSubsequenceIterator implements Iterator {
this.start = start;
this.stop = stop;
this.step = step;

// this bounds checking is necessary to convert between use of code units elsewhere, and codepoints here
// it would be nice if it were unnecessary!
int count = getCodePointCount(s);
Expand All @@ -1290,7 +1287,7 @@ class StringSubsequenceIterator implements Iterator {
else if (stop >= count) {
this.stop = count;
}

for (int i = 0; i < start; i++) {
nextCodePoint();
}
Expand All @@ -1303,7 +1300,7 @@ else if (stop >= count) {
private static int getCodePointCount(String s) {
return s.codePointCount(0, s.length());
}

public boolean hasNext() {
return current < stop;
}
Expand Down
13 changes: 3 additions & 10 deletions src/org/python/core/imp.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.InputStream;
import java.util.concurrent.locks.ReentrantLock;

import org.python.compiler.Module;
import org.python.core.util.FileUtil;

/**
Expand Down Expand Up @@ -189,9 +190,7 @@ public static String cacheCompiledSource(String sourceFilename,
}
}

public static byte[] compileSource(String name,
InputStream fp,
String filename) {
public static byte[] compileSource(String name, InputStream fp, String filename) {
ByteArrayOutputStream ofp = new ByteArrayOutputStream();
try {
if(filename == null) {
Expand All @@ -203,13 +202,7 @@ public static byte[] compileSource(String name,
} finally {
fp.close();
}
org.python.compiler.Module.compile(node,
ofp,
name + "$py",
filename,
true,
false,
null);
Module.compile(node, ofp, name + "$py", filename, true, false, null);
return ofp.toByteArray();
} catch(Throwable t) {
throw ParserFacade.fixParseError(null, t, filename);
Expand Down
17 changes: 17 additions & 0 deletions tests/java/org/python/tests/Coercions.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,21 @@ public static String take(boolean b) {
public static String take(byte bt) {
return "take with byte arg: " + bt;
}

public static int takeIterable(Iterable<Integer> it) {
int sum = 0;
for (Integer integer : it) {
sum += integer;
}
return sum;
}

public static boolean takeBoolIterable(Iterable<Boolean> it) {
for (Boolean integer : it) {
if (!integer) {
return false;
}
}
return true;
}
}

0 comments on commit 1f43040

Please sign in to comment.