// Copyright (c) Corporation for National Research Initiatives // This class implements the standard Python sys module. package org.python.core; import java.io.File; import java.io.FileInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLDecoder; import java.security.AccessControlException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.StringTokenizer; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.python.core.adapter.ClassicPyObjectAdapter; import org.python.core.adapter.ExtensiblePyObjectAdapter; import org.python.modules.Setup; /** * The "sys" module. */ // xxx this should really be a module! final public class PySystemState extends PyObject { public static final String JYTHON_JAR = "jython.jar"; private static final String JAR_URL_PREFIX = "jar:file:"; private static final String JAR_SEPARATOR = "!"; private static final String PYTHON_CACHEDIR = "python.cachedir"; protected static final String PYTHON_CACHEDIR_SKIP = "python.cachedir.skip"; protected static final String CACHEDIR_DEFAULT_NAME = "cachedir"; /** * The current version of Jython. * <p> * Usually updated by hand.<br> * Replaced by ant when doing a snapshot build. * <p> * This also applies for the <code>PY_*</code> integer values below */ public static String version = "2.2.1"; private static int PY_MAJOR_VERSION = 2; private static int PY_MINOR_VERSION = 2; private static int PY_MICRO_VERSION = 1; private static int PY_RELEASE_LEVEL = 0x0F; private static int PY_RELEASE_SERIAL = 0; public static int hexversion = ((PY_MAJOR_VERSION << 24) | (PY_MINOR_VERSION << 16) | (PY_MICRO_VERSION << 8) | (PY_RELEASE_LEVEL << 4) | (PY_RELEASE_SERIAL << 0)); public static PyTuple version_info; public static int maxunicode = 65535; /** * The copyright notice for this release. */ // TBD: should we use \u00a9 Unicode c-inside-circle? public static String copyright = "Copyright (c) 2000-2007, Jython Developers\n" + "All rights reserved.\n\n" + "Copyright (c) 2000 BeOpen.com.\n" + "All Rights Reserved.\n\n" + "Copyright (c) 2000 The Apache Software Foundation. All rights\n" + "reserved.\n\n" + "Copyright (c) 1995-2000 Corporation for National Research " + "Initiatives.\n" + "All Rights Reserved.\n\n" + "Copyright (c) 1991-1995 Stichting Mathematisch Centrum, " + "Amsterdam.\n" + "All Rights Reserved.\n\n"; /** * The arguments passed to this program on the command line. */ public PyList argv = new PyList(); /** * Exit a Python program with the given status. * * @param status the value to exit with * @exception Py.SystemExit always throws this exception. * When caught at top level the program will exit. */ public static void exit(PyObject status) { throw new PyException(Py.SystemExit, status); } /** * Exit a Python program with the status 0. */ public static void exit() { exit(Py.None); } public PyObject modules; public PyList path; public static PyObject builtins; public PyList meta_path; public PyList path_hooks; public PyObject path_importer_cache; public static String platform = "java"; public static String byteorder = "big"; public PyObject ps1 = new PyString(">>> "); public PyObject ps2 = new PyString("... "); public static int maxint = Integer.MAX_VALUE; public static int minint = Integer.MIN_VALUE; public PyObject executable = Py.None; public static PyList warnoptions; private ClassLoader classLoader = null; public ClassLoader getClassLoader() { return classLoader; } public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } public static PyTuple exc_info() { PyException exc = Py.getThreadState().exception; if (exc == null) return new PyTuple(new PyObject[] { Py.None, Py.None, Py.None }); return new PyTuple(new PyObject[] { exc.type, exc.value, exc.traceback }); } public static PyFrame _getframe() { return _getframe(-1); } public static PyFrame _getframe(int depth) { PyFrame f = Py.getFrame(); while (depth > 0 && f != null) { f = f.f_back; --depth; } if (f == null) throw Py.ValueError("call stack is not deep enough"); return f; } public PyObject stdout, stderr, stdin; public PyObject __stdout__, __stderr__, __stdin__; public PyObject __displayhook__, __excepthook__; public PyObject last_value = Py.None; public PyObject last_type = Py.None; public PyObject last_traceback = Py.None; // xxx fix this accessors public PyObject __findattr__(String name) { if (name == "exc_value") { PyException exc = Py.getThreadState().exception; if (exc == null) return null; return exc.value; } if (name == "exc_type") { PyException exc = Py.getThreadState().exception; if (exc == null) return null; return exc.type; } if (name == "exc_traceback") { PyException exc = Py.getThreadState().exception; if (exc == null) return null; return exc.traceback; } if (name == "warnoptions") { if (warnoptions == null) warnoptions = new PyList(); return warnoptions; } PyObject ret = super.__findattr__(name); if (ret != null) return ret; return __dict__.__finditem__(name); } public PyObject __dict__; public void __setattr__(String name, PyObject value) { PyType selftype = getType(); if (selftype == null) return; PyObject ret = selftype.lookup(name); // xxx fix fix fix if (ret != null) { ret.jtryset(this, value); return; } if (__dict__ == null) { __dict__ = new PyStringMap(); } __dict__.__setitem__(name, value); //throw Py.AttributeError(name); } public void __delattr__(String name) { if (__dict__ != null) { __dict__.__delitem__(name); return; } throw Py.AttributeError("del '" + name + "'"); } // xxx public void __rawdir__(PyDictionary accum) { accum.update(__dict__); } public String safeRepr() throws PyIgnoreMethodTag { return "module 'sys'"; } public String toString() { return "sys module"; } private int recursionlimit = 1000; public int getrecursionlimit() { return recursionlimit; } public void setrecursionlimit(int recursionlimit) { if (recursionlimit <= 0) { throw Py.ValueError("Recursion limit must be positive"); } this.recursionlimit = recursionlimit; } // xxx fix and polish this public PySystemState() { initialize(); modules = new PyStringMap(); argv = (PyList) defaultArgv.repeat(1); path = (PyList) defaultPath.repeat(1); path.append(Py.newString("__classpath__")); meta_path = new PyList(); meta_path.append(new PrecompiledImporter()); path_hooks = new PyList(); path_hooks.append(new JavaImporter()); path_hooks.append(PyJavaClass.lookup(ZipFileImporter.class)); path_importer_cache = new PyDictionary(); // Set up the initial standard ins and outs __stdout__ = stdout = new PyFile(System.out, "<stdout>"); __stderr__ = stderr = new PyFile(System.err, "<stderr>"); __stdin__ = stdin = new PyFile(getSystemIn(), "<stdin>"); __displayhook__ = new PySystemStateFunctions("displayhook", 10, 1, 1); __excepthook__ = new PySystemStateFunctions("excepthook", 30, 3, 3); // This isn't quite right... if (builtins == null) { builtins = new PyStringMap(); __builtin__.fillWithBuiltins(builtins); } PyModule __builtin__ = new PyModule("__builtin__", builtins); modules.__setitem__("__builtin__", __builtin__); if (getType() != null) { __dict__ = new PyStringMap(); __dict__.invoke("update", getType().getDict()); __dict__.__setitem__("displayhook", __displayhook__); __dict__.__setitem__("excepthook", __excepthook__); } } private static PyList defaultPath; private static PyList defaultArgv; public static Properties registry; // = init_registry(); public static String prefix; public static String exec_prefix = ""; private static String findRoot(Properties preProperties, Properties postProperties, String jarFileName) { String root = null; try { if (postProperties != null) root = postProperties.getProperty("python.home"); if (root == null) root = preProperties.getProperty("python.home"); if (root == null) root = preProperties.getProperty("install.root"); determinePlatform(preProperties); } catch (Exception exc) { return null; } // If install.root is undefined find JYTHON_JAR in class.path if (root == null) { String classpath = preProperties.getProperty("java.class.path"); if (classpath != null) { int jpy = classpath.toLowerCase().indexOf(JYTHON_JAR); if (jpy >= 0) { int start = classpath.lastIndexOf(java.io.File.pathSeparator, jpy) + 1; root = classpath.substring(start, jpy); } else { // in case JYTHON_JAR is referenced from a MANIFEST inside another jar on the classpath root = jarFileName; } } } return root; } public static void determinePlatform(Properties props) { String version = props.getProperty("java.version"); if (version == null) { version = "???"; } String lversion = version.toLowerCase(); if (lversion.startsWith("java")) { version = version.substring(4, version.length()); } if (lversion.startsWith("jdk") || lversion.startsWith("jre")) { version = version.substring(3, version.length()); } if (version.equals("12")) { version = "1.2"; } if (version != null) { platform = "java" + version; } } private static void initRegistry(Properties preProperties, Properties postProperties, boolean standalone, String jarFileName) { if (registry != null) { Py.writeError("systemState", "trying to reinitialize registry"); return; } registry = preProperties; prefix = exec_prefix = findRoot(preProperties, postProperties, jarFileName); // Load the default registry if (prefix != null) { if (prefix.length() == 0) { prefix = exec_prefix = "."; } try { addRegistryFile(new File(prefix, "registry")); File homeFile = new File(registry.getProperty("user.home"), ".jython"); addRegistryFile(homeFile); } catch (Exception exc) { } } if (postProperties != null) { for (Enumeration e = postProperties.keys(); e.hasMoreElements();) { String key = (String) e.nextElement(); String value = (String) postProperties.get(key); registry.put(key, value); } } if (standalone) { // set default standalone property (if not yet set) if (!registry.containsKey(PYTHON_CACHEDIR_SKIP)) { registry.put(PYTHON_CACHEDIR_SKIP, "true"); } } // Set up options from registry Options.setFromRegistry(); } private static void addRegistryFile(File file) { if (file.exists()) { if (!file.isDirectory()) { registry = new Properties(registry); try { FileInputStream fp = new FileInputStream(file); try { registry.load(fp); } finally { fp.close(); } } catch (IOException e) { System.err.println("couldn't open registry file: " + file.toString()); } } else { System.err.println("warning: " + file.toString() + " is a directory, not a file"); } } } private static boolean initialized = false; public static Properties getBaseProperties() { try { return System.getProperties(); } catch (AccessControlException ace) { return new Properties(); } } public static synchronized void initialize() { if (initialized) return; initialize(getBaseProperties(), null, new String[] { "" }); } public static synchronized void initialize(Properties preProperties, Properties postProperties, String[] argv) { initialize(preProperties, postProperties, argv, null); } public static synchronized void initialize(Properties preProperties, Properties postProperties, String[] argv, ClassLoader classLoader) { initialize(preProperties, postProperties, argv, classLoader, new ClassicPyObjectAdapter()); } public static synchronized void initialize(Properties preProperties, Properties postProperties, String[] argv, ClassLoader classLoader, ExtensiblePyObjectAdapter adapter) { //System.err.println("initializing system state"); //Thread.currentThread().dumpStack(); if (initialized) { //if (postProperties != null) { // Py.writeError("systemState", // "trying to reinitialize with new " + // "properties"); //} return; } initialized = true; Py.setAdapter(adapter); boolean standalone = false; String jarFileName = getJarFileName(); if (jarFileName != null) { standalone = isStandalone(jarFileName); } // initialize the Jython registry initRegistry(preProperties, postProperties, standalone, jarFileName); // other initializations initBuiltins(registry); initStaticFields(); // Initialize the path (and add system defaults) defaultPath = initPath(registry, standalone, jarFileName); defaultArgv = initArgv(argv); // Set up the known Java packages initPackages(registry); // Finish up standard Python initialization... Py.defaultSystemState = new PySystemState(); Py.setSystemState(Py.defaultSystemState); if (classLoader != null) Py.defaultSystemState.setClassLoader(classLoader); Py.initClassExceptions(PySystemState.builtins); // Make sure that Exception classes have been loaded new PySyntaxError("", 1, 1, "", ""); } private static void initStaticFields() { Py.None = new PyNone(); Py.NotImplemented = new PyNotImplemented(); Py.NoKeywords = new String[0]; Py.EmptyObjects = new PyObject[0]; Py.EmptyTuple = new PyTuple(Py.EmptyObjects); Py.NoConversion = new PySingleton("Error"); Py.Ellipsis = new PyEllipsis(); Py.Zero = new PyInteger(0); Py.One = new PyInteger(1); Py.EmptyString = new PyString(""); Py.Newline = new PyString("\n"); Py.Space = new PyString(" "); // Setup standard wrappers for stdout and stderr... Py.stderr = new StderrWrapper(); Py.stdout = new StdoutWrapper(); String s = null; if (PY_RELEASE_LEVEL == 0x0A) s = "alpha"; else if (PY_RELEASE_LEVEL == 0x0B) s = "beta"; else if (PY_RELEASE_LEVEL == 0x0C) s = "candidate"; else if (PY_RELEASE_LEVEL == 0x0F) s = "final"; else if (PY_RELEASE_LEVEL == 0xAA) s = "snapshot"; version_info = new PyTuple(new PyObject[] { Py.newInteger(PY_MAJOR_VERSION), Py.newInteger(PY_MINOR_VERSION), Py.newInteger(PY_MICRO_VERSION), Py.newString(s), Py.newInteger(PY_RELEASE_SERIAL) }); } public static PackageManager packageManager; public static File cachedir; public static boolean isPackageCacheEnabled() { return cachedir != null; } private static void initCacheDirectory(Properties props) { if (Py.frozen) { cachedir = null; return; } String skip = props.getProperty(PYTHON_CACHEDIR_SKIP, "false"); if (skip.equalsIgnoreCase("true")) { cachedir = null; return; } cachedir = new File(props.getProperty(PYTHON_CACHEDIR, CACHEDIR_DEFAULT_NAME)); if (!cachedir.isAbsolute()) { cachedir = new File(PySystemState.prefix, cachedir.getPath()); } } private static void initPackages(Properties props) { initCacheDirectory(props); File pkgdir; if (cachedir != null) { pkgdir = new File(cachedir, "packages"); } else { pkgdir = null; } packageManager = new SysPackageManager(pkgdir, props); } private static PyList initArgv(String[] args) { PyList argv = new PyList(); if (args != null) { for (int i = 0; i < args.length; i++) { argv.append(new PyString(args[i])); } } return argv; } private static Hashtable builtinNames; public static String[] builtin_module_names = null; private static void addBuiltin(String name) { String classname; String modname; int colon = name.indexOf(':'); if (colon != -1) { // name:fqclassname modname = name.substring(0, colon).trim(); classname = name.substring(colon + 1, name.length()).trim(); if (classname.equals("null")) // name:null, i.e. remove it classname = null; } else { modname = name.trim(); classname = "org.python.modules." + modname; } if (classname != null) builtinNames.put(modname, classname); else builtinNames.remove(modname); } private static void initBuiltins(Properties props) { builtinNames = new Hashtable(); // add builtins specified in the Setup.java file for (int i = 0; i < Setup.builtinModules.length; i++) addBuiltin(Setup.builtinModules[i]); // add builtins specified in the registry file String builtinprop = props.getProperty("python.modules.builtin", ""); StringTokenizer tok = new StringTokenizer(builtinprop, ","); while (tok.hasMoreTokens()) addBuiltin(tok.nextToken()); int n = builtinNames.size(); builtin_module_names = new String[n]; Enumeration keys = builtinNames.keys(); for (int i = 0; i < n; i++) builtin_module_names[i] = (String) keys.nextElement(); } static String getBuiltin(String name) { return (String) builtinNames.get(name); } private static PyList initPath(Properties props, boolean standalone, String jarFileName) { PyList path = new PyList(); if (!Py.frozen) { addPaths(path, props.getProperty("python.prepath", "")); if (prefix != null) { String libpath = new File(prefix, "Lib").toString(); path.append(new PyString(libpath)); } addPaths(path, props.getProperty("python.path", "")); } if (standalone) { // standalone jython: add the /Lib directory inside JYTHON_JAR to the path addPaths(path, jarFileName + "/Lib"); } return path; } /** * Check if we are in standalone mode. * * @param jarFileName The name of the jar file * * @return <code>true</code> if we have a standalone .jar file, <code>false</code> otherwise. */ private static boolean isStandalone(String jarFileName) { boolean standalone = false; if (jarFileName != null) { JarFile jarFile = null; try { jarFile = new JarFile(jarFileName); JarEntry jarEntry = jarFile.getJarEntry("Lib/javaos.py"); standalone = jarEntry != null; } catch (IOException ioe) { } finally { if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { } } } } return standalone; } /** * @return the full name of the jar file containing this class, <code>null</code> if not available. */ private static String getJarFileName() { String jarFileName = null; Class thisClass = PySystemState.class; String fullClassName = thisClass.getName(); String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1); URL url = thisClass.getResource(className + ".class"); // we expect an URL like jar:file:/install_dir/jython.jar!/org/python/core/PySystemState.class if (url != null) { try { String urlString = URLDecoder.decode(url.toString()); int jarSeparatorIndex = urlString.indexOf(JAR_SEPARATOR); if (urlString.startsWith(JAR_URL_PREFIX) && jarSeparatorIndex > 0) { jarFileName = urlString.substring(JAR_URL_PREFIX.length(), jarSeparatorIndex); } } catch (Exception e) { } } return jarFileName; } private static void addPaths(PyList path, String pypath) { StringTokenizer tok = new StringTokenizer(pypath, java.io.File.pathSeparator); while (tok.hasMoreTokens()) path.append(new PyString(tok.nextToken().trim())); } public static PyJavaPackage add_package(String n) { return add_package(n, null); } public static PyJavaPackage add_package(String n, String contents) { return packageManager.makeJavaPackage(n, contents, null); } /** * Add a classpath directory to the list of places that are searched * for java packages. * <p> * <b>Note</b>. Classes found in directory and subdirectory are not * made available to jython by this call. It only makes the java * package found in the directory available. This call is mostly * usefull if jython is embedded in an application that deals with * its own classloaders. A servlet container is a very good example. * Calling add_classdir("<context>/WEB-INF/classes") makes the java * packages in WEB-INF classes available to jython import. However the * actual classloading is completely handled by the servlet container's * context classloader. */ public static void add_classdir(String directoryPath) { packageManager.addDirectory(new File(directoryPath)); } /** * Add a .jar & .zip directory to the list of places that are searched * for java .jar and .zip files. The .jar and .zip files found will not * be cached. * <p> * <b>Note</b>. Classes in .jar and .zip files found in the directory * are not made available to jython by this call. See the note for * add_classdir(dir) for more details. * * @param directoryPath The name of a directory. * * @see #add_classdir */ public static void add_extdir(String directoryPath) { packageManager.addJarDir(directoryPath, false); } /** * Add a .jar & .zip directory to the list of places that are searched * for java .jar and .zip files. * <p> * <b>Note</b>. Classes in .jar and .zip files found in the directory * are not made available to jython by this call. See the note for * add_classdir(dir) for more details. * * @param directoryPath The name of a directory. * @param cache Controls if the packages in the zip and jar * file should be cached. * * @see #add_classdir */ public static void add_extdir(String directoryPath, boolean cache) { packageManager.addJarDir(directoryPath, cache); } public TraceFunction tracefunc = null; public TraceFunction profilefunc = null; public void settrace(PyObject tracefunc) { //InterpreterState interp = Py.getThreadState().interp; if (tracefunc == Py.None) { this.tracefunc = null; } else { this.tracefunc = new PythonTraceFunction(tracefunc); } } public void setprofile(PyObject profilefunc) { //InterpreterState interp = Py.getThreadState().interp; if (profilefunc == Py.None) { this.profilefunc = null; } else { this.profilefunc = new PythonTraceFunction(profilefunc); } } private InputStream getSystemIn() { if (Options.pollStandardIn) { return new PollingInputStream(System.in); } else { return System.in; } } public String getdefaultencoding() { return codecs.getDefaultEncoding(); } public void setdefaultencoding(String encoding) { codecs.setDefaultEncoding(encoding); } // Not public by design. We can't rebind the displayhook if // a reflected function is inserted in the class dict. static void displayhook(PyObject o) { /* Print value except if null or None */ /* After printing, also assign to '_' */ /* Before, set '_' to None to avoid recursion */ if (o == Py.None) return; PySystemState sys = Py.getThreadState().systemState; sys.builtins.__setitem__("_", Py.None); Py.stdout.println(o.__repr__()); sys.builtins.__setitem__("_", o); } static void excepthook(PyObject type, PyObject val, PyObject tb) { Py.displayException(type, val, tb, null); } public void callExitFunc() throws PyIgnoreMethodTag { PyObject exitfunc = __findattr__("exitfunc"); if (exitfunc != null) { try { exitfunc.__call__(); } catch (PyException exc) { if (!Py.matchException(exc, Py.SystemExit)) { Py.println(stderr, Py.newString("Error in sys.exitfunc:")); } Py.printException(exc); } } } } // This class is based on a suggestion from Yunho Jeon class PollingInputStream extends FilterInputStream { public PollingInputStream(InputStream s) { super(s); } private void waitForBytes() throws IOException { try { while (available() == 0) { //System.err.println("waiting..."); Thread.sleep(100); } } catch (InterruptedException e) { throw new PyException(Py.KeyboardInterrupt, "interrupt waiting on <stdin>"); } } public int read() throws IOException { waitForBytes(); return super.read(); } public int read(byte b[], int off, int len) throws IOException { waitForBytes(); return super.read(b, off, len); } } class PySystemStateFunctions extends PyBuiltinFunctionSet { PySystemStateFunctions(String name, int index, int minargs, int maxargs) { super(name, index, minargs, maxargs); } public PyObject __call__(PyObject arg) { switch (index) { case 10: PySystemState.displayhook(arg); return Py.None; default: throw info.unexpectedCall(1, false); } } public PyObject __call__(PyObject arg1, PyObject arg2, PyObject arg3) { switch (index) { case 30: PySystemState.excepthook(arg1, arg2, arg3); return Py.None; default: throw info.unexpectedCall(3, false); } } }