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