[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