org.python.core.PyClass Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-slim Show documentation
Show all versions of jython-slim Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
import org.python.core.finalization.FinalizeTrigger;
/**
* The classic Python class.
*/
@ExposedType(name = "classobj", isBaseType = false)
public class PyClass extends PyObject implements Traverseproc {
public static final PyType TYPE = PyType.fromClass(PyClass.class);
/** Holds the namespace for this class */
public PyObject __dict__;
/** The base classes of this class */
public PyTuple __bases__;
/** The name of this class */
public String __name__;
// Store these methods for performance optimization. These are only used by PyInstance
PyObject __getattr__, __setattr__, __delattr__, __tojava__, __del__, __contains__;
/**
* Create a new instance of a Python classic class.
*/
private PyClass() {
super(TYPE);
}
@ExposedNew
public static PyObject classobj___new__(PyNewWrapper new_, boolean init, PyType subtype,
PyObject[] args, String[] keywords) {
ArgParser ap = new ArgParser("function", args, keywords, "name", "bases", "dict");
PyObject name = ap.getPyObject(0);
PyObject bases = ap.getPyObject(1);
PyObject dict = ap.getPyObject(2);
return classobj___new__(name, bases, dict);
}
public static PyObject classobj___new__(PyObject name, PyObject bases, PyObject dict) {
if (!name.getType().isSubType(PyString.TYPE)) {
throw Py.TypeError("PyClass_New: name must be a string");
}
if (!(dict instanceof AbstractDict)) {
throw Py.TypeError("PyClass_New: dict must be a dictionary");
}
PyType.ensureDoc(dict);
PyType.ensureModule(dict);
if (!(bases instanceof PyTuple)) {
throw Py.TypeError("PyClass_New: bases must be a tuple");
}
PyTuple basesTuple = (PyTuple)bases;
for (PyObject base : basesTuple.getArray()) {
if (!(base instanceof PyClass)) {
if (base.getType().isCallable()) {
return base.getType().__call__(name, bases, dict);
} else {
throw Py.TypeError("PyClass_New: base must be a class");
}
}
}
PyClass klass = new PyClass();
klass.__name__ = name.toString();
klass.__bases__ = basesTuple;
klass.__dict__ = dict;
klass.cacheDescriptors();
return klass;
}
/**
* Setup cached references to methods where performance really counts
*/
private void cacheDescriptors() {
__getattr__ = lookup("__getattr__");
__setattr__ = lookup("__setattr__");
__delattr__ = lookup("__delattr__");
__tojava__ = lookup("__tojava__");
__del__ = lookup("__del__");
__contains__ = lookup("__contains__");
}
PyObject lookup(String name) {
PyObject result = __dict__.__finditem__(name);
if (result == null && __bases__ != null) {
for (PyObject base : __bases__.getArray()) {
result = ((PyClass)base).lookup(name);
if (result != null) {
break;
}
}
}
return result;
}
@Override
public PyObject fastGetDict() {
return __dict__;
}
@Override
public PyObject __findattr_ex__(String name) {
if (name == "__dict__") {
return __dict__;
}
if (name == "__bases__") {
return __bases__;
}
if (name == "__name__") {
return Py.newString(__name__);
}
PyObject result = lookup(name);
if (result == null) {
return result;
}
return result.__get__(null, this);
}
@Override
public void __setattr__(String name, PyObject value) {
if (name == "__dict__") {
setDict(value);
return;
} else if (name == "__bases__") {
setBases(value);
return;
} else if (name == "__name__") {
setName(value);
return;
} else if (name == "__getattr__") {
__getattr__ = value;
return;
} else if (name == "__setattr__") {
__setattr__ = value;
return;
} else if (name == "__delattr__") {
__delattr__ = value;
return;
} else if (name == "__tojava__") {
__tojava__ = value;
return;
} else if (name == "__del__") {
__del__ = value;
return;
} else if (name == "__contains__") {
__contains__ = value;
return;
}
if (value == null) {
try {
__dict__.__delitem__(name);
} catch (PyException pye) {
noAttributeError(name);
}
}
__dict__.__setitem__(name, value);
}
@Override
public void __delattr__(String name) {
__setattr__(name, null);
}
@Override
public void __rawdir__(PyDictionary accum) {
mergeClassDict(accum, this);
}
/**
* Customized AttributeError for class objects.
*/
@Override
public void noAttributeError(String name) {
throw Py.AttributeError(String.format("class %.50s has no attribute '%.400s'", __name__,
name));
}
@Override
public PyObject __call__(PyObject[] args, String[] keywords) {
PyInstance inst;
inst = new PyInstance(this);
if (__del__ != null) {
FinalizeTrigger.ensureFinalizer(inst);
}
inst.__init__(args, keywords);
return inst;
}
@Override
public boolean isCallable() {
return true;
}
/* PyClass's are compared based on __name__ */
@Override
public int __cmp__(PyObject other) {
if (!(other instanceof PyClass)) {
return -2;
}
int c = __name__.compareTo(((PyClass) other).__name__);
return c < 0 ? -1 : c > 0 ? 1 : 0;
}
@Override
public PyString __str__() {
// Current CPython standard is that str(class) prints as
// module.class. If the class has no module, then just the class
// name is printed.
if (__dict__ == null) {
return new PyString(__name__);
}
PyObject mod = __dict__.__finditem__("__module__");
if (mod == null || !(mod instanceof PyString)) {
return new PyString(__name__);
}
String smod = ((PyString) mod).toString();
return new PyString(smod + "." + __name__);
}
@Override
public String toString() {
PyObject mod = __dict__.__finditem__("__module__");
String modStr = (mod == null || !Py.isInstance(mod, PyString.TYPE)) ? "?" : mod.toString();
return String.format("", modStr, __name__, Py.idstr(this));
}
public boolean isSubClass(PyClass superclass) {
if (this == superclass) {
return true;
}
if (__bases__ == null || superclass.__bases__ == null) {
return false;
}
for (PyObject base: __bases__.getArray()) {
if (((PyClass)base).isSubClass(superclass)) {
return true;
}
}
return false;
}
public void setDict(PyObject value) {
if (value == null || !(value instanceof AbstractDict)) {
throw Py.TypeError("__dict__ must be a dictionary object");
}
__dict__ = value;
}
public void setBases(PyObject value) {
if (value == null || !(value instanceof PyTuple)) {
throw Py.TypeError("__bases__ must be a tuple object");
}
PyTuple bases = (PyTuple)value;
for (PyObject base : bases.getArray()) {
if (!(base instanceof PyClass)) {
throw Py.TypeError("__bases__ items must be classes");
}
if (((PyClass)base).isSubClass(this)) {
throw Py.TypeError("a __bases__ item causes an inheritance cycle");
}
}
__bases__ = bases;
}
public void setName(PyObject value) {
if (value == null || !Py.isInstance(value, PyString.TYPE)) {
throw Py.TypeError("__name__ must be a string object");
}
String name = value.toString();
if (name.contains("\u0000")) {
throw Py.TypeError("__name__ must not contain null bytes");
}
__name__ = name;
}
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
int retVal;
if (__bases__ != null) {
retVal = visit.visit(__bases__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__dict__ != null) {
retVal = visit.visit(__dict__, arg);
if (retVal != 0) {
return retVal;
}
}
//CPython also traverses the name, which is not stored
//as a PyObject in Jython.
//Py_VISIT(o->cl_name);
if (__getattr__ != null) {
retVal = visit.visit(__getattr__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__setattr__ != null) {
retVal = visit.visit(__setattr__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__delattr__ != null) {
retVal = visit.visit(__delattr__, arg);
if (retVal != 0) {
return retVal;
}
}
/* Jython-only */
if (__tojava__ != null) {
retVal = visit.visit(__tojava__, arg);
if (retVal != 0) {
return retVal;
}
}
if (__del__ != null) {
retVal = visit.visit(__del__, arg);
if (retVal != 0) {
return retVal;
}
}
return __contains__ != null ? visit.visit(__contains__, arg) : 0;
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
return ob != null && (__dict__ == ob || __bases__ == ob
|| __getattr__ == ob || __setattr__ == ob || __delattr__ == ob
|| __tojava__ == ob || __del__ == ob || __contains__ == ob);
}
}