1 module python.boilerplate; 2 3 import python.raw: isPython2, isPython3; 4 5 /// For a nicer API 6 struct Module { 7 string name; 8 } 9 10 11 /// For a nicer API 12 struct CFunctions(functions...) { 13 alias symbols = functions; 14 enum length = functions.length; 15 16 static string stringifySymbols() { 17 import std.array: join; 18 19 string[] ret; 20 21 static foreach(cfunction; symbols) 22 ret ~= __traits(identifier, cfunction); 23 24 return ret.join(", "); 25 } 26 } 27 28 /// A list of aggregates to wrap 29 struct Aggregates(T...) { 30 alias Types = T; 31 32 static string stringifyTypes() { 33 import std.array: join; 34 string[] ret; 35 36 static foreach(T; Types) 37 ret ~= T.stringof; 38 39 return ret.join(", "); 40 } 41 } 42 43 44 /** 45 A string mixin to reduce boilerplate when creating a Python module. 46 Takes a module name and a variadic list of C functions to make 47 available. 48 */ 49 string createModuleMixin(Module module_, alias cfunctions, alias aggregates)() 50 if(isPython3) 51 { 52 import std.format: format; 53 54 enum ret = q{ 55 import python.raw: PyDateTime_CAPI; 56 // This is declared as an extern C variable in python.bindings. 57 // We declare it here to avoid linker errors. 58 export __gshared extern(C) PyDateTime_CAPI* PyDateTimeAPI; 59 60 import python: ModuleInitRet; 61 62 extern(C) export ModuleInitRet PyInit_%s() { 63 import python.raw: pyDateTimeImport; 64 import python.cooked: createModule; 65 import python.boilerplate: Module, CFunctions, Aggregates; 66 67 pyDateTimeImport; 68 69 return createModule!( 70 Module("%s"), 71 CFunctions!( 72 %s 73 ), 74 Aggregates!( 75 %s 76 ) 77 ); 78 } 79 }.format(module_.name, module_.name, cfunctions.stringifySymbols, aggregates.stringifyTypes); 80 81 return ret; 82 } 83 84 string createModuleMixin(Module module_, alias cfunctions, alias aggregates)() 85 if(isPython2) 86 { 87 import std.format: format; 88 89 enum ret = q{ 90 import python.raw: PyDateTime_CAPI; 91 92 // This is declared as an extern C variable in python.bindings. 93 // We declare it here to avoid linker errors. 94 export __gshared extern(C) PyDateTime_CAPI* PyDateTimeAPI; 95 96 extern(C) export void init%s() { 97 import python.raw: pyDateTimeImport; 98 import python.cooked: initModule; 99 import python.boilerplate: Module, CFunctions, Aggregates; 100 101 pyDateTimeImport; 102 initModule!( 103 Module("%s"), 104 CFunctions!( 105 %s 106 ), 107 Aggregates!( 108 %s 109 ), 110 ); 111 } 112 }.format(module_.name, module_.name, cfunctions.stringifySymbols, aggregates.stringifyTypes); 113 114 return ret; 115 }