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