1 /* 2 Copyright 2006, 2007 Kirk McDonald 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy of 5 this software and associated documentation files (the "Software"), to deal in 6 the Software without restriction, including without limitation the rights to 7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 of the Software, and to permit persons to whom the Software is furnished to do 9 so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 */ 22 23 /++ 24 This module contains some useful type conversion functions. The two 25 most interesting operations here are python_to_d and d_to_python. 26 27 Additionally, the py function is provided as a convenience to directly 28 convert a D object into an instance of PydObject. 29 30 To convert a PydObject to a D type, use PydObject.to_d. 31 +/ 32 module pyd.make_object; 33 34 import deimos.python.Python; 35 36 import std.array; 37 import std.algorithm; 38 import std.complex; 39 import std.typetuple; 40 import std.bigint; 41 import std.datetime; 42 import std.traits; 43 import std.typecons; 44 import std.conv; 45 import std.range; 46 import std.stdio; 47 48 import core.stdc..string : memcpy, strlen; 49 50 import pyd.references; 51 import pyd.pydobject; 52 import pyd.class_wrap; 53 import pyd.struct_wrap; 54 import pyd.func_wrap; 55 import pyd.def; 56 import pyd.exception; 57 import std..string: format; 58 59 60 shared static this() { 61 init_rangewrapper(); 62 } 63 64 void init_rangewrapper() { 65 version(PydPythonExtension) { 66 on_py_init({ 67 wrap_struct!(RangeWrapper, 68 Def!(RangeWrapper.iter, PyName!"__iter__"), 69 Def!(RangeWrapper.next))(); 70 rangeWrapperInited = true; 71 }, PyInitOrdering.After); 72 }else{ 73 on_py_init( { 74 add_module!(ModuleName!"pyd")(); 75 }); 76 on_py_init( { 77 wrap_struct!(RangeWrapper, 78 ModuleName!"pyd", 79 Def!(RangeWrapper.iter, PyName!"__iter__"), 80 Def!(RangeWrapper.next))(); 81 rangeWrapperInited = true; 82 }, PyInitOrdering.After); 83 } 84 } 85 86 bool rangeWrapperInited = false; 87 88 class to_conversion_wrapper(dg_t) { 89 alias ParameterTypeTuple!(dg_t)[0] T; 90 alias ReturnType!(dg_t) Intermediate; 91 dg_t dg; 92 this(dg_t fn) { dg = fn; } 93 PyObject* opCall(T t) { 94 static if (is(Intermediate == PyObject*)) { 95 return dg(t); 96 } else { 97 return d_to_python(dg(t)); 98 } 99 } 100 } 101 class from_conversion_wrapper(dg_t) { 102 alias ParameterTypeTuple!(dg_t)[0] Intermediate; 103 alias ReturnType!(dg_t) T; 104 dg_t dg; 105 this(dg_t fn) { dg = fn; } 106 T opCall(PyObject* o) { 107 static if (is(Intermediate == PyObject*)) { 108 return dg(o); 109 } else { 110 return dg(python_to_d!(Intermediate)(o)); 111 } 112 } 113 } 114 115 template to_converter_registry(From) { 116 PyObject* delegate(From) dg=null; 117 } 118 template from_converter_registry(To) { 119 To delegate(PyObject*) dg=null; 120 } 121 122 /** 123 Extend pyd's conversion mechanism. Will be used by d_to_python only if d_to_python cannot 124 convert its argument by regular means. 125 126 Params: 127 dg = A callable which takes a D type and returns a PyObject*, or any 128 type convertible by d_to_python. 129 */ 130 void ex_d_to_python(dg_t) (dg_t dg) { 131 static if (is(dg_t == delegate) && is(ReturnType!(dg_t) == PyObject*)) { 132 to_converter_registry!(ParameterTypeTuple!(dg_t)[0]).dg = dg; 133 } else { 134 auto o = new to_conversion_wrapper!(dg_t)(dg); 135 to_converter_registry!(typeof(o).T).dg = &o.opCall; 136 } 137 } 138 139 /** 140 Extend pyd's conversion mechanims. Will be used by python_to_d only if python_to_d 141 cannot convert its argument by regular means. 142 143 Params: 144 dg = A callable which takes a PyObject*, or any type convertible by python_to_d, 145 and returns a D type. 146 */ 147 void ex_python_to_d(dg_t) (dg_t dg) { 148 static if (is(dg_t == delegate) && is(ParameterTypeTuple!(dg_t)[0] == PyObject*)) { 149 from_converter_registry!(ReturnType!(dg_t)).dg = dg; 150 } else { 151 auto o = new from_conversion_wrapper!(dg_t)(dg); 152 from_converter_registry!(typeof(o).T).dg = &o.opCall; 153 } 154 } 155 156 /** 157 * Returns a new (owned) reference to a Python object based on the passed 158 * argument. If the passed argument is a PyObject*, this "steals" the 159 * reference. (In other words, it returns the PyObject* without changing its 160 * reference count.) If the passed argument is a PydObject, this returns a new 161 * reference to whatever the PydObject holds a reference to. 162 * 163 * If the passed argument can't be converted to a PyObject, a Python 164 * RuntimeError will be raised and this function will return null. 165 */ 166 PyObject* d_to_python(T) (T t) { 167 static if (!is(T == PyObject*) && is(typeof(t is null)) && 168 !isAssociativeArray!T && !isArray!T) { 169 if (t is null) { 170 return Py_INCREF(Py_None()); 171 } 172 } 173 static if (isBoolean!T) { 174 return Py_INCREF(t ? Py_True : Py_False); 175 } else static if(isIntegral!T) { 176 static if(isUnsigned!T) { 177 return PyLong_FromUnsignedLongLong(t); 178 }else static if(isSigned!T) { 179 return PyLong_FromLongLong(t); 180 } 181 } else static if (isFloatingPoint!T) { 182 return PyFloat_FromDouble(t); 183 } else static if( isTuple!T) { 184 return d_tuple_to_python!T(t); 185 } else static if (is(T == DateTime)) { 186 if(PyDateTimeAPI is null) { 187 PyDateTime_IMPORT(); 188 } 189 return PyDateTime_FromDateAndTime(t.year, t.month, t.day, t.hour, t.minute, t.second, 0); 190 } else static if (is(T == Date)) { 191 if(PyDateTimeAPI is null) { 192 PyDateTime_IMPORT(); 193 } 194 return PyDate_FromDate(t.year, t.month, t.day); 195 } else static if (is(T == SysTime)) { 196 if(PyDateTimeAPI is null) { 197 PyDateTime_IMPORT(); 198 } 199 return PyDateTime_FromDateAndTime(t.year, t.month, t.day, t.hour, t.minute, t.second, 0); 200 } else static if (is(T == TimeOfDay)) { 201 if(PyDateTimeAPI is null) { 202 PyDateTime_IMPORT(); 203 } 204 return PyTime_FromTime(t.hour, t.minute, t.second, 0); 205 } else static if (is(Unqual!T _unused : Complex!F, F)) { 206 return PyComplex_FromDoubles(t.re, t.im); 207 } else static if(is(T == std.bigint.BigInt)) { 208 return d_bigint_to_python(t); 209 } else static if(is(Unqual!T _unused : PydInputRange!E, E)) { 210 return Py_INCREF(t.ptr); 211 } else static if(isSomeString!T) { 212 return d_string_to_python(t); 213 } else static if (isArray!(T)) { 214 return d_array_to_python(t); 215 } else static if (isAssociativeArray!(T)) { 216 return d_aarray_to_python(t); 217 } else static if (isDelegate!T || isFunctionPointer!T) { 218 PydWrappedFunc_Ready!(T)(); 219 return wrap_d_object(t); 220 } else static if (is(T : PydObject)) { 221 return Py_INCREF(t.ptr()); 222 } else static if (is(T : PyObject*)) { 223 // The function expects to be passed a borrowed reference and return an 224 // owned reference. Thus, if passed a PyObject*, this will increment the 225 // reference count. 226 Py_XINCREF(t); 227 return t; 228 } else static if (is(T == class)) { 229 // Convert wrapped type to a PyObject* 230 alias Unqual!T Tu; 231 // But only if it actually is a wrapped type. :-) 232 PyTypeObject** type = Tu.classinfo in wrapped_classes; 233 if (type) { 234 return wrap_d_object(t, *type); 235 } 236 return d_to_python_try_extends(t); 237 // If it's not a wrapped type, fall through to the exception. 238 // If converting a struct by value, create a copy and wrap that 239 } else static if (is(T == struct) && 240 !is(T == RangeWrapper) && 241 isInputRange!T) { 242 if (to_converter_registry!(T).dg) { 243 return d_to_python_try_extends(t); 244 }else static if(__traits(compiles, wrap_range(t))) { 245 assert(is_wrapped!(RangeWrapper*)); 246 return d_to_python(wrap_range(t)); 247 } 248 } else static if (is(T == struct)) { 249 alias Unqual!T Tu; 250 if (is_wrapped!(Tu*)) { 251 Tu* temp = new Tu; 252 *temp = cast(Tu) t; 253 return wrap_d_object(cast(T*)temp); 254 } 255 return d_to_python_try_extends(t); 256 // If converting a struct by reference, wrap the thing directly 257 } else static if (is(typeof(*t) == struct)) { 258 alias Unqual!T Tu; 259 if (is_wrapped!(Tu)) { 260 if (t is null) { 261 return Py_INCREF(Py_None()); 262 } 263 return wrap_d_object(t); 264 } 265 return d_to_python_try_extends(t); 266 } 267 268 assert(0); 269 } 270 271 PyObject* d_to_python_try_extends(T) (T t) { 272 if (to_converter_registry!(T).dg) { 273 return to_converter_registry!(T).dg(t); 274 } 275 PyErr_SetString(PyExc_RuntimeError, ("D conversion function d_to_python failed with type " ~ typeid(T).toString()).ptr); 276 return null; 277 } 278 279 PyObject* d_tuple_to_python(T) (T t) if (isTuple!T) { 280 T.Types tuple; 281 foreach(i, _t; T.Types) { 282 tuple[i] = t[i]; 283 } 284 return PyTuple_FromItems(tuple); 285 } 286 287 PyObject* d_bigint_to_python(BigInt t) { 288 import std..string: format; 289 string num_str = format("%s\0",t); 290 return PyLong_FromString(num_str.dup.ptr, null, 10); 291 } 292 293 PyObject* d_string_to_python(T)(T t) if(isSomeString!T) { 294 alias Unqual!(typeof(T.init[0])) C; 295 static if(is(C == char)) { 296 return PyUnicode_DecodeUTF8(t.ptr, cast(Py_ssize_t) t.length, null); 297 }else static if(is(C == wchar)) { 298 return PyUnicode_DecodeUTF16(cast(char*) t.ptr, 299 cast(Py_ssize_t)(2*t.length), null, null); 300 }else static if(is(C == dchar)) { 301 version(Python_2_6_Or_Later) { 302 return PyUnicode_DecodeUTF32(cast(char*) t.ptr, 303 cast(Py_ssize_t)(4*t.length), null, null); 304 }else{ 305 return d_to_python(to!string(t)); 306 } 307 }else static assert(false, "waht is this T? " ~ T.stringof); 308 } 309 310 PyObject* d_array_to_python(T)(T t) if(isArray!T) { 311 // Converts any array (static or dynamic) to a Python list 312 PyObject* lst = PyList_New(cast(Py_ssize_t) t.length); 313 PyObject* temp; 314 if (lst is null) return null; 315 for(int i=0; i<t.length; ++i) { 316 temp = d_to_python(t[i]); 317 if (temp is null) { 318 Py_DECREF(lst); 319 return null; 320 } 321 // Steals the reference to temp 322 PyList_SET_ITEM(lst, cast(Py_ssize_t) i, temp); 323 } 324 return lst; 325 } 326 327 PyObject* d_aarray_to_python(T)(T t) if(isAssociativeArray!T) { 328 // Converts any associative array to a Python dict 329 PyObject* dict = PyDict_New(); 330 PyObject* ktemp, vtemp; 331 int result; 332 if (dict is null) return null; 333 foreach(k, v; t) { 334 ktemp = d_to_python(k); 335 vtemp = d_to_python(v); 336 if (ktemp is null || vtemp is null) { 337 if (ktemp !is null) Py_DECREF(ktemp); 338 if (vtemp !is null) Py_DECREF(vtemp); 339 Py_DECREF(dict); 340 return null; 341 } 342 result = PyDict_SetItem(dict, ktemp, vtemp); 343 Py_DECREF(ktemp); 344 Py_DECREF(vtemp); 345 if (result == -1) { 346 Py_DECREF(dict); 347 return null; 348 } 349 } 350 return dict; 351 } 352 353 T python_to_aarray(T)(PyObject* py) if(isAssociativeArray!T) { 354 PyObject* keys = null; 355 if(PyDict_Check(py)) { 356 keys = PyDict_Keys(py); 357 }else if(PyMapping_Keys(py)) { 358 keys = PyMapping_Keys(py); 359 }else{ 360 could_not_convert!(T)(py); 361 assert(0); 362 } 363 PyObject* iterator = PyObject_GetIter(keys); 364 T result; 365 PyObject* key; 366 while ((key=PyIter_Next(iterator)) !is null) { 367 PyObject* value = PyObject_GetItem(py, key); 368 auto d_key = python_to_d!(KeyType!T)(key); 369 auto d_value = python_to_d!(ValueType!T)(value); 370 result[d_key] = d_value; 371 Py_DECREF(key); 372 Py_DECREF(value); 373 } 374 Py_DECREF(iterator); 375 return result; 376 } 377 378 /** 379 * Helper function for creating a PyTuple from a series of D items. 380 */ 381 PyObject* PyTuple_FromItems(T ...)(T t) { 382 PyObject* tuple = PyTuple_New(t.length); 383 PyObject* temp; 384 if (tuple is null) return null; 385 foreach(i, arg; t) { 386 temp = d_to_python(arg); 387 if (temp is null) { 388 Py_DECREF(tuple); 389 return null; 390 } 391 PyTuple_SetItem(tuple, i, temp); 392 } 393 return tuple; 394 } 395 396 /** 397 * Constructs an object based on the type of the argument passed in. 398 * 399 * For example, calling py(10) would return a PydObject holding the value 10. 400 * 401 * Calling this with a PydObject will return back a reference to the very same 402 * PydObject. 403 */ 404 PydObject py(T) (T t) { 405 static if(is(T : PydObject)) { 406 return t; 407 } else { 408 return new PydObject(d_to_python(t)); 409 } 410 } 411 412 /** 413 * An exception class used by python_to_d. 414 */ 415 class PydConversionException : Exception { 416 this(string msg, string file = __FILE__, size_t line = __LINE__) { 417 super(msg, file, line); 418 } 419 } 420 421 /** 422 * This converts a PyObject* to a D type. The template argument is the type to 423 * convert to. The function argument is the PyObject* to convert. For instance: 424 * 425 *$(D_CODE PyObject* i = PyInt_FromLong(20); 426 *int n = _python_to_d!(int)(i); 427 *assert(n == 20);) 428 * 429 * This throws a PydConversionException if the PyObject can't be converted to 430 * the given D type. 431 */ 432 T python_to_d(T) (PyObject* o) { 433 // This ordering is somewhat important. The checks for Tuple and Complex 434 // must be before the check for general structs. 435 version(PydPythonExtension) { 436 // druntime doesn't run module ctors :( 437 if(!rangeWrapperInited) { 438 init_rangewrapper(); 439 } 440 } 441 442 static if (is(PyObject* : T)) { 443 return o; 444 } else static if (is(PydObject : T)) { 445 return new PydObject(borrowed(o)); 446 } else static if (is(T == void)) { 447 if (o != cast(PyObject*) Py_None()) could_not_convert!(T)(o); 448 return; 449 } else static if (isTuple!T) { 450 if(PyTuple_Check(o)) { 451 return python_to_d_tuple!T(o); 452 } 453 return python_to_d_try_extends!T(o); 454 } else static if (is(Unqual!T _unused : Complex!F, F)) { 455 if (PyComplex_Check(o) || isNumpyComplexNumber(o)) { 456 return python_to_d_complex!T(o); 457 } 458 return python_to_d_try_extends!T(o); 459 } else static if(is(Unqual!T == std.bigint.BigInt)) { 460 if (isPyNumber(o)) { 461 return python_to_d_bigint!T(o); 462 } 463 if (isNumpyNumber(o)) { 464 auto i = to_python_int(o); 465 return python_to_d_bigint!T(i); 466 } 467 return python_to_d_try_extends!T(o); 468 } else static if(is(T == DateTime)) { 469 if(PyDateTimeAPI is null) { 470 PyDateTime_IMPORT(); 471 } 472 if(PyDateTime_Check(o)) { 473 int year = PyDateTime_GET_YEAR(o); 474 int month = PyDateTime_GET_MONTH(o); 475 int day = PyDateTime_GET_DAY(o); 476 int hour = PyDateTime_DATE_GET_HOUR(o); 477 int minute = PyDateTime_DATE_GET_MINUTE(o); 478 int second = PyDateTime_DATE_GET_SECOND(o); 479 return DateTime(year, month, day, hour, minute, second); 480 } 481 if(PyDate_Check(o)) { 482 int year = PyDateTime_GET_YEAR(o); 483 int month = PyDateTime_GET_MONTH(o); 484 int day = PyDateTime_GET_DAY(o); 485 return DateTime(year, month, day, 0, 0, 0); 486 } 487 if(is_numpy_datetime64(o)) { 488 return python_to_d_numpy_datetime64!T(o); 489 } 490 491 } else static if(is(T == Date)) { 492 if(PyDateTimeAPI is null) { 493 PyDateTime_IMPORT(); 494 } 495 if(PyDateTime_Check(o) || PyDate_Check(o)) { 496 int year = PyDateTime_GET_YEAR(o); 497 int month = PyDateTime_GET_MONTH(o); 498 int day = PyDateTime_GET_DAY(o); 499 return Date(year, month, day); 500 } 501 if(is_numpy_datetime64(o)) { 502 return python_to_d_numpy_datetime64!T(o); 503 } 504 } else static if(is(T == SysTime)) { 505 if(PyDateTimeAPI is null) { 506 PyDateTime_IMPORT(); 507 } 508 if(PyDateTime_Check(o)) { 509 int year = PyDateTime_GET_YEAR(o); 510 int month = PyDateTime_GET_MONTH(o); 511 int day = PyDateTime_GET_DAY(o); 512 int hour = PyDateTime_DATE_GET_HOUR(o); 513 int minute = PyDateTime_DATE_GET_MINUTE(o); 514 int second = PyDateTime_DATE_GET_SECOND(o); 515 auto dt = DateTime(year, month, day, hour, minute, second); 516 return SysTime(dt); 517 } 518 if(PyDate_Check(o)) { 519 int year = PyDateTime_GET_YEAR(o); 520 int month = PyDateTime_GET_MONTH(o); 521 int day = PyDateTime_GET_DAY(o); 522 auto dt = DateTime(year, month, day, 0, 0, 0); 523 return SysTime(dt); 524 } 525 if(is_numpy_datetime64(o)) { 526 return python_to_d_numpy_datetime64!T(o); 527 } 528 } else static if(is(T == TimeOfDay)) { 529 if(PyDateTimeAPI is null) { 530 PyDateTime_IMPORT(); 531 } 532 if(PyTime_Check(o)) { 533 int hour = PyDateTime_TIME_GET_HOUR(o); 534 int minute = PyDateTime_TIME_GET_MINUTE(o); 535 int second = PyDateTime_TIME_GET_SECOND(o); 536 return TimeOfDay(hour, minute, second); 537 } 538 if(PyDateTime_Check(o)) { 539 int hour = PyDateTime_DATE_GET_HOUR(o); 540 int minute = PyDateTime_DATE_GET_MINUTE(o); 541 int second = PyDateTime_DATE_GET_SECOND(o); 542 return TimeOfDay(hour, minute, second); 543 } 544 if(is_numpy_datetime64(o)) { 545 return python_to_d_numpy_datetime64!T(o); 546 } 547 } else static if(is(Unqual!T _unused : PydInputRange!E, E)) { 548 return cast(T) PydInputRange!E(borrowed(o)); 549 } else static if (is(T == class)) { 550 // We can only convert to a class if it has been wrapped, and of course 551 // we can only convert the object if it is the wrapped type. 552 if ( 553 is_wrapped!(T) && 554 PyObject_IsInstance(o, cast(PyObject*)&PydTypeObject!(T)) ) 555 { 556 if ( get_d_reference!T(o) !is null) { 557 return get_d_reference!(T)(o); 558 } 559 } 560 return python_to_d_try_extends!T(o); 561 } else static if (is(T == struct)) { // struct by value 562 // struct is wrapped 563 if (is_wrapped!(T*) && PyObject_TypeCheck(o, &PydTypeObject!(T*))) { 564 return *get_d_reference!(T*)(o); 565 } 566 // or struct is wrapped range 567 if(PyObject_IsInstance(o, 568 cast(PyObject*)&PydTypeObject!(RangeWrapper*))) { 569 RangeWrapper* wrapper = get_d_reference!(RangeWrapper*)(o); 570 if(typeid(T) != wrapper.tid) { 571 could_not_convert!T(o, format("typeid mismatch: %s vs %s", 572 wrapper.tid, typeid(T))); 573 } 574 T t = *cast(T*) wrapper.range; 575 return t; 576 } 577 return python_to_d_try_extends!T(o); 578 } else static if (isPointer!T && is(PointerTarget!T == struct)) { 579 // pointer to struct 580 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 581 return get_d_reference!(T)(o); 582 } 583 return python_to_d_try_extends!T(o); 584 } else static if (is(T == delegate)) { 585 // Get the original wrapped delegate out if this is a wrapped delegate 586 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 587 return get_d_reference!(T)(o); 588 // Otherwise, wrap the PyCallable with a delegate 589 } else if (PyCallable_Check(o)) { 590 return PydCallable_AsDelegate!(T)(o); 591 } 592 return python_to_d_try_extends!T(o); 593 } else static if (isDelegate!T || isFunctionPointer!T) { 594 // We can only make it a function pointer if we originally wrapped a 595 // function pointer. 596 if (is_wrapped!(T) && PyObject_TypeCheck(o, &PydTypeObject!(T))) { 597 return get_d_reference!(T)(o); 598 } 599 return python_to_d_try_extends!T(o); 600 } else static if (isSomeString!T) { 601 return python_to_d_string!T(o); 602 } else static if (isArray!T || IsStaticArrayPointer!T) { 603 static if(isPointer!T) { 604 alias Unqual!(ElementType!(PointerTarget!T)) E; 605 }else { 606 alias Unqual!(ElementType!T) E; 607 } 608 version(Python_2_6_Or_Later) { 609 if(PyObject_CheckBuffer(o)) { 610 return python_buffer_to_d!(T)(o); 611 } 612 } 613 if(o.ob_type is array_array_Type) { 614 return python_array_array_to_d!T(o); 615 }else { 616 return python_iter_to_d!T(o); 617 } 618 } else static if (isAssociativeArray!T) { 619 return python_to_aarray!T(o); 620 } else static if (isFloatingPoint!T) { 621 if (isPyNumber(o) || isNumpyNumber(o)) { 622 double res = PyFloat_AsDouble(o); 623 return cast(T) res; 624 } 625 return python_to_d_try_extends!T(o); 626 } else static if(isIntegral!T) { 627 if (isNumpyNumber(o)) { 628 o = to_python_int(o); 629 } 630 631 version(Python_3_0_Or_Later) { 632 }else{ 633 if(PyInt_Check(o)) { 634 C_long res = PyInt_AsLong(o); 635 handle_exception(); 636 static if(isUnsigned!T) { 637 if(res < 0) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, 0, T.max)); 638 if(T.max < res) could_not_convert!T(o,format("%s out of bounds [%s, %s]", res, 0, T.max)); 639 return cast(T) res; 640 }else static if(isSigned!T) { 641 if(T.min > res) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, T.min, T.max)); 642 if(T.max < res) could_not_convert!T(o, format("%s out of bounds [%s, %s]", res, T.min, T.max)); 643 return cast(T) res; 644 } 645 } 646 } 647 if(PyLong_Check(o)) { 648 static if(isUnsigned!T) { 649 static assert(T.sizeof <= C_ulonglong.sizeof); 650 C_ulonglong res = PyLong_AsUnsignedLongLong(o); 651 handle_exception(); 652 // no overflow from python to C_ulonglong, 653 // overflow from C_ulonglong to T? 654 if(T.max < res) could_not_convert!T(o); 655 return cast(T) res; 656 }else static if(isSigned!T) { 657 static assert(T.sizeof <= C_longlong.sizeof); 658 C_longlong res = PyLong_AsLongLong(o); 659 handle_exception(); 660 // no overflow from python to C_longlong, 661 // overflow from C_longlong to T? 662 if(T.min > res) could_not_convert!T(o); 663 if(T.max < res) could_not_convert!T(o); 664 return cast(T) res; 665 } 666 } 667 668 return python_to_d_try_extends!T(o); 669 } else static if (isBoolean!T) { 670 if (isPyNumber(o) || isNumpyNumber(o)) { 671 int res = PyObject_IsTrue(o); 672 return res == 1; 673 } 674 return python_to_d_try_extends!T(o); 675 } 676 677 assert(0); 678 } 679 680 PyObject* to_python_int(PyObject* o) { 681 auto builtins = new PydObject(PyEval_GetBuiltins()); 682 auto int_ = builtins["int"]; 683 return int_(o).to_d!(PyObject*)(); 684 } 685 686 T python_to_d_try_extends(T) (PyObject* o) { 687 if (from_converter_registry!(T).dg) { 688 return from_converter_registry!(T).dg(o); 689 } 690 could_not_convert!(T)(o); 691 assert(0); 692 } 693 694 T python_to_d_tuple(T) (PyObject* o) { 695 T.Types tuple; 696 auto len = PyTuple_Size(o); 697 if(len != T.Types.length) could_not_convert!T(o); 698 foreach(i,_t; T.Types) { 699 auto obj = Py_XINCREF(PyTuple_GetItem(o, i)); 700 tuple[i] = python_to_d!_t(obj); 701 Py_DECREF(obj); 702 } 703 return T(tuple); 704 } 705 706 T python_to_d_complex(T) (PyObject* o) { 707 import util.conv; 708 static if (is(Unqual!T _unused : Complex!F, F)) { 709 double real_ = python_to_d!double(PyObject_GetAttrString(o, "real")); 710 handle_exception(); 711 double imag = python_to_d!double(PyObject_GetAttrString(o, "imag")); 712 handle_exception(); 713 return complex!(F,F)(real_, imag); 714 }else static assert(false); 715 } 716 717 T python_to_d_bigint(T) (PyObject* o) { 718 string num_str = python_to_d!string(o); 719 if(num_str.endsWith("L")) num_str = num_str[0..$-1]; 720 return BigInt(num_str); 721 } 722 723 T python_to_d_string(T) (PyObject* o) { 724 alias Unqual!(typeof(T.init[0])) C; 725 PyObject* str; 726 if(PyBytes_Check(o)) { 727 static if(is(C == char)) { 728 str = o; 729 }else{ 730 version(Python_3_0_Or_Later) { 731 str = PyObject_Str(o); 732 if(!str) handle_exception(); 733 }else{ 734 str = PyObject_Unicode(o); 735 if(!str) handle_exception(); 736 } 737 } 738 }else if(PyUnicode_Check(o)) { 739 str = o; 740 }else { 741 str = PyObject_Repr(o); 742 if(!str) handle_exception(); 743 version(Python_3_0_Or_Later) { 744 }else{ 745 static if(!is(C == char)) { 746 str = PyObject_Unicode(str); 747 if(!str) handle_exception(); 748 } 749 } 750 } 751 static if(is(C == char)) { 752 if(PyBytes_Check(str)) { 753 const(char)* res = PyBytes_AsString(str); 754 if(!res) handle_exception(); 755 return to!T(res); 756 } 757 } 758 759 if(PyUnicode_Check(str)) { 760 static if(is(C == char)) { 761 PyObject* utf8 = PyUnicode_AsUTF8String(str); 762 if(!utf8) handle_exception(); 763 const(char)* res = PyBytes_AsString(utf8); 764 if(!res) handle_exception(); 765 return to!T(res); 766 }else static if(is(C == wchar)) { 767 PyObject* utf16 = PyUnicode_AsUTF16String(str); 768 if(!utf16) handle_exception(); 769 // PyUnicode_AsUTF16String puts a BOM character in front of 770 // string 771 auto ptr = cast(const(wchar)*)(PyBytes_AsString(utf16)+2); 772 Py_ssize_t len = PyBytes_Size(utf16)/2-1; 773 wchar[] ws = new wchar[](len); 774 ws[] = ptr[0 .. len]; 775 return cast(T) ws; 776 }else static if(is(C == dchar)) { 777 version(Python_2_6_Or_Later) { 778 PyObject* utf32 = PyUnicode_AsUTF32String(str); 779 if(!utf32) handle_exception(); 780 // PyUnicode_AsUTF32String puts a BOM character in front of 781 // string 782 auto ptr = cast(const(dchar)*)(PyBytes_AsString(utf32)+4); 783 Py_ssize_t len = PyBytes_Size(utf32)/4-1; 784 dchar[] ds = new dchar[](len); 785 ds[] = ptr[0 .. len]; 786 return cast(T) ds; 787 }else{ 788 return to!(T)(python_to_d!string(str)); 789 } 790 }else static assert(false, "what T is this!? " ~ T.stringof); 791 } 792 assert(0); 793 } 794 795 796 // (*^&* array doesn't implement the buffer interface, but we still 797 // want it to copy fast. 798 /// Convert an array.array object to a D object. 799 /// 800 /// Used by python_to_d. 801 T python_array_array_to_d(T)(PyObject* o) 802 if(isArray!T || IsStaticArrayPointer!T) { 803 static if(isPointer!T) 804 alias Unqual!(ElementType!(PointerTarget!T)) E; 805 else 806 alias Unqual!(ElementType!T) E; 807 if(o.ob_type !is array_array_Type) 808 could_not_convert!T(o, "not an array.array"); 809 arrayobject* arr_o = cast(arrayobject*) o; 810 // array.array's data can be got with a single memcopy. 811 enforce(arr_o.ob_descr, "array.ob_descr null!"); 812 char typecode = cast(char) arr_o.ob_descr.typecode; 813 if(!match_format_type!E(""~typecode)) { 814 could_not_convert!T(o, format("item mismatch: '%s' vs %s", 815 typecode, E.stringof)); 816 } 817 818 int itemsize = arr_o.ob_descr.itemsize; 819 if(itemsize != E.sizeof) 820 could_not_convert!T(o, 821 format("item size mismatch: %s vs %s", 822 itemsize, E.sizeof)); 823 Py_ssize_t count = Py_SIZE(arr_o); 824 if(count < 0) 825 could_not_convert!T(o, format("nonsensical array length: %s", 826 count)); 827 MatrixInfo!T.unqual _array; 828 static if(isDynamicArray!T) { 829 _array = new MatrixInfo!T.unqual(count); 830 }else { 831 if(!MatrixInfo!T.check([count])) 832 could_not_convert!T(o, 833 format("length mismatch: %s vs %s", count, T.length)); 834 } 835 // copy data, don't take slice 836 static if(isPointer!(typeof(_array))) { 837 memcpy((*_array).ptr, arr_o.ob_item, count*itemsize); 838 }else{ 839 memcpy(_array.ptr, arr_o.ob_item, count*itemsize); 840 } 841 //_array[] = cast(E[]) arr_o.ob_item[0 .. count*itemsize]; 842 return cast(T) _array; 843 } 844 845 /** 846 Convert a d array to a python array.array. 847 array.array does not support 8 byte integers. 848 849 Not used by d_to_python. 850 */ 851 PyObject* d_to_python_array_array(T)(T t) 852 if((isArray!T || IsStaticArrayPointer!T) && 853 MatrixInfo!T.ndim == 1 && 854 SimpleFormatType!(MatrixInfo!T.MatrixElementType).supported) { 855 856 alias MatrixInfo!T.MatrixElementType ME; 857 PyObject* pyformat = SimpleFormatType!ME.pyType(); 858 PyObject* args = PyTuple_New(1); 859 PyTuple_SetItem(args, 0, pyformat); 860 scope(exit) Py_DECREF(args); 861 PyObject* obj = array_array_Type.tp_new(array_array_Type, args, null); 862 if(!obj) handle_exception(); 863 arrayobject* arr_o = cast(arrayobject*) obj; 864 Py_ssize_t[] shape = MatrixInfo!T.build_shape(t); 865 size_t datalen = ME.sizeof*shape[0]; 866 Py_SET_SIZE(arr_o, shape[0]); 867 void* data = PyMem_Malloc(datalen); 868 static if(isPointer!T) { 869 memcpy(data, t, datalen); 870 }else { 871 memcpy(data, t.ptr, datalen); 872 } 873 arr_o.ob_item = cast(ubyte*) data; 874 return obj; 875 } 876 877 /** 878 Convert a D object to python bytes (str, in python 2). 879 */ 880 PyObject* d_to_python_bytes(T)(T t) if(is(T == string)) { 881 return PyBytes_FromStringAndSize(t.ptr, cast(Py_ssize_t) t.length); 882 } 883 884 /** Convert an iterable Python object to a D object. 885 * 886 * Used by python_to_d. 887 */ 888 T python_iter_to_d(T)(PyObject* o) if(isArray!T || IsStaticArrayPointer!T) { 889 static if(isPointer!T) 890 alias Unqual!(ElementType!(PointerTarget!T)) E; 891 else 892 alias Unqual!(ElementType!T) E; 893 PyObject* iter = PyObject_GetIter(o); 894 if (iter is null) { 895 PyErr_Clear(); 896 could_not_convert!(T)(o); 897 } 898 scope(exit) Py_DECREF(iter); 899 Py_ssize_t len = PyObject_Length(o); 900 if (len == -1) { 901 PyErr_Clear(); 902 could_not_convert!(T)(o); 903 } 904 905 MatrixInfo!T.unqual _array; 906 static if(isDynamicArray!T) { 907 _array = new MatrixInfo!T.unqual(len); 908 }else static if(isStaticArray!T){ 909 if(len != T.length) 910 could_not_convert!T(o, 911 format("length mismatch: %s vs %s", 912 len, T.length)); 913 }else static if(isPointer!T){ 914 ubyte[] bufi = new ubyte[](PointerTarget!T.sizeof); 915 _array = cast(MatrixInfo!T.unqual)(bufi.ptr); 916 } 917 int i = 0; 918 PyObject* item = PyIter_Next(iter); 919 while (item) { 920 try { 921 _array[i] = python_to_d!(E)(item); 922 } catch(PydConversionException e) { 923 Py_DECREF(item); 924 // We re-throw the original conversion exception, rather than 925 // complaining about being unable to convert to an array. The 926 // partially constructed array is left to the GC. 927 throw e; 928 } 929 ++i; 930 Py_DECREF(item); 931 item = PyIter_Next(iter); 932 } 933 return cast(T) _array; 934 } 935 936 bool isPyNumber(PyObject* obj) { 937 version(Python_3_0_Or_Later) { 938 return 939 PyLong_Check(obj) || 940 PyFloat_Check(obj); 941 }else{ 942 return 943 PyInt_Check(obj) || 944 PyLong_Check(obj) || 945 PyFloat_Check(obj); 946 } 947 } 948 949 const(char)[] type_name(PyObject* obj) { 950 auto type = cast(PyTypeObject*)PyObject_Type(obj); 951 return type.tp_name[0 .. strlen(type.tp_name)]; 952 } 953 954 bool isNumpyBool(PyObject* obj) { 955 switch(type_name(obj)) { 956 case "numpy.bool_": 957 return true; 958 default: 959 return false; 960 } 961 } 962 963 bool isNumpyInteger(PyObject* obj) { 964 switch(type_name(obj)) { 965 case "numpy.int8": 966 case "numpy.int16": 967 case "numpy.int32": 968 case "numpy.int64": 969 case "numpy.uint8": 970 case "numpy.uint16": 971 case "numpy.uint32": 972 case "numpy.uint64": 973 return true; 974 default: 975 return false; 976 } 977 } 978 979 bool isNumpyFloat(PyObject* obj) { 980 switch(type_name(obj)) { 981 case "numpy.float32": 982 case "numpy.float64": 983 return true; 984 default: 985 return false; 986 } 987 } 988 989 bool isNumpyComplexNumber(PyObject* obj) { 990 switch(type_name(obj)) { 991 case "numpy.complex32": 992 case "numpy.complex64": 993 return true; 994 default: 995 return false; 996 } 997 } 998 999 bool isNumpyNumber(PyObject* obj) { 1000 return isNumpyBool(obj) || isNumpyInteger(obj) || isNumpyFloat(obj); 1001 } 1002 1003 version(Python_2_6_Or_Later) { 1004 /// Convert a Python new-style buffer to a D object. 1005 /// 1006 /// Used by python_to_d. 1007 T python_buffer_to_d(T)(PyObject* o) 1008 if (isArray!T || IsStaticArrayPointer!T) { 1009 PydObject bob = new PydObject(borrowed(o)); 1010 auto buf = bob.buffer_view(); 1011 alias MatrixInfo!T.MatrixElementType ME; 1012 MatrixInfo!T.unqual _array; 1013 /+ 1014 if(buf.itemsize != ME.sizeof) 1015 could_not_convert!T(o, format("item size mismatch: %s vs %s", 1016 buf.itemsize, ME.sizeof)); 1017 +/ 1018 if(!match_format_type!ME(buf.format)) { 1019 could_not_convert!T(o, format("item type mismatch: '%s' vs %s", 1020 buf.format, ME.stringof)); 1021 } 1022 if(buf.has_nd) { 1023 if(!MatrixInfo!T.check(buf.shape)) 1024 could_not_convert!T(o, 1025 format("dimension mismatch: %s vs %s", 1026 buf.shape, MatrixInfo!T.dimstring)); 1027 if(buf.c_contiguous) { 1028 // woohoo! single memcpy 1029 static if(MatrixInfo!T.isRectArray && isStaticArray!T) { 1030 memcpy(_array.ptr, buf.buf.ptr, buf.buf.length); 1031 }else{ 1032 alias MatrixInfo!T.RectArrayType RectArrayType; 1033 static if(!isStaticArray!(RectArrayType)) { 1034 ubyte[] dbuf = new ubyte[](buf.buf.length); 1035 memcpy(dbuf.ptr, buf.buf.ptr, buf.buf.length); 1036 } 1037 size_t rectsize = ME.sizeof; 1038 size_t MErectsize = 1; 1039 foreach(i; MatrixInfo!T.rectArrayAt .. MatrixInfo!T.ndim) { 1040 rectsize *= buf.shape[i]; 1041 MErectsize *= buf.shape[i]; 1042 } 1043 static if(MatrixInfo!T.isRectArray) { 1044 static if(isPointer!T) 1045 _array = cast(typeof(_array)) dbuf.ptr; 1046 else { 1047 static assert(isDynamicArray!T); 1048 _array = cast(typeof(_array)) dbuf; 1049 } 1050 }else{ 1051 // rubbish. much pointer pointing 1052 size_t offset = 0; 1053 static if(isDynamicArray!T) { 1054 _array = new MatrixInfo!T.unqual(buf.shape[0]); 1055 } 1056 enum string xx = (MatrixInfo!T.matrixIter( 1057 "_array", "buf.shape", "_indices", 1058 MatrixInfo!T.rectArrayAt, q{ 1059 static if(isDynamicArray!(typeof($array_ixn))) { 1060 $array_ixn = new typeof($array_ixn)(buf.shape[$i+1]); 1061 } 1062 static if(is(typeof($array_ixn) == RectArrayType)) { 1063 // should be innermost loop 1064 assert(offset + rectsize <= buf.buf.length, 1065 "uh oh: overflow!"); 1066 alias typeof($array_ixn) rectarr; 1067 static if(isStaticArray!rectarr) { 1068 memcpy($array_ixn.ptr, buf.buf.ptr + offset, rectsize); 1069 }else{ 1070 static assert(isDynamicArray!rectarr); 1071 1072 $array_ixn = (cast(typeof($array_ixn.ptr))(dbuf.ptr + offset)) 1073 [0 .. MErectsize]; 1074 } 1075 offset += rectsize; 1076 } 1077 }, 1078 "")); 1079 mixin(xx); 1080 } 1081 } 1082 }else if(buf.fortran_contiguous) { 1083 // really rubbish. no memcpy. 1084 static if(isDynamicArray!T) { 1085 _array = new MatrixInfo!T.unqual(buf.shape[0]); 1086 }else static if(isPointer!T) { 1087 ubyte[] dubuf = new ubyte[](buf.buffer.len); 1088 _array = cast(typeof(_array)) dubuf.ptr; 1089 1090 } 1091 enum string xx = (MatrixInfo!T.matrixIter( 1092 "_array", "buf.shape", "_indices", 1093 MatrixInfo!T.ndim, q{ 1094 static if(isDynamicArray!(typeof($array_ixn))) { 1095 $array_ixn = new typeof($array_ixn)(buf.shape[$i+1]); 1096 }else static if(is(typeof($array_ixn) == ME)) { 1097 $array_ixn = buf.item!ME(cast(Py_ssize_t[]) _indices); 1098 } 1099 }, 1100 "")); 1101 mixin(xx); 1102 }else { 1103 // wut? 1104 could_not_convert!T(o,("todo: know what todo")); 1105 assert(0); 1106 } 1107 return cast(T) _array; 1108 }else if(buf.has_simple) { 1109 /* 1110 static if(isDynamicArray!T) { 1111 E[] array = new E[](buf.buf.length); 1112 }else static if(isStaticArray!T) { 1113 if(buf.buf.length != T.length) 1114 could_not_convert!T(o, 1115 format("length mismatch: %s vs %s", 1116 buf.buf.length, T.length)); 1117 E[T.length] array; 1118 } 1119 return cast(T) array; 1120 */ 1121 assert(0, "py jingo wat we do here?"); 1122 } 1123 return cast(T) _array; 1124 } 1125 } 1126 1127 /** 1128 Wrap a D input range as a python iterator object. 1129 1130 Does not work for UFCS ranges (e.g. arrays), classes 1131 */ 1132 auto wrap_range(Range)(Range range) if(is(Range == struct)) { 1133 static assert(!is(Range == RangeWrapper)); 1134 import core.memory; 1135 RangeWrapper wrap; 1136 // the hackery! the hackery! 1137 Range* keeper = cast(Range*) GC.calloc(Range.sizeof); 1138 std.algorithm.move(range, *keeper); 1139 wrap.range = cast(void*) keeper; 1140 wrap.tid = typeid(Range); 1141 wrap.empty = dg_wrapper(keeper, &Range.empty); 1142 wrap.popFront = dg_wrapper(keeper, &Range.popFront); 1143 auto front_dg = 1144 dg_wrapper(keeper, cast(ElementType!Range function()) &Range.front); 1145 wrap.front = delegate PyObject*() { 1146 return d_to_python(front_dg()); 1147 }; 1148 return wrap; 1149 } 1150 1151 /** 1152 Wrapper type wrapping a D input range as a python iterator object 1153 1154 Lives in reserved python module "pyd". 1155 */ 1156 struct RangeWrapper { 1157 void* range; 1158 void delegate() popFront; 1159 PyObject* delegate() front; 1160 bool delegate() empty; 1161 TypeInfo tid; 1162 1163 RangeWrapper* iter() { 1164 return &this; 1165 } 1166 PyObject* next() { 1167 if(this.empty()) { 1168 return null; 1169 }else { 1170 auto result = d_to_python(this.front()); 1171 this.popFront(); 1172 return result; 1173 } 1174 } 1175 } 1176 1177 /// Check T against format 1178 /// See_Also: 1179 /// <a href='http://docs.python.org/library/struct.html#struct-format-strings'> 1180 /// Struct Format Strings </a> 1181 bool match_format_type(T)(string format) { 1182 alias T S; 1183 size_t S_size = S.sizeof; 1184 enforce(format.length > 0); 1185 1186 bool native_size = false; 1187 switch(format[0]) { 1188 case '@': 1189 // this (*&^& function is not defined 1190 //PyBuffer_SizeFromFormat() 1191 native_size = true; 1192 goto case; 1193 case '=','<','>','!': 1194 format = format[1 .. $]; 1195 default: 1196 break; 1197 } 1198 // by typeishness 1199 switch(format[0]) { 1200 case 'x', 's', 'p': 1201 // don't support these 1202 enforce(false, "unsupported format: " ~ format); 1203 case 'c': 1204 break; 1205 case 'b', 'h','i','l','q': 1206 if(!isSigned!S) return false; 1207 else break; 1208 case 'B', 'H', 'I', 'L','Q': 1209 if(!isUnsigned!S) return false; 1210 else break; 1211 case 'f','d': 1212 if(!isFloatingPoint!S) return false; 1213 else break; 1214 case '?': 1215 if(!isBoolean!S) return false; 1216 case 'Z': 1217 if (format.length > 1) { 1218 static if(is(S : Complex!F, F)) { 1219 S_size = F.sizeof; 1220 }else{ 1221 return false; 1222 } 1223 } 1224 format = format[1..$]; 1225 break; 1226 default: 1227 enforce(false, "unknown format: " ~ format); 1228 } 1229 1230 // by sizeishness 1231 if(native_size) { 1232 // grr 1233 assert(0, "todo"); 1234 }else{ 1235 switch(format[0]) { 1236 case 'c','b','B','?': 1237 return (S_size == 1); 1238 case 'h','H': 1239 return (S_size == 2); 1240 case 'i','I','l','L','f': 1241 return (S_size == 4); 1242 case 'q','Q','d': 1243 return (S_size == 8); 1244 default: 1245 enforce(false, "unknown format: " ~ format); 1246 assert(0); // seriously, d? 1247 1248 } 1249 } 1250 } 1251 1252 /// generate a struct format string from T 1253 template SimpleFormatType(T) { 1254 enum supported = 1255 (isFloatingPoint!T && (T.sizeof == 4 || T.sizeof == 8) || 1256 isIntegral!T); 1257 1258 PyObject* pyType() { 1259 //assert(supported); 1260 static if(supported) { 1261 version(Python_3_0_Or_Later) { 1262 alias to_python = d_to_python; 1263 }else{ 1264 // stinking py2 array won't take unicode 1265 alias to_python = d_to_python_bytes; 1266 } 1267 static if(isFloatingPoint!T && T.sizeof == 4) { 1268 return to_python("f"); 1269 }else static if(isFloatingPoint!T && T.sizeof == 8) { 1270 return to_python("d"); 1271 }else static if(isIntegral!T && T.sizeof == 1) { 1272 return to_python(isSigned!T ? "b" : "B"); 1273 }else static if(isIntegral!T && T.sizeof == 2) { 1274 return to_python(isSigned!T ? "h" : "H"); 1275 }else static if(isIntegral!T && T.sizeof == 4) { 1276 return to_python(isSigned!T ? "i" : "I"); 1277 }else static if(isIntegral!T && T.sizeof == 8) { 1278 return to_python(isSigned!T ? "q" : "Q"); 1279 } 1280 return null; 1281 }else{ 1282 assert(false); 1283 } 1284 } 1285 } 1286 1287 1288 /** 1289 Check that T is a pointer to a rectangular static array. 1290 */ 1291 template IsStaticArrayPointer(T) { 1292 template _Inner(S) { 1293 static if(isStaticArray!S) { 1294 enum _Inner = _Inner!(ElementType!S); 1295 } else static if(isArray!S || isPointer!S) { 1296 enum _Inner = false; 1297 }else { 1298 enum _Inner = true; 1299 } 1300 } 1301 static if(isPointer!T) { 1302 enum bool IsStaticArrayPointer = _Inner!(PointerTarget!T); 1303 }else{ 1304 enum bool IsStaticArrayPointer = false; 1305 } 1306 } 1307 1308 /** 1309 Some reflective information about multidimensional arrays 1310 1311 Handles dynamic arrays, static arrays, and pointers to static arrays. 1312 */ 1313 template MatrixInfo(T) if(isArray!T || IsStaticArrayPointer!T) { 1314 template ElementType2(_T) { 1315 static if(isSomeString!_T) { 1316 alias ElementType2=_T; 1317 }else{ 1318 alias ElementType2=ElementType!_T; 1319 } 1320 } 1321 1322 template _dim_list(T, dimi...) { 1323 static if(isSomeString!T) { 1324 alias dimi list; 1325 alias T elt; 1326 alias Unqual!T unqual; 1327 } else static if(isDynamicArray!T) { 1328 alias _dim_list!(ElementType2!T, dimi,-1) next; 1329 alias next.list list; 1330 alias next.elt elt; 1331 alias next.unqual[] unqual; 1332 }else static if(isStaticArray!T) { 1333 alias _dim_list!(ElementType2!T, dimi, cast(Py_ssize_t) T.length) next; 1334 alias next.list list; 1335 alias next.elt elt; 1336 alias next.unqual[T.length] unqual; 1337 }else { 1338 alias dimi list; 1339 alias T elt; 1340 alias Unqual!T unqual; 1341 } 1342 } 1343 1344 string tuple2string(T...)() { 1345 string s = "["; 1346 foreach(i, t; T) { 1347 if(t == -1) s ~= "*"; 1348 else s ~= to!string(t); 1349 if(i == T.length-1) { 1350 s ~= "]"; 1351 }else{ 1352 s ~= ","; 1353 } 1354 } 1355 return s; 1356 } 1357 1358 /** 1359 Build shape from t. Assumes all arrays in a dimension are initialized 1360 and of uniform length. 1361 */ 1362 Py_ssize_t[] build_shape(T t) { 1363 Py_ssize_t[] shape = new Py_ssize_t[](ndim); 1364 mixin(shape_builder_mixin("t", "shape")); 1365 return shape; 1366 } 1367 1368 string shape_builder_mixin(string arr_name, string shape_name) { 1369 static if(isPointer!T) { 1370 string s_ixn = "(*" ~ arr_name ~ ")"; 1371 }else{ 1372 string s_ixn = arr_name; 1373 } 1374 string s = ""; 1375 foreach(i; 0 .. ndim) { 1376 s ~= shape_name ~ "["~ to!string(i) ~"] = cast(Py_ssize_t)" ~ s_ixn ~ ".length;"; 1377 s_ixn ~= "[0]"; 1378 } 1379 return s; 1380 } 1381 1382 /** 1383 Ensures that T can store a matrix of _shape shape. 1384 */ 1385 bool check(Py_ssize_t[] shape) { 1386 if (shape.length != dim_list.length) return false; 1387 foreach(i, d; dim_list) { 1388 static if(dim_list[i] == -1) continue; 1389 else if(d != shape[i]) return false; 1390 } 1391 return true; 1392 } 1393 1394 /** 1395 Generate a mixin string of nested for loops that iterate over the 1396 first ndim dimensions of an array of type T (or, preferrably 1397 MatrixInfo!T.unqual). 1398 1399 Params: 1400 arr_name = name of array to iterate. 1401 shape_name = name of array of dimension lengths. 1402 index_name = name to use for index vector. Declared in a new nested scoped. 1403 ndim = number of dimensions to iterate over. 1404 pre_code = code to mixin each for loop before beginning the nested for loop. 1405 post_code = code to mix in to each for loop after finishing the nested for loop. 1406 */ 1407 1408 string matrixIter(string arr_name, string shape_name, 1409 string index_name, 1410 size_t ndim, 1411 string pre_code, string post_code) { 1412 string s_begin = "{\n"; 1413 string s_end = "}\n"; 1414 static if(isPointer!T) { 1415 string s_ixn = "(*" ~ arr_name ~ ")"; 1416 }else{ 1417 string s_ixn = arr_name; 1418 } 1419 1420 s_begin ~= "size_t[" ~ to!string(ndim) ~ "] " ~ index_name ~ ";\n"; 1421 foreach(i; 0 .. ndim) { 1422 string s_i = to!string(i); 1423 s_ixn ~= "["~ index_name ~ "[" ~ s_i ~ "]]"; 1424 string index = index_name~ "[" ~ s_i ~ "]"; 1425 string shape_i = shape_name ~ "[" ~ s_i ~ "]"; 1426 s_begin ~= "for("~index~" = 0;" ~index ~ " < " ~ shape_i ~ 1427 "; " ~ index ~ "++) {"; 1428 s_end ~= "}\n"; 1429 1430 string pre_code_i = replace(pre_code, "$array_ixn", s_ixn); 1431 pre_code_i = replace(pre_code_i, "$i", s_i); 1432 s_begin ~= pre_code_i; 1433 string post_code_i = replace(post_code, "$array_ixn", s_ixn); 1434 post_code_i = replace(post_code_i, "$i", s_i); 1435 s_end ~= post_code_i; 1436 } 1437 return s_begin ~ s_end; 1438 } 1439 1440 static if(isPointer!T && isStaticArray!(PointerTarget!T)) { 1441 alias _dim_list!(PointerTarget!T) _dim; 1442 /// T, with all nonmutable qualifiers stripped away. 1443 alias _dim.unqual* unqual; 1444 }else{ 1445 alias _dim_list!T _dim; 1446 alias _dim.unqual unqual; 1447 } 1448 /// tuple of dimensions of T. 1449 /// dim_list[0] will be the dimension furthest from the MatrixElementType 1450 /// i.e. for double[1][2][3], dim_list == (3, 2, 1). 1451 /// Lists -1 as dimension of dynamic arrays. 1452 alias _dim.list dim_list; 1453 /// number of dimensions of this matrix 1454 enum ndim = dim_list.length; 1455 /// T is a RectArray if: 1456 /// * it is any multidimensional static array (or a pointer to) 1457 /// * it is a 1 dimensional dynamic array 1458 enum bool isRectArray = staticIndexOf!(-1, dim_list) == -1 || dim_list.length == 1; 1459 //(1,2,3) -> rectArrayAt == 0 1460 //(-1,2,3) -> rectArrayAt == 1 == 3 - 2 == len - max(indexof_rev, 1) 1461 //(-1,-1,1) -> rectArrayAt == 2 == 3 - 1 == len - max(indexof_rev,1) 1462 //(-1,-1,-1) -> rectArrayAt == 2 == 3 - 1 == len - max(indexof_rev,1) 1463 //(2,2,-1) -> rectArrayAt == 2 1464 enum size_t indexof_rev = staticIndexOf!(-1, Reverse!dim_list); 1465 /// Highest dimension where it and all subsequent dimensions form a 1466 /// RectArray. 1467 enum size_t rectArrayAt = isRectArray ? 0 : dim_list.length - max(indexof_rev, 1); 1468 template _rect_type(S, size_t i) { 1469 static if(i == rectArrayAt) { 1470 alias S _rect_type; 1471 } else { 1472 alias _rect_type!(ElementType!S, i+1) _rect_type; 1473 } 1474 } 1475 /// unqualified highest dimension subtype of T forming RectArray 1476 alias _rect_type!(unqual, 0) RectArrayType; 1477 /// Pretty string of dimension list for T 1478 enum string dimstring = tuple2string!(dim_list)(); 1479 /// Matrix element type of T 1480 /// E.g. immutable(double) for T=immutable(double[4][4]) 1481 alias _dim.elt MatrixElementType; 1482 } 1483 1484 @property PyTypeObject* array_array_Type() { 1485 static PyTypeObject* m_type; 1486 if(!m_type) { 1487 PyObject* array = PyImport_ImportModule("array"); 1488 scope(exit) Py_XDECREF(array); 1489 m_type = cast(PyTypeObject*) PyObject_GetAttrString(array, "array"); 1490 } 1491 return m_type; 1492 } 1493 1494 alias python_to_d!(Object) python_to_d_Object; 1495 1496 void could_not_convert(T) (PyObject* o, string reason = "", 1497 string file = __FILE__, size_t line = __LINE__) { 1498 // Pull out the name of the type of this Python object, and the 1499 // name of the D type. 1500 string py_typename, d_typename; 1501 PyObject* py_type, py_type_str; 1502 py_type = PyObject_Type(o); 1503 if (py_type is null) { 1504 py_typename = "<unknown>"; 1505 } else { 1506 py_type_str = PyObject_GetAttrString(py_type, cast(const(char)*) "__name__".ptr); 1507 Py_DECREF(py_type); 1508 if (py_type_str is null) { 1509 py_typename = "<unknown>"; 1510 } else { 1511 py_typename = python_to_d!string(py_type_str); 1512 Py_DECREF(py_type_str); 1513 } 1514 } 1515 d_typename = typeid(T).toString(); 1516 string because; 1517 if(reason != "") because = format(" because: %s", reason); 1518 throw new PydConversionException( 1519 format("Couldn't convert Python type '%s' to D type '%s'%s", 1520 py_typename, 1521 d_typename, 1522 because), 1523 file, line 1524 ); 1525 } 1526 1527 // stuff this down here until we can figure out what to do with it. 1528 // Python-header-file: Modules/arraymodule.c: 1529 1530 struct arraydescr{ 1531 int typecode; 1532 int itemsize; 1533 PyObject* function(arrayobject*, Py_ssize_t) getitem; 1534 int function(arrayobject*, Py_ssize_t, PyObject*) setitem; 1535 } 1536 1537 struct arrayobject { 1538 mixin PyObject_VAR_HEAD; 1539 ubyte* ob_item; 1540 Py_ssize_t allocated; 1541 arraydescr* ob_descr; 1542 PyObject* weakreflist; /* List of weak references */ 1543 } 1544 1545 template get_type(string _module, string type_name) { 1546 @property PyTypeObject* get_type() { 1547 static PyTypeObject* m_type; 1548 static bool inited = false; 1549 if(!inited) { 1550 inited = true; 1551 PyObject* py_module = PyImport_ImportModule(_module); 1552 if(py_module) { 1553 scope(exit) Py_XDECREF(py_module); 1554 m_type = cast(PyTypeObject*) PyObject_GetAttrString( 1555 py_module, type_name 1556 ); 1557 }else{ 1558 PyErr_Clear(); 1559 } 1560 } 1561 return m_type; 1562 } 1563 } 1564 1565 alias numpy_datetime64 = get_type!("numpy", "datetime64"); 1566 alias datetime_datetime = get_type!("datetime", "datetime"); 1567 1568 1569 bool is_numpy_datetime64(PyObject* py) { 1570 auto py_type = cast(PyTypeObject*) PyObject_Type(py); 1571 return (numpy_datetime64 !is null && py_type == numpy_datetime64); 1572 } 1573 1574 T python_to_d_numpy_datetime64(T)(PyObject* py) { 1575 PyObject* astype = PyObject_GetAttrString(py, "astype"); 1576 PyObject* args = PyTuple_FromItems(cast(PyObject*) datetime_datetime); 1577 scope(exit) Py_DECREF(args); 1578 PyObject* datetime = PyObject_CallObject(astype, args); 1579 scope(exit) Py_DECREF(datetime); 1580 return python_to_d!T(datetime); 1581 }