All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.org.python.jsr223.PyScriptEngine Maven / Gradle / Ivy

Go to download

Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform.

There is a newer version: 2.7.4
Show newest version
package org.python.jsr223;

import java.lang.reflect.Method;
import org.python.core.*;
import java.io.Reader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import org.python.util.PythonInterpreter;

public class PyScriptEngine extends AbstractScriptEngine implements Compilable, Invocable, AutoCloseable {

    private final PythonInterpreter interp;
    private final ScriptEngineFactory factory;

    PyScriptEngine(ScriptEngineFactory factory) {
        this.factory = factory;
        interp = PythonInterpreter.threadLocalStateInterpreter(new PyScriptEngineScope(this, context));
    }

    public Object eval(String script, ScriptContext context) throws ScriptException {
        return eval(compileScript(script, context), context);
    }

    private Object eval(PyCode code, ScriptContext context) throws ScriptException {
        try {
            interp.setIn(context.getReader());
            interp.setOut(context.getWriter());
            interp.setErr(context.getErrorWriter());
            interp.setLocals(new PyScriptEngineScope(this, context));

            // set sys.argv if FILENAME, ARGV attributes are defined
            String filename = (String) context.getAttribute(ScriptEngine.FILENAME);
            String[] argv = (String[]) context.getAttribute(ScriptEngine.ARGV);
            if (argv != null || filename != null) {
                PyList pyargv = new PyList();
                if (filename != null) {
                    pyargv.append(Py.java2py(filename));
                }
                if (argv != null) {
                    for (int i = 0; i < argv.length; i++) {
                        pyargv.append(Py.java2py(argv[i]));
                    }
                }
                interp.getSystemState().argv = pyargv;
            }

            return interp.eval(code).__tojava__(Object.class);
        } catch (PyException pye) {
            throw scriptException(pye);
        }
    }

    public Object eval(Reader reader, ScriptContext context) throws ScriptException {
        return eval(compileScript(reader, context), context);
    }

    public Bindings createBindings() {
        return new SimpleBindings();
    }

    public ScriptEngineFactory getFactory() {
        return factory;
    }

    public CompiledScript compile(String script) throws ScriptException {
        return new PyCompiledScript(compileScript(script, context));
    }

    public CompiledScript compile(Reader reader) throws ScriptException {
        return new PyCompiledScript(compileScript(reader, context));
    }

    private PyCode compileScript(String script, ScriptContext context) throws ScriptException {
        try {
            String filename = (String) context.getAttribute(ScriptEngine.FILENAME);
            if (filename == null) {
                return interp.compile(script);
            } else {
                interp.getLocals().__setitem__(Py.newString("__file__"), Py.newString(filename));
                return interp.compile(script, filename);
            }
        } catch (PyException pye) {
            throw scriptException(pye);
        }
    }

    private PyCode compileScript(Reader reader, ScriptContext context) throws ScriptException {
        try {
            String filename = (String) context.getAttribute(ScriptEngine.FILENAME);
            if (filename == null) {
                return interp.compile(reader);
            } else {
                interp.getLocals().__setitem__(Py.newString("__file__"), Py.newString(filename));
                return interp.compile(reader, filename);
            }
        } catch (PyException pye) {
            throw scriptException(pye);
        }
    }

    public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException,
            NoSuchMethodException {
        try {
            interp.setLocals(new PyScriptEngineScope(this, context));
            if (!(thiz instanceof PyObject)) {
                thiz = Py.java2py(thiz);
            }
            PyObject method = ((PyObject) thiz).__findattr__(name);
            if (method == null) {
                throw new NoSuchMethodException(name);
            }
            //return method.__call__(Py.javas2pys(args)).__tojava__(Object.class);
            PyObject result;
            if(args != null) {
               result = method.__call__(Py.javas2pys(args));
            } else {
               result = method.__call__();
            }
            return result.__tojava__(Object.class);
        } catch (PyException pye) {
            throw scriptException(pye);
        }
    }

    public Object invokeFunction(String name, Object... args) throws ScriptException,
            NoSuchMethodException {
        try {
            interp.setLocals(new PyScriptEngineScope(this, context));
            PyObject function = interp.get(name);
            if (function == null) {
                throw new NoSuchMethodException(name);
            }
            PyObject result;
            if(args != null) {
                result = function.__call__(Py.javas2pys(args));
            } else {
                result = function.__call__();
            }
            return result.__tojava__(Object.class);
        } catch (PyException pye) {
            throw scriptException(pye);
        }
    }

    public  T getInterface(Class clazz) {
        return getInterface(new PyModule("__jsr223__", interp.getLocals()), clazz);
    }

    public  T getInterface(Object obj, Class clazz) {
        if (obj == null) {
            throw new IllegalArgumentException("object expected");
        }
        if (clazz == null || !clazz.isInterface()) {
            throw new IllegalArgumentException("interface expected");
        }
        interp.setLocals(new PyScriptEngineScope(this, context));
        final PyObject thiz = Py.java2py(obj);
        @SuppressWarnings("unchecked")
        T proxy = (T) Proxy.newProxyInstance(
            clazz.getClassLoader(),
            new Class[] { clazz },
            new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    try {
                        interp.setLocals(new PyScriptEngineScope(PyScriptEngine.this, context));
                        PyObject pyMethod = thiz.__findattr__(method.getName());
                        if (pyMethod == null)
                            throw new NoSuchMethodException(method.getName());
                        PyObject result;
                        if(args != null) {
                            result = pyMethod.__call__(Py.javas2pys(args));
                        } else {
                            result = pyMethod.__call__();
                        }
                        return result.__tojava__(Object.class);
                    } catch (PyException pye) {
                        throw scriptException(pye);
                    }
                }
            });
        return proxy;
    }

    private static ScriptException scriptException(PyException pye) {
        ScriptException se = null;
        try {
            pye.normalize();

            PyObject type = pye.type;
            PyObject value = pye.value;
            PyTraceback tb = pye.traceback;

            if (__builtin__.isinstance(value, Py.SyntaxError)) {
                PyObject filename = value.__findattr__("filename");
                PyObject lineno = value.__findattr__("lineno");
                PyObject offset = value.__findattr__("offset");
                value = value.__findattr__("msg");

                se = new ScriptException(
                        Py.formatException(type, value),
                        filename == null ? "