Changeset 44
- Timestamp:
- 11/03/06 04:32:46 (2 years ago)
- Files:
-
- trunk/examples/testdll/testdll.d (modified) (1 diff)
- trunk/html_doc/class_wrapping.html (modified) (2 diffs)
- trunk/html_doc/index.html (modified) (1 diff)
- trunk/infrastructure/pyd/func_wrap.d (modified) (1 diff)
- trunk/infrastructure/pyd/make_object.d (modified) (2 diffs)
- trunk/infrastructure/pyd/op_wrap.d (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/examples/testdll/testdll.d
r41 r44 48 48 void foo() { 49 49 writefln("Foo.foo(): i = %s", m_i); 50 } 51 int length() { return 10; } 52 int opSlice(int i1, int i2) { 53 writefln(i1, " ", i2); 54 return 12; 55 } 56 int opIndex(int x, int y) { 57 writefln(x, " ", y); 58 return x+y; 50 59 } 51 60 Foo opAdd(Foo f) { return new Foo(m_i + f.m_i); } trunk/html_doc/class_wrapping.html
r43 r44 85 85 <p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>wrapped_class.alt_iter</code>.</p> 86 86 87 <!-- This is not yet implemented. 88 <p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code>. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p> 89 --> 87 <p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p> 90 88 91 89 <p><b>Notes on wrapped operators</b></p> … … 93 91 <dl> 94 92 <dt><code>opApply</code></dt> <dd>Pyd wraps D's iteration protocol with the help of Mikola Lysenko's StackThreads package.</dd> 95 <dt><code>opIndex, opIndexAssign</code></dt> <dd>Pyd only supports these overloads if they have precisely one index argument. This is a limitation of the Python/C API.</dd> 96 <dt><code>opSlice, opSliceAssign</code></dt> <dd>Pyd only supports these overloads if both of their two indexes are implicitly convertable to type <code>int</code>. This is a limitation of the Python/C API.</dd> 93 <dt><code>opSlice, opSliceAssign</code></dt> <dd>Pyd only supports these overloads if both of their two indexes are implicitly convertable to type <code>int</code>. This is a limitation of the Python/C API. Note that this means the zero-argument form of opSlice (for allowing the "empty slice," e.g. <code>foo[]</code>) cannot be wrapped. <i>(I may work around this in the future.)</i> Because Pyd can only automatically wrap the lexically-first method in a class, it will fail to wrap opSlice and opSliceAssign if you define an empty form first.</dd> 97 94 <dt><code>opCat, opCatAssign</code></dt> <dd>Python does not have a dedicated array concatenation operator. The plus sign (<code>+</code>) is reused for this purpose. Therefore, odd behavior may result with classes that define both <code>opAdd/opAddAssign</code> and one or both of these operators. (Consider yourself warned.) However, the Python/C API considers addition and concatenation distinct operations, and so both of these sets of operator overloads are supported.</dd> 98 95 <dt><code>opIn_r</code></dt> <dd>Python expects the <code>in</code> operator to return a boolean value (it is a containment test). D convention is for <code>in</code> to search for the value in the container, and to return a pointer to the found item, or <code>null</code> if the item is not found. That said, D does not enforce any particular signature on the <code>in</code> overload, while the Python/C API does. Pyd will check the boolean result of a call to <code>opIn_r</code>, and return that value to Python.</dd> trunk/html_doc/index.html
r42 r44 23 23 24 24 <h1>Pyd</h1> 25 <p>Pyd is a library for Dthat wraps the raw <a href="http://docs.python.org/api/api.html">Python/C API</a> with a cleaner, simpler interface. It makes exposing raw D functions and classes to Python almost trivially simple. It bears certain similarities to <a href="http://www.boost.org/libs/python/doc/">Boost.Python</a>, and indeed Boost.Python is a major influence on Pyd.</p>25 <p>Pyd is a library for the D programming language that wraps the raw <a href="http://docs.python.org/api/api.html">Python/C API</a> with a cleaner, simpler interface. It makes exposing raw D functions and classes to Python almost trivially simple. It bears certain similarities to <a href="http://www.boost.org/libs/python/doc/">Boost.Python</a>, and indeed Boost.Python is a major influence on Pyd.</p> 26 26 27 27 <p>Pyd also comes with its own extension to Python's <a href="http://docs.python.org/dist/dist.html">distutils</a>, called <a href="celerid.html">CeleriD</a>, making the building of extension modules quite easy.</p> trunk/infrastructure/pyd/func_wrap.d
r40 r44 69 69 } 70 70 71 private void setWrongArgsError(int gotArgs, uint minArgs, uint maxArgs) { 72 char[] str = "Wrong number of arguments. Got " ~ 73 toString(gotArgs) ~ 74 ", expected "; 75 if (minArgs == maxArgs) str ~= toString(minArgs) ~ "."; 76 else str ~= "between " ~ toString(minArgs) ~ " and " ~ toString(maxArgs) ~ "."; 71 void setWrongArgsError(int gotArgs, uint minArgs, uint maxArgs, char[] funcName="") { 72 char[] str; 73 if (funcName == "") { 74 str ~= "function takes "; 75 } else { 76 str ~= funcName ~ "() takes "; 77 } 78 79 char[] argStr(int args) { 80 char[] temp = toString(args) ~ " argument"; 81 if (args > 1) { 82 temp ~= "s"; 83 } 84 return temp; 85 } 86 87 if (minArgs == maxArgs) { 88 if (minArgs == 0) { 89 str ~= "no arguments"; 90 } else { 91 str ~= "exactly " ~ argStr(minArgs); 92 } 93 } 94 else if (gotArgs < minArgs) { 95 str ~= "at least " ~ argStr(minArgs); 96 } else { 97 str ~= "at most " ~ argStr(maxArgs); 98 } 99 str ~= " (" ~ toString(gotArgs) ~ " given)"; 100 77 101 PyErr_SetString(PyExc_TypeError, str ~ \0); 78 102 } trunk/infrastructure/pyd/make_object.d
r37 r44 196 196 // 197 197 // This also means that: 198 // (1) Conversion to Object will construct an object and return that.198 // (1) Conversion to DPyObject will construct an object and return that. 199 199 // (2) Any integral type smaller than a C_long (which is usually just 200 200 // an int, meaning short and byte) will use the bool conversion. … … 203 203 return o; 204 204 } else static if (is(DPyObject : T)) { 205 return new DPyObject(o );205 return new DPyObject(o, true); 206 206 } else static if (is(T == void)) { 207 207 if (o != Py_None) could_not_convert!(T)(o); trunk/infrastructure/pyd/op_wrap.d
r43 r44 31 31 32 32 private import meta.FuncMeta; 33 private import meta.Nameof; 33 34 34 35 template wrapped_class_as_number(T) { … … 77 78 template wrapped_class_as_sequence(T) { 78 79 static PySequenceMethods wrapped_class_as_sequence = { 79 null,/*sq_length*/80 length_wrap!(T), /*sq_length*/ 80 81 opCat_wrap!(T), /*sq_concat*/ 81 82 null, /*sq_repeat*/ … … 84 85 opIndexAssign_sequence_wrap!(T), /*sq_ass_item*/ 85 86 opSliceAssign_wrap!(T), /*sq_ass_slice*/ 86 null,/*sq_contains*/87 opIn_wrap!(T), /*sq_contains*/ 87 88 opCatAssign_wrap!(T), /*sq_inplace_concat*/ 88 89 null, /*sq_inplace_repeat*/ … … 98 99 } 99 100 101 //----------------// 102 // Implementation // 103 //----------------// 100 104 template opfunc_binary_wrap(T, alias opfn) { 101 105 alias wrapped_class_object!(T) wrap_object; … … 105 109 return exception_catcher(delegate PyObject*() { 106 110 auto dg = dg_wrapper((cast(wrap_object*)self).d_obj, &opfn); 107 return _py(dg(d_type!(Info.Meta.ArgType!(0))(o))); 111 pragma(msg, prettytypeof!(typeof(dg))); 112 pragma(msg, symbolnameof!(opfn)); 113 return _py( 114 dg( 115 d_type!(Info.Meta.ArgType!(0))(o) 116 ) 117 ); 108 118 }); 109 119 } … … 143 153 } 144 154 155 template opindex_mapping_pyfunc(T) { 156 alias wrapped_class_object!(T) wrap_object; 157 alias funcDelegInfoT!(typeof(&T.opIndex)) Info; 158 const uint ARGS = Info.numArgs; 159 160 // Multiple arguments are converted into tuples, and thus become a standard 161 // wrapped member function call. A single argument is passed directly. 162 static if (ARGS == 1) { 163 alias Info.Meta.ArgType!(0) KeyT; 164 extern(C) 165 PyObject* func(PyObject* self, PyObject* key) { 166 return exception_catcher(delegate PyObject*() { 167 return _py((cast(wrap_object*)self).d_obj.opIndex(d_type!(KeyT)(key))); 168 }); 169 } 170 } else { 171 extern(C) 172 PyObject* func(PyObject* self, PyObject* key) { 173 int args; 174 if (!PyTuple_CheckExact(key)) { 175 args = 1; 176 } else { 177 args = PySequence_Length(key); 178 } 179 if (ARGS != args) { 180 setWrongArgsError(args, ARGS, ARGS); 181 return null; 182 } 183 return func_wrap!(T.opIndex, ARGS, T).func(self, key); 184 } 185 } 186 } 187 145 188 template opindexassign_mapping_pyfunc(T) { 146 189 alias wrapped_class_object!(T) wrap_object; 147 190 alias funcDelegInfoT!(typeof(&T.opIndexAssign)) Info; 148 alias Info.Meta.ArgType!(0) ValT; 149 alias Info.Meta.ArgType!(1) KeyT; 150 151 extern(C) 152 int func(PyObject* self, PyObject* key, PyObject* val) { 153 return exception_catcher(delegate int() { 154 (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(ValT)(val), d_type!(KeyT)(key)); 191 const uint ARGS = Info.numArgs; 192 193 static if (ARGS > 2) { 194 extern(C) 195 int func(PyObject* self, PyObject* key, PyObject* val) { 196 int args; 197 if (!PyTuple_CheckExact(key)) { 198 args = 2; 199 } else { 200 args = PySequence_Length(key) + 1; 201 } 202 if (ARGS != args) { 203 setWrongArgsError(args, ARGS, ARGS); 204 return -1; 205 } 206 // Build a new tuple with the value at the front. 207 PyObject* temp = PyTuple_New(ARGS); 208 if (temp is null) return -1; 209 scope(exit) Py_DECREF(temp); 210 PyTuple_SetItem(temp, 0, val); 211 for (int i=1; i<ARGS; ++i) { 212 Py_INCREF(PyTuple_GetItem(key, i-1)); 213 PyTuple_SetItem(temp, i, PyTuple_GetItem(key, i-1)); 214 } 215 func_wrap!(T.opIndexAssign, ARGS, T).func(self, temp); 155 216 return 0; 156 }); 217 } 218 } else { 219 alias Info.Meta.ArgType!(0) ValT; 220 alias Info.Meta.ArgType!(1) KeyT; 221 222 extern(C) 223 int func(PyObject* self, PyObject* key, PyObject* val) { 224 return exception_catcher(delegate int() { 225 (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(ValT)(val), d_type!(KeyT)(key)); 226 return 0; 227 }); 228 } 157 229 } 158 230 } … … 217 289 } 218 290 219 // The rest of the file is composed of these short stubs 291 template length_pyfunc(T) { 292 alias wrapped_class_object!(T) wrap_object; 293 294 extern(C) 295 int func(PyObject* self) { 296 return exception_catcher(delegate int() { 297 return (cast(wrap_object*)self).d_obj.length(); 298 }); 299 } 300 } 301 302 //----------// 303 // Dispatch // 304 //----------// 305 template length_wrap(T) { 306 static if ( 307 is(typeof(&T.length)) && 308 is(typeof(&T.length()) : int) 309 ) { 310 const inquiry length_wrap = &length_pyfunc!(T).func; 311 } else { 312 const inquiry length_wrap = null; 313 } 314 } 315 220 316 template opIndex_sequence_wrap(T) { 221 317 static if ( … … 245 341 static if ( 246 342 is(typeof(&T.opIndex)) && 247 funcDelegInfoT!(typeof(&T.opIndex)).numArgs == 1 &&248 !is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int) 343 (funcDelegInfoT!(typeof(&T.opIndex)).numArgs > 1 || 344 !is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int)) 249 345 ) { 250 const binaryfunc opIndex_mapping_wrap = &op func_binary_wrap!(T, T.opIndex).func;346 const binaryfunc opIndex_mapping_wrap = &opindex_mapping_pyfunc!(T).func; 251 347 } else { 252 348 const binaryfunc opIndex_mapping_wrap = null; … … 257 353 static if ( 258 354 is(typeof(&T.opIndexAssign)) && 259 funcDelegInfoT!(typeof(&T.opIndexAssign)).numArgs == 2 &&260 !is(funcDelegInfoT!(typeof(&T.opIndexAssign)).Meta.ArgType!(1) : int) 355 (funcDelegInfoT!(typeof(&T.opIndexAssign)).numArgs > 2 || 356 !is(funcDelegInfoT!(typeof(&T.opIndexAssign)).Meta.ArgType!(1) : int)) 261 357 ) { 262 358 const objobjargproc opIndexAssign_mapping_wrap = &opindexassign_mapping_pyfunc!(T).func; … … 273 369 is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(1) : int) 274 370 ) { 275 const intintargfunc opSlice_wrap = opslice_pyfunc!(T).func;371 const intintargfunc opSlice_wrap = &opslice_pyfunc!(T).func; 276 372 } else { 277 373 const intintargfunc opSlice_wrap = null; … … 286 382 is(funcDelegInfoT!(typeof(&T.opSlice)).Meta.ArgType!(2) : int) 287 383 ) { 288 const intintobjargproc opSliceAssign_wrap = opsliceassign_pyfunc!(T).func;384 const intintobjargproc opSliceAssign_wrap = &opsliceassign_pyfunc!(T).func; 289 385 } else { 290 386 const intintobjargproc opSliceAssign_wrap = null; … … 509 605 template opIn_wrap(T) { 510 606 static if (is(typeof(&T.opIn_r))) { 511 const binaryfunc opIn_wrap = &opin_wrap.func;512 } else { 513 const binaryfunc opIn_wrap = null;607 const objobjproc opIn_wrap = &opin_wrap.func; 608 } else { 609 const objobjproc opIn_wrap = null; 514 610 } 515 611 }
