package org.python.util;
import java.io.Reader;
import java.io.StringReader;
import java.util.Properties;
import org.python.antlr.base.mod;
import org.python.core.CompileMode;
import org.python.core.CompilerFlags;
import org.python.core.ParserFacade;
import org.python.core.Py;
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;
import org.python.core.PyStringMap;
import org.python.core.PySystemState;
import org.python.core.__builtin__;
import org.python.core.PyFileReader;
/**
* The PythonInterpreter class is a standard wrapper for a Jython interpreter
* for embedding in a Java application.
*/
public class PythonInterpreter {
// Defaults if the interpreter uses thread-local state
protected PySystemState systemState;
PyObject globals;
protected ThreadLocal<PyObject> threadLocals;
protected CompilerFlags cflags = new CompilerFlags();
/**
* Initializes the Jython runtime. This should only be called
* once, before any other Python objects (including
* PythonInterpreter) are created.
*
* @param preProperties
* A set of properties. Typically
* System.getProperties() is used. preProperties
* override properties from the registry file.
* @param postProperties
* Another set of properties. Values like python.home,
* python.path and all other values from the registry
* files can be added to this property
* set. postProperties override system properties and
* registry properties.
* @param argv
* Command line arguments, assigned to sys.argv.
*/
public static void initialize(Properties preProperties, Properties postProperties, String[] argv) {
PySystemState.initialize(preProperties, postProperties, argv);
}
/**
* Creates a new interpreter with an empty local namespace.
*/
public PythonInterpreter() {
this(null, null);
}
/**
* Creates a new interpreter with the ability to maintain a
* separate local namespace for each thread (set by invoking
* setLocals()).
*
* @param dict
* a Python mapping object (e.g., a dictionary) for use
* as the default namespace
*/
public static PythonInterpreter threadLocalStateInterpreter(PyObject dict) {
return new PythonInterpreter(dict, null, true);
}
/**
* Creates a new interpreter with a specified local namespace.
*
* @param dict
* a Python mapping object (e.g., a dictionary) for use
* as the namespace
*/
public PythonInterpreter(PyObject dict) {
this(dict, null);
}
public PythonInterpreter(PyObject dict, PySystemState systemState) {
this(dict, systemState, false);
}
protected PythonInterpreter(PyObject dict, PySystemState systemState, boolean useThreadLocalState) {
if (dict == null) {
dict = Py.newStringMap();
}
globals = dict;
if (systemState == null)
systemState = Py.getSystemState();
this.systemState = systemState;
setSystemState();
if (useThreadLocalState) {
threadLocals = new ThreadLocal<PyObject>();
} else {
PyModule module = new PyModule("__main__", dict);
systemState.modules.__setitem__("__main__", module);
}
}
public PySystemState getSystemState() {
return systemState;
}
protected void setSystemState() {
Py.setSystemState(getSystemState());
}
/**
* Sets a Python object to use for the standard input stream.
*
* @param inStream
* a Python file-like object to use as input stream
*/
public void setIn(PyObject inStream) {
getSystemState().stdin = inStream;
}
public void setIn(java.io.Reader inStream) {
setIn(new PyFileReader(inStream));
}
/**
* Sets a java.io.InputStream to use for the standard input
* stream.
*
* @param inStream
* InputStream to use as input stream
*/
public void setIn(java.io.InputStream inStream) {
setIn(new PyFile(inStream));
}
/**
* Sets a Python object to use for the standard output stream.
*
* @param outStream
* Python file-like object to use as output stream
*/
public void setOut(PyObject outStream) {
getSystemState().stdout = outStream;
}
public void setOut(java.io.Writer outStream) {
setOut(new PyFileWriter(outStream));
}
/**
* Sets a java.io.OutputStream to use for the standard output
* stream.
*
* @param outStream
* OutputStream to use as output stream
*/
public void setOut(java.io.OutputStream outStream) {
setOut(new PyFile(outStream));
}
public void setErr(PyObject outStream) {
getSystemState().stderr = outStream;
}
public void setErr(java.io.Writer outStream) {
setErr(new PyFileWriter(outStream));
}
public void setErr(java.io.OutputStream outStream) {
setErr(new PyFile(outStream));
}
/**
* Evaluates a string as a Python expression and returns the
* result.
*/
public PyObject eval(String s) {
setSystemState();
return __builtin__.eval(new PyString(s), getLocals());
}
/**
* Evaluates a Python code object and returns the result.
*/
public PyObject eval(PyObject code) {
setSystemState();
return __builtin__.eval(code, getLocals());
}
/**
* Executes a string of Python source in the local namespace.
*/
public void exec(String s) {
setSystemState();
Py.exec(Py.compile_flags(s, "<string>", CompileMode.exec, cflags), getLocals(), null);
Py.flushLine();
}
/**
* Executes a Python code object in the local namespace.
*/
public void exec(PyObject code) {
setSystemState();
Py.exec(code, getLocals(), null);
Py.flushLine();
}
/**
* Executes a file of Python source in the local namespace.
*/
public void execfile(String filename) {
PyObject locals = getLocals();
setSystemState();
__builtin__.execfile_flags(filename, locals, locals, cflags);
Py.flushLine();
}
public void execfile(java.io.InputStream s) {
execfile(s, "<iostream>");
}
public void execfile(java.io.InputStream s, String name) {
setSystemState();
Py.runCode(Py.compile_flags(s, name, CompileMode.exec, cflags), null, getLocals());
Py.flushLine();
}
/**
* Compiles a string of Python source as either an expression (if
* possible) or a module.
*
* Designed for use by a JSR 223 implementation: "the Scripting
* API does not distinguish between scripts which return values
* and those which do not, nor do they make the corresponding
* distinction between evaluating or executing objects."
* (SCR.4.2.1)
*/
public PyCode compile(String script) {
return compile(script, "<script>");
}
public PyCode compile(Reader reader) {
return compile(reader, "<script>");
}
public PyCode compile(String script, String filename) {
return compile(new StringReader(script), filename);
}
public PyCode compile(Reader reader, String filename) {
mod node = ParserFacade.parseExpressionOrModule(reader, filename, cflags);
setSystemState();
return Py.compile_flags(node, filename, CompileMode.eval, cflags);
}
public PyObject getLocals() {
if (threadLocals == null)
return globals;
PyObject locals = threadLocals.get();
if (locals != null)
return locals;
return globals;
}
public void setLocals(PyObject d) {
if (threadLocals == null)
globals = d;
else
threadLocals.set(d);
}
/**
* Sets a variable in the local namespace.
*
* @param name
* the name of the variable
* @param value
* the object to set the variable to (as converted to
* an appropriate Python object)
*/
public void set(String name, Object value) {
getLocals().__setitem__(name.intern(), Py.java2py(value));
}
/**
* Sets a variable in the local namespace.
*
* @param name
* the name of the variable
* @param value
* the Python object to set the variable to
*/
public void set(String name, PyObject value) {
getLocals().__setitem__(name.intern(), value);
}
/**
* Returns the value of a variable in the local namespace.
*
* @param name
* the name of the variable
* @return the value of the variable, or null if that name isn't
* assigned
*/
public PyObject get(String name) {
return getLocals().__finditem__(name.intern());
}
/**
* Returns the value of a variable in the local namespace.
*
* The value will be returned as an instance of the given Java class.
* <code>interp.get("foo", Object.class)</code> will return the most
* appropriate generic Java object.
*
* @param name
* the name of the variable
* @param javaclass
* the class of object to return
* @return the value of the variable as the given class, or null
* if that name isn't assigned
*/
public <T> T get(String name, Class<T> javaclass) {
PyObject val = getLocals().__finditem__(name.intern());
if (val == null) {
return null;
}
return Py.tojava(val, javaclass);
}
public void cleanup() {
setSystemState();
PySystemState sys = Py.getSystemState();
sys.callExitFunc();
try {
sys.stdout.invoke("flush");
} catch (PyException pye) {
// fall through
}
try {
sys.stderr.invoke("flush");
} catch (PyException pye) {
// fall through
}
sys.cleanup();
}
}