/** * Sets the attribute name to value. * * @param name * @param value */ public void __setattr__(String name, PyObject value) { if ("destinationDataHandler".equals(name)) { this.destDH = (Class) value.__tojava__(Class.class); } else if ("sourceDataHandler".equals(name)) { this.sourceDH = (Class) value.__tojava__(Class.class); } else if ("batchsize".equals(name)) { this.batchsize = ((Number) value.__tojava__(Number.class)).intValue(); } else if ("queuesize".equals(name)) { this.queuesize = ((Number) value.__tojava__(Number.class)).intValue(); } else { super.__setattr__(name, value); } }
/** * Ensure that if the test runner has a {@code __del__} attribute, it is called when the thread * is shutdown. Normally Jython defers this to the Java garbage collector, so we might have done * something like * * <blockquote> * * <pre> * m_testRunner = null; * Runtime.getRuntime().gc(); * </pre> * * </blockquote> * * instead. However this would have a number of problems: * * <ol> * <li>Some JVM's may chose not to finalise the test runner in response to {@code gc()}. * <li>{@code __del__} would be called by a GC thread. * <li>The standard Jython finalizer wrapping around {@code __del__} logs to {@code stderr}. * </ol> * * <p>Instead, we call any {@code __del__} ourselves. After calling this method, the {@code * PyObject} that underlies this class is made invalid. */ @Override public void shutdown() throws ScriptExecutionException { final PyObject del = m_testRunner.__findattr__("__del__"); if (del != null) { try { del.__call__(); } catch (final PyException e) { throw new JythonScriptExecutionException("deleting TestRunner instance", e); } finally { // To avoid the (pretty small) chance of the test runner being // finalised and __del__ being run twice, we disable it. // Unfortunately, Jython caches the __del__ attribute and makes // it impossible to turn it off at a class level. Instead we do // this: m_testRunner.__setattr__("__class__", m_dieQuietly); } } }
/** * Open file and return a stream. Raise IOError upon failure. This is a port to Java of the * CPython _io.open (Modules/_io/_iomodule.c) following the same logic, but expressed with the * benefits of Java syntax. * * @param args array of arguments from Python call via Jython framework * @param kwds array of keywords from Python call via Jython framework * @return the stream object */ public static PyObject open(PyObject[] args, String[] kwds) { // Get the arguments to variables ArgParser ap = new ArgParser("open", args, kwds, openKwds, 1); PyObject file = ap.getPyObject(0); String m = ap.getString(1, "r"); int buffering = ap.getInt(2, -1); final String encoding = ap.getString(3, null); final String errors = ap.getString(4, null); final String newline = ap.getString(5, null); boolean closefd = Py.py2boolean(ap.getPyObject(6, Py.True)); // Decode the mode string OpenMode mode = new OpenMode(m) { @Override public void validate() { super.validate(); validate(encoding, errors, newline); } }; mode.checkValid(); /* * Create the Raw file stream. Let the constructor deal with the variants and argument * checking. */ PyFileIO raw = new PyFileIO(file, mode, closefd); /* * From the Python documentation for io.open() buffering = 0 to switch buffering off (only * allowed in binary mode), 1 to select line buffering (only usable in text mode), and an * integer > 1 to indicate the size of a fixed-size buffer. * * When no buffering argument is given, the default buffering policy works as follows: * Binary files are buffered in fixed-size chunks; "Interactive" text files (files for which * isatty() returns True) use line buffering. Other text files use the policy described * above for binary files. * * In Java, it seems a stream never is *known* to be interactive, but we ask anyway, and * maybe one day we shall know. */ boolean line_buffering = false; if (buffering == 0) { if (!mode.binary) { throw Py.ValueError("can't have unbuffered text I/O"); } return raw; } else if (buffering == 1) { // The stream is to be read line-by-line. line_buffering = true; // Force default size for actual buffer buffering = -1; } else if (buffering < 0 && raw.isatty()) { // No buffering argument given but stream is inteeractive. line_buffering = true; } if (buffering < 0) { /* * We are still being asked for the default buffer size. CPython establishes the default * buffer size using fstat(fd), but Java appears to give no clue. A useful study of * buffer sizes in NIO is http://www.evanjones.ca/software/java-bytebuffers.html . This * leads us to the fixed choice of _DEFAULT_BUFFER_SIZE (=8KB). */ buffering = _DEFAULT_BUFFER_SIZE; } /* * We now know just what particular class of file we are opening, and therefore what stack * (buffering and text encoding) we should build. */ if (buffering == 0) { // Not buffering, return the raw file object return raw; } else { // We are buffering, so wrap raw into a buffered file PyObject bufferType = null; PyObject io = imp.load("io"); if (mode.updating) { bufferType = io.__getattr__("BufferedRandom"); } else if (mode.writing || mode.appending) { bufferType = io.__getattr__("BufferedWriter"); } else { // = reading bufferType = io.__getattr__("BufferedReader"); } PyInteger pyBuffering = new PyInteger(buffering); PyObject buffer = bufferType.__call__(raw, pyBuffering); if (mode.binary) { // If binary, return the just the buffered file return buffer; } else { // We are opening in text mode, so wrap buffered file in a TextIOWrapper. PyObject textType = io.__getattr__("TextIOWrapper"); PyObject[] textArgs = { buffer, ap.getPyObject(3, Py.None), ap.getPyObject(4, Py.None), ap.getPyObject(5, Py.None), Py.newBoolean(line_buffering) }; PyObject wrapper = textType.__call__(textArgs); wrapper.__setattr__("mode", new PyString(m)); return wrapper; } } }