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 }