From: <zy...@us...> - 2009-03-21 21:23:26
|
Revision: 6103 http://jython.svn.sourceforge.net/jython/?rev=6103&view=rev Author: zyasoft Date: 2009-03-21 21:23:22 +0000 (Sat, 21 Mar 2009) Log Message: ----------- Reinstated PythonInterpreter#setErr(java.io.Writer), #setOut(java.io.Writer) (but deprecating). This uses PyFileWriter which implements a file-like interface sufficient for stdout/stderr usage. Fixes #1266 Modified Paths: -------------- trunk/jython/src/org/python/core/StdoutWrapper.java trunk/jython/src/org/python/util/PythonInterpreter.java Added Paths: ----------- trunk/jython/Lib/test/test_pythoninterpreter_jy.py trunk/jython/src/org/python/core/PyFileWriter.java Added: trunk/jython/Lib/test/test_pythoninterpreter_jy.py =================================================================== --- trunk/jython/Lib/test/test_pythoninterpreter_jy.py (rev 0) +++ trunk/jython/Lib/test/test_pythoninterpreter_jy.py 2009-03-21 21:23:22 UTC (rev 6103) @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +import java.io.StringWriter +import sys +import traceback +import unittest +import test.test_support + + +def exec_code_in_pi(function, out, err, locals=None): + """Runs code in a separate context: (thread, PySystemState, PythonInterpreter)""" + + def function_context(): + from org.python.core import Py + from org.python.util import PythonInterpreter + from org.python.core import PySystemState + + ps = PySystemState() + pi = PythonInterpreter({}, ps) + if locals: + pi.setLocals(locals) + pi.setOut(out) + pi.setErr(err) + try: + pi.exec(function.func_code) + except: + print '-'*60 + traceback.print_exc(file=sys.stdout) + print '-'*60 + + + import threading + context = threading.Thread(target=function_context) + context.start() + context.join() + + +class InterpreterTest(unittest.TestCase): + + # in these tests, note the promotion to unicode by java.io.Writer, + # because these are character-oriented streams. caveat emptor! + + def test_pi_out_unicode(self): + source_text = [ + u'Some text', + 'Plain text', + u'\u1000\u2000\u3000\u4000', + # Some language names from wikipedia + u'Català · Česky · Dansk · Deutsch · English · Español · Esperanto · Français · Bahasa Indonesia · Italiano · Magyar · Nederlands · 日本語 · Norsk (bokmål) · Polski · Português · Русский · Română · Slovenčina · Suomi · Svenska · Türkçe · Українська · Volapük · 中文', + ] + + def f(): + global text + for x in text: + print x + out = java.io.StringWriter() + err = java.io.StringWriter() + exec_code_in_pi(f, out, err, {'text': source_text}) + output_text = out.toString().splitlines() + for source, output in zip(source_text, output_text): + self.assertEquals(source, output) + + def test_pi_out(self): + def f(): + print 42 + out = java.io.StringWriter() + err = java.io.StringWriter() + exec_code_in_pi(f, out, err) + self.assertEquals(u"42\n", out.toString()) + + def test_more_output(self): + def f(): + for i in xrange(42): + print "*" * i + out = java.io.StringWriter() + err = java.io.StringWriter() + exec_code_in_pi(f, out, err) + output = out.toString().splitlines() + for i, line in enumerate(output): + self.assertEquals(line, u'*' * i) + self.assertEquals(42, len(output)) + + + +def test_main(): + test.test_support.run_unittest(InterpreterTest) + +if __name__ == "__main__": + test_main() Added: trunk/jython/src/org/python/core/PyFileWriter.java =================================================================== --- trunk/jython/src/org/python/core/PyFileWriter.java (rev 0) +++ trunk/jython/src/org/python/core/PyFileWriter.java 2009-03-21 21:23:22 UTC (rev 6103) @@ -0,0 +1,83 @@ +// A file-like object for writing to java.io.Writer objects; +// only to be used for stdout, stderr in PythonInterpreter#setOut(Writer), #setErr(Writer) +// (for backwards compatibility) +// +// no attempts to close etc at shutdown are done for this object (unlike PyFile), +// since again just for PythonInterpreter +// nor is this exposed as a type +package org.python.core; + +import java.io.Writer; +import java.io.IOException; + +public class PyFileWriter extends PyObject { + + private final Writer writer; + private boolean closed; + public boolean softspace = false; + + public PyFileWriter(Writer writer) { + this.writer = writer; + closed = false; + } + + public boolean closed() { + return closed; + } + + public void checkClosed() { + if (closed()) { + throw Py.ValueError("I/O operation on closed file"); + } + } + + public synchronized void flush() { + checkClosed(); + try { + writer.flush(); + } catch (IOException e) { + throw Py.IOError(e); + } + } + + public void close() { + try { + writer.close(); + closed = true; + } catch (IOException e) { + throw Py.IOError(e); + } + } + + public void write(PyObject o) { + if (o instanceof PyUnicode) { + write(((PyUnicode) o).string); + } else if (o instanceof PyString) { + write(((PyString) o).string); + } else { + throw Py.TypeError("write requires a string as its argument"); + } + } + + public synchronized void write(String s) { + checkClosed(); + try { + writer.write(s); + } catch (IOException e) { + throw Py.IOError(e); + } + } + + public synchronized void writelines(PyObject a) { + checkClosed(); + PyObject iter = Py.iter(a, "writelines() requires an iterable argument"); + + PyObject item = null; + while ((item = iter.__iternext__()) != null) { + if (!(item instanceof PyString)) { + throw Py.TypeError("writelines() argument must be a sequence of strings"); + } + write(item); + } + } +} Modified: trunk/jython/src/org/python/core/StdoutWrapper.java =================================================================== --- trunk/jython/src/org/python/core/StdoutWrapper.java 2009-03-20 01:16:13 UTC (rev 6102) +++ trunk/jython/src/org/python/core/StdoutWrapper.java 2009-03-21 21:23:22 UTC (rev 6103) @@ -122,6 +122,36 @@ file.softspace = false; } file.flush(); + } else if (obj instanceof PyFileWriter) { + PyFileWriter file = (PyFileWriter)obj; + if (file.softspace) { + file.write(" "); + file.softspace = false; + } + + // since we are outputting directly to a character stream, + // avoid doing an encoding + String s; + if (o instanceof PyString) { + s = ((PyString)o).string; + } else { + s = o.toString(); + } + int len = s.length(); + file.write(s); + if (o instanceof PyString) { + if (len == 0 || !Character.isWhitespace(s.charAt(len - 1)) + || s.charAt(len - 1) == ' ') { + file.softspace = space; + } + } else { + file.softspace = space; + } + if (newline) { + file.write("\n"); + file.softspace = false; + } + file.flush(); } else { PyObject ss = obj.__findattr__("softspace"); if (ss != null && ss.__nonzero__()) { Modified: trunk/jython/src/org/python/util/PythonInterpreter.java =================================================================== --- trunk/jython/src/org/python/util/PythonInterpreter.java 2009-03-20 01:16:13 UTC (rev 6102) +++ trunk/jython/src/org/python/util/PythonInterpreter.java 2009-03-21 21:23:22 UTC (rev 6103) @@ -7,6 +7,7 @@ import org.python.core.PyCode; import org.python.core.PyException; import org.python.core.PyFile; +import org.python.core.PyFileWriter; import org.python.core.PyModule; import org.python.core.PyObject; import org.python.core.PyString; @@ -90,6 +91,11 @@ systemState.stdout = outStream; } + /** @deprecated */ + public void setOut(java.io.Writer outStream) { + setOut(new PyFileWriter(outStream)); + } + /** * Set a java.io.OutputStream to use for the standard output stream * @@ -104,6 +110,11 @@ systemState.stderr = outStream; } + /** @deprecated */ + public void setErr(java.io.Writer outStream) { + setErr(new PyFileWriter(outStream)); + } + public void setErr(java.io.OutputStream outStream) { setErr(new PyFile(outStream)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |