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

src.org.python.util.jython 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
// Copyright (c) Corporation for National Research Initiatives
package org.python.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.python.Version;
import org.python.core.CodeFlag;
import org.python.core.CompileMode;
import org.python.core.Options;
import org.python.core.Py;
import org.python.core.PyCode;
import org.python.core.PyException;
import org.python.core.PyFile;
import org.python.core.PyList;
import org.python.core.PyString;
import org.python.core.PyStringMap;
import org.python.core.PySystemState;
import org.python.core.imp;
import org.python.core.util.RelativeFile;
import org.python.modules._systemrestart;
import org.python.modules.posix.PosixModule;
import org.python.modules.thread.thread;

public class jython {
    private static final String COPYRIGHT =
        "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.";

    static final String usageHeader =
        "usage: jython [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";

    private static final String usage = usageHeader +
        "Options and arguments:\n" + //(and corresponding environment variables):\n" +
        "-B       : don't write .py[co] files on import\n" + // "; also PYTHONDONTWRITEBYTECODE=x\n" +
        "-c cmd   : program passed in as string (terminates option list)\n" +
        //"-d       : debug output from parser (also PYTHONDEBUG=x)\n" +
        "-Dprop=v : Set the property `prop' to value `v'\n"+
        //"-E       : ignore environment variables (such as PYTHONPATH)\n" +
        "-C codec : Use a different codec when reading from the console.\n"+
        "-h       : print this help message and exit (also --help)\n" +
        "-i       : inspect interactively after running script\n" + //, (also PYTHONINSPECT=x)\n" +
        "           and force prompts, even if stdin does not appear to be a terminal\n" +
        "-jar jar : program read from __run__.py in jar file\n"+
        "-m mod   : run library module as a script (terminates option list)\n" +
        //"-O       : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n" +
        //"-OO      : remove doc-strings in addition to the -O optimizations\n" +
        "-Q arg   : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n" +
        // XXX: support -s
        //"-s       : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n" +
        "-S       : don't imply 'import site' on initialization\n" +
        //"-t       : issue warnings about inconsistent tab usage (-tt: issue errors)\n" +
        "-u       : unbuffered binary stdout and stderr\n" + // (also PYTHONUNBUFFERED=x)\n" +
        //"           see man page for details on internal buffering relating to '-u'\n" +
        "-v       : verbose (trace import statements)\n" + // (also PYTHONVERBOSE=x)\n" +
        "           can be supplied multiple times to increase verbosity\n" +
        "-V       : print the Python version number and exit (also --version)\n" +
        "-W arg   : warning control (arg is action:message:category:module:lineno)\n" +
        //"-x       : skip first line of source, allowing use of non-Unix forms of #!cmd\n" +
        "-3       : warn about Python 3.x incompatibilities that 2to3 cannot trivially fix\n" +
        "file     : program read from script file\n" +
        "-        : program read from stdin (default; interactive mode if a tty)\n" +
        "arg ...  : arguments passed to program in sys.argv[1:]\n" +
        "\n" +
        "Other environment variables:\n" +
        "JYTHONPATH: '" + File.pathSeparator +
        "'-separated list of directories prefixed to the default module\n" +
        "            search path.  The result is sys.path.";

    public static boolean shouldRestart;

    /**
     * Runs a JAR file, by executing the code found in the file __run__.py, 
     * which should be in the root of the  JAR archive. 
     * 
     * Note that the __name__ is set to the base name of the JAR file and not 
     * to "__main__" (for historic reasons). 
     * 
     * This method do NOT handle exceptions. the caller SHOULD handle any 
     * (Py)Exceptions thrown by the code.
     * 
     * @param filename The path to the filename to run. 
     */
    public static void runJar(String filename) {
        // TBD: this is kind of gross because a local called `zipfile' just magically
        // shows up in the module's globals.  Either `zipfile' should be called
        // `__zipfile__' or (preferrably, IMO), __run__.py should be imported and a main()
        // function extracted.  This function should be called passing zipfile in as an
        // argument.
        //
        // Probably have to keep this code around for backwards compatibility (?)
        try {
            ZipFile zip = new ZipFile(filename);

            ZipEntry runit = zip.getEntry("__run__.py");
            if (runit == null) {
                throw Py.ValueError("jar file missing '__run__.py'");
            }

            PyStringMap locals = Py.newStringMap();

            // Stripping the stuff before the last File.separator fixes Bug #931129 by
            // keeping illegal characters out of the generated proxy class name
            int beginIndex;
            if ((beginIndex = filename.lastIndexOf(File.separator)) != -1) {
                filename = filename.substring(beginIndex + 1);
            }

            locals.__setitem__("__name__", new PyString(filename));
            locals.__setitem__("zipfile", Py.java2py(zip));

            InputStream file = zip.getInputStream(runit);
            PyCode code;
            try {
                code = Py.compile(file, "__run__", CompileMode.exec);
            } finally {
                file.close();
            }
            Py.runCode(code, locals, locals);
        } catch (IOException e) {
            throw Py.IOError(e);
        }
    }

    public static void main(String[] args) {
        do {
            shouldRestart = false;
            run(args);
        } while (shouldRestart);
    }

    private static List warnOptionsFromEnv() {
        ArrayList opts = new ArrayList();

        try {
            String envVar = System.getenv("PYTHONWARNINGS");
            if (envVar == null) {
                return opts;
            }


            for (String opt : envVar.split(",")) {
                opt = opt.trim();
                if (opt.length() == 0) {
                    continue;
                }
                opts.add(opt);
            }
        } catch (SecurityException e) {
        }

        return opts;
    }

    private static List validWarnActions = Arrays.asList(
        "error", "ignore", "always", "default", "module", "once");

    private static void addWarnings(List from, PyList to) {
        outerLoop : for (String opt : from) {
            String action = opt.split(":")[0];
            for (String validWarnAction : validWarnActions) {
                if (validWarnAction.startsWith(action)) {
                    if (opt.contains(":")) {
                        to.append(Py.newString(validWarnAction + opt.substring(opt.indexOf(":"))));
                    }
                    else {
                        to.append(Py.newString(validWarnAction));
                    }
                    continue outerLoop;
                }
            }
            System.err.println(String.format("Invalid -W option ignored: invalid action: '%s'", action));
        }
    }

    public static void run(String[] args) {
        // Parse the command line options
        CommandLineOptions opts = new CommandLineOptions();
        if (!opts.parse(args)) {
            if (opts.version) {
                System.err.println("Jython " + Version.PY_VERSION);
                System.exit(0);
            }
            if (opts.help) {
                System.err.println(usage);
            } else if (!opts.runCommand && !opts.runModule) {
                System.err.print(usageHeader);
                System.err.println("Try `jython -h' for more information.");
            }

            int exitcode = opts.help ? 0 : -1;
            System.exit(exitcode);
        }

        // Setup the basic python system state from these options
        PySystemState.initialize(PySystemState.getBaseProperties(), opts.properties, opts.argv);
        PySystemState systemState = Py.getSystemState();

        PyList warnoptions = new PyList();
        addWarnings(opts.warnoptions, warnoptions);
        addWarnings(warnOptionsFromEnv(), warnoptions);
        systemState.setWarnoptions(warnoptions);

        // Make sure warnings module is loaded if there are warning options
        // Not sure this is needed, but test_warnings.py expects this
        if (warnoptions.size() > 0) {
            imp.load("warnings");
        }


        // Decide if stdin is interactive
        if (!opts.fixInteractive || opts.interactive) {
            opts.interactive = ((PyFile)Py.defaultSystemState.stdin).isatty();
            if (!opts.interactive) {
                systemState.ps1 = systemState.ps2 = Py.EmptyString;
            }
        }

        // Now create an interpreter
        InteractiveConsole interp = newInterpreter(opts.interactive);
        systemState.__setattr__("_jy_interpreter", Py.java2py(interp));

        // Print banner and copyright information (or not)
        if (opts.interactive && opts.notice && !opts.runModule) {
            System.err.println(InteractiveConsole.getDefaultBanner());
        }

        if (Options.importSite) {
            try {
                imp.load("site");
                if (opts.interactive && opts.notice && !opts.runModule) {
                    System.err.println(COPYRIGHT);
                }
            } catch (PyException pye) {
                if (!pye.match(Py.ImportError)) {
                    System.err.println("error importing site");
                    Py.printException(pye);
                    System.exit(-1);
                }
            }
        }

        if (opts.division != null) {
            if ("old".equals(opts.division)) {
                Options.division_warning = 0;
            } else if ("warn".equals(opts.division)) {
                Options.division_warning = 1;
            } else if ("warnall".equals(opts.division)) {
                Options.division_warning = 2;
            } else if ("new".equals(opts.division)) {
                Options.Qnew = true;
                interp.cflags.setFlag(CodeFlag.CO_FUTURE_DIVISION);
            }
        }

        // was there a filename on the command line?
        if (opts.filename != null) {
            String path;
            try {
                 path = new File(opts.filename).getCanonicalFile().getParent();
            } catch (IOException ioe) {
                 path = new File(opts.filename).getAbsoluteFile().getParent();
            }
            if (path == null) {
                path = "";
            }
            Py.getSystemState().path.insert(0, new PyString(path));
            if (opts.jar) {
            	try {
            		runJar(opts.filename);
            	} catch (Throwable t) {
                    Py.printException(t);
                    System.exit(-1);            		
            	}
            } else if (opts.filename.equals("-")) {
                try {
                    interp.globals.__setitem__(new PyString("__file__"), new PyString(""));
                    interp.execfile(System.in, "");
                } catch (Throwable t) {
                    Py.printException(t);
                }
            } else {
                try {
                   interp.globals.__setitem__(new PyString("__file__"),
                                              new PyString(opts.filename));

                   FileInputStream file;
                   try {
                       file = new FileInputStream(new RelativeFile(opts.filename));
                   } catch (FileNotFoundException e) {
                       throw Py.IOError(e);
                   }
                   try {
                       if (PosixModule.getPOSIX().isatty(file.getFD())) {
                           opts.interactive = true;
                           interp.interact(null, new PyFile(file));
                           return;
                       } else {
                           interp.execfile(file, opts.filename);
                       }
                   } finally {
                       file.close();
                   }
                } catch (Throwable t) {
                    if (t instanceof PyException
                        && ((PyException)t).match(_systemrestart.SystemRestart)) {
                        // Shutdown this instance...
                        shouldRestart = true;
                        shutdownInterpreter();
                        interp.cleanup();
                        // ..reset the state...
                        Py.setSystemState(new PySystemState());
                        // ...and start again
                        return;
                    } else {
                        Py.printException(t);
                        interp.cleanup();
                        System.exit(-1);
                    }
                }
            }
        }
        else {
            // if there was no file name on the command line, then "" is the first element
            // on sys.path.  This is here because if there /was/ a filename on the c.l.,
            // and say the -i option was given, sys.path[0] will have gotten filled in
            // with the dir of the argument filename.
            Py.getSystemState().path.insert(0, Py.EmptyString);

            if (opts.command != null) {
                try {
                    interp.exec(opts.command);
                } catch (Throwable t) {
                    Py.printException(t);
                    System.exit(1);
                }
            }

            if (opts.moduleName != null) {
                // PEP 338 - Execute module as a script
                try {
                    interp.exec("import runpy");
                    interp.set("name", Py.newString(opts.moduleName));
                    interp.exec("runpy.run_module(name, run_name='__main__', alter_sys=True)");
                    interp.cleanup();
                    return;
                } catch (Throwable t) {
                    Py.printException(t);
                    interp.cleanup();
                    System.exit(-1);
                }
            }
        }

        if (opts.fixInteractive || (opts.filename == null && opts.command == null)) {
            if (opts.encoding == null) {
                opts.encoding = PySystemState.registry.getProperty("python.console.encoding");
            }
            if (opts.encoding != null) {
                if (!Charset.isSupported(opts.encoding)) {
                    System.err.println(opts.encoding
                                       + " is not a supported encoding on this JVM, so it can't "
                                       + "be used in python.console.encoding.");
                    System.exit(1);
                }
                interp.cflags.encoding = opts.encoding;
            }
            try {
                interp.interact(null, null);
            } catch (Throwable t) {
                Py.printException(t);
            }
        }
        interp.cleanup();
    }

    /**
     * Returns a new python interpreter using the InteractiveConsole subclass from the
     * python.console registry key.
     * 

* When stdin is interactive the default is {@link JLineConsole}. Otherwise the * featureless {@link InteractiveConsole} is always used as alternative consoles cause * unexpected behavior with the std file streams. */ private static InteractiveConsole newInterpreter(boolean interactiveStdin) { if (!interactiveStdin) { return new InteractiveConsole(); } String interpClass = PySystemState.registry.getProperty("python.console", ""); if (interpClass.length() > 0) { try { return (InteractiveConsole)Class.forName(interpClass).newInstance(); } catch (Throwable t) { // fall through } } return new JLineConsole(); } /** * Run any finalizations on the current interpreter in preparation for a SytemRestart. */ public static void shutdownInterpreter() { // Stop all the active threads and signal the SystemRestart thread.interruptAllThreads(); Py.getSystemState()._systemRestart = true; // Close all sockets -- not all of their operations are stopped by // Thread.interrupt (in particular pre-nio sockets) try { imp.load("socket").__findattr__("_closeActiveSockets").__call__(); } catch (PyException pye) { // continue } } } class CommandLineOptions { public String filename; public boolean jar, interactive, notice; public boolean runCommand, runModule; public boolean fixInteractive; public boolean help, version; public String[] argv; public Properties properties; public String command; public List warnoptions = Generic.list(); public String encoding; public String division; public String moduleName; public CommandLineOptions() { filename = null; jar = fixInteractive = false; interactive = notice = true; runModule = false; properties = new Properties(); help = version = false; } public void setProperty(String key, String value) { properties.put(key, value); try { System.setProperty(key, value); } catch (SecurityException e) { // continue } } private boolean argumentExpected(String arg) { System.err.println("Argument expected for the " + arg + " option"); return false; } public boolean parse(String[] args) { int index = 0; while (index < args.length && args[index].startsWith("-")) { String arg = args[index]; if (arg.equals("-h") || arg.equals("-?") || arg.equals("--help")) { help = true; return false; } else if (arg.equals("-V") || arg.equals("--version")) { version = true; return false; } else if (arg.equals("-")) { if (!fixInteractive) { interactive = false; } filename = "-"; } else if (arg.equals("-i")) { fixInteractive = true; interactive = true; } else if (arg.equals("-jar")) { jar = true; if (!fixInteractive) { interactive = false; } } else if (arg.equals("-u")) { Options.unbuffered = true; } else if (arg.equals("-v")) { Options.verbose++; } else if (arg.equals("-vv")) { Options.verbose += 2; } else if (arg.equals("-vvv")) { Options.verbose +=3 ; } else if (arg.equals("-S")) { Options.importSite = false; } else if (arg.equals("-B")) { Options.dont_write_bytecode = true; } else if (arg.startsWith("-c")) { runCommand = true; if (arg.length() > 2) { command = arg.substring(2); } else if ((index + 1) < args.length) { command = args[++index]; } else { return argumentExpected(arg); } if (!fixInteractive) { interactive = false; } index++; break; } else if (arg.startsWith("-W")) { if (arg.length() > 2) { warnoptions.add(arg.substring(2)); } else if ((index + 1) < args.length) { warnoptions.add(args[++index]); } else { return argumentExpected(arg); } } else if (arg.equals("-C")) { encoding = args[++index]; setProperty("python.console.encoding", encoding); } else if (arg.equals("-E")) { // XXX: accept -E (ignore environment variables) to be compatiable with // CPython. do nothing for now (we could ignore the registry) Options.ignore_environment = true; } else if (arg.startsWith("-D")) { String key = null; String value = null; int equals = arg.indexOf("="); if (equals == -1) { String arg2 = args[++index]; key = arg.substring(2, arg.length()); value = arg2; } else { key = arg.substring(2, equals); value = arg.substring(equals + 1, arg.length()); } setProperty(key, value); } else if (arg.startsWith("-Q")) { if (arg.length() > 2) { division = arg.substring(2); } else { division = args[++index]; } } else if (arg.startsWith("-m")) { runModule = true; if (arg.length() > 2) { moduleName = arg.substring(2); } else if ((index + 1) < args.length) { moduleName = args[++index]; } else { return argumentExpected(arg); } if (!fixInteractive) { interactive = false; } index++; int n = args.length - index + 1; argv = new String[n]; argv[0] = moduleName; for (int i = 1; index < args.length; i++, index++) { argv[i] = args[index]; } return true; } else if (arg.startsWith("-3")) { Options.py3k_warning = true; } else { String opt = args[index]; if (opt.startsWith("--")) { opt = opt.substring(2); } else if (opt.startsWith("-")) { opt = opt.substring(1); } System.err.println("Unknown option: " + opt); return false; } index += 1; } notice = interactive; if (filename == null && index < args.length && command == null) { filename = args[index++]; if (!fixInteractive) { interactive = false; } notice = false; } if (command != null) { notice = false; } int n = args.length - index + 1; argv = new String[n]; if (filename != null) { argv[0] = filename; } else if (command != null) { argv[0] = "-c"; } else { argv[0] = ""; } for (int i = 1; i < n; i++, index++) { argv[i] = args[index]; } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy