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