org.python.core.PySystemState Maven / Gradle / Ivy
Show all versions of jython-slim Show documentation
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import static org.python.core.RegistryKey.PYTHON_CACHEDIR;
import static org.python.core.RegistryKey.PYTHON_CACHEDIR_SKIP;
import static org.python.core.RegistryKey.PYTHON_CONSOLE;
import static org.python.core.RegistryKey.PYTHON_CONSOLE_ENCODING;
import static org.python.core.RegistryKey.PYTHON_IO_ENCODING;
import static org.python.core.RegistryKey.PYTHON_IO_ERRORS;
import static org.python.core.RegistryKey.PYTHON_MODULES_BUILTIN;
import static org.python.core.RegistryKey.PYTHON_PATH;
import static org.python.core.RegistryKey.USER_HOME;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.python.Version;
import org.python.core.adapter.ClassicPyObjectAdapter;
import org.python.core.adapter.ExtensiblePyObjectAdapter;
import org.python.core.packagecache.PackageManager;
import org.python.core.packagecache.SysPackageManager;
import org.python.expose.ExposedGet;
import org.python.expose.ExposedType;
import org.python.modules.Setup;
import org.python.util.Generic;
import com.carrotsearch.sizeof.RamUsageEstimator;
import jnr.posix.util.Platform;
/**
* The "sys" module.
*/
// xxx Many have lamented, this should really be a module!
// but it will require some refactoring to see this wish come true.
public class PySystemState extends PyObject
implements AutoCloseable, ClassDictInit, Closeable, Traverseproc {
private static final Logger logger = Logger.getLogger("org.python.core");
private static final String CACHEDIR_DEFAULT_NAME = ".jython_cache";
public static final String JYTHON_JAR = "jython.jar";
public static final String JYTHON_DEV_JAR = "jython-dev.jar";
public static final PyString version = new PyString(Version.getVersion());
public static final PyTuple subversion =
new PyTuple(new PyString("Jython"), Py.EmptyString, Py.EmptyString);
public static final int hexversion = ((Version.PY_MAJOR_VERSION << 24)
| (Version.PY_MINOR_VERSION << 16) | (Version.PY_MICRO_VERSION << 8)
| (Version.PY_RELEASE_LEVEL << 4) | (Version.PY_RELEASE_SERIAL << 0));
public static final PyVersionInfo version_info = getVersionInfo();
public static final int maxunicode = 1114111;
// XXX: we should someday make this Long.MAX_VALUE, but see test_index.py
// for tests that would need to pass but today would not.
public final static int maxsize = Integer.MAX_VALUE;
public final static PyString float_repr_style = Py.newString("short");
/** Nominal Jython file system encoding (as sys.getfilesystemencoding()
) */
static final PyString FILE_SYSTEM_ENCODING = Py.newString("utf-8");
public static boolean py3kwarning = false;
public final static Class flags = Options.class;
public final static PyTuple _git = new PyTuple(Py.newString("Jython"),
Py.newString(Version.getGitIdentifier()), Py.newString(Version.getGitVersion()));
/** The copyright notice for this release. */
public static final PyObject copyright =
Py.newString("Copyright (c) 2000-2017 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.\n"
+ "All rights 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.");
private static Map builtinNames;
public static PyTuple builtin_module_names = null;
public static PackageManager packageManager;
private static File cachedir;
private static PyList defaultPath; // list of bytes or unicode
private static PyList defaultArgv; // list of bytes or unicode
private static PyObject defaultExecutable; // bytes or unicode or None
public static Properties registry; // = init_registry();
/**
* A string giving the site-specific directory prefix where the platform independent Python
* files are installed; by default, this is based on the property python.home
or
* the location of the Jython JAR. The main collection of Python library modules is installed in
* the directory prefix/Lib
. This object should contain bytes in the file system
* encoding for consistency with use in the standard library (see sysconfig.py
).
*/
public static PyObject prefix;
/**
* A string giving the site-specific directory prefix where the platform-dependent Python files
* are installed; by default, this is the same as {@link #exec_prefix}. This object should
* contain bytes in the file system encoding for consistency with use in the standard library
* (see sysconfig.py
).
*/
public static PyObject exec_prefix;
public static final PyString byteorder = new PyString("big");
public static final int maxint = Integer.MAX_VALUE;
public static final int minint = Integer.MIN_VALUE;
private static boolean initialized = false;
/** The arguments passed to this program on the command line. */
public PyList argv = new PyList();
public PyObject modules;
public Map modules_reloading;
private ReentrantLock importLock;
private ClassLoader syspathJavaLoader;
public PyList path;
public PyList warnoptions = new PyList();
public PyObject builtins;
private static PyObject defaultPlatform = new PyShadowString("java", getNativePlatform());
public PyObject platform = defaultPlatform;
public PyList meta_path;
public PyList path_hooks;
public PyObject path_importer_cache;
// Only defined if interactive, see https://docs.python.org/2/library/sys.html#sys.ps1
public PyObject ps1 = PyAttributeDeleted.INSTANCE;
public PyObject ps2 = PyAttributeDeleted.INSTANCE;
public PyObject executable;
private String currentWorkingDir;
private ClassLoader classLoader = null;
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;
public PyObject __name__ = new PyString("sys");
public PyObject __dict__;
private int recursionlimit = 1000;
private int checkinterval = 100;
private volatile codecs.CodecState codecState;
/** Whether bytecode should be written to disk on import. */
public boolean dont_write_bytecode = false;
// Automatically close resources associated with a PySystemState when they get GCed
private final PySystemStateCloser closer;
private static final ReferenceQueue systemStateQueue =
new ReferenceQueue();
private static final ConcurrentMap, PySystemStateCloser> sysClosers =
Generic.concurrentMap();
// float_info
public static final PyObject float_info = FloatInfo.getInfo();
// long_info
public static final PyObject long_info = LongInfo.getInfo();
public PySystemState() {
initialize();
closer = new PySystemStateCloser(this);
modules = new PyStringMap();
modules_reloading = new HashMap();
importLock = new ReentrantLock();
syspathJavaLoader = new SyspathJavaLoader(imp.getParentClassLoader());
argv = (PyList) defaultArgv.repeat(1);
path = (PyList) defaultPath.repeat(1);
path.append(Py.newString(JavaImporter.JAVA_IMPORT_PATH_ENTRY));
path.append(Py.newString(ClasspathPyImporter.PYCLASSPATH_PREFIX));
executable = defaultExecutable;
builtins = getDefaultBuiltins();
platform = defaultPlatform;
meta_path = new PyList();
path_hooks = new PyList();
path_hooks.append(new JavaImporter());
path_hooks.append(org.python.modules.zipimport.zipimporter.TYPE);
path_hooks.append(ClasspathPyImporter.TYPE);
path_importer_cache = new PyDictionary();
currentWorkingDir = new File("").getAbsolutePath();
dont_write_bytecode = Options.dont_write_bytecode;
py3kwarning = Options.py3k_warning; // XXX why here if static?
// Set up the initial standard ins and outs
String mode = Options.unbuffered ? "b" : "";
int buffering = Options.unbuffered ? 0 : 1;
stdin = __stdin__ = new PyFile(System.in, "", "r" + mode, buffering, false);
stdout = __stdout__ = new PyFile(System.out, "", "w" + mode, buffering, false);
stderr = __stderr__ = new PyFile(System.err, "", "w" + mode, 0, false);
initEncoding();
__displayhook__ = new PySystemStateFunctions("displayhook", 10, 1, 1);
__excepthook__ = new PySystemStateFunctions("excepthook", 30, 3, 3);
if (builtins == null) {
builtins = getDefaultBuiltins();
}
modules.__setitem__("__builtin__", new PyModule("__builtin__", getDefaultBuiltins()));
__dict__ = new PyStringMap();
__dict__.invoke("update", getType().fastGetDict());
__dict__.__setitem__("displayhook", __displayhook__);
__dict__.__setitem__("excepthook", __excepthook__);
logger.config("sys module instance created");
}
public static void classDictInit(PyObject dict) {
// XXX: Remove bean accessors for settrace/profile that we don't want
dict.__setitem__("trace", null);
dict.__setitem__("profile", null);
dict.__setitem__("windowsversion", null);
if (!System.getProperty("os.name").startsWith("Windows")) {
dict.__setitem__("getwindowsversion", null);
}
}
void reload() throws PyIgnoreMethodTag {
__dict__.invoke("update", getType().fastGetDict());
}
private static void checkReadOnly(String name) {
switch (name) {
case "__dict__":
case "__class__":
case "registry":
case "exec_prefix":
case "packageManager":
throw Py.TypeError("readonly attribute");
default:
// pass
}
}
private static void checkMustExist(String name) {
switch (name) {
case "__dict__":
case "__class__":
case "registry":
case "exec_prefix":
case "platform":
case "packageManager":
case "builtins":
case "warnoptions":
throw Py.TypeError("readonly attribute");
default:
// pass
}
}
/**
* Initialise the encoding of sys.stdin
, sys.stdout
, and
* sys.stderr
, and their error handling policy, from registry variables. Under the
* console app util.jython, values reflect PYTHONIOENCODING if not overridden. Note that the
* encoding must name a Python codec, as in codecs.encode()
.
*/
private void initEncoding() {
// Two registry variables, counterparts to PYTHONIOENCODING = [encoding][:errors]
String encoding = registry.getProperty(PYTHON_IO_ENCODING);
String errors = registry.getProperty(PYTHON_IO_ERRORS);
if (encoding == null) {
// We still don't have an explicit selection for this: match the console.
encoding = Py.getConsole().getEncoding();
}
((PyFile) stdin).setEncoding(encoding, errors);
((PyFile) stdout).setEncoding(encoding, errors);
((PyFile) stderr).setEncoding(encoding, "backslashreplace");
}
@Deprecated
public void shadow() {
// Now a no-op
}
private static class DefaultBuiltinsHolder {
static final PyObject builtins = fillin();
static PyObject fillin() {
PyObject temp = new PyStringMap();
__builtin__.fillWithBuiltins(temp);
return temp;
}
}
public static PyObject getDefaultBuiltins() {
return DefaultBuiltinsHolder.builtins;
}
public PyObject getBuiltins() {
return builtins;
}
public void setBuiltins(PyObject value) {
builtins = value;
modules.__setitem__("__builtin__", new PyModule("__builtin__", value));
}
public PyObject getWarnoptions() {
return warnoptions;
}
public void setWarnoptions(PyObject value) {
warnoptions = new PyList(value);
}
public PyObject getPlatform() {
return platform;
}
public void setPlatform(PyObject value) {
platform = value;
}
public WinVersion getwindowsversion() {
return WinVersion.getWinVersion();
}
public codecs.CodecState getCodecState() {
if (codecState == null) {
importLock.lock();
try {
if (codecState == null) {
codecState = new codecs.CodecState();
// we have the importLock locked
imp.load("encodings");
}
} catch (PyException exc) {
if (exc.type != Py.ImportError) {
throw exc;
}
} finally {
importLock.unlock();
}
}
return codecState;
}
public ReentrantLock getImportLock() {
return importLock;
}
public ClassLoader getSyspathJavaLoader() {
return syspathJavaLoader;
}
// xxx fix this accessors
@Override
public PyObject __findattr_ex__(String name) {
if (name == "exc_value") {
PyException exc = Py.getThreadState().exception;
if (exc == null) {
return null;
}
return exc.value;
} else if (name == "exc_type") {
PyException exc = Py.getThreadState().exception;
if (exc == null) {
return null;
}
return exc.type;
} else if (name == "exc_traceback") {
PyException exc = Py.getThreadState().exception;
if (exc == null) {
return null;
}
return exc.traceback;
} else {
PyObject ret = super.__findattr_ex__(name);
if (ret != null) {
if (ret instanceof PyMethod) {
if (__dict__.__finditem__(name) instanceof PyReflectedFunction) {
return ret; // xxx depends on nonstandard __dict__
}
} else if (ret == PyAttributeDeleted.INSTANCE) {
return null;
} else {
return ret;
}
}
return __dict__.__finditem__(name);
}
}
@Override
public void __setattr__(String name, PyObject value) {
checkReadOnly(name);
if ("builtins".equals(name)) {
setBuiltins(value);
} else {
PyObject ret = getType().lookup(name); // xxx fix fix fix
if (ret != null && ret._doset(this, value)) {
return;
}
__dict__.__setitem__(name, value);
}
}
@Override
public void __delattr__(String name) {
checkMustExist(name);
PyObject ret = getType().lookup(name); // xxx fix fix fix
if (ret != null) {
ret._doset(this, PyAttributeDeleted.INSTANCE);
}
try {
__dict__.__delitem__(name);
} catch (PyException pye) { // KeyError
if (ret == null) {
throw Py.AttributeError(name);
}
}
}
// xxx
@Override
public void __rawdir__(PyDictionary accum) {
accum.update(__dict__);
}
@Override
public String toString() {
return "";
}
public int getrecursionlimit() {
return recursionlimit;
}
@SuppressWarnings("unused")
public long getsizeof(Object obj, long defaultVal) {
return getsizeof(obj);
}
public long getsizeof(Object obj) {
return RamUsageEstimator.shallowSizeOf(obj);
}
public void setrecursionlimit(int recursionlimit) {
if (recursionlimit <= 0) {
throw Py.ValueError("Recursion limit must be positive");
}
this.recursionlimit = recursionlimit;
}
public PyObject gettrace() {
ThreadState ts = Py.getThreadState();
if (ts.tracefunc == null) {
return Py.None;
} else {
return ((PythonTraceFunction) ts.tracefunc).tracefunc;
}
}
public void settrace(PyObject tracefunc) {
ThreadState ts = Py.getThreadState();
if (tracefunc == Py.None) {
ts.tracefunc = null;
} else {
ts.tracefunc = new PythonTraceFunction(tracefunc);
}
}
public PyObject getprofile() {
ThreadState ts = Py.getThreadState();
if (ts.profilefunc == null) {
return Py.None;
} else {
return ((PythonTraceFunction) ts.profilefunc).tracefunc;
}
}
public void setprofile(PyObject profilefunc) {
ThreadState ts = Py.getThreadState();
if (profilefunc == Py.None) {
ts.profilefunc = null;
} else {
ts.profilefunc = new PythonTraceFunction(profilefunc);
}
}
public PyString getdefaultencoding() {
return new PyString(codecs.getDefaultEncoding());
}
public void setdefaultencoding(String encoding) {
codecs.setDefaultEncoding(encoding);
}
public PyObject getfilesystemencoding() {
return FILE_SYSTEM_ENCODING;
}
/* get and setcheckinterval really do nothing, but it helps when some code tries to use these */
public PyInteger getcheckinterval() {
return new PyInteger(checkinterval);
}
public void setcheckinterval(int interval) {
checkinterval = interval;
}
/**
* Change the current working directory to the specified path.
*
* path is assumed to be absolute and canonical (via os.path.realpath).
*
* @param path a path String
*/
public void setCurrentWorkingDir(String path) {
currentWorkingDir = path;
}
/**
* Return a string representing the current working directory.
*
* @return a path String
*/
public String getCurrentWorkingDir() {
return currentWorkingDir;
}
/**
* Resolve a path. Returns the full path taking the current working directory into account.
*
* @param path a path String
* @return a resolved path String
*/
public String getPath(String path) {
return getPath(this, path);
}
/**
* Resolve a path. Returns the full path taking the current working directory into account.
*
* Like getPath but called statically. The current PySystemState is only consulted for the
* current working directory when it's necessary (when the path is relative).
*
* @param path a path String
* @return a resolved path String
*/
public static String getPathLazy(String path) {
// XXX: This method likely an unnecessary optimization
return getPath(null, path);
}
private static String getPath(PySystemState sys, String path) {
if (path != null) {
path = getFile(sys, path).getAbsolutePath();
}
return path;
}
/**
* Resolve a path, returning a {@link File}, taking the current working directory into account.
*
* @param path a path String
* @return a resolved File
*/
public File getFile(String path) {
return getFile(this, path);
}
/**
* Resolve a path, returning a {@link File}, taking the current working directory of the
* specified PySystemState
into account. Use of a static
here is a
* trick to avoid getting the current state if the path is absolute. (Noted that this may be
* needless optimisation.)
*
* @param sys a PySystemState
or null meaning the current one
* @param path a path String
* @return a resolved File
*/
private static File getFile(PySystemState sys, String path) {
File file = new File(path);
if (!file.isAbsolute()) {
// path meaning depends on the current working directory
if (sys == null) {
sys = Py.getSystemState();
}
String cwd = sys.getCurrentWorkingDir();
if (Platform.IS_WINDOWS) {
// Form absolute reference (with mysterious Windows semantics)
file = getWindowsFile(cwd, path);
} else {
// Form absolute reference (with single slash)
file = new File(cwd, path);
}
}
return file;
}
/**
* Resolve a relative path against the supplied current working directory or Windows environment
* working directory for any drive specified in the path. and return a file object. Essentially
* equivalent to os.path.join, but the work is done by {@link File}. The intention is that
* calling {@link File#getAbsolutePath()} should return the corresponding absolute path.
*
* Note: in the context where we use this method, path
is already known not to be
* absolute, and cwd
is assumed to be absolute.
*
* @param cwd current working directory (of some {@link PySystemState})
* @param path to resolve
* @return specifier of the intended file
*/
private static File getWindowsFile(String cwd, String path) {
// Assumptions: cwd is absolute and path is not absolute
// Start by getting the slashes the right (wrong) way round.
if (path.indexOf('/') >= 0) {
path = path.replace('/', '\\');
}
// Does path start with a drive letter?
char d = driveLetter(path);
if (d != 0) {
if (d == driveLetter(cwd)) {
/*
* path specifies the same drive letter as in the cwd of this PySystemState. Let
* File interpret the rest of the path relative to cwd as parent.
*/
return new File(cwd, path.substring(2));
} else {
// Let File resolve the specified drive against the process environment.
return new File(path);
}
} else if (path.startsWith("\\")) {
// path replaces the file part of the cwd. (Method assumes path is not UNC.)
if (driveLetter(cwd) != 0) {
// cwd has a drive letter
return new File(cwd.substring(0, 2), path);
} else {
// cwd has no drive letter, so should be a UNC path \\host\share\directory\etc
return new File(uncShare(cwd), path);
}
} else {
// path is relative to the cwd of this PySystemState.
return new File(cwd, path);
}
}
/**
* Return the Windows drive letter from the start of the path, upper case, or 0 if the path does
* not start X: where X is a letter.
*
* @param path to examine
* @return drive letter or char 0 if no drive letter
*/
private static char driveLetter(String path) {
if (path.length() >= 2 && path.charAt(1) == ':') {
// Looks like both strings start with a drive letter
char pathDrive = path.charAt(0);
if (Character.isLetter(pathDrive)) {
return Character.toUpperCase(pathDrive);
}
}
return (char) 0;
}
/**
* Return the Windows UNC share name from the start of the path, or null
if the
* path is not of Windows UNC type. The path has to be formed with Windows-backslashes: slashes
* '/' are not accepted as a substitute here.
*
* @param path to examine
* @return share name or null
*/
private static String uncShare(String path) {
int n = path.length();
// Has to accommodate at least \\A (3 chars)
if (n >= 5 && path.startsWith("\\\\")) {
// Look for the separator backslash A\B
int p = path.indexOf('\\', 2);
// Has to be at least index 3 (path begins \\A) and 2 more characters left \B
if (p >= 3 && n > p + 2) {
// Look for directory backslash that ends the share name
int dir = path.indexOf('\\', p + 1);
if (dir < 0) {
// path has the form \\A\B (is just the share name)
return path;
} else if (dir > p + 1) {
// path has the form \\A\B\C
return path.substring(0, dir);
}
}
}
return null;
}
public void callExitFunc() throws PyIgnoreMethodTag {
PyObject exitfunc = __findattr__("exitfunc");
if (exitfunc != null) {
try {
exitfunc.__call__();
} catch (PyException exc) {
if (!exc.match(Py.SystemExit)) {
Py.println(stderr, Py.newString("Error in sys.exitfunc:"));
}
Py.printException(exc);
}
}
Py.flushLine();
}
public ClassLoader getClassLoader() {
return classLoader;
}
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Work out the root directory of the installation of Jython. Sources for this information are
* quite diverse. {@code python.home} will take precedence if set in either
* {@code postProperties} or {@code preProperties}, {@code install.root} in
* {@code preProperties}, in that order. After this, we search the class path for a JAR, or
* nagigate from the JAR deduced by from the class path, or finally {@code jarFileName}.
*
* We also set by side-effect: {@link #defaultPlatform} from {@code java.version}.
*/
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 || root.equals("")) {
String classpath = preProperties.getProperty("java.class.path");
if (classpath != null) {
String lowerCaseClasspath = classpath.toLowerCase();
int jarIndex = lowerCaseClasspath.indexOf(JYTHON_JAR);
if (jarIndex < 0) {
jarIndex = lowerCaseClasspath.indexOf(JYTHON_DEV_JAR);
}
if (jarIndex >= 0) {
int start = classpath.lastIndexOf(File.pathSeparator, jarIndex) + 1;
root = classpath.substring(start, jarIndex);
} else if (jarFileName != null) {
// in case JYTHON_JAR is referenced from a MANIFEST inside another jar on the
// classpath
root = new File(jarFileName).getParent();
}
}
}
if (root == null) {
return null;
}
File rootFile = new File(root);
try {
return rootFile.getCanonicalPath();
} catch (IOException ioe) {
return rootFile.getAbsolutePath();
}
}
/** Set {@link #defaultPlatform} by examination of the {@code java.version} JVM property. */
private 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";
}
defaultPlatform = new PyShadowString("java" + version, getNativePlatform());
}
/**
* Emulates CPython's way to name sys.platform. Works according to this table:
*
*
* Platform names
*
* System
* Value
*
*
* Linux (2.x and 3.x)
* linux2
*
*
* Windows
* win32
*
*
* Windows/Cygwin
* cygwin
*
*
* Mac OS X
* darwin
*
*
* OS/2
* os2
*
*
* OS/2 EMX
* os2emx
*
*
* RiscOS
* riscos
*
*
* AtheOS
* atheos
*
*
*
*/
public static String getNativePlatform() {
String osname = System.getProperty("os.name");
if (osname.equals("Linux")) {
return "linux2";
} else if (osname.equals("Mac OS X")) {
return "darwin";
} else if (osname.toLowerCase().contains("cygwin")) {
return "cygwin";
} else if (osname.startsWith("Windows")) {
return "win32";
} else {
return osname.replaceAll("[\\s/]", "").toLowerCase();
}
}
/**
* Install the first argument as the application-wide {@link #registry} (a
* {@code java.util.Properties} object), merge values from system and local (or user) properties
* files, and finally allow values from {@code postProperties} to override. Usually the first
* argument is the {@code System.getProperties()}, if were allowed to access it, and therefore
* represents definitions made on the command-line. The net precedence order is:
*
* Precedence order of registry sources
*
* Source
* Filled by
*
*
* postProperties
* Custom {@link JythonInitializer}
*
*
* preProperties
* Command-line definitions {@code -Dkey=value})
*
*
* ... preProperties also contains ...
* Environment variables via {@link org.python.util.jython}
*
*
* [user.home]/.jython
* User-specific registry file
*
*
* [python.home]/registry
* Installation-wide registry file
*
*
* Environmental inference
* e.g. {@code locale} command for console encoding
*
*
*
* We call {@link Options#setFromRegistry()} to translate certain final values to
* application-wide controls. By side-effect, set {@link #prefix} and {@link #exec_prefix} from
* {@link #findRoot(Properties, Properties, String)}. If it has not been set otherwise, a
* default value for python.console.encoding is derived from the OS environment, via
* {@link #getConsoleEncoding(Properties)}.
*
* @param preProperties initial registry
* @param postProperties overriding values
* @param standalone default {@code python.cachedir.skip} to true (if not otherwise defined)
* @param jarFileName as a clue to the location of the installation
*/
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;
// Work out sys.prefix
String prefix = findRoot(preProperties, postProperties, jarFileName);
if (prefix == null || prefix.length() == 0) {
/*
* All strategies in find_root failed (can happen in embedded use), but sys.prefix is
* generally assumed not to be null (or even None). Go for current directory.
*/
prefix = ".";
logger.config("No property 'jython.home' or other clue. sys.prefix defaulting to ''.");
}
// sys.exec_prefix is the same initially
String exec_prefix = prefix;
// Load the default registry
try {
// user registry has precedence over installed registry
File homeFile = new File(registry.getProperty(USER_HOME), ".jython");
addRegistryFile(homeFile);
addRegistryFile(new File(prefix, "registry"));
} catch (Exception exc) {
// Continue: addRegistryFile does its own logging.
}
// Exposed values have to be properly-encoded objects
PySystemState.prefix = Py.fileSystemEncode(prefix);
PySystemState.exec_prefix = Py.fileSystemEncode(exec_prefix);
// Now the post properties (possibly set by custom JythonInitializer).
registry.putAll(postProperties);
if (standalone) {
// set default standalone property (if not yet set)
if (!registry.containsKey(PYTHON_CACHEDIR_SKIP)) {
registry.put(PYTHON_CACHEDIR_SKIP, "true");
}
}
/*
* The console encoding is the one used by line-editing consoles to decode on the OS side
* and encode on the Python side. It must be a Java codec name, so any relationship to
* python.io.encoding is dubious.
*/
if (!registry.containsKey(PYTHON_CONSOLE_ENCODING)) {
registry.put(PYTHON_CONSOLE_ENCODING, getConsoleEncoding(registry));
}
// Set up options from registry
Options.setFromRegistry();
}
/**
* Try to determine the console encoding from the platform, if necessary using a sub-process to
* enquire. If everything fails, assume UTF-8.
*
* @param props in which to look for clues (normally the Jython registry)
* @return the console encoding (and never {@code null})
*/
private static String getConsoleEncoding(Properties props) {
// From Java 8 onwards, the answer may already be to hand in the registry:
String encoding = props.getProperty("sun.stdout.encoding");
String os = props.getProperty("os.name");
if (encoding != null) {
return encoding;
} else if (os != null && os.startsWith("Windows")) {
// Go via the Windows code page built-in command "chcp".
String output = Py.getCommandResultWindows("chcp");
/*
* The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or
* "활성 코드 페이지: 949". Assume the first number with 2 or more digits is the code page.
*/
final Pattern DIGITS_PATTERN = Pattern.compile("[1-9]\\d+");
Matcher matcher = DIGITS_PATTERN.matcher(output);
if (matcher.find()) {
return "cp".concat(output.substring(matcher.start(), matcher.end()));
}
} else {
// Try a Unix-like "locale charmap".
String output = Py.getCommandResult("locale", "charmap");
// The result of "locale charmap" is just the charmap name ~ Charset or codec name.
if (output.length() > 0) {
return output;
}
}
// If we land here it is because we found no answer, and we will assume UTF-8.
return "utf-8";
}
/**
* Merge the contents of a property file into the registry, but existing entries with the same
* key take precedence.
*
* @param file
*/
private static void addRegistryFile(File file) {
if (file.exists()) {
if (!file.isDirectory()) {
// pre (e.g. system) properties should override the registry,
// therefore only add missing properties from this registry file
Properties fileProperties = new Properties();
try {
FileInputStream fp = new FileInputStream(file);
try {
fileProperties.load(fp);
for (Entry kv : fileProperties.entrySet()) {
Object key = kv.getKey();
if (!registry.containsKey(key)) {
registry.put(key, kv.getValue());
}
}
} 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");
}
}
}
public static Properties getBaseProperties() {
// Moved to PrePy since does not depend on PyObject). Retain in 2.7.x for compatibility.
return PrePy.getSystemProperties();
}
public static synchronized void initialize() {
initialize(null, null);
}
public static synchronized void initialize(Properties preProperties,
Properties postProperties) {
initialize(preProperties, postProperties, 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) {
if (initialized) {
return;
}
if (preProperties == null) {
preProperties = PrePy.getSystemProperties();
}
if (postProperties == null) {
postProperties = new Properties();
}
try {
ClassLoader context = Thread.currentThread().getContextClassLoader();
if (context != null) {
if (initialize(preProperties, postProperties, argv, classLoader, adapter,
context)) {
return;
}
} else {
Py.writeDebug("initializer", "Context class loader null, skipping");
}
ClassLoader sysStateLoader = PySystemState.class.getClassLoader();
if (sysStateLoader != null) {
if (initialize(preProperties, postProperties, argv, classLoader, adapter,
sysStateLoader)) {
return;
}
} else {
Py.writeDebug("initializer", "PySystemState.class class loader null, skipping");
}
} catch (UnsupportedCharsetException e) {
Py.writeWarning("initializer",
"Unable to load the UTF-8 charset to read an initializer definition");
e.printStackTrace(System.err);
} catch (SecurityException e) {
// Must be running in a security environment that doesn't allow access to the class
// loader
} catch (Exception e) {
Py.writeWarning("initializer",
"Unexpected exception thrown while trying to use initializer service");
e.printStackTrace(System.err);
}
doInitialize(preProperties, postProperties, argv, classLoader, adapter);
}
private static final String INITIALIZER_SERVICE =
"META-INF/services/org.python.core.JythonInitializer";
/**
* Attempts to read a SystemStateInitializer service from the given class loader, instantiate
* it, and initialize with it.
*
* @throws UnsupportedCharsetException if unable to load UTF-8 to read a service definition
* @return true if a service is found and successfully initializes.
*/
private static boolean initialize(Properties pre, Properties post, String[] argv,
ClassLoader sysClassLoader, ExtensiblePyObjectAdapter adapter,
ClassLoader initializerClassLoader) {
InputStream in = initializerClassLoader.getResourceAsStream(INITIALIZER_SERVICE);
if (in == null) {
Py.writeDebug("initializer",
"'" + INITIALIZER_SERVICE + "' not found on " + initializerClassLoader);
return false;
}
BufferedReader r = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")));
String className;
try {
className = r.readLine();
} catch (IOException e) {
Py.writeWarning("initializer",
"Failed reading '" + INITIALIZER_SERVICE + "' from " + initializerClassLoader);
e.printStackTrace(System.err);
return false;
}
Class> initializer;
try {
initializer = initializerClassLoader.loadClass(className);
} catch (ClassNotFoundException e) {
Py.writeWarning("initializer",
"Specified initializer class '" + className + "' not found, continuing");
return false;
}
try {
((JythonInitializer) initializer.getDeclaredConstructor().newInstance()).initialize(pre,
post, argv, sysClassLoader, adapter);
} catch (Exception e) {
Py.writeWarning("initializer",
"Failed initializing with class '" + className + "', continuing");
e.printStackTrace(System.err);
return false;
}
if (!initialized) {
Py.writeWarning("initializer", "Initializer '" + className
+ "' failed to call doInitialize, using default initialization");
}
return initialized;
}
public static synchronized PySystemState doInitialize(Properties preProperties,
Properties postProperties, String[] argv, ClassLoader classLoader,
ExtensiblePyObjectAdapter adapter) {
if (initialized) {
return Py.defaultSystemState;
}
initialized = true;
Py.setAdapter(adapter);
boolean standalone = false;
String jarFileName = Py.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);
defaultExecutable = initExecutable(registry);
// Set up the known Java packages
initPackages(registry);
// Condition the console
initConsole(registry);
/*
* Create the first interpreter (which is also the first instance of the sys module) and
* cache it as the default state.
*/
Py.defaultSystemState = new PySystemState();
Py.setSystemState(Py.defaultSystemState);
if (classLoader != null) {
Py.defaultSystemState.setClassLoader(classLoader);
}
Py.initClassExceptions(getDefaultBuiltins());
// Make sure that Exception classes have been loaded
new PySyntaxError("", 1, 1, "", "");
// Cause sys to export the console handler that was installed
Py.defaultSystemState.__setattr__("_jy_console", Py.java2py(Py.getConsole()));
return Py.defaultSystemState;
}
private static PyVersionInfo getVersionInfo() {
String s;
if (Version.PY_RELEASE_LEVEL == 0x0A) {
s = "alpha";
} else if (Version.PY_RELEASE_LEVEL == 0x0B) {
s = "beta";
} else if (Version.PY_RELEASE_LEVEL == 0x0C) {
s = "candidate";
} else if (Version.PY_RELEASE_LEVEL == 0x0F) {
s = "final";
} else {
throw new RuntimeException(
"Illegal value for PY_RELEASE_LEVEL: " + Version.PY_RELEASE_LEVEL);
}
return new PyVersionInfo(//
Py.newInteger(Version.PY_MAJOR_VERSION), //
Py.newInteger(Version.PY_MINOR_VERSION), //
Py.newInteger(Version.PY_MICRO_VERSION), //
Py.newString(s), //
Py.newInteger(Version.PY_RELEASE_SERIAL));
}
public static boolean isPackageCacheEnabled() {
return cachedir != null;
}
private static void initCacheDirectory(Properties props) {
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()) {
String prefixString = props.getProperty("user.dir", "");
cachedir = new File(prefixString, cachedir.getPath());
cachedir = cachedir.getAbsoluteFile();
}
logger.log(Level.CONFIG, "cache at {0}", cachedir);
}
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 (String arg : args) {
// For consistency with CPython and the standard library, sys.argv is FS-encoded.
argv.append(Py.fileSystemEncode(arg));
}
}
return argv;
}
/**
* Determine the default sys.executable value from the registry. If registry is not set (as in
* standalone jython jar), we will use sys.prefix + /bin/jython(.exe) and the file may not
* exist. Users can create a wrapper in it's place to make it work in embedded environments.
* Only if sys.prefix is null, returns Py.None
*
* @param props a Properties registry
* @return a PyObject path string or Py.None
*/
private static PyObject initExecutable(Properties props) {
String executable = props.getProperty("python.executable");
File executableFile;
if (executable != null) {
// The executable from the registry is a Unicode String path
executableFile = new File(executable);
} else {
// The prefix is a unicode or encoded bytes object
executableFile = new File(Py.fileSystemDecode(prefix),
Platform.IS_WINDOWS ? "bin\\jython.exe" : "bin/jython");
}
try {
executableFile = executableFile.getCanonicalFile();
} catch (IOException ioe) {
executableFile = executableFile.getAbsoluteFile();
}
return Py.newStringOrUnicode(executableFile.getPath()); // XXX always bytes in CPython
}
/**
* Wrap standard input with a customised console handler specified in the property
* python.console
in the supplied property set, which in practice is the
* fully-initialised Jython {@link #registry}. The value of python.console
is the
* name of a class that implements {@link org.python.core.Console}. An instance is constructed
* with the value of python.console.encoding
, and the console
* System.in
returns characters in that encoding. After the call, the console
* object may be accessed via {@link Py#getConsole()}.
*
* @param props containing (or not) python.console
*
* @see org.python.core.RegistryKey#PYTHON_CONSOLE
*/
private static void initConsole(Properties props) {
// At this stage python.console.encoding is always defined (but null=default)
String encoding = props.getProperty(PYTHON_CONSOLE_ENCODING);
// The console type is chosen by this registry entry:
String consoleName = props.getProperty(PYTHON_CONSOLE, "").trim();
// And must be of type ...
final Class consoleType = Console.class;
if (consoleName.length() > 0 && Py.isInteractive()) {
try {
// Load the class specified as the console
Class> consoleClass = Class.forName(consoleName);
// Ensure it can be cast to the interface type of all consoles
if (!consoleType.isAssignableFrom(consoleClass)) {
throw new ClassCastException();
}
// Construct an instance
Constructor> consoleConstructor = consoleClass.getConstructor(String.class);
Object consoleObject = consoleConstructor.newInstance(encoding);
Console console = consoleType.cast(consoleObject);
// Replace System.in with stream this console manufactures
Py.installConsole(console);
return;
} catch (NoClassDefFoundError e) {
writeConsoleWarning(consoleName, "not found");
} catch (ClassCastException e) {
writeConsoleWarning(consoleName, "does not implement " + consoleType);
} catch (NoSuchMethodException e) {
writeConsoleWarning(consoleName, "has no constructor from String");
} catch (InvocationTargetException e) {
writeConsoleWarning(consoleName, e.getCause().toString());
} catch (Exception e) {
writeConsoleWarning(consoleName, e.toString());
}
}
// No special console required, or requested installation failed somehow
try {
// Default is a plain console
Py.installConsole(new PlainConsole(encoding));
return;
} catch (Exception e) {
/*
* May end up here if prior console won't uninstall: but then at least we have a
* console. Or it may be an unsupported encoding, in which case Py.getConsole() will try
* "ascii"
*/
writeConsoleWarning(consoleName, e.toString());
}
}
/**
* Convenience method wrapping {@link Py#writeWarning(String, String)} to issue a warning
* message something like: "console: Failed to load 'org.python.util.ReadlineConsole':
* msg.". It's only a warning because the interpreter will fall back to a plain console,
* but it is useful to know exactly why it didn't work.
*
* @param consoleName console class name we're trying to initialise
* @param msg specific cause of the failure
*/
private static void writeConsoleWarning(String consoleName, String msg) {
Py.writeWarning("console", "Failed to install '" + consoleName + "': " + msg + ".");
}
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 = Generic.map();
// add the oddball builtins that are specially handled
builtinNames.put("__builtin__", "");
builtinNames.put("sys", "");
// add builtins specified in the Setup.java file
for (String builtinModule : Setup.builtinModules) {
addBuiltin(builtinModule);
}
// 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();
PyObject[] built_mod = new PyObject[n];
int i = 0;
for (String key : builtinNames.keySet()) {
built_mod[i++] = Py.newString(key);
}
builtin_module_names = new PyTuple(built_mod);
}
public static String getBuiltin(String name) {
return builtinNames.get(name);
}
private static PyList initPath(Properties props, boolean standalone, String jarFileName) {
PyList path = new PyList();
addPaths(path, props.getProperty(PYTHON_PATH, ""));
String libpath = new File(Py.fileSystemDecode(prefix), "Lib").toString();
path.append(Py.fileSystemEncode(libpath)); // XXX or newUnicode?
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 true
if we have a standalone .jar file, false
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/os.py");
standalone = jarEntry != null;
} catch (IOException ioe) {
// Continue
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException e) {
// Continue
}
}
}
}
return standalone;
}
private static void addPaths(PyList path, String pypath) {
StringTokenizer tok = new StringTokenizer(pypath, java.io.File.pathSeparator);
while (tok.hasMoreTokens()) {
// Use unicode object if necessary to represent the element
path.append(Py.newStringOrUnicode(tok.nextToken().trim())); // XXX or newUnicode?
}
}
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.
*
* Note. Classes found in directory and sub-directory are not made available to jython by
* this call. It only makes the java package found in the directory available. This call is
* mostly useful if jython is embedded in an application that deals with its own class loaders.
* A servlet container is a very good example. Calling
* {@code add_classdir("/WEB-INF/classes")} makes the java packages in WEB-INF classes
* available to jython import. However the actual class loading 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 and .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.
*
* Note. 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 and .zip directory to the list of places that are searched for java .jar and .zip
* files.
*
* Note. 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);
}
// 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 None */
/* After printing, also assign to '_' */
/* Before, set '_' to None to avoid recursion */
if (o == Py.None) {
return;
}
PyObject currentBuiltins = Py.getSystemState().getBuiltins();
currentBuiltins.__setitem__("_", Py.None);
Py.stdout.println(o.__repr__());
currentBuiltins.__setitem__("_", o);
}
static void excepthook(PyObject type, PyObject val, PyObject tb) {
Py.displayException(type, val, tb, null);
}
/**
* Exit a Python program with the given status.
*
* @param status the value to exit with
* @throws PyException {@code 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 static PyTuple exc_info() {
PyException exc = Py.getThreadState().exception;
if (exc == null) {
return new PyTuple(Py.None, Py.None, Py.None);
}
PyObject tb = exc.traceback;
PyObject value = exc.value;
return new PyTuple(exc.type, value == null ? Py.None : value, tb == null ? Py.None : tb);
}
public static void exc_clear() {
Py.getThreadState().exception = null;
}
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 static PyDictionary _current_frames() {
return ThreadStateMapping._current_frames();
}
public void registerCloser(Callable resourceCloser) {
closer.registerCloser(resourceCloser);
}
public boolean unregisterCloser(Callable resourceCloser) {
return closer.unregisterCloser(resourceCloser);
}
public void cleanup() {
closer.cleanup();
}
@Override
public void close() {
cleanup();
}
public static class PySystemStateCloser {
private final Set> resourceClosers =
Collections.synchronizedSet(new LinkedHashSet>());
private volatile boolean isCleanup = false;
private final Thread shutdownHook;
private PySystemStateCloser(PySystemState sys) {
shutdownHook = initShutdownCloser();
WeakReference ref =
new WeakReference(sys, systemStateQueue);
sysClosers.put(ref, this);
cleanupOtherClosers();
}
private static void cleanupOtherClosers() {
Reference extends PySystemState> ref;
while ((ref = systemStateQueue.poll()) != null) {
PySystemStateCloser closer = sysClosers.get(ref);
sysClosers.remove(ref);
closer.cleanup();
}
}
private void registerCloser(Callable closer) {
if (!isCleanup) {
resourceClosers.add(closer);
}
}
private boolean unregisterCloser(Callable closer) {
return resourceClosers.remove(closer);
}
private synchronized void cleanup() {
if (isCleanup) {
return;
}
isCleanup = true;
// close this thread so we can unload any associated classloaders in cycle
// with this instance
if (shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
} catch (IllegalStateException e) {
// JVM is already shutting down, so we cannot remove this shutdown hook anyway
}
}
// Close the listed resources (and clear the list)
runClosers();
resourceClosers.clear();
// XXX Not sure this is ok, but it makes repeat testing possible.
// Re-enable the management of resource closers
isCleanup = false;
}
private synchronized void runClosers() {
// resourceClosers can be null in some strange cases
if (resourceClosers != null) {
/*
* Although a Set, the container iterates in the order closers were added. Make a
* Deque of it and deal from the top.
*/
LinkedList> rc = new LinkedList>(resourceClosers);
Iterator> iter = rc.descendingIterator();
while (iter.hasNext()) {
Callable callable = iter.next();
try {
callable.call();
} catch (Exception e) {
// just continue, nothing we can do
}
}
}
}
// Python scripts expect that files are closed upon an orderly cleanup of the VM.
private Thread initShutdownCloser() {
try {
Thread shutdownHook =
new Thread(new ShutdownCloser(this), "Jython Shutdown Closer");
Runtime.getRuntime().addShutdownHook(shutdownHook);
return shutdownHook;
} catch (SecurityException se) {
Py.writeDebug("PySystemState", "Can't register cleanup closer hook");
return null;
}
}
private class ShutdownCloser implements Runnable {
PySystemStateCloser closer = null;
public ShutdownCloser(PySystemStateCloser closer) {
super();
this.closer = closer;
}
@Override
public void run() {
synchronized (this.closer) {
runClosers();
resourceClosers.clear();
}
}
}
}
/**
* Attempt to find the OS version. The mechanism on Windows is to extract it from the result of
* {@code cmd.exe /C ver}, and otherwise (assumed Unix-like OS) to use {@code uname -v
}.
*/
public static String getSystemVersionString() {
if (System.getProperty("os.name").startsWith("Windows")) {
// Windows ver command returns a string similar to:
// "Microsoft Windows [Version 10.0.10586]"
// "Microsoft Windows XP [Version 5.1.2600]"
// "Microsoft Windows [版本 10.0.17134.472]"
// We match the dots and digits within square brackets.
Pattern p = Pattern.compile("\\[.* ([\\d.]+)\\]");
Matcher m = p.matcher(Py.getCommandResultWindows("ver"));
return m.find() ? m.group(1) : "";
} else {
return Py.getCommandResult("uname", "-v");
}
}
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
int retVal;
if (argv != null) {
retVal = visit.visit(argv, arg);
if (retVal != 0) {
return retVal;
}
}
if (modules != null) {
retVal = visit.visit(modules, arg);
if (retVal != 0) {
return retVal;
}
}
if (path != null) {
retVal = visit.visit(path, arg);
if (retVal != 0) {
return retVal;
}
}
if (warnoptions != null) {
retVal = visit.visit(warnoptions, arg);
if (retVal != 0) {
return retVal;
}
}
if (builtins != null) {
retVal = visit.visit(builtins, arg);
if (retVal != 0) {
return retVal;
}
}
if (platform != null) {
retVal = visit.visit(platform, arg);
if (retVal != 0) {
return retVal;
}
}
if (meta_path != null) {
retVal = visit.visit(meta_path, arg);
if (retVal != 0) {
return retVal;
}
}
if (path_hooks != null) {
retVal = visit.visit(path_hooks, arg);
if (retVal != 0) {
return retVal;
}
}
if (path_importer_cache != null) {
retVal = visit.visit(path_importer_cache, arg);
if (retVal != 0) {
return retVal;
}
}
if (ps1 != null) {
retVal = visit.visit(ps1, arg);
if (retVal != 0) {
return retVal;
}
}
if (ps2 != null) {
retVal = visit.visit(ps2, arg);
if (retVal != 0) {
return retVal;
}
}
if (executable != null) {
retVal = visit.visit(executable, arg);
if (retVal != 0) {
return retVal;
}
}
if (stdout != null) {
retVal = visit.visit(stdout, arg);
if (retVal != 0) {
return retVal;
}
}
if (stderr != null) {
retVal = visit.visit(stderr, arg);
if (retVal != 0) {
return retVal;
}
}
if (stdin != null) {
retVal = visit.visit(stdin, arg);
if (retVal != 0) {
return retVal;
}
}
if (__stdout__ != null) {
retVal = visit.visit(__stdout__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__stderr__ != null) {
retVal = visit.visit(__stderr__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__stdin__ != null) {
retVal = visit.visit(__stdin__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__displayhook__ != null) {
retVal = visit.visit(__displayhook__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__excepthook__ != null) {
retVal = visit.visit(__excepthook__, arg);
if (retVal != 0) {
return retVal;
}
}
if (last_value != null) {
retVal = visit.visit(last_value, arg);
if (retVal != 0) {
return retVal;
}
}
if (last_type != null) {
retVal = visit.visit(last_type, arg);
if (retVal != 0) {
return retVal;
}
}
if (last_traceback != null) {
retVal = visit.visit(last_traceback, arg);
if (retVal != 0) {
return retVal;
}
}
if (__name__ != null) {
retVal = visit.visit(__name__, arg);
if (retVal != 0) {
return retVal;
}
}
return __dict__ == null ? 0 : visit.visit(__dict__, arg);
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
return ob != null && (ob == argv || ob == modules || ob == path || ob == warnoptions
|| ob == builtins || ob == platform || ob == meta_path || ob == path_hooks
|| ob == path_importer_cache || ob == ps1 || ob == ps2 || ob == executable
|| ob == stdout || ob == stderr || ob == stdin || ob == __stdout__
|| ob == __stderr__ || ob == __stdin__ || ob == __displayhook__
|| ob == __excepthook__ || ob == last_value || ob == last_type
|| ob == last_traceback || ob == __name__ || ob == __dict__);
}
/**
* Helper abstracting common code from {@link ShutdownCloser#run()} and
* {@link PySystemStateCloser#cleanup()} to close resources (such as still-open files). The
* closing sequence is from last-created resource to first-created, so that dependencies between
* them are respected. (There are some amongst layers in the _io module.)
*
* @param resourceClosers to be called in turn
*/
}
@Untraversable
class PySystemStateFunctions extends PyBuiltinFunctionSet {
PySystemStateFunctions(String name, int index, int minargs, int maxargs) {
super(name, index, minargs, maxargs);
}
@Override
public PyObject __call__(PyObject arg) {
switch (index) {
case 10:
PySystemState.displayhook(arg);
return Py.None;
default:
throw info.unexpectedCall(1, false);
}
}
@Override
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);
}
}
}
/**
* Value of a class or instance variable when the corresponding attribute is deleted. Used only in
* PySystemState for now.
*/
@Untraversable
class PyAttributeDeleted extends PyObject {
final static PyAttributeDeleted INSTANCE = new PyAttributeDeleted();
private PyAttributeDeleted() {}
@Override
public String toString() {
return "";
}
@Override
public Object __tojava__(Class c) {
if (c == PyObject.class) {
return this;
}
// we can't quite "delete" non-PyObject attributes; settle for
// null or nothing
if (c.isPrimitive()) {
return Py.NoConversion;
}
return null;
}
}
@ExposedType(name = "sys.float_info", isBaseType = false)
class FloatInfo extends PyTuple {
@ExposedGet
public PyObject max, max_exp, max_10_exp, min, min_exp, min_10_exp, dig, mant_dig, epsilon,
radix, rounds;
public static final PyType TYPE = PyType.fromClass(FloatInfo.class);
private FloatInfo(PyObject... vals) {
super(TYPE, vals);
max = vals[0];
max_exp = vals[1];
max_10_exp = vals[2];
min = vals[3];
min_exp = vals[4];
min_10_exp = vals[5];
dig = vals[6];
mant_dig = vals[7];
epsilon = vals[8];
radix = vals[9];
rounds = vals[10];
}
static public FloatInfo getInfo() {
// max_10_exp, dig and epsilon taken from ssj library Num class
// min_10_exp, mant_dig, radix and rounds by ɲeuroburɳ (bit.ly/Iwo2LT)
return new FloatInfo( //
Py.newFloat(Double.MAX_VALUE), // DBL_MAX
Py.newLong(Double.MAX_EXPONENT), // DBL_MAX_EXP
Py.newLong(308), // DBL_MIN_10_EXP
Py.newFloat(Double.MIN_VALUE), // DBL_MIN
Py.newLong(Double.MIN_EXPONENT), // DBL_MIN_EXP
Py.newLong(-307), // DBL_MIN_10_EXP
Py.newLong(10), // DBL_DIG
Py.newLong(53), // DBL_MANT_DIG
Py.newFloat(2.2204460492503131e-16), // DBL_EPSILON
Py.newLong(2), // FLT_RADIX
Py.newLong(1) // FLT_ROUNDS
);
}
@Override
public PyString __repr__() {
return (PyString) Py.newString(TYPE.fastGetName() + "("
+ "max=%r, max_exp=%r, max_10_exp=%r, min=%r, min_exp=%r, min_10_exp=%r, "
+ "dig=%r, mant_dig=%r, epsilon=%r, radix=%r, rounds=%r)").__mod__(this);
}
/*
* Note for Traverseproc implementation: We needn't visit the fields, because they are also
* represented as tuple elements in the parent class. So deferring to super-implementation is
* sufficient.
*/
}
@ExposedType(name = "sys.long_info", isBaseType = false)
class LongInfo extends PyTuple {
@ExposedGet
public PyObject bits_per_digit, sizeof_digit;
public static final PyType TYPE = PyType.fromClass(LongInfo.class);
private LongInfo(PyObject... vals) {
super(TYPE, vals);
bits_per_digit = vals[0];
sizeof_digit = vals[1];
}
// XXX: I've cheated and just used the values that CPython gives me for my
// local Ubuntu system. I'm not sure that they are correct.
static public LongInfo getInfo() {
return new LongInfo(Py.newLong(30), Py.newLong(4));
}
@Override
public PyString __repr__() {
return (PyString) Py
.newString(TYPE.fastGetName() + "(" + "bits_per_digit=%r, sizeof_digit=%r)")
.__mod__(this);
}
/*
* Note for Traverseproc implementation: We needn't visit the fields, because they are also
* represented as tuple elements in the parent class. So deferring to super-implementation is
* sufficient.
*/
}
@ExposedType(name = "sys.getwindowsversion", isBaseType = false)
class WinVersion extends PyTuple {
@ExposedGet
public PyObject major, minor, build, platform, service_pack;
public static final PyType TYPE = PyType.fromClass(WinVersion.class);
private WinVersion(PyObject... vals) {
super(TYPE, vals);
major = vals[0];
minor = vals[1];
build = vals[2];
platform = vals[3];
service_pack = vals[4];
}
public static WinVersion getWinVersion() {
try {
String sysver = PySystemState.getSystemVersionString();
String[] sys_ver = sysver.split("\\.");
int major = Integer.parseInt(sys_ver[0]);
int minor = Integer.parseInt(sys_ver[1]);
int build = Integer.parseInt(sys_ver[2]);
if (major > 6) {
major = 6;
minor = 2;
build = 9200;
} else if (major == 6 && minor > 2) {
minor = 2;
build = 9200;
}
// emulate deprecation behavior of GetVersionEx:
return new WinVersion(Py.newInteger(major), // major
Py.newInteger(minor), // minor
Py.newInteger(build), // build
Py.newInteger(2), // platform
Py.EmptyString); // service_pack
} catch (Exception e) {
return new WinVersion(Py.EmptyString, Py.EmptyString, Py.EmptyString, Py.EmptyString,
Py.EmptyString);
}
}
@Override
public PyString __repr__() {
return (PyString) Py.newString(TYPE.fastGetName() + "(major=%r, minor=%r, build=%r, "
+ "platform=%r, service_pack=%r)").__mod__(this);
}
/*
* Note for traverseproc implementation: We needn't visit the fields, because they are also
* represented as tuple elements in the parent class. So deferring to super-implementation is
* sufficient.
*
* (In CPython sys.getwindowsversion can have some keyword-only elements. So far we don't
* support these here. If that changes, an actual traverseproc implementation might be required.
*/
}