[Jython-checkins] jython: Add Java _io.UnsupportedOperation
jeff.allen
jython-checkins at python.org
Sun Dec 9 21:29:35 CET 2012
http://hg.python.org/jython/rev/092e145a18f2
changeset: 6890:092e145a18f2
user: Jeff Allen <ja...py at farowl.co.uk>
date: Wed Dec 05 19:39:12 2012 +0000
summary:
Add Java _io.UnsupportedOperation
files:
Lib/_jyio.py | 5 +-
src/org/python/modules/_io/_io.java | 60 ++++++-
tests/java/org/python/modules/_io/_ioTest.java | 84 ++++++++++
3 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/Lib/_jyio.py b/Lib/_jyio.py
--- a/Lib/_jyio.py
+++ b/Lib/_jyio.py
@@ -20,7 +20,7 @@
from __future__ import (print_function, unicode_literals)
-import _io # for some diagnostic code
+import _io # Java implementations to replace this module
import os
import abc
@@ -268,8 +268,7 @@
return open(*args, **kwargs)
-class UnsupportedOperation(ValueError, IOError):
- pass
+from _io import UnsupportedOperation
class _IOBase:
diff --git a/src/org/python/modules/_io/_io.java b/src/org/python/modules/_io/_io.java
--- a/src/org/python/modules/_io/_io.java
+++ b/src/org/python/modules/_io/_io.java
@@ -1,24 +1,78 @@
-/* Copyright (c) Jython Developers */
+/* Copyright (c)2012 Jython Developers */
package org.python.modules._io;
import org.python.core.ClassDictInit;
+import org.python.core.Py;
+import org.python.core.PyException;
import org.python.core.PyObject;
import org.python.core.PyString;
+import org.python.core.PyStringMap;
+import org.python.core.PyType;
+import org.python.core.imp;
/**
- * The Python _fileio module.
+ * The Python _io module.
*/
public class _io implements ClassDictInit {
- public static final PyString __doc__ = new PyString("Fast implementation of io.FileIO.");
+ public static final PyString __doc__ = new PyString("Java implementation of _io.");
+ /**
+ * This method is called when the module is loaded, to populate the namespace (dictionary) of
+ * the module. The dictionary has been initialised at this point reflectively from the methods
+ * of this class and this method nulls those entries that ought not to be exposed.
+ *
+ * @param dict namespace of the module
+ */
public static void classDictInit(PyObject dict) {
dict.__setitem__("__name__", new PyString("_io"));
dict.__setitem__("__doc__", __doc__);
dict.__setitem__("FileIO", PyFileIO.TYPE);
+ // Define UnsupportedOperation exception by constructing the type
+
+ PyObject exceptions = imp.load("exceptions");
+ PyObject ValueError = exceptions.__getattr__("ValueError");
+ PyObject IOError = exceptions.__getattr__("IOError");
+ // Equivalent to class UnsupportedOperation(ValueError, IOError) : pass
+ // UnsupportedOperation = makeException(dict, "UnsupportedOperation", ValueError, IOError);
+ // XXX Work-around: slots not properly initialised unless IOError comes first
+ UnsupportedOperation = makeException(dict, "UnsupportedOperation", IOError, ValueError);
+
// Hide from Python
dict.__setitem__("classDictInit", null);
+ dict.__setitem__("makeException", null);
+ }
+
+ /** A Python class for the <code>UnsupportedOperation</code> exception. */
+ public static PyType UnsupportedOperation;
+
+ /**
+ * A function that returns a {@link PyException}, which is a Java exception suitable for
+ * throwing, and that will be raised as an <code>UnsupportedOperation</code> Python exception.
+ *
+ * @param message text message parameter to the Python exception
+ * @return nascent <code>UnsupportedOperation</code> Python exception
+ */
+ public static PyException UnsupportedOperation(String message) {
+ return new PyException(UnsupportedOperation, message);
+ }
+
+ /**
+ * Convenience method for constructing a type object of a Python exception, named as given, and
+ * added to the namespace of the "_io" module.
+ *
+ * @param dict module dictionary
+ * @param excname name of the exception
+ * @param bases one or more bases (superclasses)
+ * @return the constructed exception type
+ */
+ private static PyType makeException(PyObject dict, String excname, PyObject... bases) {
+ PyStringMap classDict = new PyStringMap();
+ classDict.__setitem__("__module__", Py.newString("_io"));
+ PyType type = (PyType)Py.makeClass(excname, bases, classDict);
+ dict.__setitem__(excname, type);
+ return type;
}
}
diff --git a/tests/java/org/python/modules/_io/_ioTest.java b/tests/java/org/python/modules/_io/_ioTest.java
new file mode 100644
--- /dev/null
+++ b/tests/java/org/python/modules/_io/_ioTest.java
@@ -0,0 +1,84 @@
+/* Copyright (c)2012 Jython Developers */
+package org.python.modules._io;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.python.core.PyException;
+import org.python.core.PyObject;
+import org.python.util.PythonInterpreter;
+
+/**
+ * Tests of specific methods in the Python _io module (org.python.modules._io._io). There is an
+ * extensive regression test in Lib/test/test_io.py, but that is quite complex. This test case
+ * exists to exercise selected functionality in isolation.
+ */
+public class _ioTest {
+
+ /** We need the interpreter to be initialised for these tests **/
+ PythonInterpreter interp;
+
+ /**
+ * Initialisation called before each test.
+ *
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+
+ // Initialise a Jython interpreter
+ interp = new PythonInterpreter();
+
+ }
+
+ /**
+ * Test importing the _io module into the global namespace of {@link #interp}.
+ */
+ @Test
+ public void moduleImport() {
+ interp.exec("import _io");
+ PyObject _io = interp.get("_io");
+ org.junit.Assert.assertNotNull(_io);
+ }
+
+ /**
+ * Test raising a Python _io.UnsupportedOperation from Java code directly.
+ */
+ @Test
+ public void javaRaiseUnsupportedOperation() {
+
+ // Built-in modules seem not to initialise until we actually use an interpreter
+ interp.exec("import io");
+
+ // There should be a helper function
+ PyException pye = _io.UnsupportedOperation("Message from _ioTest");
+ PyObject type = pye.type;
+ String repr = type.toString();
+ assertEquals("Class name", "<class '_io.UnsupportedOperation'>", repr);
+
+ // Raise from Java into Python and catch it in a variable: _IOBase.fileno() raises it
+ interp.exec("try :\n io.IOBase().fileno()\n" + "except Exception as e:\n pass");
+ PyObject e = interp.get("e");
+
+ String m = e.toString();
+ assertThat(m, both(containsString("UnsupportedOperation")).and(containsString("fileno")));
+
+ }
+
+ /**
+ * Test raising a Python _io.UnsupportedOperation from Python code into Java.
+ */
+ @Test
+ public void pythonRaiseUnsupportedOperation() {
+ interp.exec("import _io");
+ try {
+ interp.exec("raise _io.UnsupportedOperation()");
+ fail("_io.UnsupportedOperation not raised when expected");
+ } catch (PyException e) {
+ assertEquals(_io.UnsupportedOperation, e.type);
+ }
+ }
+
+}
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list