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 static if(__traits(compiles, toPython(*value))) { 82 import std.traits: PointerTarget; 83 import std.string: fromStringz; 84 85 static if(is(PointerTarget!T == const(char)) || is(PointerTarget!T == immutable(char))) 86 return value.fromStringz.toPython; 87 else 88 return toPython(*value); 89 } else { 90 import std.traits: fullyQualifiedName; 91 enum msg = "could not convert " ~ fullyQualifiedName!T ~ " to Python"; 92 pragma(msg, "WARNING: ", msg); 93 throw new Exception(msg); 94 } 95 } 96 97 98 PyObject* toPython(T)(T value) 99 if(isPointer!T && is(Unqual!(PointerTarget!T) == void)) 100 { 101 throw new Exception("Converting void* to Python is not supported"); 102 } 103 104 105 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) { 106 import python.raw: pyDateTimeFromDateAndTime; 107 return pyDateTimeFromDateAndTime(value.year, value.month, value.day, 108 value.hour, value.minute, value.second); 109 } 110 111 112 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) { 113 import python.raw: pyDateFromDate; 114 return pyDateFromDate(value.year, value.month, value.day); 115 } 116 117 118 PyObject* toPython(T)(T value) if(isSomeString!T) { 119 import python.raw: pyUnicodeFromStringAndSize; 120 import std.conv: to; 121 auto str = value.to!string; 122 return pyUnicodeFromStringAndSize(str.ptr, str.length); 123 } 124 125 126 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) { 127 import python.raw: PyBool_FromLong; 128 return PyBool_FromLong(value); 129 } 130 131 132 PyObject* toPython(T)(T value) if(isStaticArray!T) { 133 return toPython(value[]); 134 } 135 136 137 PyObject* toPython(T)(T value) if(isAssociativeArray!T) { 138 import python.raw: PyDict_New, PyDict_SetItem; 139 140 auto ret = PyDict_New; 141 142 foreach(k, v; value) { 143 PyDict_SetItem(ret, k.toPython, v.toPython); 144 } 145 146 return ret; 147 } 148 149 PyObject* toPython(T)(T value) if(isTuple!T) { 150 import python.raw: PyTuple_New, PyTuple_SetItem; 151 152 auto ret = PyTuple_New(value.length); 153 154 static foreach(i; 0 .. T.length) { 155 PyTuple_SetItem(ret, i, value[i].toPython); 156 } 157 158 return ret; 159 } 160 161 162 PyObject* toPython(T)(T value) if(is(Unqual!T == char) || is(Unqual!T == wchar) || is(Unqual!T == dchar)) { 163 return [value].toPython; 164 } 165 166 167 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) { 168 import python.type: pythonCallable; 169 return pythonCallable(value); 170 } 171 172 173 PyObject* toPython(T)(T value) if(is(Unqual!T == Duration)) { 174 import python.raw: pyDeltaFromDSU; 175 int days, seconds, useconds; 176 value.split!("days", "seconds", "usecs")(days, seconds, useconds); 177 return pyDeltaFromDSU(days, seconds, useconds); 178 } 179 180 181 PyObject* toPython(T)(T value) if(is(T == enum)) { 182 import std.traits: OriginalType; 183 return toPython(cast(OriginalType!T) value); 184 }