/* Copyright (c) Jython Developers */ package org.python.core; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; /** * The Python super type. */ @ExposedType(name = "super", doc = BuiltinDocs.super_doc) public class PySuper extends PyObject { public static final PyType TYPE = PyType.fromClass(PySuper.class); @ExposedGet(name = "__thisclass__", doc = BuiltinDocs.super___thisclass___doc) protected PyType superType; @ExposedGet(name = "__self__", doc = BuiltinDocs.super___self___doc) protected PyObject obj; @ExposedGet(name = "__self_class__", doc = BuiltinDocs.super___self_class___doc) protected PyType objType; public PySuper() { this(TYPE); } public PySuper(PyType subType) { super(subType); } @ExposedMethod @ExposedNew public void super___init__(PyObject[] args, String[] keywords) { if (keywords.length != 0 || !PyBuiltinCallable.DefaultInfo.check(args.length, 1, 2)) { throw PyBuiltinCallable.DefaultInfo.unexpectedCall(args.length, keywords.length != 0, "super", 1, 2); } if (!(args[0] instanceof PyType)) { throw Py.TypeError("super: argument 1 must be type"); } PyType type = (PyType)args[0]; PyObject obj = null; PyType objType = null; if (args.length == 2 && args[1] != Py.None) { obj = args[1]; } if (obj != null) { objType = supercheck(type, obj); } this.superType = type; this.obj = obj; this.objType = objType; } /** * Check that a super() call makes sense. Return a type object. * * obj can be a new-style class, or an instance of one: * * - If it is a class, it must be a subclass of 'type'. This case is used for class * methods; the return value is obj. * * - If it is an instance, it must be an instance of 'type'. This is the normal case; * the return value is obj.__class__. * * But... when obj is an instance, we want to allow for the case where objType is not * a subclass of type, but obj.__class__ is! This will allow using super() with a * proxy for obj. * * @param type the PyType superType associated with the super * @param obj a the PyObject obj associated with the super * @return a PyType superType */ private PyType supercheck(PyType type, PyObject obj) { // Check for first bullet above (special case) if (obj instanceof PyType && ((PyType)obj).isSubType(type)) { return (PyType)obj; } // Normal case PyType objType = obj.getType(); if (objType.isSubType(type)) { return objType; } else { // Try the slow way PyObject classAttr = obj.__findattr__("__class__"); if (classAttr != null && classAttr instanceof PyType) { if (((PyType)classAttr).isSubType(type)) { return (PyType)classAttr; } } } throw Py.TypeError("super(type, obj): obj must be an instance or subtype of type"); } public PyObject __findattr_ex__(String name) { return super___findattr_ex__(name); } final PyObject super___findattr_ex__(String name) { if (objType != null && name != "__class__") { PyObject descr = objType.super_lookup(superType, name); if (descr != null) { return descr.__get__(objType == obj ? null : obj, objType); } } return super.__findattr_ex__(name); } @ExposedMethod(doc = BuiltinDocs.super___getattribute___doc) final PyObject super___getattribute__(PyObject name) { PyObject ret = super___findattr_ex__(asName(name)); if (ret == null) { noAttributeError(asName(name)); } return ret; } public PyObject __get__(PyObject obj, PyObject type) { return super___get__(obj, type); } @ExposedMethod(defaults = "null", doc = BuiltinDocs.super___get___doc) final PyObject super___get__(PyObject obj, PyObject type) { if (obj == null || obj == Py.None || this.obj != null) { return this; } if (getType() != TYPE) { // If an instance of a (strict) subclass of super, call its type return getType().__call__(type, obj); } else { // Inline the common case PyType objType = supercheck(this.superType, obj); PySuper newsuper = new PySuper(); newsuper.superType = this.superType; newsuper.obj = obj; newsuper.objType = objType; return newsuper; } } public String toString() { String superTypeName = superType != null ? superType.fastGetName() : "NULL"; if (objType != null) { return String.format("<super: <class '%s'>, <%s object>>", superTypeName, objType.fastGetName()); } else { return String.format("<super: <class '%s'>, NULL>", superTypeName); } } public PyType getSuperType() { return superType; } public PyObject getObj() { return obj; } public PyType getObjType() { return objType; } }