1 module python.conv.d_to_python;
2 
3 
4 import python.raw: PyObject;
5 import python.type: isUserAggregate, isTuple, isNonRangeUDT;
6 import std.traits: Unqual, isIntegral, isFloatingPoint, isAggregateType,
7     isStaticArray, isAssociativeArray, isPointer, isSomeChar,
8     isCallable, isSomeString, isFunctionPointer, isDelegate,
9     PointerTarget;
10 import std.range: isInputRange, isInfinite;
11 import std.datetime: Date, DateTime;
12 import core.time: Duration;
13 
14 
15 PyObject* toPython(T)(T value) @trusted if(isIntegral!T && !is(T == enum)) {
16     import python.raw: PyLong_FromLong;
17     return PyLong_FromLong(value);
18 }
19 
20 
21 PyObject* toPython(T)(T value) @trusted if(isFloatingPoint!T) {
22     import python.raw: PyFloat_FromDouble;
23     return PyFloat_FromDouble(value);
24 }
25 
26 
27 PyObject* toPython(T)(T value) if(is(Unqual!T == void[])) {
28     auto bytes = cast(ubyte[]) value;
29     return bytes.toPython;
30 }
31 
32 
33 PyObject* toPython(T)(T value)
34     if(isInputRange!T && !isInfinite!T && !isSomeString!T && !isStaticArray!T)
35 {
36     import python.raw: PyList_New, PyList_SetItem, PyList_Append;
37     import std.range: isForwardRange, enumerate;
38 
39     static if(__traits(hasMember, T, "length")) {
40         const length = value.length;
41         enum append = false;
42     } else static if(isForwardRange!T) {
43         import std.range: walkLength;
44         import std.array: save;
45         const length = walkLength(value.save);
46         enum append = false;
47     } else {
48         enum length = 0;
49         enum append = true;
50     }
51 
52     auto ret = PyList_New(length);
53 
54     foreach(i, elt; value.enumerate) {
55         static if(append)
56             PyList_Append(ret, toPython(elt));
57         else
58             PyList_SetItem(ret, i, toPython(elt));
59     }
60 
61     return ret;
62 }
63 
64 PyObject* toPython(T)(T value)
65     if(isInputRange!T && isInfinite!T)
66 {
67     import python.type: pythonClass;
68     return pythonClass(value);
69 }
70 
71 
72 PyObject* toPython(T)(auto ref T value) if(isNonRangeUDT!T) {
73     import python.type: pythonClass;
74     return pythonClass(value);
75 }
76 
77 
78 PyObject* toPython(T)(T value)
79     if(isPointer!T && !isFunctionPointer!T && !isDelegate!T && !is(Unqual!(PointerTarget!T) == void))
80 {
81     import autowrap.common: AlwaysTry;
82 
83     static if(AlwaysTry || __traits(compiles, toPython(*value))) {
84         import std.traits: PointerTarget;
85         import std..string: fromStringz;
86 
87         static if(is(PointerTarget!T == const(char)) || is(PointerTarget!T == immutable(char)))
88             return value.fromStringz.toPython;
89         else
90             return toPython(*value);
91     } else {
92         import std.traits: fullyQualifiedName;
93         enum msg = "could not convert " ~ fullyQualifiedName!T ~ " to Python";
94         pragma(msg, "WARNING: ", msg);
95         throw new Exception(msg);
96     }
97 }
98 
99 
100 PyObject* toPython(T)(T value)
101     if(isPointer!T && is(Unqual!(PointerTarget!T) == void))
102 {
103     throw new Exception("Converting void* to Python is not supported");
104 }
105 
106 
107 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) {
108     import python.raw: pyDateTimeFromDateAndTime;
109     return pyDateTimeFromDateAndTime(value.year, value.month, value.day,
110                                      value.hour, value.minute, value.second);
111 }
112 
113 
114 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) {
115     import python.raw: pyDateFromDate;
116     return pyDateFromDate(value.year, value.month, value.day);
117 }
118 
119 
120 PyObject* toPython(T)(T value) if(isSomeString!T) {
121     import python.raw: pyUnicodeFromStringAndSize;
122     import std.conv: to;
123     auto str = value.to!string;
124     return pyUnicodeFromStringAndSize(str.ptr, str.length);
125 }
126 
127 
128 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
129     import python.raw: PyBool_FromLong;
130     return PyBool_FromLong(value);
131 }
132 
133 
134 PyObject* toPython(T)(T value) if(isStaticArray!T) {
135     return toPython(value[]);
136 }
137 
138 
139 PyObject* toPython(T)(T value) if(isAssociativeArray!T) {
140     import python.raw: PyDict_New, PyDict_SetItem;
141 
142     auto ret = PyDict_New;
143 
144     foreach(k, v; value) {
145         PyDict_SetItem(ret, k.toPython, v.toPython);
146     }
147 
148     return ret;
149 }
150 
151 PyObject* toPython(T)(T value) if(isTuple!T) {
152     import python.raw: PyTuple_New, PyTuple_SetItem;
153 
154     auto ret = PyTuple_New(value.length);
155 
156     static foreach(i; 0 .. T.length) {
157         PyTuple_SetItem(ret, i, value[i].toPython);
158     }
159 
160     return ret;
161 }
162 
163 
164 PyObject* toPython(T)(T value) if(is(Unqual!T == char) || is(Unqual!T == wchar) || is(Unqual!T == dchar)) {
165     return [value].toPython;
166 }
167 
168 
169 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) {
170     import python.type: pythonCallable;
171     return pythonCallable(value);
172 }
173 
174 
175 PyObject* toPython(T)(T value) if(is(Unqual!T == Duration)) {
176     import python.raw: pyDeltaFromDSU;
177     int days, seconds, useconds;
178     value.split!("days", "seconds", "usecs")(days, seconds, useconds);
179     return pyDeltaFromDSU(days, seconds, useconds);
180 }
181 
182 
183 PyObject* toPython(T)(T value) if(is(T == enum)) {
184     import std.traits: OriginalType;
185     return toPython(cast(OriginalType!T) value);
186 }