Skip to content

Commit

Permalink
refactor redirect streams to take OutputStreams
Browse files Browse the repository at this point in the history
  • Loading branch information
ndjensen committed Jul 31, 2021
1 parent 5ccaace commit f67b874
Showing 5 changed files with 113 additions and 37 deletions.
13 changes: 10 additions & 3 deletions src/main/java/jep/Jep.java
Original file line number Diff line number Diff line change
@@ -185,9 +185,16 @@ protected void configureInterpreter(JepConfig config) throws JepException {
exec("del sharedImporter");
}
setupJavaImportHook(config.classEnquirer);
if (config.redirectOutputStreams) {
if (config.redirectStdout != null || config.redirectStderr != null) {
exec("from jep import redirect_streams");
exec("redirect_streams.setup()");
if (config.redirectStdout != null) {
set("stdoutOutputStream", config.redirectStdout);
exec("redirect_streams.redirectStdout(stdoutOutputStream)");
}
if (config.redirectStderr != null) {
set("stderrOutputStream", config.redirectStderr);
exec("redirect_streams.redirectStderr(stderrOutputStream)");
}
}
}

@@ -358,7 +365,7 @@ private native Object getValue(long tstate, String str, Class<?> clazz)
@Override
public void set(String name, Object v) throws JepException {
isValidThread();
set(tstate,name,v);
set(tstate, name, v);
}

private native void set(long tstate, String name, Object v)
36 changes: 28 additions & 8 deletions src/main/java/jep/JepConfig.java
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
package jep;

import java.io.File;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -51,7 +52,9 @@ public class JepConfig {

protected ClassEnquirer classEnquirer = null;

protected boolean redirectOutputStreams = false;
protected OutputStream redirectStdout = null;

protected OutputStream redirectStderr = null;

protected Set<String> sharedModules = null;

@@ -118,15 +121,32 @@ public JepConfig setClassEnquirer(ClassEnquirer classEnquirer) {
}

/**
* Sets whether to redirect the Python sys.stdout and sys.stderr streams to
* the Java System.out and System.err streams
*
* @param redirectOutputStreams
* whether to redirect Python streams to Java
* Redirects the Python interpreter's sys.stdout to the provided
* OutputStream.
*
* @param outputStream
* the Java OutputStream to redirect Python stdout to
* @return a reference to this JepConfig
*
* @since 4.0
*/
public JepConfig redirectStdout(OutputStream outputStream) {
this.redirectStdout = outputStream;
return this;
}

/**
* Redirects the Python interpreter's sys.stderr to the provided
* OutputStream.
*
* @param outputStream
* the Java OutputStream to redirect Python stderr to
* @return a reference to this JepConfig
*
* @since 4.0
*/
public JepConfig setRedirectOutputStreams(boolean redirectOutputStreams) {
this.redirectOutputStreams = redirectOutputStreams;
public JepConfig redirectStdErr(OutputStream outputStream) {
this.redirectStderr = outputStream;
return this;
}

37 changes: 11 additions & 26 deletions src/main/python/jep/redirect_streams.py
Original file line number Diff line number Diff line change
@@ -25,38 +25,23 @@

import sys

class StdOutToJava(object):
"Redirects Python's sys.stdout to Java's System.out"
class StreamRedirect(object):
"Redirects a Python output stream to a Java OutputStream"

def __init__(self):
from java.lang import System
self.oldout = sys.stdout
self.printmethod = getattr(System.out, 'print')
self.flushmethod = getattr(System.out, 'flush')
def __init__(self, javaOutputStream):
from java.io import PrintStream
self.printstream = PrintStream(javaOutputStream)
self.printmethod = getattr(self.printstream, 'print')
self.flushmethod = getattr(self.printstream, 'flush')

def write(self, msg):
self.printmethod(msg)

def flush(self):
self.flushmethod()

def redirectStdout(javaOutputStream):
sys.stdout = StreamRedirect(javaOutputStream)

class StdErrToJava(object):
"Redirects Python's sys.stderr to Java's System.err"

def __init__(self):
from java.lang import System
self.olderr = sys.stderr
self.printmethod = getattr(System.err, 'print')
self.flushmethod = getattr(System.err, 'flush')

def write(self, msg):
self.printmethod(msg)

def flush(self):
self.flushmethod()


def setup():
sys.stdout = StdOutToJava()
sys.stderr = StdErrToJava()
def redirectStderr(javaOutputStream):
sys.stderr = StreamRedirect(javaOutputStream)
54 changes: 54 additions & 0 deletions src/test/java/jep/test/TestRedirectStreams.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package jep.test;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;

import jep.Interpreter;
import jep.JepConfig;
import jep.SubInterpreter;

/**
* Created: July 2021
*
* @author Nate Jensen
* @since 4.0
*/
public class TestRedirectStreams {

public static void main(String[] args) throws Exception {
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();

try (Interpreter interp = new SubInterpreter(new JepConfig()
.redirectStdout(stdout).redirectStdErr(stderr))) {
String testString = "This string came from Python's print function.";
interp.set("testString", testString);
interp.exec("print(testString)");
String stdoutOutput = new String(stdout.toByteArray(),
StandardCharsets.UTF_8);
// Python print function will add a \n on the end
testString += "\n";
if (!testString.equals(stdoutOutput)) {
throw new IllegalStateException(
"testString did not match stdoutOutput! testString="
+ testString + " stdoutOutput=" + stdoutOutput);
}

String line1 = "stderrLine1";
String line2 = "stderrLine2";
interp.set("line1", line1);
interp.set("line2", line2);
interp.exec("import sys");
interp.exec("print(line1, file=sys.stderr)");
interp.exec("sys.stderr.write(line2)");
String stderrOutput = new String(stderr.toByteArray(),
StandardCharsets.UTF_8);
String combined = line1 + "\n" + line2;
if (!combined.equals(stderrOutput)) {
throw new IllegalStateException(
"testString did not match stderrOutput! testString="
+ combined + " stderrOutput=" + stderrOutput);
}
}
}
}
10 changes: 10 additions & 0 deletions src/test/python/test_redirect_streams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import unittest

from jep_pipe import jep_pipe
from jep_pipe import build_java_process_cmd

class TestRedirectStreams(unittest.TestCase):

def test_compiledScript(self):
jep_pipe(build_java_process_cmd('jep.test.TestRedirectStreams'))

0 comments on commit f67b874

Please sign in to comment.