org.python.core.Py Maven / Gradle / Ivy
Show all versions of jython-slim Show documentation
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import org.python.antlr.base.mod;
import org.python.core.adapter.ClassicPyObjectAdapter;
import org.python.core.adapter.ExtensiblePyObjectAdapter;
import org.python.modules.posix.PosixModule;
import jline.console.UserInterruptException;
import jnr.constants.Constant;
import jnr.constants.platform.Errno;
import jnr.posix.util.Platform;
public final class Py extends PrePy {
static class SingletonResolver implements Serializable {
private String which;
SingletonResolver(String which) {
this.which = which;
}
private Object readResolve() throws ObjectStreamException {
if (which.equals("None")) {
return Py.None;
} else if (which.equals("Ellipsis")) {
return Py.Ellipsis;
} else if (which.equals("NotImplemented")) {
return Py.NotImplemented;
}
throw new StreamCorruptedException("unknown singleton: " + which);
}
}
/* Holds the singleton None and Ellipsis objects */
/** The singleton None Python object **/
public final static PyObject None = PyNone.getInstance();
/** The singleton Ellipsis Python object - written as ... when indexing */
public final static PyObject Ellipsis = new PyEllipsis();
/** The singleton NotImplemented Python object. Used in rich comparison */
public final static PyObject NotImplemented = new PyNotImplemented();
/** A zero-length array of Strings to pass to functions that
don't have any keyword arguments **/
public final static String[] NoKeywords = new String[0];
/** A zero-length array of PyObject's to pass to functions when we have no arguments **/
public final static PyObject[] EmptyObjects = new PyObject[0];
/** A frozenset with zero elements **/
public final static PyFrozenSet EmptyFrozenSet = new PyFrozenSet();
/** A tuple with zero elements **/
public final static PyTuple EmptyTuple = new PyTuple(Py.EmptyObjects);
/** The Python integer 0 **/
public final static PyInteger Zero = new PyInteger(0);
/** The Python integer 1 **/
public final static PyInteger One = new PyInteger(1);
/** The Python boolean False **/
public final static PyBoolean False = new PyBoolean(false);
/** The Python boolean True **/
public final static PyBoolean True = new PyBoolean(true);
/** A zero-length Python byte string **/
public final static PyString EmptyString = PyString.fromInterned("");
/** A zero-length Python Unicode string **/
public final static PyUnicode EmptyUnicode = new PyUnicode("");
/** A Python string containing '\n' **/
public final static PyString Newline = PyString.fromInterned("\n");
/** A Python unicode string containing '\n' **/
public final static PyUnicode UnicodeNewline = new PyUnicode("\n");
/** A Python string containing ' ' **/
public final static PyString Space = PyString.fromInterned(" ");
/** A Python unicode string containing ' ' **/
public final static PyUnicode UnicodeSpace = new PyUnicode(" ");
/** Set if the type object is dynamically allocated */
public final static long TPFLAGS_HEAPTYPE = 1L << 9;
/** Set if the type allows subclassing */
public final static long TPFLAGS_BASETYPE = 1L << 10;
/** Type is abstract and cannot be instantiated */
public final static long TPFLAGS_IS_ABSTRACT = 1L << 20;
/** A unique object to indicate no conversion is possible
in __tojava__ methods **/
public final static Object NoConversion = new PySingleton("Error");
public static PyObject OSError;
public static PyException OSError(String message) {
return new PyException(Py.OSError, message);
}
public static PyException OSError(IOException ioe) {
return fromIOException(ioe, Py.OSError);
}
public static PyException OSError(Constant errno) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value));
return new PyException(Py.OSError, args);
}
public static PyException OSError(Constant errno, PyObject filename) {
int value = errno.intValue();
// see https://github.com/jruby/jruby/commit/947c661e46683ea82f8016dde9d3fa597cd10e56
// for rationale to do this mapping, but in a nutshell jnr-constants is automatically
// generated from header files, so that's not the right place to do this mapping,
// but for Posix compatibility reasons both CPython andCRuby do this mapping;
// except CPython chooses EEXIST instead of CRuby's ENOENT
if (Platform.IS_WINDOWS && (value == 20047 || value == Errno.ESRCH.intValue())) {
value = Errno.EEXIST.intValue();
}
// Pass to strerror because jnr-constants currently lacks Errno descriptions on
// Windows, and strerror falls back to Linux's
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename);
return new PyException(Py.OSError, args);
}
public static PyObject NotImplementedError;
public static PyException NotImplementedError(String message) {
return new PyException(Py.NotImplementedError, message);
}
public static PyObject EnvironmentError;
public static PyException EnvironmentError(String message) {
return new PyException(Py.EnvironmentError, message);
}
/* The standard Python exceptions */
public static PyObject OverflowError;
public static PyException OverflowError(String message) {
return new PyException(Py.OverflowError, message);
}
public static PyObject RuntimeError;
public static PyException RuntimeError(String message) {
return new PyException(Py.RuntimeError, message);
}
public static PyObject KeyboardInterrupt;
public static PyException KeyboardInterrupt(String message) {
return new PyException(Py.KeyboardInterrupt, message);
}
public static PyObject FloatingPointError;
public static PyException FloatingPointError(String message) {
return new PyException(Py.FloatingPointError, message);
}
public static PyObject SyntaxError;
public static PyException SyntaxError(String message) {
return new PyException(Py.SyntaxError, message);
}
public static PyObject IndentationError;
public static PyObject TabError;
public static PyObject AttributeError;
public static PyException AttributeError(String message) {
return new PyException(Py.AttributeError, message);
}
public static PyObject IOError;
public static PyException IOError(IOException ioe) {
return fromIOException(ioe, Py.IOError);
}
public static PyException IOError(String message) {
return new PyException(Py.IOError, message);
}
public static PyException IOError(Constant errno) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value));
return new PyException(Py.IOError, args);
}
public static PyException IOError(Constant errno, String filename) {
return IOError(errno, Py.fileSystemEncode(filename));
}
public static PyException IOError(Constant errno, PyObject filename) {
int value = errno.intValue();
PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename);
return new PyException(Py.IOError, args);
}
private static PyException fromIOException(IOException ioe, PyObject err) {
String message = ioe.getMessage();
if (message == null) {
message = ioe.getClass().getName();
}
if (ioe instanceof FileNotFoundException) {
PyTuple args = new PyTuple(Py.newInteger(Errno.ENOENT.intValue()),
Py.newStringOrUnicode("File not found - " + message));
return new PyException(err, args);
}
return new PyException(err, message);
}
public static PyObject KeyError;
public static PyException KeyError(String message) {
return new PyException(Py.KeyError, message);
}
public static PyException KeyError(PyObject key) {
return new PyException(Py.KeyError, key);
}
public static PyObject AssertionError;
public static PyException AssertionError(String message) {
return new PyException(Py.AssertionError, message);
}
public static PyObject TypeError;
public static PyException TypeError(String message) {
return new PyException(Py.TypeError, message);
}
public static PyObject ReferenceError;
public static PyException ReferenceError(String message) {
return new PyException(Py.ReferenceError, message);
}
public static PyObject SystemError;
public static PyException SystemError(String message) {
return new PyException(Py.SystemError, message);
}
public static PyObject IndexError;
public static PyException IndexError(String message) {
return new PyException(Py.IndexError, message);
}
public static PyObject ZeroDivisionError;
public static PyException ZeroDivisionError(String message) {
return new PyException(Py.ZeroDivisionError, message);
}
public static PyObject NameError;
public static PyException NameError(String message) {
return new PyException(Py.NameError, message);
}
public static PyObject UnboundLocalError;
public static PyException UnboundLocalError(String message) {
return new PyException(Py.UnboundLocalError, message);
}
public static PyObject SystemExit;
static void maybeSystemExit(PyException exc) {
if (exc.match(Py.SystemExit)) {
// No actual exit here if Options.interactive (-i flag) is in force.
handleSystemExit(exc);
}
}
/**
* Exit the process, if {@value Options#inspect}{@code ==false}, cleaning up the system state.
* This exception (normally SystemExit) determines the message, if any, and the
* {@code System.exit} status.
*
* @param exc supplies the message or exit status
*/
static void handleSystemExit(PyException exc) {
if (!Options.inspect) {
PyObject value = exc.value;
if (PyException.isExceptionInstance(exc.value)) {
value = value.__findattr__("code");
}
// Decide exit status and produce message while Jython still works
int exitStatus;
if (value instanceof PyInteger) {
exitStatus = ((PyInteger) value).getValue();
} else {
if (value != Py.None) {
try {
Py.println(value);
exitStatus = 1;
} catch (Throwable t) {
exitStatus = 0;
}
} else {
exitStatus = 0;
}
}
// Shut down Jython
PySystemState sys = Py.getSystemState();
sys.callExitFunc();
sys.close();
System.exit(exitStatus);
}
}
public static PyObject StopIteration;
public static PyException StopIteration(String message) {
return new PyException(Py.StopIteration, message);
}
public static PyObject GeneratorExit;
public static PyException GeneratorExit(String message) {
return new PyException(Py.GeneratorExit, message);
}
public static PyObject ImportError;
public static PyException ImportError(String message) {
return new PyException(Py.ImportError, message);
}
public static PyObject ValueError;
public static PyException ValueError(String message) {
return new PyException(Py.ValueError, message);
}
public static PyObject UnicodeError;
public static PyException UnicodeError(String message) {
return new PyException(Py.UnicodeError, message);
}
public static PyObject UnicodeTranslateError;
public static PyException UnicodeTranslateError(String object,
int start,
int end, String reason) {
return new PyException(Py.UnicodeTranslateError, new PyTuple(new PyString(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject UnicodeDecodeError;
public static PyException UnicodeDecodeError(String encoding,
String object,
int start,
int end,
String reason) {
return new PyException(Py.UnicodeDecodeError, new PyTuple(new PyString(encoding),
new PyString(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject UnicodeEncodeError;
public static PyException UnicodeEncodeError(String encoding,
String object,
int start,
int end,
String reason) {
return new PyException(Py.UnicodeEncodeError, new PyTuple(new PyString(encoding),
new PyUnicode(object),
new PyInteger(start),
new PyInteger(end),
new PyString(reason)));
}
public static PyObject EOFError;
public static PyException EOFError(String message) {
return new PyException(Py.EOFError, message);
}
public static PyObject MemoryError;
public static void memory_error(OutOfMemoryError t) {
if (Options.showJavaExceptions) {
t.printStackTrace();
}
}
public static PyException MemoryError(String message) {
return new PyException(Py.MemoryError, message);
}
public static PyObject BufferError;
public static PyException BufferError(String message) {
return new PyException(Py.BufferError, message);
}
public static PyObject ArithmeticError;
public static PyObject LookupError;
public static PyObject StandardError;
public static PyObject Exception;
public static PyObject BaseException;
public static PyObject Warning;
public static void Warning(String message) {
warning(Warning, message);
}
public static PyObject UserWarning;
public static void UserWarning(String message) {
warning(UserWarning, message);
}
public static PyObject DeprecationWarning;
public static void DeprecationWarning(String message) {
warning(DeprecationWarning, message);
}
public static PyObject PendingDeprecationWarning;
public static void PendingDeprecationWarning(String message) {
warning(PendingDeprecationWarning, message);
}
public static PyObject SyntaxWarning;
public static void SyntaxWarning(String message) {
warning(SyntaxWarning, message);
}
public static PyObject RuntimeWarning;
public static void RuntimeWarning(String message) {
warning(RuntimeWarning, message);
}
public static PyObject FutureWarning;
public static void FutureWarning(String message) {
warning(FutureWarning, message);
}
public static PyObject ImportWarning;
public static void ImportWarning(String message) {
warning(ImportWarning, message);
}
public static PyObject UnicodeWarning;
public static void UnicodeWarning(String message) {
warning(UnicodeWarning, message);
}
public static PyObject BytesWarning;
public static void BytesWarning(String message) {
warning(BytesWarning, message);
}
public static void warnPy3k(String message) {
warnPy3k(message, 1);
}
public static void warnPy3k(String message, int stacklevel) {
if (Options.py3k_warning) {
warning(DeprecationWarning, message, stacklevel);
}
}
private static PyObject warnings_mod;
private static PyObject importWarnings() {
if (warnings_mod != null) {
return warnings_mod;
}
PyObject mod;
try {
mod = __builtin__.__import__("warnings");
} catch (PyException e) {
if (e.match(ImportError)) {
return null;
}
throw e;
}
warnings_mod = mod;
return mod;
}
private static String warn_hcategory(PyObject category) {
PyObject name = category.__findattr__("__name__");
if (name != null) {
return "[" + name + "]";
}
return "[warning]";
}
public static void warning(PyObject category, String message) {
warning(category, message, 1);
}
public static void warning(PyObject category, String message, int stacklevel) {
PyObject func = null;
PyObject mod = importWarnings();
if (mod != null) {
func = mod.__getattr__("warn");
}
if (func == null) {
System.err.println(warn_hcategory(category) + ": " + message);
return;
} else {
func.__call__(Py.newString(message), category, Py.newInteger(stacklevel));
}
}
public static void warning(PyObject category, String message,
String filename, int lineno, String module,
PyObject registry) {
PyObject func = null;
PyObject mod = importWarnings();
if (mod != null) {
func = mod.__getattr__("warn_explicit");
}
if (func == null) {
System.err.println(filename + ":" + lineno + ":" +
warn_hcategory(category) + ": " + message);
return;
} else {
func.__call__(new PyObject[]{
Py.newString(message), category,
Py.newString(filename), Py.newInteger(lineno),
(module == null) ? Py.None : Py.newString(module),
registry
}, Py.NoKeywords);
}
}
public static PyObject JavaError;
public static PyException JavaError(Throwable t) {
if (t instanceof PyException) {
return (PyException) t;
} else if (t instanceof InvocationTargetException) {
return JavaError(((InvocationTargetException) t).getTargetException());
} else if (t instanceof StackOverflowError) {
return Py.RuntimeError("maximum recursion depth exceeded (Java StackOverflowError)");
} else if (t instanceof OutOfMemoryError) {
memory_error((OutOfMemoryError) t);
} else if (t instanceof UserInterruptException) {
return Py.KeyboardInterrupt("");
}
PyObject exc = PyJavaType.wrapJavaObject(t);
PyException pyex = new PyException(exc.getType(), exc);
// Set the cause to the original throwable to preserve
// the exception chain.
pyex.initCause(t);
return pyex;
}
private Py() {
}
/**
Convert a given PyObject
to an instance of a Java class.
Identical to o.__tojava__(c)
except that it will
raise a TypeError
if the conversion fails.
@param o the PyObject
to convert.
@param c the class to convert it to.
**/
@SuppressWarnings("unchecked")
public static T tojava(PyObject o, Class c) {
Object obj = o.__tojava__(c);
if (obj == Py.NoConversion) {
throw Py.TypeError("can't convert " + o.__repr__() + " to " +
c.getName());
}
return (T)obj;
}
// ??pending: was @deprecated but is actually used by proxie code.
// Can get rid of it?
public static Object tojava(PyObject o, String s) {
Class> c = findClass(s);
if (c == null) {
throw Py.TypeError("can't convert to: " + s);
}
return tojava(o, c); // prev:Class.forName
}
/* Helper functions for PyProxy's */
/* Convenience methods to create new constants without using "new" */
private final static PyInteger[] integerCache = new PyInteger[1000];
static {
for (int j = -100; j < 900; j++) {
integerCache[j + 100] = new PyInteger(j);
}
}
public static final PyInteger newInteger(int i) {
if (i >= -100 && i < 900) {
return integerCache[i + 100];
} else {
return new PyInteger(i);
}
}
public static PyObject newInteger(long i) {
if (i < Integer.MIN_VALUE || i > Integer.MAX_VALUE) {
return new PyLong(i);
} else {
return newInteger((int) i);
}
}
public static PyLong newLong(String s) {
return new PyLong(s);
}
public static PyLong newLong(java.math.BigInteger i) {
return new PyLong(i);
}
public static PyLong newLong(int i) {
return new PyLong(i);
}
public static PyLong newLong(long l) {
return new PyLong(l);
}
public static PyComplex newImaginary(double v) {
return new PyComplex(0, v);
}
public static PyFloat newFloat(float v) {
return new PyFloat((double) v);
}
public static PyFloat newFloat(double v) {
return new PyFloat(v);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code char}. The character code
* must < 256. (This is checked.)
*
* @param c character codes < 256.
* @return a new or re-used {@code PyString}
*/
public static PyString newString(char c) {
return makeCharacter(c);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String}. The character codes
* must all be all < 256.
*
* @param s character codes are all < 256.
* @param promise is true if the caller promises the codes are all < 256.
* @return a new or re-used {@code PyString}
*/
static PyString newString(String s, boolean promise) {
int n = s.length();
if (n > 1) {
return new PyString(s, promise);
} else if (n == 1) {
return makeCharacter(s.charAt(0));
} else {
return Py.EmptyString;
}
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String}. The character codes
* must all be all < 256. (This is checked.)
*
* @param s character codes should all be < 256 or an error occurs.
* @return a new or re-used {@code PyString}
*/
public static PyString newString(String s) {
return newString(s, false);
}
/**
* Return a not-necessarily new {@link PyString} from a Java {@code String} where the caller guarantees that the
* character codes are all < 256. (This is not checked.)
*
* @param s character codes are all < 256.
* @return a new {@code PyString}
*/
static PyString newBytes(String s) {
return newString(s, true);
}
/**
* Return a {@link PyString} for the given Java String
, if it can be represented as
* US-ASCII, and a {@link PyUnicode} otherwise.
*
* @param s string content
* @return PyString
or PyUnicode
according to content of
* s
.
*/
public static PyString newStringOrUnicode(String s) {
return newStringOrUnicode(Py.EmptyString, s);
}
/**
* Return a {@link PyString} for the given Java String
, if it can be represented as
* US-ASCII and if a preceding object is not a PyUnicode
, and a {@link PyUnicode}
* otherwise. In some contexts, we want the result to be a PyUnicode
if some
* preceding result is a PyUnicode
.
*
* @param precedent string of which the type sets a precedent
* @param s string content
* @return PyString
or PyUnicode
according to content of
* s
.
*/
public static PyString newStringOrUnicode(PyObject precedent, String s) {
if (!(precedent instanceof PyUnicode) && PyString.charsFitWidth(s, 7)) {
return Py.newBytes(s);
} else {
return Py.newUnicode(s);
}
}
public static PyString newStringUTF8(String s) {
if (PyString.charsFitWidth(s, 7)) {
// ascii of course is a subset of UTF-8
return Py.newBytes(s);
} else {
return Py.newBytes(codecs.PyUnicode_EncodeUTF8(s, null));
}
}
/**
* Return a file name or path as Unicode (Java UTF-16 String
), decoded if necessary
* from a Python bytes
object, using the file system encoding. In Jython, this
* encoding is UTF-8, irrespective of the OS platform. This method is comparable with Python 3
* os.fsdecode
, but for Java use, in places such as the os
module. If
* the argument is not a PyUnicode
, it will be decoded using the nominal Jython
* file system encoding. If the argument is a PyUnicode
, its
* String
is returned.
*
* @param filename as bytes
to decode, or already as unicode
* @return unicode version of path
*/
public static String fileSystemDecode(PyString filename) {
String s = filename.getString();
if (filename instanceof PyUnicode || PyString.charsFitWidth(s, 7)) {
// Already decoded or bytes usable as ASCII
return s;
} else {
// It's bytes, so must decode properly
assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString());
return codecs.PyUnicode_DecodeUTF8(s, null);
}
}
/**
* As {@link #fileSystemDecode(PyString)} but raising ValueError
if not a
* str
or unicode
.
*
* @param filename as bytes
to decode, or already as unicode
* @return unicode version of the file name
*/
public static String fileSystemDecode(PyObject filename) {
if (filename instanceof PyString) {
return fileSystemDecode((PyString)filename);
} else {
throw Py.TypeError(String.format("coercing to Unicode: need string, %s type found",
filename.getType().fastGetName()));
}
}
/**
* Return a PyString object we can use as a file name or file path in places where Python
* expects a bytes
(that is a str
) object in the file system encoding.
* In Jython, this encoding is UTF-8, irrespective of the OS platform.
*
* This is subtly different from CPython's use of "file system encoding", which tracks the
* platform's choice so that OS services may be called that have a bytes interface. Jython's
* interaction with the OS occurs via Java using String arguments representing Unicode values,
* so we have no need to match the encoding actually chosen by the platform (e.g. 'mbcs' on
* Windows). Rather we need a nominal Jython file system encoding, for use where the standard
* library forces byte paths on us (in Python 2). There is no reason for this choice to vary
* with OS platform. Methods receiving paths as bytes
will
* {@link #fileSystemDecode(PyString)} them again for Java.
*
* @param filename as unicode
to encode, or already as bytes
* @return encoded bytes version of path
*/
public static PyString fileSystemEncode(String filename) {
if (PyString.charsFitWidth(filename, 7)) {
// Just wrap it as US-ASCII is a subset of the file system encoding
return Py.newBytes(filename);
} else {
// It's non just US-ASCII, so must encode properly
assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString());
return Py.newBytes(codecs.PyUnicode_EncodeUTF8(filename, null));
}
}
/**
* Return a PyString object we can use as a file name or file path in places where Python
* expects a bytes
(that is, str
) object in the file system encoding.
* In Jython, this encoding is UTF-8, irrespective of the OS platform. This method is comparable
* with Python 3 os.fsencode
. If the argument is a PyString, it is returned
* unchanged. If the argument is a PyUnicode, it is converted to a bytes
using the
* nominal Jython file system encoding.
*
* @param filename as unicode
to encode, or already as bytes
* @return encoded bytes version of path
*/
public static PyString fileSystemEncode(PyString filename) {
return (filename instanceof PyUnicode) ? fileSystemEncode(filename.getString()) : filename;
}
/**
* Convert a PyList
path to a list of Java String
objects decoded from
* the path elements to strings guaranteed usable in the Java API.
*
* @param path a Python search path
* @return equivalent Java list
*/
private static List fileSystemDecode(PyList path) {
List list = new ArrayList<>(path.__len__());
for (PyObject filename : path.getList()) {
list.add(fileSystemDecode(filename));
}
return list;
}
/**
* Get the environment variables from {@code os.environ}. Keys and values should be
* {@code PyString}s in the file system encoding, and it may be a {@code dict} but nothing can
* be guaranteed. (Note that in the case of multiple interpreters, the target is in the current
* interpreter's copy of {@code os}.)
*
* @return {@code os.environ}
*/
private static PyObject getEnvironment() {
PyObject os = imp.importName("os", true);
PyObject environ = os.__getattr__("environ");
return environ;
}
/** The same as {@code getenv(name, null)}. See {@link #getenv(PyString, PyString)}. */
public static PyString getenv(PyString name) {
return getenv(name, null);
}
/**
* Get the value of the environment variable named from {@code os.environ} or return the given
* default value. Empty string values are treated as undefined for this purpose.
*
* @param name of the environment variable.
* @param defaultValue to return if {@code key} is not defined (may be {@code null}.
* @return the corresponding value or defaultValue
.
*/
public static PyString getenv(PyString name, PyString defaultValue) {
try {
PyObject value = getEnvironment().__finditem__(name);
if (value == null) {
return defaultValue;
} else {
return value.__str__();
}
} catch (PyException e) {
// Something is fishy about os.environ, so the name is not defined.
return defaultValue;
}
}
/** The same as {@code getenv(name, null)}. See {@link #getenv(String, String)}. */
public static String getenv(String name) {
return getenv(name, null);
}
/**
* Get the value of the environment variable named from {@code os.environ} or return the given
* default value. This is a convenience wrapper on {@link #getenv(PyString, PyString)} which
* takes care of the fact that environment variables are FS-encoded.
*
* @param name to access in the environment.
* @param defaultValue to return if {@code key} is not defined.
* @return the corresponding value or defaultValue
.
*/
public static String getenv(String name, String defaultValue) {
PyString value = getenv(newUnicode(name), null);
if (value == null) {
return defaultValue;
} else {
// Environment variables are FS-encoded byte strings
return fileSystemDecode(value);
}
}
public static PyStringMap newStringMap() {
return new PyStringMap();
}
/**
* Return a not-necessarily new {@link PyUnicode} from a Java {@code char}. Some low index chars
* (ASCII) return a re-used {@code PyUnicode}. This method does not assume the character is
* basic-plane.
*
* @param c to convert to a {@code PyUnicode}.
* @return a new or re-used {@code PyUnicode}
*/
public static PyUnicode newUnicode(char c) {
return PyUnicode.from(c);
}
/**
* Return a not-necessarily new {@link PyUnicode} from a Java {@code String}. Empty and some
* single-character strings return a re-used {@code PyUnicode}. This method does not assume the
* character codes are basic-plane, but scans the string to find out. (See
* {@link #newUnicode(String, boolean)} for one that allows the caller to assert that it is.
*
* @param s to wrap as a {@code PyUnicode}.
* @return a new or re-used {@code PyUnicode}
*/
public static PyUnicode newUnicode(String s) {
return PyUnicode.fromString(s, false);
}
public static PyUnicode newUnicode(String s, boolean isBasic) {
return PyUnicode.fromString(s, isBasic);
}
public static PyBoolean newBoolean(boolean t) {
return t ? Py.True : Py.False;
}
public static PyObject newDate(Date date) {
if (date == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject dateClass = datetimeModule.__getattr__("date");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return dateClass.__call__(newInteger(cal.get(Calendar.YEAR)),
newInteger(cal.get(Calendar.MONTH) + 1),
newInteger(cal.get(Calendar.DAY_OF_MONTH)));
}
public static PyObject newTime(Time time) {
if (time == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject timeClass = datetimeModule.__getattr__("time");
Calendar cal = Calendar.getInstance();
cal.setTime(time);
return timeClass.__call__(newInteger(cal.get(Calendar.HOUR_OF_DAY)),
newInteger(cal.get(Calendar.MINUTE)),
newInteger(cal.get(Calendar.SECOND)),
newInteger(cal.get(Calendar.MILLISECOND) *
1000));
}
public static PyObject newDatetime(Timestamp timestamp) {
if (timestamp == null) {
return Py.None;
}
PyObject datetimeModule = __builtin__.__import__("datetime");
PyObject datetimeClass = datetimeModule.__getattr__("datetime");
Calendar cal = Calendar.getInstance();
cal.setTime(timestamp);
return datetimeClass.__call__(new PyObject[] {
newInteger(cal.get(Calendar.YEAR)),
newInteger(cal.get(Calendar.MONTH) + 1),
newInteger(cal.get(Calendar.DAY_OF_MONTH)),
newInteger(cal.get(Calendar.HOUR_OF_DAY)),
newInteger(cal.get(Calendar.MINUTE)),
newInteger(cal.get(Calendar.SECOND)),
newInteger(timestamp.getNanos() / 1000)});
}
public static PyObject newDecimal(String decimal) {
if (decimal == null) {
return Py.None;
}
PyObject decimalModule = __builtin__.__import__("decimal");
PyObject decimalClass = decimalModule.__getattr__("Decimal");
return decimalClass.__call__(newString(decimal));
}
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
boolean args, boolean keywords,
PyFunctionTable funcs, int func_id,
String[] cellvars, String[] freevars,
int npurecell, int moreflags) {
return new PyTableCode(argcount, varnames,
filename, name, 0, args, keywords, funcs,
func_id, cellvars, freevars, npurecell,
moreflags);
}
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
int firstlineno,
boolean args, boolean keywords,
PyFunctionTable funcs, int func_id,
String[] cellvars, String[] freevars,
int npurecell, int moreflags) {
return new PyTableCode(argcount, varnames,
filename, name, firstlineno, args, keywords,
funcs, func_id, cellvars, freevars, npurecell,
moreflags);
}
// --
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
boolean args, boolean keywords,
PyFunctionTable funcs, int func_id) {
return new PyTableCode(argcount, varnames,
filename, name, 0, args, keywords, funcs,
func_id);
}
public static PyCode newCode(int argcount, String varnames[],
String filename, String name,
int firstlineno,
boolean args, boolean keywords,
PyFunctionTable funcs, int func_id) {
return new PyTableCode(argcount, varnames,
filename, name, firstlineno, args, keywords,
funcs, func_id);
}
public static PyCode newJavaCode(Class> cls, String name) {
return new JavaCode(newJavaFunc(cls, name));
}
public static PyObject newJavaFunc(Class> cls, String name) {
try {
Method m = cls.getMethod(name, new Class>[]{PyObject[].class, String[].class});
return new JavaFunc(m);
} catch (NoSuchMethodException e) {
throw Py.JavaError(e);
}
}
private static PyObject initExc(String name, PyObject exceptions,
PyObject dict) {
PyObject tmp = exceptions.__getattr__(name);
dict.__setitem__(name, tmp);
return tmp;
}
static void initClassExceptions(PyObject dict) {
PyObject exc = imp.load("exceptions");
BaseException = initExc("BaseException", exc, dict);
Exception = initExc("Exception", exc, dict);
SystemExit = initExc("SystemExit", exc, dict);
StopIteration = initExc("StopIteration", exc, dict);
GeneratorExit = initExc("GeneratorExit", exc, dict);
StandardError = initExc("StandardError", exc, dict);
KeyboardInterrupt = initExc("KeyboardInterrupt", exc, dict);
ImportError = initExc("ImportError", exc, dict);
EnvironmentError = initExc("EnvironmentError", exc, dict);
IOError = initExc("IOError", exc, dict);
OSError = initExc("OSError", exc, dict);
EOFError = initExc("EOFError", exc, dict);
RuntimeError = initExc("RuntimeError", exc, dict);
NotImplementedError = initExc("NotImplementedError", exc, dict);
NameError = initExc("NameError", exc, dict);
UnboundLocalError = initExc("UnboundLocalError", exc, dict);
AttributeError = initExc("AttributeError", exc, dict);
SyntaxError = initExc("SyntaxError", exc, dict);
IndentationError = initExc("IndentationError", exc, dict);
TabError = initExc("TabError", exc, dict);
TypeError = initExc("TypeError", exc, dict);
AssertionError = initExc("AssertionError", exc, dict);
LookupError = initExc("LookupError", exc, dict);
IndexError = initExc("IndexError", exc, dict);
KeyError = initExc("KeyError", exc, dict);
ArithmeticError = initExc("ArithmeticError", exc, dict);
OverflowError = initExc("OverflowError", exc, dict);
ZeroDivisionError = initExc("ZeroDivisionError", exc, dict);
FloatingPointError = initExc("FloatingPointError", exc, dict);
ValueError = initExc("ValueError", exc, dict);
UnicodeError = initExc("UnicodeError", exc, dict);
UnicodeEncodeError = initExc("UnicodeEncodeError", exc, dict);
UnicodeDecodeError = initExc("UnicodeDecodeError", exc, dict);
UnicodeTranslateError = initExc("UnicodeTranslateError", exc, dict);
ReferenceError = initExc("ReferenceError", exc, dict);
SystemError = initExc("SystemError", exc, dict);
MemoryError = initExc("MemoryError", exc, dict);
BufferError = initExc("BufferError", exc, dict);
Warning = initExc("Warning", exc, dict);
UserWarning = initExc("UserWarning", exc, dict);
DeprecationWarning = initExc("DeprecationWarning", exc, dict);
PendingDeprecationWarning = initExc("PendingDeprecationWarning", exc, dict);
SyntaxWarning = initExc("SyntaxWarning", exc, dict);
RuntimeWarning = initExc("RuntimeWarning", exc, dict);
FutureWarning = initExc("FutureWarning", exc, dict);
ImportWarning = initExc("ImportWarning", exc, dict);
UnicodeWarning = initExc("UnicodeWarning", exc, dict);
BytesWarning = initExc("BytesWarning", exc, dict);
// Pre-initialize the PyJavaClass for OutOfMemoryError so when we need
// it it creating the pieces for it won't cause an additional out of
// memory error. Fix for bug #1654484
PyType.fromClass(OutOfMemoryError.class);
}
public static volatile PySystemState defaultSystemState;
// This is a hack to get initializations to work in proper order
public static synchronized boolean initPython() {
PySystemState.initialize();
return true;
}
private static boolean syspathJavaLoaderRestricted = false;
/**
* Common code for {@link #findClass(String)} and {@link #findClassEx(String, String)}.
*
* @param name of the Java class to load and initialise
* @param reason to be given in debug output (or {@code null} to suppress debug output.
* @return the loaded class
* @throws ClassNotFoundException if the class wasn't found by the class loader
*/
private static Class> findClassInternal(String name, String reason)
throws ClassNotFoundException {
ClassLoader classLoader = Py.getSystemState().getClassLoader();
if (classLoader != null) {
findClassTrying(name, reason, classLoader, "sys.classLoader");
return loadAndInitClass(name, classLoader);
}
if (!syspathJavaLoaderRestricted) {
try {
classLoader = imp.getSyspathJavaLoader();
findClassTrying(name, reason, classLoader, "SysPathJavaLoader");
} catch (SecurityException e) {
syspathJavaLoaderRestricted = true;
}
}
if (syspathJavaLoaderRestricted) {
classLoader = imp.getParentClassLoader();
findClassTrying(name, reason, classLoader, "Jython's parent class loader");
}
if (classLoader != null) {
try {
return loadAndInitClass(name, classLoader);
} catch (ClassNotFoundException cnfe) {
// let the default classloader try
/*
* XXX: by trying another classloader that may not be on a parent/child relationship
* with the Jython's parent classsloader we are risking some nasty class loading
* problems (such as having two incompatible copies for the same class that is
* itself a dependency of two classes loaded from these two different class
* loaders).
*/
}
}
classLoader = Thread.currentThread().getContextClassLoader();
findClassTrying(name, reason, classLoader,
"context class loader, for backwards compatibility");
return loadAndInitClass(name, classLoader);
}
private static void findClassTrying(String name, String reason, ClassLoader cl, String place) {
if (cl != null && reason != null && importLogger.isLoggable(Level.FINE)) {
importLogger.log(Level.FINE, "# trying {0} as {1} in {2}",
new Object[] {name, reason, place});
}
}
/**
* Find and load a Java class by name.
*
* @param name of the Java class.
* @return the class, or {@code null} if it wasn't found or something went wrong
*/
public static Class> findClass(String name) {
try {
return findClassInternal(name, null);
} catch (ClassNotFoundException | IllegalArgumentException | NoClassDefFoundError e) {
// e.printStackTrace();
return null;
}
}
/**
* Find and load a Java class by name.
*
* @param name Name of the Java class.
* @param reason for finding the class. Used in debugging messages.
* @return the class, or {@code null} if it simply wasn't found
* @throws PyException {@code JavaError} wrapping errors occurring when the class is found but
* cannot be loaded.
*/
public static Class> findClassEx(String name, String reason) throws PyException {
try {
return findClassInternal(name, reason);
} catch (ClassNotFoundException e) {
return null;
} catch (IllegalArgumentException | LinkageError e) {
throw JavaError(e);
}
}
// An alias to express intent (since boolean flags aren't exactly obvious).
// We *need* to initialize classes on findClass/findClassEx, so that import
// statements can trigger static initializers
private static Class> loadAndInitClass(String name, ClassLoader loader)
throws ClassNotFoundException {
return Class.forName(name, true, loader);
}
public static void initProxy(PyProxy proxy, String module, String pyclass, Object[] args)
{
if (proxy._getPyInstance() != null) {
return;
}
PyObject instance = (PyObject)(ThreadContext.initializingProxy.get()[0]);
ThreadState ts = Py.getThreadState();
if (instance != null) {
if (JyAttribute.hasAttr(instance, JyAttribute.JAVA_PROXY_ATTR)) {
throw Py.TypeError("Proxy instance reused");
}
JyAttribute.setAttr(instance, JyAttribute.JAVA_PROXY_ATTR, proxy);
proxy._setPyInstance(instance);
proxy._setPySystemState(ts.getSystemState());
return;
}
// Ensure site-packages are available before attempting to import module.
// This step enables supporting modern Python apps when using proxies
// directly from Java (eg through clamp).
importSiteIfSelected();
PyObject mod = imp.importName(module.intern(), false);
PyType pyc = (PyType)mod.__getattr__(pyclass.intern());
PyObject[] pargs;
if (args == null || args.length == 0) {
pargs = Py.EmptyObjects;
} else {
pargs = Py.javas2pys(args);
}
instance = pyc.__call__(pargs);
JyAttribute.setAttr(instance, JyAttribute.JAVA_PROXY_ATTR, proxy);
proxy._setPyInstance(instance);
proxy._setPySystemState(ts.getSystemState());
}
/**
* Initializes a default PythonInterpreter and runs the code from
* {@link PyRunnable#getMain} as __main__
*
* Called by the code generated in {@link org.python.compiler.Module#addMain()}
*/
public static void runMain(PyRunnable main, String[] args) throws Exception {
runMain(new PyRunnableBootstrap(main), args);
}
/**
* Initializes a default PythonInterpreter and runs the code loaded from the
* {@link CodeBootstrap} as __main__ Called by the code generated in
* {@link org.python.compiler.Module#addMain()}
*/
public static void runMain(CodeBootstrap main, String[] args)
throws Exception {
PySystemState.initialize(null, null, args, main.getClass().getClassLoader());
try {
imp.createFromCode("__main__", CodeLoader.loadCode(main));
} catch (PyException e) {
Py.getSystemState().callExitFunc();
if (e.match(Py.SystemExit)) {
return;
}
throw e;
}
Py.getSystemState().callExitFunc();
}
//XXX: this needs review to make sure we are cutting out all of the Java exceptions.
private static String getStackTrace(Throwable javaError) {
CharArrayWriter buf = new CharArrayWriter();
javaError.printStackTrace(new PrintWriter(buf));
String str = buf.toString();
int index = -1;
if (index == -1) {
index = str.indexOf(
"at org.python.core.PyReflectedConstructor.__call__");
}
if (index == -1) {
index = str.indexOf("at org.python.core.PyReflectedFunction.__call__");
}
if (index == -1) {
index = str.indexOf(
"at org/python/core/PyReflectedConstructor.__call__");
}
if (index == -1) {
index = str.indexOf("at org/python/core/PyReflectedFunction.__call__");
}
if (index != -1) {
index = str.lastIndexOf("\n", index);
}
int index0 = str.indexOf("\n");
if (index >= index0) {
str = str.substring(index0 + 1, index + 1);
}
return str;
}
/**
* Display an exception and stack trace through
* {@link #printException(Throwable, PyFrame, PyObject)}.
*
* @param t to display
*/
public static void printException(Throwable t) {
printException(t, null, null);
}
/**
* Display an exception and stack trace through
* {@link #printException(Throwable, PyFrame, PyObject)}.
*
* @param t to display
* @param f frame at which to start the stack trace
*/
public static void printException(Throwable t, PyFrame f) {
printException(t, f, null);
}
/**
* Display an exception and stack trace. If the exception was {@link Py#SystemExit} and
* {@link Options#inspect}{@code ==false}, this will exit the JVM.
*
* @param t to display
* @param f frame at which to start the stack trace
* @param file output onto this stream or {@link Py#stderr} if {@code null}
*/
public static synchronized void printException(Throwable t, PyFrame f,
PyObject file) {
StdoutWrapper stderr = Py.stderr;
if (file != null) {
stderr = new FixedFileWrapper(file);
}
if (Options.showJavaExceptions) {
stderr.println("Java Traceback:");
java.io.CharArrayWriter buf = new java.io.CharArrayWriter();
if (t instanceof PyException) {
((PyException)t).super__printStackTrace(new java.io.PrintWriter(buf));
} else {
t.printStackTrace(new java.io.PrintWriter(buf));
}
stderr.print(buf.toString());
}
PyException exc = Py.JavaError(t);
// Act on SystemExit here.
maybeSystemExit(exc);
setException(exc, f);
ThreadState ts = getThreadState();
PySystemState sys = ts.getSystemState();
sys.last_value = exc.value;
sys.last_type = exc.type;
sys.last_traceback = exc.traceback;
PyObject exceptHook = sys.__findattr__("excepthook");
if (exceptHook != null) {
try {
exceptHook.__call__(exc.type, exc.value, exc.traceback);
} catch (PyException exc2) {
exc2.normalize();
flushLine();
stderr.println("Error in sys.excepthook:");
displayException(exc2.type, exc2.value, exc2.traceback, file);
stderr.println();
stderr.println("Original exception was:");
displayException(exc.type, exc.value, exc.traceback, file);
}
} else {
stderr.println("sys.excepthook is missing");
displayException(exc.type, exc.value, exc.traceback, file);
}
ts.exception = null;
}
/**
* Print the description of an exception as a big string. The arguments are closely equivalent
* to the tuple returned by Python sys.exc_info
, on standard error or a given
* byte-oriented file. Compare with Python traceback.print_exception
.
*
* @param type of exception
* @param value the exception parameter (second argument to raise
)
* @param tb traceback of the call stack where the exception originally occurred
* @param file to print encoded string to, or null meaning standard error
*/
public static void displayException(PyObject type, PyObject value, PyObject tb, PyObject file) {
// Output is to standard error, unless a file object has been given.
StdoutWrapper stderr = Py.stderr;
// As we format the exception in Unicode, we deal with encoding in this method
String encoding, errors = codecs.REPLACE;
if (file != null) {
// Ostensibly writing to a file: assume file content encoding (file.encoding)
stderr = new FixedFileWrapper(file);
encoding = codecs.getDefaultEncoding();
} else {
// Not a file, assume we should encode for the console
encoding = getAttr(Py.getSystemState().__stderr__, "encoding", null);
}
// But if the stream can tell us directly, of course we use that answer.
encoding = getAttr(stderr.myFile(), "encoding", encoding);
errors = getAttr(stderr.myFile(), "errors", errors);
flushLine();
// The creation of the report operates entirely in Java String (to support Unicode).
try {
// Be prepared for formatting or printing to fail
PyString bytes = exceptionToBytes(type, value, tb, encoding, errors);
stderr.print(bytes);
} catch (Exception ex) {
// Looks like that exception just won't convert or print
value = Py.newString("");
PyString bytes = exceptionToBytes(type, value, tb, encoding, errors);
stderr.print(bytes);
}
}
/** Get a String attribute from an object or a return a default. */
private static String getAttr(PyObject target, String internedName, String def) {
PyObject attr = target.__findattr__(internedName);
if (attr == null) {
return def;
} else if (attr instanceof PyUnicode) {
return ((PyUnicode)attr).getString();
} else {
return attr.__str__().getString();
}
}
/**
* Helper for {@link #displayException(PyObject, PyObject, PyObject, PyObject)}, falling back to
* US-ASCII as the last resort encoding.
*/
private static PyString exceptionToBytes(PyObject type, PyObject value, PyObject tb,
String encoding, String errors) {
String string = exceptionToString(type, value, tb);
String bytes; // not UTF-16
try {
// Format the exception and stack-trace in all its glory
bytes = codecs.encode(Py.newUnicode(string), encoding, errors);
} catch (Exception ex) {
// Sometimes a working codec is just too much to ask
bytes = codecs.PyUnicode_EncodeASCII(string, string.length(), codecs.REPLACE);
}
return Py.newString(bytes);
}
/**
* Format the description of an exception as a big string. The arguments are closely equivalent
* to the tuple returned by Python sys.exc_info
. Compare with Python
* traceback.format_exception
.
*
* @param type of exception
* @param value the exception parameter (second argument to raise
)
* @param tb traceback of the call stack where the exception originally occurred
* @return string representation of the traceback and exception
*/
static String exceptionToString(PyObject type, PyObject value, PyObject tb) {
// Compose the stack dump, syntax error, and actual exception in this buffer:
StringBuilder buf;
if (tb instanceof PyTraceback) {
buf = new StringBuilder(((PyTraceback)tb).dumpStack());
} else {
buf = new StringBuilder();
}
if (__builtin__.isinstance(value, Py.SyntaxError)) {
// The value part of the exception is a syntax error: first emit that.
appendSyntaxError(buf, value);
// Now supersede it with just the syntax error message for the next phase.
value = value.__findattr__("msg");
if (value == null) {
value = Py.None;
}
}
if (value.getJavaProxy() != null) {
Object javaError = value.__tojava__(Throwable.class);
if (javaError != null && javaError != Py.NoConversion) {
// The value is some Java Throwable: append that too
buf.append(getStackTrace((Throwable)javaError));
}
}
// Formatting the value may raise UnicodeEncodeError: client must deal
buf.append(formatException(type, value)).append('\n');
return buf.toString();
}
/**
* Helper to {@link #tracebackToString(PyObject, PyObject)} when the value in an exception turns
* out to be a syntax error.
*/
private static void appendSyntaxError(StringBuilder buf, PyObject value) {
PyObject filename = value.__findattr__("filename");
PyObject text = value.__findattr__("text");
PyObject lineno = value.__findattr__("lineno");
buf.append(" File \"");
buf.append(filename == Py.None || filename == null ? "" : filename.toString());
buf.append("\", line ");
buf.append(lineno == null ? Py.newString('0') : lineno);
buf.append('\n');
if (text != Py.None && text != null && text.__len__() != 0) {
appendSyntaxErrorText(buf, value.__findattr__("offset").asInt(), text.toString());
}
}
/**
* Generate two lines showing where a SyntaxError was caused.
*
* @param buf to append with generated message text
* @param offset the offset into text
* @param text a source code line
*/
private static void appendSyntaxErrorText(StringBuilder buf, int offset, String text) {
if (offset >= 0) {
if (offset > 0 && offset == text.length()) {
offset--;
}
// Eat lines if the offset is on a subsequent line
while (true) {
int nl = text.indexOf("\n");
if (nl == -1 || nl >= offset) {
break;
}
offset -= nl + 1;
text = text.substring(nl + 1, text.length());
}
// lstrip
int i = 0;
for (; i < text.length(); i++) {
char c = text.charAt(i);
if (c != ' ' && c != '\t') {
break;
}
offset--;
}
text = text.substring(i, text.length());
}
buf.append(" ");
buf.append(text);
if (text.length() == 0 || !text.endsWith("\n")) {
buf.append('\n');
}
if (offset == -1) {
return;
}
// The indicator line " ^"
buf.append(" ");
for (offset--; offset > 0; offset--) {
buf.append(' ');
}
buf.append("^\n");
}
public static String formatException(PyObject type, PyObject value) {
return formatException(type, value, false);
}
public static String formatException(PyObject type, PyObject value, boolean useRepr) {
StringBuilder buf = new StringBuilder();
if (PyException.isExceptionClass(type)) {
String className = PyException.exceptionClassName(type);
int lastDot = className.lastIndexOf('.');
if (lastDot != -1) {
className = className.substring(lastDot + 1);
}
PyObject moduleName = type.__findattr__("__module__");
if (moduleName == null) {
buf.append("");
} else {
String moduleStr = moduleName.toString();
if (!moduleStr.equals("exceptions")) {
buf.append(moduleStr);
buf.append(".");
}
}
buf.append(className);
} else {
// Never happens since Python 2.7? Do something sensible anyway.
buf.append(asMessageString(type, useRepr));
}
if (value != null && value != Py.None) {
String s = asMessageString(value, useRepr);
// Print colon and object (unless it renders as "")
if (s.length() > 0) {
buf.append(": ").append(s);
}
}
return buf.toString();
}
/** Defensive method to avoid exceptions from decoding (or import encodings) */
private static String asMessageString(PyObject value, boolean useRepr) {
if (useRepr) {
value = value.__repr__();
}
if (value instanceof PyUnicode) {
return value.asString();
} else {
return value.__str__().getString();
}
}
public static void writeUnraisable(Throwable unraisable, PyObject obj) {
PyException pye = JavaError(unraisable);
stderr.println(String.format("Exception %s in %s ignored",
formatException(pye.type, pye.value, true), obj));
}
/* Equivalent to Python's assert statement */
public static void assert_(PyObject test, PyObject message) {
if (!test.__nonzero__()) {
throw new PyException(Py.AssertionError, message);
}
}
public static void assert_(PyObject test) {
assert_(test, Py.None);
}
/* Helpers to implement finally clauses */
public static void addTraceback(Throwable t, PyFrame frame) {
Py.JavaError(t).tracebackHere(frame, true);
}
/* Helpers to implement except clauses */
public static PyException setException(Throwable t, PyFrame frame) {
PyException pye = Py.JavaError(t);
pye.normalize();
pye.tracebackHere(frame);
getThreadState().exception = pye;
return pye;
}
/**
* @deprecated As of Jython 2.5, use {@link PyException#match} instead.
*/
@Deprecated
public static boolean matchException(PyException pye, PyObject exc) {
return pye.match(exc);
}
// XXX: the following 4 are backwards compat. for the
// oldcompiler. newcompiler should just call doRaise instead
public static PyException makeException(PyObject type, PyObject value,
PyObject traceback) {
return PyException.doRaise(type, value, traceback);
}
public static PyException makeException(PyObject type, PyObject value) {
return makeException(type, value, null);
}
public static PyException makeException(PyObject type) {
return makeException(type, null);
}
public static PyException makeException() {
return makeException(null);
}
public static PyObject runCode(PyCode code, PyObject locals, PyObject globals) {
PyFrame f;
ThreadState ts = getThreadState();
if (locals == null || locals == Py.None) {
if (globals != null && globals != Py.None) {
locals = globals;
} else {
locals = ts.frame.getLocals();
}
}
if (globals == null || globals == Py.None) {
globals = ts.frame.f_globals;
} else if (globals.__finditem__("__builtins__") == null) {
// Apply side effect of copying into globals,
// per documentation of eval and observed behavior of exec
try {
globals.__setitem__("__builtins__", Py.getSystemState().modules.__finditem__("__builtin__").__getattr__("__dict__"));
} catch (PyException e) {
// Quietly ignore if cannot set __builtins__ - Jython previously allowed a much wider range of
// mappable objects for the globals mapping than CPython, do not want to break existing code
// as we try to get better CPython compliance
if (!e.match(AttributeError)) {
throw e;
}
}
}
PyBaseCode baseCode = null;
if (code instanceof PyBaseCode) {
baseCode = (PyBaseCode) code;
}
f = new PyFrame(baseCode, locals, globals, Py.getSystemState().getBuiltins());
return code.call(ts, f);
}
public static void exec(PyObject o, PyObject globals, PyObject locals) {
PyCode code;
int flags = 0;
if (o instanceof PyTuple) {
PyTuple tuple = (PyTuple) o;
int len = tuple.__len__();
if ((globals == null || globals.equals(None))
&& (locals == null || locals.equals(None))
&& (len >= 2 && len <= 3)) {
o = tuple.__getitem__(0);
globals = tuple.__getitem__(1);
if (len == 3) {
locals = tuple.__getitem__(2);
}
}
}
if (o instanceof PyCode) {
code = (PyCode) o;
if (locals == null && o instanceof PyBaseCode && ((PyBaseCode) o).hasFreevars()) {
throw Py.TypeError("code object passed to exec may not contain free variables");
}
} else {
String contents = null;
if (o instanceof PyString) {
if (o instanceof PyUnicode) {
flags |= CompilerFlags.PyCF_SOURCE_IS_UTF8;
}
contents = o.toString();
} else if (o instanceof PyFile) {
PyFile fp = (PyFile) o;
if (fp.getClosed()) {
return;
}
contents = fp.read().toString();
} else {
throw Py.TypeError(
"exec: argument 1 must be string, code or file object");
}
code = Py.compile_flags(contents, "", CompileMode.exec,
getCompilerFlags(flags, false));
}
Py.runCode(code, locals, globals);
}
private final static ThreadStateMapping threadStateMapping = new ThreadStateMapping();
public static final ThreadState getThreadState() {
return getThreadState(null);
}
public static final ThreadState getThreadState(PySystemState newSystemState) {
return threadStateMapping.getThreadState(newSystemState);
}
public static final PySystemState setSystemState(PySystemState newSystemState) {
ThreadState ts = getThreadState(newSystemState);
PySystemState oldSystemState = ts.getSystemState();
if (oldSystemState != newSystemState) {
//XXX: should we make this a real warning?
//System.err.println("Warning: changing systemState "+
// "for same thread!");
ts.setSystemState(newSystemState);
}
return oldSystemState;
}
public static final PySystemState getSystemState() {
return getThreadState().getSystemState();
}
/* Get and set the current frame */
public static PyFrame getFrame() {
ThreadState ts = getThreadState();
if (ts == null) {
return null;
}
return ts.frame;
}
public static void setFrame(PyFrame f) {
getThreadState().frame = f;
}
/**
* The handler for interactive consoles, set by {@link #installConsole(Console)} and accessed by
* {@link #getConsole()}.
*/
private static Console console;
/**
* Get the Jython Console (used for input()
, raw_input()
, etc.) as
* constructed and set by {@link PySystemState} initialization.
*
* @return the Jython Console
*/
public static Console getConsole() {
if (console == null) {
// We really shouldn't ask for a console before PySystemState initialization but ...
try {
// ... something foolproof that we can supersede.
installConsole(new PlainConsole("ascii"));
} catch (Exception e) {
// This really, really shouldn't happen
throw Py.RuntimeError("Could not create fall-back PlainConsole: " + e);
}
}
return console;
}
/**
* Install the provided Console, first uninstalling any current one. The Jython Console is used
* for raw_input()
etc., and may provide line-editing and history recall at the
* prompt. A Console may replace System.in
with its line-editing input method.
*
* @param console The new Console object
* @throws UnsupportedOperationException if some prior Console refuses to uninstall
* @throws IOException if {@link Console#install()} raises it
*/
public static void installConsole(Console console) throws UnsupportedOperationException,
IOException {
if (Py.console != null) {
// Some Console class already installed: may be able to uninstall
Py.console.uninstall();
Py.console = null;
}
// Install the specified Console
console.install();
Py.console = console;
// Cause sys (if it exists) to export the console handler that was installed
if (Py.defaultSystemState != null) {
Py.defaultSystemState.__setattr__("_jy_console", Py.java2py(console));
}
}
private static final String IMPORT_SITE_ERROR = ""
+ "Cannot import site module and its dependencies: %s\n"
+ "Determine if the following attributes are correct:\n" //
+ " * sys.path: %s\n"
+ " This attribute might be including the wrong directories, such as from CPython\n"
+ " * sys.prefix: %s\n"
+ " This attribute is set by the system property python.home, although it can\n"
+ " be often automatically determined by the location of the Jython jar file\n\n"
+ "You can use the -S option or python.import.site=false to not import the site module";
public static boolean importSiteIfSelected() {
// Ensure sys.flags.no_site actually reflects what happened. (See docs of these two.)
Options.no_site = !Options.importSite;
if (Options.importSite) {
try {
// Ensure site-packages are available
imp.load("site");
return true;
} catch (PyException pye) {
if (pye.match(Py.ImportError)) {
PySystemState sys = Py.getSystemState();
String value = pye.value.__getattr__("args").__getitem__(0).toString();
List path = fileSystemDecode(sys.path);
String prefix = fileSystemDecode(PySystemState.prefix);
throw Py.ImportError(String.format(IMPORT_SITE_ERROR, value, path, prefix));
} else {
throw pye;
}
}
}
return false;
}
/* A collection of functions for implementing the print statement */
public static StdoutWrapper stderr = new StderrWrapper();
static StdoutWrapper stdout = new StdoutWrapper();
//public static StdinWrapper stdin;
public static void print(PyObject file, PyObject o) {
if (file == None) {
print(o);
} else {
new FixedFileWrapper(file).print(o);
}
}
public static void printComma(PyObject file, PyObject o) {
if (file == None) {
printComma(o);
} else {
new FixedFileWrapper(file).printComma(o);
}
}
public static void println(PyObject file, PyObject o) {
if (file == None) {
println(o);
} else {
new FixedFileWrapper(file).println(o);
}
}
public static void printlnv(PyObject file) {
if (file == None) {
println();
} else {
new FixedFileWrapper(file).println();
}
}
public static void print(PyObject o) {
stdout.print(o);
}
public static void printComma(PyObject o) {
stdout.printComma(o);
}
public static void println(PyObject o) {
stdout.println(o);
}
public static void println() {
stdout.println();
}
public static void flushLine() {
stdout.flushLine();
}
/*
* A collection of convenience functions for converting PyObjects to Java primitives
*/
public static boolean py2boolean(PyObject o) {
return o.__nonzero__();
}
public static byte py2byte(PyObject o) {
if (o instanceof PyInteger) {
return (byte) ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Byte.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError("integer required");
}
return ((Byte) i).byteValue();
}
public static short py2short(PyObject o) {
if (o instanceof PyInteger) {
return (short) ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Short.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError("integer required");
}
return ((Short) i).shortValue();
}
public static int py2int(PyObject o) {
return py2int(o, "integer required");
}
public static int py2int(PyObject o, String msg) {
if (o instanceof PyInteger) {
return ((PyInteger) o).getValue();
}
Object obj = o.__tojava__(Integer.TYPE);
if (obj == Py.NoConversion) {
throw Py.TypeError(msg);
}
return ((Integer) obj).intValue();
}
public static long py2long(PyObject o) {
if (o instanceof PyInteger) {
return ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Long.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError("integer required");
}
return ((Long) i).longValue();
}
public static float py2float(PyObject o) {
if (o instanceof PyFloat) {
return (float) ((PyFloat) o).getValue();
}
if (o instanceof PyInteger) {
return ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Float.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError("float required");
}
return ((Float) i).floatValue();
}
public static double py2double(PyObject o) {
if (o instanceof PyFloat) {
return ((PyFloat) o).getValue();
}
if (o instanceof PyInteger) {
return ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Double.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError("float required");
}
return ((Double) i).doubleValue();
}
public static char py2char(PyObject o) {
return py2char(o, "char required");
}
public static char py2char(PyObject o, String msg) {
if (o instanceof PyString) {
PyString s = (PyString) o;
if (s.__len__() != 1) {
throw Py.TypeError(msg);
}
return s.toString().charAt(0);
}
if (o instanceof PyInteger) {
return (char) ((PyInteger) o).getValue();
}
Object i = o.__tojava__(Character.TYPE);
if (i == null || i == Py.NoConversion) {
throw Py.TypeError(msg);
}
return ((Character) i).charValue();
}
public static void py2void(PyObject o) {
if (o != Py.None) {
throw Py.TypeError("None required for void return");
}
}
/** Table used by {@link #makeCharacter(char)} to intern single byte strings. */
private final static PyString[] bytes = new PyString[256];
static {
for (char j = 0; j < 256; j++) {
bytes[j] = new PyString(j);
}
}
public static final PyString makeCharacter(Character o) {
return makeCharacter(o.charValue());
}
public static final PyString makeCharacter(char c) {
if (c < 256) {
return bytes[c];
} else {
// This will throw IllegalArgumentException since non-byte value
return new PyString(c);
}
}
public static final PyUnicode makeUnicodeCharacter(int codepoint) {
return PyUnicode.fromCodepoint(codepoint);
}
/**
* Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn o into a PyObject.
*
* @see ClassicPyObjectAdapter - default PyObjectAdapter type
*/
public static PyObject java2py(Object o) {
return getAdapter().adapt(o);
}
/**
* Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn
* objects
into an array of PyObjects.
*
* @see ClassicPyObjectAdapter - default PyObjectAdapter type
*/
public static PyObject[] javas2pys(Object... objects) {
PyObject[] objs = new PyObject[objects.length];
for (int i = 0; i < objs.length; i++) {
objs[i] = java2py(objects[i]);
}
return objs;
}
/**
* @return the ExtensiblePyObjectAdapter used by java2py.
*/
public static ExtensiblePyObjectAdapter getAdapter() {
if (adapter == null) {
adapter = new ClassicPyObjectAdapter();
}
return adapter;
}
/**
* Set the ExtensiblePyObjectAdapter used by java2py.
*
* @param adapter The new ExtensiblePyObjectAdapter
*/
protected static void setAdapter(ExtensiblePyObjectAdapter adapter) {
Py.adapter = adapter;
}
/**
* Handles wrapping Java objects in PyObject to expose them to jython.
*/
private static ExtensiblePyObjectAdapter adapter;
// XXX: The following two makeClass overrides are *only* for the
// old compiler, they should be removed when the newcompiler hits
public static PyObject makeClass(String name, PyObject[] bases, PyCode code) {
return makeClass(name, bases, code, null);
}
public static PyObject makeClass(String name, PyObject[] bases, PyCode code,
PyObject[] closure_cells) {
ThreadState state = getThreadState();
PyObject dict = code.call(state, Py.EmptyObjects, Py.NoKeywords,
state.frame.f_globals, Py.EmptyObjects, new PyTuple(closure_cells));
return makeClass(name, bases, dict);
}
public static PyObject makeClass(String name, PyObject base, PyObject dict) {
PyObject[] bases = base == null ? EmptyObjects : new PyObject[] {base};
return makeClass(name, bases, dict);
}
/**
* Create a new Python class.
*
* @param name the String name of the class
* @param bases an array of PyObject base classes
* @param dict the class's namespace, containing the class body
* definition
* @return a new Python Class PyObject
*/
public static PyObject makeClass(String name, PyObject[] bases, PyObject dict) {
PyObject metaclass = dict.__finditem__("__metaclass__");
if (metaclass == null) {
if (bases.length != 0) {
PyObject base = bases[0];
metaclass = base.__findattr__("__class__");
if (metaclass == null) {
metaclass = base.getType();
}
} else {
PyObject globals = getFrame().f_globals;
if (globals != null) {
metaclass = globals.__finditem__("__metaclass__");
}
if (metaclass == null) {
metaclass = PyClass.TYPE;
}
}
}
try {
return metaclass.__call__(new PyString(name), new PyTuple(bases), dict);
} catch (PyException pye) {
if (!pye.match(TypeError)) {
throw pye;
}
pye.value = Py.newString(String.format("Error when calling the metaclass bases\n "
+ "%s", pye.value.__str__().toString()));
throw pye;
}
}
private static int nameindex = 0;
public static synchronized String getName() {
String name = "org.python.pycode._pyx" + nameindex;
nameindex += 1;
return name;
}
public static CompilerFlags getCompilerFlags() {
return CompilerFlags.getCompilerFlags();
}
public static CompilerFlags getCompilerFlags(int flags, boolean dont_inherit) {
final PyFrame frame;
if (dont_inherit) {
frame = null;
} else {
frame = Py.getFrame();
}
return CompilerFlags.getCompilerFlags(flags, frame);
}
public static CompilerFlags getCompilerFlags(CompilerFlags flags, boolean dont_inherit) {
final PyFrame frame;
if (dont_inherit) {
frame = null;
} else {
frame = Py.getFrame();
}
return CompilerFlags.getCompilerFlags(flags, frame);
}
// w/o compiler-flags
public static PyCode compile(InputStream istream, String filename, CompileMode kind) {
return compile_flags(istream, filename, kind, new CompilerFlags());
}
/**
* Entry point for compiling modules.
*
* @param node Module node, coming from the parsing process
* @param name Internal name for the compiled code. Typically generated by
* calling {@link #getName()}.
* @param filename Source file name
* @param linenumbers True to track source line numbers on the generated
* code
* @param printResults True to call the sys.displayhook on the result of
* the code
* @param cflags Compiler flags
* @return Code object for the compiled module
*/
public static PyCode compile_flags(mod node, String name, String filename,
boolean linenumbers, boolean printResults,
CompilerFlags cflags) {
return CompilerFacade.compile(node, name, filename, linenumbers, printResults, cflags);
}
public static PyCode compile_flags(mod node, String filename,
CompileMode kind, CompilerFlags cflags) {
return Py.compile_flags(node, getName(), filename, true,
kind == CompileMode.single, cflags);
}
/**
* Compiles python source code coming from a file or another external stream
*/
public static PyCode compile_flags(InputStream istream, String filename,
CompileMode kind, CompilerFlags cflags) {
mod node = ParserFacade.parse(istream, kind, filename, cflags);
return Py.compile_flags(node, filename, kind, cflags);
}
/**
* Compiles python source code coming from String (raw bytes) data.
*
* If the String is properly decoded (from PyUnicode) the PyCF_SOURCE_IS_UTF8 flag
* should be specified.
*/
public static PyCode compile_flags(String data, String filename,
CompileMode kind, CompilerFlags cflags) {
if (data.contains("\0")) {
throw Py.TypeError("compile() expected string without null bytes");
}
if (cflags != null && cflags.dont_imply_dedent) {
data += "\n";
} else {
data += "\n\n";
}
mod node = ParserFacade.parse(data, kind, filename, cflags);
return Py.compile_flags(node, filename, kind, cflags);
}
public static PyObject compile_command_flags(String string, String filename,
CompileMode kind, CompilerFlags cflags, boolean stdprompt) {
mod node = ParserFacade.partialParse(string + "\n", kind, filename,
cflags, stdprompt);
if (node == null) {
return Py.None;
}
return Py.compile_flags(node, Py.getName(), filename, true, true, cflags);
}
public static PyObject[] unpackSequence(PyObject obj, int length) {
if (obj instanceof PyTuple && obj.__len__() == length) {
// optimization
return ((PyTuple)obj).getArray();
}
PyObject[] ret = new PyObject[length];
PyObject iter = obj.__iter__();
for (int i = 0; i < length; i++) {
PyObject tmp = iter.__iternext__();
if (tmp == null) {
throw Py.ValueError(String.format("need more than %d value%s to unpack", i,
i == 1 ? "" : "s"));
}
ret[i] = tmp;
}
if (iter.__iternext__() != null) {
throw Py.ValueError("too many values to unpack");
}
return ret;
}
public static PyObject iter(PyObject seq, String message) {
try {
return seq.__iter__();
} catch (PyException exc) {
if (exc.match(Py.TypeError)) {
throw Py.TypeError(message);
}
throw exc;
}
}
private static IdImpl idimpl = new IdImpl();
public static long id(PyObject o) {
return idimpl.id(o);
}
public static String idstr(PyObject o) {
return idimpl.idstr(o);
}
public static long java_obj_id(Object o) {
return idimpl.java_obj_id(o);
}
public static void printResult(PyObject ret) {
Py.getThreadState().getSystemState().invoke("displayhook", ret);
}
public static void saveClassFile(String name, ByteArrayOutputStream bytestream) {
String dirname = Options.proxyDebugDirectory;
if (dirname == null) {
return;
}
byte[] bytes = bytestream.toByteArray();
File dir = new File(dirname);
File file = makeFilename(name, dir);
new File(file.getParent()).mkdirs();
try {
FileOutputStream o = new FileOutputStream(file);
o.write(bytes);
o.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
private static File makeFilename(String name, File dir) {
int index = name.indexOf(".");
if (index == -1) {
return new File(dir, name + ".class");
}
return makeFilename(name.substring(index + 1, name.length()),
new File(dir, name.substring(0, index)));
}
public static boolean isInstance(PyObject inst, PyObject cls) {
// Quick test for an exact match
if (inst.getType() == cls) {
return true;
}
if (cls instanceof PyTuple) {
for (PyObject item : cls.asIterable()) {
if (isInstance(inst, item)) {
return true;
}
}
return false;
}
PyObject checkerResult;
if ((checkerResult = dispatchToChecker(inst, cls, "__instancecheck__")) != null) {
return checkerResult.__nonzero__();
}
return recursiveIsInstance(inst, cls);
}
static boolean recursiveIsInstance(PyObject inst, PyObject cls) {
if (cls instanceof PyClass && inst instanceof PyInstance) {
PyClass inClass = ((PyInstance) inst).fastGetClass();
return inClass.isSubClass((PyClass) cls);
}
if (cls instanceof PyType) {
PyType type = (PyType)cls;
//Special case PyStringMap to compare as an instance type dict.
if (inst instanceof PyStringMap &&
type.equals(PyDictionary.TYPE)) {
return true;
}
PyType instType = inst.getType();
// equiv. to PyObject_TypeCheck
if (instType == type || instType.isSubType(type)) {
return true;
}
PyObject instCls = inst.__findattr__("__class__");
if (instCls != null && instCls != instType && instCls instanceof PyType) {
return ((PyType) instCls).isSubType(type);
}
return false;
}
checkClass(cls, "isinstance() arg 2 must be a class, type, or tuple of classes and types");
PyObject instCls = inst.__findattr__("__class__");
if (instCls == null) {
return false;
}
return abstractIsSubClass(instCls, cls);
}
public static boolean isSubClass(PyObject derived, PyObject cls) {
if (cls instanceof PyTuple) {
for (PyObject item : cls.asIterable()) {
if (isSubClass(derived, item)) {
return true;
}
}
return false;
}
PyObject checkerResult;
if ((checkerResult = dispatchToChecker(derived, cls, "__subclasscheck__")) != null) {
return checkerResult.__nonzero__();
}
return recursiveIsSubClass(derived, cls);
}
static boolean recursiveIsSubClass(PyObject derived, PyObject cls) {
if (derived instanceof PyType && cls instanceof PyType) {
if (derived == cls) {
return true;
}
PyType type = (PyType)cls;
PyType subtype = (PyType)derived;
// Special case PyStringMap to compare as a subclass of
// PyDictionary. Note that we don't need to check for stringmap
// subclasses, since stringmap can't be subclassed. PyStringMap's
// TYPE is computed lazily, so we have to use PyType.fromClass :(
if (type == PyDictionary.TYPE &&
subtype == PyType.fromClass(PyStringMap.class)) {
return true;
}
return subtype.isSubType(type);
}
if (derived instanceof PyClass && cls instanceof PyClass) {
return ((PyClass) derived).isSubClass((PyClass) cls);
}
checkClass(derived, "issubclass() arg 1 must be a class");
checkClass(cls, "issubclass() arg 2 must be a class or tuple of classes");
return abstractIsSubClass(derived, cls);
}
private static boolean abstractIsSubClass(PyObject derived, PyObject cls) {
while (true) {
if (derived == cls) {
return true;
}
PyTuple bases = abstractGetBases(derived);
if (bases == null) {
return false;
}
int basesSize = bases.size();
if (basesSize == 0) {
return false;
}
if (basesSize == 1) {
// Avoid recursivity in the single inheritance case
derived = bases.pyget(0);
continue;
}
for (PyObject base : bases.asIterable()) {
if (abstractIsSubClass(base, cls)) {
return true;
}
}
return false;
}
}
/**
* Attempt to dispatch an isinstance/issubclass call to cls's associated
* __instancecheck__/__subclasscheck__.
*
* @param checkerArg the argument to call the checker with
* @param cls a Python class
* @param checkerName the checker name
* @return null if cls provides no checker, otherwise the result of calling the
* checker
*/
private static PyObject dispatchToChecker(PyObject checkerArg, PyObject cls,
String checkerName) {
//Ignore old style classes.
if (cls instanceof PyClass) {
return null;
}
/* Here we would actually like to call cls.__findattr__("__metaclass__")
* rather than cls.getType(). However there are circumstances where the
* metaclass doesn't show up as __metaclass__. On the other hand we need
* to avoid that checker refers to builtin type___subclasscheck__ or
* type___instancecheck__. Filtering out checker-instances of
* PyBuiltinMethodNarrow does the trick. We also filter out PyMethodDescr
* to shortcut some unnecessary looping.
*/
PyObject checker = cls.getType().__findattr__(checkerName);
if (checker == null || checker instanceof PyMethodDescr ||
checker instanceof PyBuiltinMethodNarrow) {
return null;
}
return checker.__call__(cls, checkerArg);
}
/**
* Return the __bases__ of cls. Returns null if no valid __bases__ are found.
*/
private static PyTuple abstractGetBases(PyObject cls) {
PyObject bases = cls.__findattr__("__bases__");
return bases instanceof PyTuple ? (PyTuple) bases : null;
}
/**
* Throw a TypeError with the specified message if cls does not appear to be a Python
* class.
*/
private static void checkClass(PyObject cls, String message) {
if (abstractGetBases(cls) == null) {
throw Py.TypeError(message);
}
}
/**
* Turn any Python iterable into an array of its elements.
*
* @param iterable to evaluate
* @return array of elements from iterable
*/
static PyObject[] make_array(PyObject iterable) {
// Special-case the common tuple and list cases, for efficiency
if (iterable instanceof PySequenceList) {
return ((PySequenceList) iterable).getArray();
} else {
int n = 10;
if (!(iterable instanceof PyGenerator)) {
try {
n = iterable.__len__(); // may be available, otherwise ...
} catch (PyException pye) { /* ... leave n at 0 */ }
}
List objs = new ArrayList(n);
for (PyObject item : iterable.asIterable()) {
objs.add(item);
}
return objs.toArray(Py.EmptyObjects);
}
}
//------------------------constructor-section---------------------------
static class py2JyClassCacheItem {
List> interfaces;
List pyClasses;
public py2JyClassCacheItem(Class> initClass, PyObject initPyClass) {
if (!initClass.isInterface()) {
throw
new IllegalArgumentException("cls must be an interface.");
}
interfaces = new ArrayList<>(1);
pyClasses = new ArrayList<>(1);
interfaces.add(initClass);
pyClasses.add(initPyClass);
}
public PyObject get(Class> cls) {
for (int i = 0; i < interfaces.size(); ++i) {
if (cls.isAssignableFrom(interfaces.get(i))) {
return pyClasses.get(i);
}
}
return null;
}
public void add(Class> cls, PyObject pyCls) {
if (!cls.isInterface()) {
throw
new IllegalArgumentException("cls must be an interface.");
}
interfaces.add(0, cls);
pyClasses.add(0, pyCls);
for (int i = interfaces.size()-1; i > 0; --i) {
if (interfaces.get(i).isAssignableFrom(cls)) {
interfaces.remove(i);
pyClasses.remove(i);
}
}
}
}
protected static PyObject ensureInterface(PyObject cls, Class> interfce) {
PyObject pjc = PyType.fromClass(interfce);
if (Py.isSubClass(cls, pjc)) {
return cls;
}
PyObject[] bases = {cls, pjc};
return Py.makeClass(interfce.getName(), bases, new PyStringMap());
}
/**
* Returns a Python-class that extends {@code cls} and {@code interfce}. If {@code cls} already
* extends {@code interfce}, simply {@code cls} is returned. Otherwise a new class is created
* (if not yet cached). It caches such classes and only creates a new one if no appropriate
* class was cached yet.
*
* @return a Python-class that extends {@code cls} and {@code interfce}
*/
public static synchronized PyObject javaPyClass(PyObject cls, Class> interfce) {
py2JyClassCacheItem cacheItem = (py2JyClassCacheItem) JyAttribute.getAttr(cls,
JyAttribute.PYCLASS_PY2JY_CACHE_ATTR);
PyObject result;
if (cacheItem == null) {
result = ensureInterface(cls, interfce);
cacheItem = new py2JyClassCacheItem(interfce, result);
JyAttribute.setAttr(cls, JyAttribute.PYCLASS_PY2JY_CACHE_ATTR, cacheItem);
} else {
result = cacheItem.get(interfce);
if (result == null) {
result = ensureInterface(cls, interfce);
cacheItem.add(interfce, result);
}
}
return result;
}
/**
* This method is a compact helper to access Python-constructors from Java. It creates an
* instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface.
* This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that
* case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the
* fly.
*
* It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* For keyword-support use {@link #newJ(PyObject, Class, String[], Object...)}.
*
* @see #newJ(PyObject, Class, PyObject[], String[])
* @see #newJ(PyObject, Class, String[], Object...)
* @see #newJ(PyModule, Class, Object...)
* @see #newJ(PyModule, Class, String[], Object...)
* @see PyModule#newJ(Class, Object...)
* @see PyModule#newJ(Class, String[], Object...)
*
* @param cls - the class to be instanciated
* @param jcls - the Java-type to be returned
* @param args are automatically converted to Jython-PyObjects
* @return an instance of cls in form of the interface jcls
*/
@SuppressWarnings("unchecked")
public static T newJ(PyObject cls, Class jcls, Object... args) {
PyObject cls2 = javaPyClass(cls, jcls);
PyObject resultPy = cls2.__call__(Py.javas2pys(args));
return (T) resultPy.__tojava__(jcls);
}
/**
* This method is a compact helper to access Python-constructors from Java. It creates an
* instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface.
* This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that
* case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the
* fly.
*
* {@code keywordss} are applied to the last {@code args} in the list.
*
* @see #newJ(PyObject, Class, Object...)
* @see #newJ(PyObject, Class, String[], Object...)
* @see #newJ(PyModule, Class, Object...)
* @see #newJ(PyModule, Class, String[], Object...)
* @see PyModule#newJ(Class, Object...)
* @see PyModule#newJ(Class, String[], Object...)
*
* @param cls - the class to be instanciated
* @param jcls - the Java-type to be returned
* @param keywords are applied to the last args
* @param args for the Python-class constructor
* @return an instance of cls in form of the interface jcls
*/
@SuppressWarnings("unchecked")
public static T newJ(PyObject cls, Class jcls, PyObject[] args, String[] keywords) {
PyObject cls2 = javaPyClass(cls, jcls);
PyObject resultPy = cls2.__call__(args, keywords);
return (T) resultPy.__tojava__(jcls);
}
/**
* This method is a compact helper to access Python-constructors from Java. It creates an
* instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface.
* This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that
* case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the
* fly.
*
* It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* {@code keywordss} are applied to the last {@code args} in the list.
*
* @see #newJ(PyObject, Class, PyObject[], String[])
* @see #newJ(PyObject, Class, Object...)
* @see #newJ(PyModule, Class, Object...)
* @see #newJ(PyModule, Class, String[], Object...)
* @see PyModule#newJ(Class, Object...)
* @see PyModule#newJ(Class, String[], Object...)
*
* @param cls - the class to be instanciated
* @param jcls - the Java-type to be returned
* @param keywords are applied to the last args
* @param args are automatically converted to Jython-PyObjects
* @return an instance of cls in form of the interface jcls
*/
@SuppressWarnings("unchecked")
public static T newJ(PyObject cls, Class jcls, String[] keywords, Object... args) {
PyObject cls2 = javaPyClass(cls, jcls);
PyObject resultPy = cls2.__call__(Py.javas2pys(args), keywords);
return (T) resultPy.__tojava__(jcls);
}
/**
* Works like {@link #newJ(PyObject, Class, Object...)}, but looks up the Python-class in the
* module-dict using the interface-name, i.e. {@code jcls.getSimpleName()}.
*
* For keywords-support use {@link #newJ(PyModule, Class, String[], Object...)}.
*
* @see #newJ(PyModule, Class, String[], Object...)
* @see #newJ(PyObject, Class, PyObject[], String[])
* @see #newJ(PyObject, Class, Object...)
* @see #newJ(PyObject, Class, String[], Object...)
* @see PyModule#newJ(Class, Object...)
* @see PyModule#newJ(Class, String[], Object...)
*
* @param module the module containing the desired class
* @param jcls Java-type of the desired clas, must have the same name
* @param args constructor-arguments
* @return a new instance of the desired class
*/
public static T newJ(PyModule module, Class jcls, Object... args) {
PyObject cls = module.__getattr__(jcls.getSimpleName().intern());
return newJ(cls, jcls, args);
}
/**
* Works like {@link #newJ(PyObject, Class, String[], Object...)}, but looks up the Python-class
* in the module-dict using the interface-name, i.e. {@code jcls.getSimpleName()}.
*
* {@code keywordss} are applied to the last {@code args} in the list.
*
* @see #newJ(PyModule, Class, Object...)
* @see #newJ(PyObject, Class, PyObject[], String[])
* @see #newJ(PyObject, Class, Object...)
* @see #newJ(PyObject, Class, String[], Object...)
* @see PyModule#newJ(Class, Object...)
* @see PyModule#newJ(Class, String[], Object...)
*
* @param module the module containing the desired class
* @param jcls Java-type of the desired class, must have the same name
* @param keywords are applied to the last {@code args} in the list
* @param args constructor-arguments
* @return a new instance of the desired class
*/
public static T newJ(PyModule module, Class jcls, String[] keywords, Object... args) {
PyObject cls = module.__getattr__(jcls.getSimpleName().intern());
return newJ(cls, jcls, keywords, args);
}
//----------------end of constructor-section------------------
}
class FixedFileWrapper extends StdoutWrapper {
private PyObject file;
public FixedFileWrapper(PyObject file) {
name = "fixed file";
this.file = file;
if (file.getJavaProxy() != null) {
Object tojava = file.__tojava__(OutputStream.class);
if (tojava != null && tojava != Py.NoConversion) {
this.file = new PyFile((OutputStream) tojava);
}
}
}
@Override
protected PyObject myFile() {
return file;
}
}
/**
* A code object wrapper for a python function.
*/
class JavaCode extends PyCode implements Traverseproc {
private PyObject func;
public JavaCode(PyObject func) {
this.func = func;
if (func instanceof PyReflectedFunction) {
this.co_name = ((PyReflectedFunction) func).__name__;
}
}
@Override
public PyObject call(ThreadState state, PyFrame frame, PyObject closure) {
/* This should actually
* throw new UnsupportedOperationException(
* "JavaCode doesn't support call with signature "+
* "(ThreadState state, PyFrame frame, PyObject closure).");
* However since this would be an API-change, for 2.7 series we just warn.
*/
Py.warning(Py.RuntimeWarning, "JavaCode doesn't support call with signature "+
"(ThreadState state, PyFrame frame, PyObject closure).");
return Py.None;
}
@Override
public PyObject call(ThreadState state, PyObject args[], String keywords[],
PyObject globals, PyObject[] defaults,
PyObject closure) {
return func.__call__(args, keywords);
}
@Override
public PyObject call(ThreadState state, PyObject self, PyObject args[], String keywords[],
PyObject globals, PyObject[] defaults,
PyObject closure) {
return func.__call__(self, args, keywords);
}
@Override
public PyObject call(ThreadState state, PyObject globals, PyObject[] defaults,
PyObject closure) {
return func.__call__();
}
@Override
public PyObject call(ThreadState state, PyObject arg1, PyObject globals,
PyObject[] defaults, PyObject closure) {
return func.__call__(arg1);
}
@Override
public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject globals,
PyObject[] defaults, PyObject closure) {
return func.__call__(arg1, arg2);
}
@Override
public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject arg3,
PyObject globals, PyObject[] defaults,
PyObject closure) {
return func.__call__(arg1, arg2, arg3);
}
@Override
public PyObject call(ThreadState state, PyObject arg1, PyObject arg2,
PyObject arg3, PyObject arg4, PyObject globals,
PyObject[] defaults, PyObject closure) {
return func.__call__(arg1, arg2, arg3, arg4);
}
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
return func != null ? visit.visit(func, arg) : 0;
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
return ob != null && ob == func;
}
}
/**
* A function object wrapper for a java method that complies with the
* PyArgsKeywordsCall standard.
*/
@Untraversable
class JavaFunc extends PyObject {
Method method;
public JavaFunc(Method method) {
this.method = method;
}
@Override
public PyObject __call__(PyObject[] args, String[] kws) {
Object[] margs = new Object[]{args, kws};
try {
return Py.java2py(method.invoke(null, margs));
} catch (Throwable t) {
throw Py.JavaError(t);
}
}
@Override
public PyObject _doget(PyObject container) {
return _doget(container, null);
}
@Override
public PyObject _doget(PyObject container, PyObject wherefound) {
if (container == null) {
return this;
}
return new PyMethod(this, container, wherefound);
}
public boolean _doset(PyObject container) {
throw Py.TypeError("java function not settable: " + method.getName());
}
}