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

org.python.core.PyClass Maven / Gradle / Ivy

Go to download

Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform.

There is a newer version: 2.7.4
Show newest version
// Copyright (c) Corporation for National Research Initiatives
package org.python.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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy