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(); } }