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 }