| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 122d3af commit 94260ae
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -133,6 +133,13 @@ private static ClassBase CreateClass(Type type) { | |||
| 133 | 133 | // required that the ClassObject.ctors be changed to internal | |
| 134 | 134 | if (co != null) { | |
| 135 | 135 | if (co.ctors.Length > 0) { | |
| 136 | + // Implement Overloads on the class object | ||
| 137 | + ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); | ||
| 138 | + // ExtensionType types are untracked, so don't Incref() them. | ||
| 139 | + // XXX deprecate __overloads__ soon... | ||
| 140 | + Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); | ||
| 141 | + Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); | ||
| 142 | + | ||
| 136 | 143 | IntPtr doc = co.GetDocString(); | |
| 137 | 144 | Runtime.PyDict_SetItemString(dict, "__doc__", doc); | |
| 138 | 145 | Runtime.Decref(doc); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,238 @@ | |||
| 1 | + // ========================================================================== | ||
| 2 | + // This software is subject to the provisions of the Zope Public License, | ||
| 3 | + // Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. | ||
| 4 | + // THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
| 5 | + // WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| 6 | + // WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
| 7 | + // FOR A PARTICULAR PURPOSE. | ||
| 8 | + // ========================================================================== | ||
| 9 | + | ||
| 10 | + using System; | ||
| 11 | + using System.Reflection; | ||
| 12 | + | ||
| 13 | + namespace Python.Runtime { | ||
| 14 | + | ||
| 15 | + /// <summary> | ||
| 16 | + /// Implements a Python type that wraps a CLR ctor call. Constructor objects | ||
| 17 | + /// support a .Overloads[] syntax to allow explicit ctor overload selection. | ||
| 18 | + /// </summary> | ||
| 19 | + /// <remarks> | ||
| 20 | + /// ClassManager stores a ConstructorBinding instance in the class's __dict__['Overloads'] | ||
| 21 | + /// | ||
| 22 | + /// SomeType.Overloads[Type, ...] works like this: | ||
| 23 | + /// 1) Python retreives the Overloads attribute from this ClassObject's dictionary normally | ||
| 24 | + /// and finds a non-null tp_descr_get slot which is called by the interpreter | ||
| 25 | + /// and returns an IncRef()ed pyHandle to itself. | ||
| 26 | + /// 2) The ConstructorBinding object handles the [] syntax in its mp_subscript by matching | ||
| 27 | + /// the Type object parameters to a contructor overload using Type.GetConstructor() | ||
| 28 | + /// [NOTE: I don't know why method overloads are not searched the same way.] | ||
| 29 | + /// and creating the BoundContructor oject which contains ContructorInfo object. | ||
| 30 | + /// 3) In tp_call, if ctorInfo is not null, ctorBinder.InvokeRaw() is called. | ||
| 31 | + /// </remarks> | ||
| 32 | + internal class ConstructorBinding : ExtensionType | ||
| 33 | + { | ||
| 34 | + Type type; // The managed Type being wrapped in a ClassObject | ||
| 35 | + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. | ||
| 36 | + ConstructorBinder ctorBinder; | ||
| 37 | + IntPtr repr; | ||
| 38 | + | ||
| 39 | + public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() { | ||
| 40 | + this.type = type; | ||
| 41 | + Runtime.Incref(pyTypeHndl); | ||
| 42 | + this.pyTypeHndl = pyTypeHndl; | ||
| 43 | + this.ctorBinder = ctorBinder; | ||
| 44 | + repr = IntPtr.Zero; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /// <summary> | ||
| 48 | + /// Descriptor __get__ implementation. | ||
| 49 | + /// Implements a Python type that wraps a CLR ctor call that requires the use | ||
| 50 | + /// of a .Overloads[pyTypeOrType...] syntax to allow explicit ctor overload | ||
| 51 | + /// selection. | ||
| 52 | + /// </summary> | ||
| 53 | + /// <param name="op"> PyObject* to a Constructors wrapper </param> | ||
| 54 | + /// <param name="instance"> the instance that the attribute was accessed through, | ||
| 55 | + /// or None when the attribute is accessed through the owner </param> | ||
| 56 | + /// <param name="owner"> always the owner class </param> | ||
| 57 | + /// <returns> a CtorMapper (that borrows a reference to this python type and the | ||
| 58 | + /// ClassObject's ConstructorBinder) wrapper. </returns> | ||
| 59 | + /// | ||
| 60 | + /// <remarks> | ||
| 61 | + /// Python 2.6.5 docs: | ||
| 62 | + /// object.__get__(self, instance, owner) | ||
| 63 | + /// Called to get the attribute of the owner class (class attribute access) | ||
| 64 | + /// or of an instance of that class (instance attribute access). | ||
| 65 | + /// owner is always the owner class, while instance is the instance that | ||
| 66 | + /// the attribute was accessed through, or None when the attribute is accessed through the owner. | ||
| 67 | + /// This method should return the (computed) attribute value or raise an AttributeError exception. | ||
| 68 | + /// </remarks> | ||
| 69 | + public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) | ||
| 70 | + { | ||
| 71 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); | ||
| 72 | + if (self == null) { | ||
| 73 | + return IntPtr.Zero; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + // It doesn't seem to matter if it's accessed through an instance (rather than via the type). | ||
| 77 | + /*if (instance != IntPtr.Zero) { | ||
| 78 | + // This is ugly! PyObject_IsInstance() returns 1 for true, 0 for false, -1 for error... | ||
| 79 | + if (Runtime.PyObject_IsInstance(instance, owner) < 1) { | ||
| 80 | + return Exceptions.RaiseTypeError("How in the world could that happen!"); | ||
| 81 | + } | ||
| 82 | + }*/ | ||
| 83 | + /* Since ExtensionType calls Runtime.PyObject_GC_UnTrack(py), don't | ||
| 84 | + Runtime.Incref(self.pyHandle); // Decref'd by the interpreter??? */ | ||
| 85 | + return self.pyHandle; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + //==================================================================== | ||
| 89 | + // Implement explicit overload selection using subscript syntax ([]). | ||
| 90 | + //==================================================================== | ||
| 91 | + /// <summary> | ||
| 92 | + /// ConstructorBinding.GetItem(PyObject *o, PyObject *key) | ||
| 93 | + /// Return element of o corresponding to the object key or NULL on failure. | ||
| 94 | + /// This is the equivalent of the Python expression o[key]. | ||
| 95 | + /// </summary> | ||
| 96 | + /// <param name="tp"></param> | ||
| 97 | + /// <param name="idx"></param> | ||
| 98 | + /// <returns></returns> | ||
| 99 | + public static IntPtr mp_subscript(IntPtr op, IntPtr key) { | ||
| 100 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); | ||
| 101 | + | ||
| 102 | + Type[] types = Runtime.PythonArgsToTypeArray(key); | ||
| 103 | + if (types == null) { | ||
| 104 | + return Exceptions.RaiseTypeError("type(s) expected"); | ||
| 105 | + } | ||
| 106 | + //MethodBase[] methBaseArray = self.ctorBinder.GetMethods(); | ||
| 107 | + //MethodBase ci = MatchSignature(methBaseArray, types); | ||
| 108 | + ConstructorInfo ci = self.type.GetConstructor(types); | ||
| 109 | + if (ci == null) { | ||
| 110 | + string msg = "No match found for constructor signature"; | ||
| 111 | + return Exceptions.RaiseTypeError(msg); | ||
| 112 | + } | ||
| 113 | + BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); | ||
| 114 | + | ||
| 115 | + /* Since ExtensionType calls Runtime.PyObject_GC_UnTrack(py), don't | ||
| 116 | + Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ | ||
| 117 | + return boundCtor.pyHandle; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + //==================================================================== | ||
| 121 | + // ConstructorBinding __repr__ implementation [borrowed from MethodObject]. | ||
| 122 | + //==================================================================== | ||
| 123 | + | ||
| 124 | + public static IntPtr tp_repr(IntPtr ob) { | ||
| 125 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); | ||
| 126 | + if (self.repr != IntPtr.Zero) { | ||
| 127 | + Runtime.Incref(self.repr); | ||
| 128 | + return self.repr; | ||
| 129 | + } | ||
| 130 | + MethodBase[] methods = self.ctorBinder.GetMethods(); | ||
| 131 | + string name = self.type.Name; | ||
| 132 | + string doc = ""; | ||
| 133 | + for (int i = 0; i < methods.Length; i++) { | ||
| 134 | + if (doc.Length > 0) | ||
| 135 | + doc += "\n"; | ||
| 136 | + string str = methods[i].ToString(); | ||
| 137 | + int idx = str.IndexOf("("); | ||
| 138 | + doc += String.Format("{0}{1}", name, str.Substring(idx)); | ||
| 139 | + } | ||
| 140 | + self.repr = Runtime.PyString_FromString(doc); | ||
| 141 | + Runtime.Incref(self.repr); | ||
| 142 | + return self.repr; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + //==================================================================== | ||
| 146 | + // ConstructorBinding dealloc implementation. | ||
| 147 | + //==================================================================== | ||
| 148 | + | ||
| 149 | + public static new void tp_dealloc(IntPtr ob) { | ||
| 150 | + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); | ||
| 151 | + Runtime.Decref(self.repr); | ||
| 152 | + Runtime.Decref(self.pyTypeHndl); | ||
| 153 | + ExtensionType.FinalizeObject(self); | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + /// <summary> | ||
| 158 | + /// Implements a Python type that constucts the given Type given a particular ContructorInfo. | ||
| 159 | + /// </summary> | ||
| 160 | + /// <remarks> | ||
| 161 | + /// Here mostly because I wanted a new __repr__ function for the selected constructor. | ||
| 162 | + /// An earlier implementation hung the __call__ on the ContructorBinding class and | ||
| 163 | + /// returned an Incref()ed self.pyHandle from the __get__ function. | ||
| 164 | + /// </remarks> | ||
| 165 | + internal class BoundContructor : ExtensionType { | ||
| 166 | + Type type; // The managed Type being wrapped in a ClassObject | ||
| 167 | + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. | ||
| 168 | + ConstructorBinder ctorBinder; | ||
| 169 | + ConstructorInfo ctorInfo; | ||
| 170 | + IntPtr repr; | ||
| 171 | + | ||
| 172 | + public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci) | ||
| 173 | + : base() { | ||
| 174 | + this.type = type; | ||
| 175 | + Runtime.Incref(pyTypeHndl); | ||
| 176 | + this.pyTypeHndl = pyTypeHndl; | ||
| 177 | + this.ctorBinder = ctorBinder; | ||
| 178 | + ctorInfo = ci; | ||
| 179 | + repr = IntPtr.Zero; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + /// <summary> | ||
| 183 | + /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw) | ||
| 184 | + /// </summary> | ||
| 185 | + /// <param name="ob"> PyObject *callable_object </param> | ||
| 186 | + /// <param name="args"> PyObject *args </param> | ||
| 187 | + /// <param name="kw"> PyObject *kw </param> | ||
| 188 | + /// <returns> A reference to a new instance of the class by invoking the selected ctor(). </returns> | ||
| 189 | + public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) { | ||
| 190 | + BoundContructor self = (BoundContructor)GetManagedObject(op); | ||
| 191 | + // Even though a call with null ctorInfo just produces the old behavior | ||
| 192 | + /*if (self.ctorInfo == null) { | ||
| 193 | + string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]"; | ||
| 194 | + return Exceptions.RaiseTypeError(msg); | ||
| 195 | + }*/ | ||
| 196 | + // Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr | ||
| 197 | + // which will fire self.ctorInfo using ConstructorInfo.Invoke(). | ||
| 198 | + Object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); | ||
| 199 | + if (obj == null) { | ||
| 200 | + // XXX set an error | ||
| 201 | + return IntPtr.Zero; | ||
| 202 | + } | ||
| 203 | + // Instantiate the python object that wraps the result of the method call | ||
| 204 | + // and return the PyObject* to it. | ||
| 205 | + return CLRObject.GetInstHandle(obj, self.pyTypeHndl); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + //==================================================================== | ||
| 209 | + // BoundContructor __repr__ implementation [borrowed from MethodObject]. | ||
| 210 | + //==================================================================== | ||
| 211 | + | ||
| 212 | + public static IntPtr tp_repr(IntPtr ob) { | ||
| 213 | + BoundContructor self = (BoundContructor)GetManagedObject(ob); | ||
| 214 | + if (self.repr != IntPtr.Zero) { | ||
| 215 | + Runtime.Incref(self.repr); | ||
| 216 | + return self.repr; | ||
| 217 | + } | ||
| 218 | + string name = self.type.FullName; | ||
| 219 | + string str = self.ctorInfo.ToString(); | ||
| 220 | + int idx = str.IndexOf("("); | ||
| 221 | + str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); | ||
| 222 | + self.repr = Runtime.PyString_FromString(str); | ||
| 223 | + Runtime.Incref(self.repr); | ||
| 224 | + return self.repr; | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + //==================================================================== | ||
| 228 | + // ConstructorBinding dealloc implementation. | ||
| 229 | + //==================================================================== | ||
| 230 | + | ||
| 231 | + public static new void tp_dealloc(IntPtr ob) { | ||
| 232 | + BoundContructor self = (BoundContructor)GetManagedObject(ob); | ||
| 233 | + Runtime.Decref(self.repr); | ||
| 234 | + Runtime.Decref(self.pyTypeHndl); | ||
| 235 | + ExtensionType.FinalizeObject(self); | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments