7#include "openFileStream.h"
22 fs <<
"//Allocation and deallocation\n";
23 fs <<
"PyObject * "+className+
"_newC(PyTypeObject * type, PyObject * args, PyObject * kwds);\n\n";
40 fs <<
"struct "+className+
"{\n";
41 fs <<
"\tPyObject_HEAD\n";
43 for(PVecClassAttribute::const_iterator it(vecAttr.begin()); it != vecAttr.end(); ++it){
50 fs <<
"//TODO : add new and free for array data\n";
51 fs <<
"//getter and setters\n";
58 fs <<
"PyObject * "+className+
"_newC(PyTypeObject * type, PyObject * args, PyObject * kwds);\n";
59 fs <<
"void "+className+
"_dealloc("+className+
" * self);\n\n";
61 fs <<
"\nextern PyGetSetDef "+className+
"_getseters[];\n";
62 fs <<
"extern PyMemberDef "+className+
"_members[];\n";
63 fs <<
"extern PyMethodDef "+className+
"_methods[];\n";
64 fs <<
"extern PyTypeObject "+className+
"Type;\n\n";
73 const std::vector<PClassAttribute> & vecAttr = classConfig.
getListAttribute();
74 PString pythonClassName(classConfig.
getName());
75 PString className(
"WP"+pythonClassName);
76 if(vecAttr.size() == 0lu){
77 fs <<
"#error \""+className+
" error : Missing enum values as attribute !\"" << std::endl;
80 fs <<
"///Generic function to create a "+className+
" or a variable\n";
81 fs <<
"/**\t@param extraPythonCode : extra python code to be added to the existing one\n";
82 fs <<
" * \t@param objectName : name of the object to get\n";
83 fs <<
" * \t@return pointer to the asked object name or NULL if the object was not found\n";
85 fs <<
"PyObject* "+className+
"_newGeneric(const std::string & extraPythonCode, const std::string & objectName){\n";
86 fs <<
"\t//First let's write the python code in a string\n";
87 fs <<
"\t//Important note : it there is no default value of the enumerate values, we get a nice segmentation fault because why not\n";
88 fs <<
"\tstd::string pythonStr(\"from enum import Enum\\n\"\n";
89 fs <<
"\t\t\"class "+pythonClassName+
"(Enum):\\n\"\n";
91 for(std::vector<PClassAttribute>::const_iterator it(vecAttr.begin()); it != vecAttr.end(); ++it){
92 fs <<
"\t\t\"\t"+it->getName();
94 if(it->getDefaultValue() !=
""){
95 fs << it->getDefaultValue();
102 fs <<
"\t\t\"\tdef getTypeName():\\n\"\n";
103 fs <<
"\t\t\"\t\treturn \\\""+pythonClassName+
"\\\"\\n\"\n";
104 fs <<
"\t\t\"\");\n";
105 fs <<
"\tpythonStr += extraPythonCode;\n";
106 fs <<
"\t//Now, we create the global dictionnary of python\n";
107 fs <<
"\tPyObject *global_dict = PyDict_New(), *outputEnum = NULL;\n";
108 fs <<
"\tif(global_dict != NULL){\t//If we can create the global_dict\n";
109 fs <<
"\t\t//Py_single_input\n";
110 fs <<
"\t\tPyObject * runRes = PyRun_String(pythonStr.c_str(), Py_file_input, global_dict, global_dict);\n";
111 fs <<
"\t\tif(runRes != NULL){\t//If Python is happy\n";
112 fs <<
"\t\t\t//We try to get our enum back from the interpretor\n";
113 fs <<
"\t\t\toutputEnum = PyDict_GetItemString(global_dict, objectName.c_str());\n";
114 fs <<
"\t\t\tif(outputEnum == NULL){\n";
115 fs <<
"\t\t\t\tPyErr_SetString(PyExc_KeyError, std::string(\""+className+
"_newGeneric : could not get '\"+objectName+\"' with the ugly trick due to the fact that using an enum in a wrapper is even worst than using numpy\").c_str());\n";
116 fs <<
"\t\t\t}else{\n";
117 fs <<
"\t\t\t\tPy_INCREF(outputEnum);\n";
119 fs <<
"\t\t}else{\n";
120 fs <<
"\t\t\tPyErr_Print();\n";
121 fs <<
"\t\t\tPyErr_SetString(PyExc_KeyError, \""+className+
"_newGeneric : error when executing ugly python trick for enum\");\n";
124 fs <<
"\t\tPyErr_SetString(PyExc_KeyError, std::string(\""+className+
"_newGeneric : error when creating dictionnary to get enum '\"+objectName+\"'\").c_str());\n";
126 fs <<
"\tPy_XDECREF(global_dict);\t//Same import error with of without\n";
127 fs <<
"\treturn outputEnum;\n";
130 fs <<
"///Allocate the "+className+
"\n";
131 fs <<
"/**\t@param type : type variable\n";
132 fs <<
" * \t@param args : args variable\n";
133 fs <<
" * \t@param kwds : kwds variable\n";
134 fs <<
" * \t@return object to be allocated\n";
136 fs <<
"PyObject * "+className+
"_newC(PyTypeObject * type, PyObject * args, PyObject * kwds){\n";
137 fs <<
"\t//Here, we will use a very ugly trick but since we are doing python nobody will notice\n";
138 fs <<
"\tPyObject* outputEnum = "+className+
"_newGeneric(\"\", \""+pythonClassName+
"\");\n";
139 fs <<
"\treturn outputEnum;\n";
142 fs <<
"///Allocate the "+className+
"\n";
143 fs <<
"/**\t@param type : type variable\n";
144 fs <<
" * \t@param args : args variable\n";
145 fs <<
" * \t@param kwds : kwds variable\n";
146 fs <<
" * \t@return object to be allocated\n";
148 fs <<
"PyObject * "+className+
"_newAttributeC(){\n";
149 fs <<
"\t//Here, we will use a very ugly trick but since we are doing python nobody will notice\n";
150 fs <<
"\tPyObject* outputEnum = "+className+
"_newGeneric(\"_var_______ = "+pythonClassName+
"."+vecAttr.front().getName()+
"\\n\\n\", \"_var_______\");\n";
151 fs <<
"\treturn outputEnum;\n";
174 PString className(
"WP"+classConfig.
getName());
176 fs <<
"///Allocate the "+className+
"\n";
177 fs <<
"/**\t@param type : type variable\n";
178 fs <<
" * \t@param args : args variable\n";
179 fs <<
" * \t@param kwds : kwds variable\n";
180 fs <<
" * \t@return object to be allocated\n";
182 fs <<
"PyObject * "+className+
"_newC(PyTypeObject * type, PyObject * args, PyObject * kwds){\n";
183 fs <<
"\t"+className+
" *self;\n";
184 fs <<
"\tself = ("+className+
" *)type->tp_alloc(type, 0);\n";
185 fs <<
"\tif(self != NULL){\n";
186 const std::vector<PClassAttribute> & vecAttr = classConfig.
getListAttribute();
187 for(std::vector<PClassAttribute>::const_iterator it(vecAttr.begin()); it != vecAttr.end(); ++it){
188 PString attrType(it->getType());
190 fs <<
"\t\tself->"+it->getName()+
" = 0;\n";
191 }
else if(attrType ==
"std::string"){
192 fs <<
"\t\tself->"+it->getName()+
" = Py_BuildValue(\"s\", \"\");\n";
193 }
else if(attrType ==
"DataStreamMsg"){
194 fs <<
"\t\tself->"+it->getName()+
" = PyByteArray_FromStringAndSize(\"\", 0lu);\n";
196 fs <<
"\t\tself->"+it->getName()+
" = PyList_New(0);\n";
200 fs <<
"\t\t//There is not type for enum because of the very ugly trick of Python\n";
201 fs <<
"\t\tself->"+it->getName()+
" = WP"+attrType+
"_newAttributeC();\n";
203 fs <<
"\t\tself->"+it->getName()+
" = WP"+attrType+
"_newC(&WP"+attrType+
"Type, NULL, NULL);\n";
208 fs <<
"\treturn (PyObject *)self;\n";
217 PString className(
"WP"+classConfig.
getName());
218 fs <<
"///Deallocate the structure "+className+
"\n";
219 fs <<
"/**\t@param self : object to be deallocated\n";
221 fs <<
"void "+className+
"_dealloc("+className+
" * self){\n";
222 const std::vector<PClassAttribute> & vecAttr = classConfig.
getListAttribute();
223 for(std::vector<PClassAttribute>::const_iterator it(vecAttr.begin()); it != vecAttr.end(); ++it){
225 PString attrName = it->getName();
226 fs <<
"\t//Free the "+attrName+
" attribute\n";
227 fs <<
"\tPyObject* "+attrName+
"_tmp = self->"+attrName+
";\n";
228 fs <<
"\tself->"+attrName+
" = NULL;\n";
229 fs <<
"\tPy_XDECREF("+attrName+
"_tmp);\n";
244 fs <<
"///Getters and setters of the class "<<className<<
"\n";
245 fs <<
"PyGetSetDef "<<className<<
"_getseters[] = {\n";
248 fs <<
"\t{NULL} /* Sentinel */\n";
252 fs <<
"///Members of class "+className+
"\n";
253 fs <<
"PyMemberDef "+className+
"_members[] = {\n";
255 fs <<
"\t{NULL} /* Sentinel */\n";
258 fs <<
"///Methods of class "<<className<<
"\n";
259 fs <<
"PyMethodDef "<<className<<
"_methods[] = {\n";
261 fs <<
"\t{NULL, NULL} /* Sentinel */\n";
283 if(headerFile ==
"")
return false;
285 if(!openFileStream(fs, headerFile)){
return false;}
288 fs <<
"#ifndef " << macroDef << std::endl;
289 fs <<
"#define " << macroDef << std::endl << std::endl;
290 fs <<
"#include <Python.h>\n";
291 fs <<
"#include <structmember.h>\n";
292 fs <<
"#include <iostream>\n\n";
293 fs <<
"#include <string>" << std::endl<< std::endl;
294 if(vecInclude.size() != 0lu){
295 for(PVecPath::const_iterator it(vecInclude.begin()); it != vecInclude.end(); ++it){
296 fs <<
"#include " << *it << std::endl;
302 for(std::vector<PClassConfig>::const_iterator it(vecClassConfig.begin()); it != vecClassConfig.end(); ++it){
310 fs << std::endl << std::endl <<
"#endif" << std::endl << std::endl;
324 if(sourceFile ==
"" || headerFile ==
"")
return false;
326 if(!openFileStream(fs, sourceFile)){
return false;}
328 fs << std::endl <<
"#include \"" << headerFile.getFileName() <<
"\"" << std::endl << std::endl;
329 for(std::vector<PClassConfig>::const_iterator it(vecClassConfig.begin()); it != vecClassConfig.end(); ++it){
349 if(baseFileName ==
"")
return false;
350 PPath outputDir = outputSourceDir / PPath(mode.
moduleName);
351 if(!outputDir.createDirectory()){
return false;}
353 if(!
wrapper_generator_class_sourceFile(manager, outputDir / PPath(baseFileName + PString(
"_wrapper.cpp")), PPath(baseFileName + PString(
"_wrapper.h")), vecClassConfig, mode)){
return false;}
367 if(!openFileStream(fs, fileNameSetup)){
return false;}
370 fs <<
"from setuptools import setup\n";
371 fs <<
"from setuptools import Extension\n";
372 fs <<
"import sys\n";
373 fs <<
"#import numpy as np\n";
374 fs <<
"import subprocess\n";
376 fs <<
"def getConfigInfo(commandName, option):" << std::endl;
377 fs <<
"\t\"\"\"" << std::endl;
378 fs <<
"\tGet information of a dependency from a command" << std::endl;
379 fs <<
"\t# Parameters" << std::endl;
380 fs <<
"\t- `commandName` : command to be executed" << std::endl;
381 fs <<
"\t- `option` : option to be used" << std::endl;
382 fs <<
"\t# Returns" << std::endl;
383 fs <<
"\tCorresponding dependency info" << std::endl;
384 fs <<
"\t\"\"\"" << std::endl;
385 fs <<
"\treturn subprocess.run([commandName, option], capture_output = True, text = True).stdout.strip(\"\\n\")" << std::endl;
387 fs <<
"def addWrapperDependency(listIncludeDir, listLibDir, listLib, dependencyConfigProgram, listLibDep):" << std::endl;
388 fs <<
"\t\"\"\"" << std::endl;
389 fs <<
"\tAdd a dependency to the list of existing ones" << std::endl;
390 fs <<
"\t# Parameters" << std::endl;
391 fs <<
"\t- `listIncludeDir` : list of include directories" << std::endl;
392 fs <<
"\t- `listLibDir` : list of libraries directories" << std::endl;
393 fs <<
"\t- `listLib` : list of libraries" << std::endl;
394 fs <<
"\t- `dependencyConfigProgram` : executable to be called to get include and lib dir of the dependency" << std::endl;
395 fs <<
"\t- `listLibDep` : list of libraries to be appended to the listLib" << std::endl;
396 fs <<
"\t\"\"\"" << std::endl;
397 fs <<
"\tlistIncludeDir.append(getConfigInfo(dependencyConfigProgram, \"--include\"))" << std::endl;
398 fs <<
"\tlistLibDir.append(getConfigInfo(dependencyConfigProgram, \"--lib\"))" << std::endl;
399 fs <<
"\tlistLib.extend(listLibDep)" << std::endl;
401 fs <<
"listIncludeDir = []" << std::endl;
402 fs <<
"listLibDir = []" << std::endl;
403 fs <<
"listLib = []" << std::endl;
405 fs <<
"#listIncludeDir.append(np.get_include())" << std::endl;
406 fs <<
"#Here we call all trait wrapper such as" << std::endl;
407 fs <<
"#addWrapperDependency(listIncludeDir, listLibDir, listLib, \"phoenixdatastream-config\", [\"phoenix_data_stream\"])" << std::endl;
409 fs <<
"#The rest of the includes" << std::endl;
410 fs <<
"listIncludeDir.append(\"./\")" << std::endl;
411 fs <<
"listIncludeDir.append(\""<<moduleName<<
"/\")" << std::endl;
413 fs <<
"ext_modules = [\n";
414 fs <<
"\tExtension(\""+moduleName+
"\", sources=([\n";
416 fs <<
"\t\t\"src/"+moduleName+
"/"+config.
getFileName().getFileName().eraseExtension()+
"_wrapper.cpp\",\n";
418 fs <<
"\t\t\"src/"+moduleName+
"/"+projectParam.
name.toLower()+
"_module.cpp\"\n";
420 fs <<
"\textra_compile_args = [\"-O3\", \"-Werror\", \"-g\"],\n";
422 fs <<
"\tinclude_dirs = listIncludeDir,\n";
423 fs <<
"\tlibraries=listLib,\n";
424 fs <<
"\tlibrary_dirs=listLibDir,\n";
430 fs <<
"\t\tname=\""+moduleName+
"\",\n";
431 fs <<
"\t\tversion=\""+projectVersion+
"\",\n";
432 fs <<
"\t\text_modules=ext_modules,\n";
434 fs <<
"except Exception as e:\n";
435 fs <<
"\tprint(str(e))\n";
436 fs <<
"\tsys.exit(-1)\n";
454 PString className(classConfig.
getName());
455 PPath fileNameTest(testDirectory / PPath(
"test_" + className +
".py"));
457 if(!openFileStream(fs, fileNameTest)){
return false;}
463 fs <<
"import "+moduleName+
"\n";
465 fs <<
"from "+moduleName+
" import "+className+
"\n";
508 if(!testDirectory.createDirectory()){
return false;}
511 for(std::vector<PClassConfig>::const_iterator it(vecClassConfig.begin()); it != vecClassConfig.end() && b; ++it){
512 updateMode.
mapClass[it->getName()] = *it;
514 for(std::vector<PClassConfig>::const_iterator it(vecClassConfig.begin()); it != vecClassConfig.end() && b; ++it){
532 PPath baseFileName = config.
getFileName().getFileName().eraseExtension();
std::vector< PClassAttribute > PVecClassAttribute
std::vector< PClassConfig > PVecClassConfig
Class to describe a basic class.
const PString & getClassDocumentation() const
Returns the class documentation.
const std::vector< PClassAttribute > & getListAttribute() const
Returns the list of attributes of the class.
const PString & getName() const
Returns the class name.
bool getIsEnum() const
Say if the current PClassConfig is an enum.
Class to describe a basic class.
const PVecClassConfig & getVecClassConfig() const
Get the vector of all config class of the current pdata file.
const PPath & getFileName() const
Get the file name of the current PDataConfig.
const PVecPath & getVecInclude() const
Get the vector of all include files of the current pdata file.
Manager of the Trait backends.
void classMethodDeclaration(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Declaration of class method.
void registerClassMember(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Register class member.
void registerClassMethod(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Register class method.
void registerClassGetterSetter(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Register class getter and setter.
void classMethodImplementation(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Implementation of class method.
void testFunction(std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode) const
Implementation of test function.
void setupAddDependency(std::ofstream &fs, const GeneratorMode &mode) const
Add dependency in the setup.py.
void headerExtraInclude(std::ofstream &fs, const GeneratorMode &mode) const
Add extra include on the header.
PString getCMakeListsHeader()
Get the CMakeLists.txt header.
std::map< std::string, PClassConfig > mapClass
Map of the generated class.
PString moduleName
Name of the wrapper python module.
Set of parameters to generate a project.
PPath outputProjectDir
Output path of the full project.
GeneratorMode mode
Mode to be used to generate the project.
PString version
Version of the project.
PPath outputTestDir
Output path of the unit tests.
PVecDataConfig vecDataConfig
Configuration of classes to be generated.
PString name
Name of the project.
PPath outputSourceDir
Output path of the sources.
bool generator_typeIsList(const PString &type)
Say if a given type is a std::list.
bool getIsSimpleType(const PString &varType)
Check if the given type is a simple type.
bool project_wrapper_moduleGeneratorMain(const PPath &fileName, const ProjectParam &projectParam)
Create the main wrapper module.
bool wrapper_generator_class_headerFile(const PWrapperTraitBackendManager &manager, const PPath &headerFile, const PVecClassConfig &vecClassConfig, const GeneratorMode &mode, const PVecPath &vecInclude)
Create the wrapper declaration of the given class.
void wrapper_generator_class_source(const PWrapperTraitBackendManager &manager, std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode)
Create the wrapper implementation of the given class.
void wrapper_generator_enum_header(const PWrapperTraitBackendManager &manager, std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode)
Create the wrapper declaration of the given class.
bool project_wrapper_classTest(const PWrapperTraitBackendManager &manager, const PPath &testDirectory, const PString &moduleName, const PClassConfig &classConfig, const GeneratorMode &mode)
Generate the test for all class inside the module.
bool wrapper_generator_class_cpp_test(const PWrapperTraitBackendManager &manager, const PPath &testDirectory, const PString &moduleName, const std::vector< PClassConfig > &vecClassConfig, const GeneratorMode &mode)
Generate the test for all class inside the module.
void wrapper_generator_class_header(const PWrapperTraitBackendManager &manager, std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode)
Create the wrapper declaration of the given class.
bool wrapper_generator_class_cpp(const PWrapperTraitBackendManager &manager, const std::vector< PClassConfig > &vecClassConfig, const PPath &outputSourceDir, const PPath &baseFileName, const GeneratorMode &mode, const PVecPath &vecInclude)
Creates wrapper header and source files.
void wrapper_generator_class_implDealloc(std::ofstream &fs, const PClassConfig &classConfig)
Implement new and dealloc.
bool wrapper_generator_class_sourceFile(const PWrapperTraitBackendManager &manager, const PPath &sourceFile, const PPath &headerFile, const std::vector< PClassConfig > &vecClassConfig, const GeneratorMode &mode)
Create the wrapper implementation of the given file.
void project_wrapper_enumImplNewc(std::ofstream &fs, const PClassConfig &classConfig)
Implement new and dealloc.
bool wrapper_generator_class_full(const PWrapperTraitBackendManager &manager, const ProjectParam &projectParam)
Generate the full sources and related unit tests from configuration.
bool project_wrapper_generator_setuppy(const PWrapperTraitBackendManager &manager, const ProjectParam &projectParam, const PPath &fileNameSetup, const PString &projectVersion)
Create the readme of the project directory.
void wrapper_generator_class_implNewc(std::ofstream &fs, const PClassConfig &classConfig)
Implement new and dealloc.
void wrapper_generator_enum_source(const PWrapperTraitBackendManager &manager, std::ofstream &fs, const PClassConfig &classConfig, const GeneratorMode &mode)
Create the wrapper implementation of the given class.
PString project_wrapper_classImplPythonType(const PClassConfig &classConfig, const PString &moduleName, const PString &fromOtherType)
Create the Python type of the given class.
PString project_wrapper_attributeDef(const PClassAttribute &attr)
Get the C++ definition of an attribute.
PString wrapper_getClassName(const PClassConfig &classConfig)
Get the corresponding wrapper class name.