001: // Copyright (c) Corporation for National Research Initiatives
002: package org.python.core;
003:
004: /**
005: * A python method.
006: */
007:
008: public class PyMethod extends PyObject {
009: public PyObject im_self;
010: public PyObject im_func;
011: public PyObject im_class;
012: public String __name__;
013: public PyObject __doc__;
014:
015: public PyMethod(PyObject self, PyObject f, PyObject wherefound) {
016: if (self == Py.None) {
017: self = null;
018: }
019: im_func = f;
020: im_self = self;
021: im_class = wherefound;
022: }
023:
024: public PyMethod(PyObject self, PyFunction f, PyObject wherefound) {
025: this (self, (PyObject) f, wherefound);
026: __name__ = f.__name__;
027: __doc__ = f.__doc__;
028: }
029:
030: public PyMethod(PyObject self, PyReflectedFunction f,
031: PyObject wherefound) {
032: this (self, (PyObject) f, wherefound);
033: __name__ = f.__name__;
034: __doc__ = f.__doc__;
035: }
036:
037: private static final String[] __members__ = { "im_self", "im_func",
038: "im_class", "__doc__", "__name__", "__dict__", };
039:
040: // TBD: this should be unnecessary
041: public PyObject __dir__() {
042: PyString members[] = new PyString[__members__.length];
043: for (int i = 0; i < __members__.length; i++)
044: members[i] = new PyString(__members__[i]);
045: PyList ret = new PyList(members);
046: PyObject k = im_func.__getattr__("__dict__").invoke("keys");
047: ret.extend(k);
048: return ret;
049: }
050:
051: private void throwReadonly(String name) {
052: for (int i = 0; i < __members__.length; i++)
053: if (__members__[i] == name)
054: throw Py.TypeError("readonly attribute");
055: throw Py.AttributeError(name);
056: }
057:
058: public PyObject __findattr__(String name) {
059: PyObject ret = super .__findattr__(name);
060: if (ret != null)
061: return ret;
062: return im_func.__findattr__(name);
063: }
064:
065: public void __delattr__(String name) {
066: if (name == "__doc__") {
067: throwReadonly(name);
068: }
069: im_func.__delattr__(name);
070: }
071:
072: public PyObject _doget(PyObject container) {
073: return _doget(container, null);
074: }
075:
076: public PyObject _doget(PyObject container, PyObject wherefound) {
077: /* Only if classes are compatible */
078: if (container == null || im_self != null) {
079: return this ;
080: } else if (__builtin__.issubclass(container.fastGetClass(),
081: im_class)) {
082: if (im_func instanceof PyFunction) {
083: return new PyMethod(container, (PyFunction) im_func,
084: im_class);
085: } else if (im_func instanceof PyReflectedFunction) {
086: return new PyMethod(container,
087: (PyReflectedFunction) im_func, im_class);
088: } else {
089: return new PyMethod(container, im_func, im_class);
090: }
091: } else {
092: return this ;
093: }
094: }
095:
096: public PyObject __call__(PyObject[] args, String[] keywords) {
097: if (im_self != null)
098: // bound method
099: return im_func.__call__(im_self, args, keywords);
100: // unbound method.
101: boolean badcall = false;
102: if (im_class == null)
103: // TBD: An example of this is running any function defined in
104: // the os module. If you "import os", you'll find it's a
105: // jclass object instead of a module object. Still unclear
106: // whether that's wrong, but it's definitely not easily fixed
107: // right now. Running, e.g. os.getcwd() creates an unbound
108: // method with im_class == null. For backwards compatibility,
109: // let this pass the call test
110: ;
111: else if (args.length < 1)
112: badcall = true;
113: else
114: // xxx can be faster?
115: // first argument must be an instance who's class is im_class
116: // or a subclass of im_class
117: badcall = !__builtin__.issubclass(args[0].fastGetClass(),
118: im_class);
119: if (badcall) {
120: String got = "nothing";
121: if (args.length >= 1)
122: got = class_name(args[0].fastGetClass()) + " instance";
123: throw Py.TypeError("unbound method " + __name__
124: + "() must be " + "called with "
125: + class_name(im_class)
126: + " instance as first argument" + " (got " + got
127: + " instead)");
128: } else
129: return im_func.__call__(args, keywords);
130: }
131:
132: public int __cmp__(PyObject other) {
133: if (other instanceof PyMethod) {
134: PyMethod mother = (PyMethod) other;
135: if (im_self != mother.im_self)
136: return System.identityHashCode(im_self) < System
137: .identityHashCode(mother.im_self) ? -1 : 1;
138: if (im_func != mother.im_func)
139: return System.identityHashCode(im_func) < System
140: .identityHashCode(mother.im_func) ? -1 : 1;
141: return 0;
142: }
143: return -2;
144: }
145:
146: public String safeRepr() throws PyIgnoreMethodTag {
147: return "'method' object";
148: }
149:
150: private String class_name(PyObject cls) {
151: if (cls instanceof PyClass)
152: return ((PyClass) cls).__name__;
153: if (cls instanceof PyType)
154: return ((PyType) cls).fastGetName();
155: return "?";
156: }
157:
158: public String toString() {
159: String classname = "?";
160: if (im_class != null)
161: classname = class_name(im_class);
162: if (im_self == null)
163: // this is an unbound method
164: return "<unbound method " + classname + "." + __name__
165: + ">";
166: else
167: return "<method " + classname + "." + __name__ + " of "
168: + class_name(im_self.fastGetClass()) + " instance "
169: + Py.idstr(im_self) + ">";
170: }
171: }
|