source: sasview/src/sas/models/c_extension/python_wrapper/WrapperGenerator.py @ 1f5f206

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 1f5f206 was 1f5f206, checked in by butler, 9 years ago

Fix sphinx compile errors with autogenerated model files. Was including
the path in doc string which for windows uses a slash which ReST
interprets as an escape charater. Was not rendering the source file
correctly for ANY of the generated but was a particular problem for
files that had an f as \f is formfeed.

  • Property mode set to 100644
File size: 23.2 KB
RevLine 
[fd5ac0d]1#!/usr/bin/env python
2""" WrapperGenerator class to generate model code automatically.
3"""
4
[13e46abe]5import os, sys, re
[fd5ac0d]6import lineparser
7
[13e46abe]8class WrapperGenerator(object):
[fd5ac0d]9    """ Python wrapper generator for C models
[13e46abe]10
11        The developer must provide a header file describing
[fd5ac0d]12        the new model.
[13e46abe]13
[fd5ac0d]14        To provide the name of the Python class to be
[13e46abe]15        generated, the .h file must contain the following
[fd5ac0d]16        string in the comments:
[13e46abe]17
[fd5ac0d]18        // [PYTHONCLASS] = my_model
[13e46abe]19
[fd5ac0d]20        where my_model must be replaced by the name of the
21        class that you want to import from sas.models.
22        (example: [PYTHONCLASS] = MyModel
23          will create a class MyModel in sas.models.MyModel.
[13e46abe]24          It will also create a class CMyModel in
[fd5ac0d]25          sas_extension.c_models.)
[13e46abe]26
27        Also in comments, each parameter of the params
[fd5ac0d]28        dictionary must be declared with a default value
29        in the following way:
[13e46abe]30
[fd5ac0d]31        // [DEFAULT]=param_name=default_value
[13e46abe]32
[fd5ac0d]33        (example:
34            //  [DEFAULT]=radius=20.0
35        )
[13e46abe]36
[fd5ac0d]37        See cylinder.h for an example.
[13e46abe]38
[fd5ac0d]39        A .c file corresponding to the .h file should also
40        be provided (example: my_model.h, my_model.c).
[13e46abe]41
[fd5ac0d]42        The .h file should define two function definitions. For example,
43        cylinder.h defines the following:
[13e46abe]44
[fd5ac0d]45        /// 1D scattering function
46        double cylinder_analytical_1D(CylinderParameters *pars, double q);
[13e46abe]47
[fd5ac0d]48        /// 2D scattering function
49        double cylinder_analytical_2D(CylinderParameters *pars, double q, double phi);
[13e46abe]50
[fd5ac0d]51        The .c file implements those functions.
[13e46abe]52
[fd5ac0d]53        @author: Mathieu Doucet / UTK
54        @contact: mathieu.doucet@nist.gov
55    """
[13e46abe]56
[fd5ac0d]57    def __init__(self, filename, output_dir='.', c_wrapper_dir='.'):
58        """ Initialization """
[13e46abe]59
[fd5ac0d]60        ## Name of .h file to generate wrapper from
61        self.file = filename
[13e46abe]62
[fd5ac0d]63        # Info read from file
[13e46abe]64
[fd5ac0d]65        ## Name of python class to write
66        self.pythonClass = None
67        ## Parser in struct section
68        self.inStruct = False
69        self.foundCPP = False
70        self.inParDefs = False
71        ## Name of struct for the c object
72        self.structName = None
73        ## Dictionary of parameters
74        self.params = {}
75        ## ModelCalculation module flag
76        self.modelCalcFlag = False
77        ## List of default parameters (text)
78        self.default_list = ""
79        ## Dictionary of units
80        self.details = ""
81        ## List of dispersed parameters
82        self.disp_params = []
83        #model description
[13e46abe]84        self.description = ''
[fd5ac0d]85        # paramaters for fittable
[13e46abe]86        self.fixed = []
[fd5ac0d]87        # paramaters for non-fittable
[13e46abe]88        self.non_fittable = []
[fd5ac0d]89        ## parameters with orientation
[13e46abe]90        self.orientation_params = []
[fd5ac0d]91        ## parameter with magnetism
92        self.magentic_params = []
93        # Model category
94        self.category = None
95        # Whether model belongs to multifunc
96        self.is_multifunc = False
97        ## output directory for wrappers
98        self.output_dir = output_dir
99        self.c_wrapper_dir = c_wrapper_dir
100
101    def __repr__(self):
102        """ Simple output for printing """
[13e46abe]103
104        rep = "\n Python class: %s\n\n" % self.pythonClass
[fd5ac0d]105        rep += "  struc name: %s\n\n" % self.structName
106        rep += "  params:     %s\n\n" % self.params
107        rep += "  description:    %s\n\n" % self.description
[13e46abe]108        rep += "  Fittable parameters:     %s\n\n" % self.fixed
109        rep += "  Non-Fittable parameters:     %s\n\n" % self.non_fittable
110        rep += "  Orientation parameters:  %s\n\n" % self.orientation_params
111        rep += "  Magnetic parameters:  %s\n\n" % self.magnetic_params
[fd5ac0d]112        return rep
[13e46abe]113
[fd5ac0d]114    def read(self):
115        """ Reads in the .h file to catch parameters of the wrapper """
[13e46abe]116
[fd5ac0d]117        # Check if the file is there
118        if not os.path.isfile(self.file):
119            raise ValueError, "File %s is not a regular file" % self.file
[13e46abe]120
[fd5ac0d]121        # Read file
[13e46abe]122        f = open(self.file, 'r')
[fd5ac0d]123        buf = f.read()
[13e46abe]124
[fd5ac0d]125        self.default_list = "\n    List of default parameters:\n\n"
126        #lines = string.split(buf,'\n')
127        lines = buf.split('\n')
[13e46abe]128        self.details = "## Parameter details [units, min, max]\n"
[fd5ac0d]129        self.details += "        self.details = {}\n"
[13e46abe]130
[fd5ac0d]131        #open item in this case Fixed
[13e46abe]132        text = 'text'
133        key2 = "<%s>" % text.lower()
[fd5ac0d]134        # close an item in this case fixed
[13e46abe]135        text = 'TexT'
136        key3 = "</%s>" % text.lower()
137
[fd5ac0d]138        ## Catch fixed parameters
139        key = "[FIXED]"
140        try:
[13e46abe]141            self.fixed = lineparser.readhelper(lines, key,
142                                               key2, key3, file=self.file)
[fd5ac0d]143        except:
[13e46abe]144            raise
[fd5ac0d]145        ## Catch non-fittable parameters parameters
146        key = "[NON_FITTABLE_PARAMS]"
147        try:
[13e46abe]148            self.non_fittable = lineparser.readhelper(lines, key, key2,
149                                                      key3, file=self.file)
[fd5ac0d]150        except:
[13e46abe]151            raise
[fd5ac0d]152
153        ## Catch parameters with orientation
[13e46abe]154        key = "[ORIENTATION_PARAMS]"
[fd5ac0d]155        try:
[13e46abe]156            self.orientation_params = lineparser.readhelper(lines, key,
157                                                            key2, key3, file=self.file)
[fd5ac0d]158        except:
[13e46abe]159            raise
160
[fd5ac0d]161        ## Catch parameters with orientation
[13e46abe]162        key = "[MAGNETIC_PARAMS]"
[fd5ac0d]163        try:
[13e46abe]164            self.magnetic_params = lineparser.readhelper(lines, key,
165                                                         key2, key3, file=self.file)
[fd5ac0d]166        except:
[13e46abe]167            raise
168
[fd5ac0d]169        ## Catch Description
170        key = "[DESCRIPTION]"
[13e46abe]171
[fd5ac0d]172        find_description = False
[13e46abe]173        temp = ""
[fd5ac0d]174        for line in lines:
[13e46abe]175            if line.count(key) > 0:
[fd5ac0d]176                try:
[13e46abe]177                    find_description = True
[fd5ac0d]178                    index = line.index(key)
[13e46abe]179                    toks = line[index:].split("=", 1)
180                    temp = toks[1].lstrip().rstrip()
181                    text = 'text'
182                    key2 = "<%s>" % text.lower()
183                    if re.match(key2, temp) != None:
184
185                        toks2 = temp.split(key2, 1)
186                        self.description = toks2[1]
187                        text = 'text'
188                        key2 = "</%s>" % text.lower()
189                        if re.search(key2, toks2[1]) != None:
190                            temp = toks2[1].split(key2, 1)
191                            self.description = temp[0]
[fd5ac0d]192                            break
[13e46abe]193
[fd5ac0d]194                    else:
[13e46abe]195                        self.description = temp
[fd5ac0d]196                        break
197                except:
[13e46abe]198                    raise ValueError, "Could not parse file %s" % self.file
[fd5ac0d]199            elif find_description:
[13e46abe]200                text = 'text'
201                key2 = "</%s>" % text.lower()
202                if re.search(key2, line) != None:
203                    tok = line.split(key2, 1)
204                    temp = tok[0].split("//", 1)
205                    self.description += tok[1].lstrip().rstrip()
[fd5ac0d]206                    break
207                else:
[13e46abe]208                    if re.search("//", line) != None:
209                        temp = line.split("//", 1)
210                        self.description += '\n\t\t' + temp[1].lstrip().rstrip()
211
[fd5ac0d]212                    else:
[13e46abe]213                        self.description += '\n\t\t' + line.lstrip().rstrip()
214
215
216
[fd5ac0d]217        for line in lines:
[13e46abe]218
[fd5ac0d]219            # Catch class name
220            key = "[PYTHONCLASS]"
[13e46abe]221            if line.count(key) > 0:
[fd5ac0d]222                try:
223                    index = line.index(key)
[13e46abe]224                    toks = line[index:].split("=")
[fd5ac0d]225                    self.pythonClass = toks[1].lstrip().rstrip()
226
227                except:
228                    raise ValueError, "Could not parse file %s" % self.file
[13e46abe]229
[fd5ac0d]230            key = "[CATEGORY]"
[13e46abe]231            if line.count(key) > 0:
[fd5ac0d]232                try:
233                    index = line.index(key)
234                    toks = line[index:].split("=")
235                    self.category = toks[1].lstrip().rstrip()
236
237                except:
238                    raise ValueError, "Could not parse file %s" % self.file
239
240            # is_multifunc
241            key = "[MULTIPLICITY_INFO]"
242            if line.count(key) > 0:
243                self.is_multifunc = True
244                try:
245                    index = line.index(key)
246                    toks = line[index:].split("=")
247                    self.multiplicity_info = toks[1].lstrip().rstrip()
248                except:
249                    raise ValueError, "Could not parse file %s" % self.file
250
251            # Catch struct name
252            # C++ class definition
[13e46abe]253            if line.count("class") > 0:
[fd5ac0d]254                # We are entering a class definition
255                self.inParDefs = True
256                self.foundCPP = True
[13e46abe]257
[fd5ac0d]258            # Old-Style C struct definition
[13e46abe]259            if line.count("typedef struct") > 0:
[fd5ac0d]260                # We are entering a struct block
261                self.inParDefs = True
262                self.inStruct = True
[13e46abe]263
264            if self.inParDefs and line.count("}") > 0:
[fd5ac0d]265                # We are exiting a struct block
266                self.inParDefs = False
[13e46abe]267
[fd5ac0d]268                if self.inStruct:
269                    self.inStruct = False
270                    # Catch the name of the struct
271                    index = line.index("}")
[13e46abe]272                    toks = line[index + 1:].split(";")
[fd5ac0d]273                    # Catch pointer definition
274                    toks2 = toks[0].split(',')
275                    self.structName = toks2[0].lstrip().rstrip()
[13e46abe]276
[fd5ac0d]277            # Catch struct content
278            key = "[DEFAULT]"
[13e46abe]279            if self.inParDefs and line.count(key) > 0:
[fd5ac0d]280                # Found a new parameter
281                try:
282                    index = line.index(key)
283                    toks = line[index:].split("=")
284                    toks2 = toks[2].split()
285                    val = float(toks2[0])
286                    self.params[toks[1]] = val
287                    #self.pythonClass = toks[1].lstrip().rstrip()
288                    units = ""
289                    if len(toks2) >= 2:
290                        units = toks2[1]
291                    self.default_list += "    * %-15s = %s %s\n" % \
292                        (toks[1], val, units)
[13e46abe]293
[fd5ac0d]294                    # Check for min and max
[13e46abe]295                    value_min = "None"
296                    value_max = "None"
[fd5ac0d]297                    if len(toks2) == 4:
[13e46abe]298                        value_min = toks2[2]
299                        value_max = toks2[3]
300
[fd5ac0d]301                    self.details += "        self.details['%s'] = ['%s', %s, %s]\n" % \
[13e46abe]302                        (toks[1].lstrip().rstrip(), units.lstrip().rstrip(), value_min, value_max)
[fd5ac0d]303                except:
304                    raise ValueError, "Could not parse input file %s \n  %s" % \
305                        (self.file, sys.exc_value)
[13e46abe]306
307
[fd5ac0d]308            # Catch need for numerical calculations
309            key = "CalcParameters calcPars"
[13e46abe]310            if line.count(key) > 0:
[fd5ac0d]311                self.modelCalcFlag = True
[13e46abe]312
[fd5ac0d]313            # Catch list of dispersed parameters
314            key = "[DISP_PARAMS]"
[13e46abe]315            if line.count(key) > 0:
[fd5ac0d]316                try:
317                    index = line.index(key)
318                    toks = line[index:].split("=")
319                    list_str = toks[1].lstrip().rstrip()
320                    self.disp_params = list_str.split(',')
321                except:
322                    raise ValueError, "Could not parse file %s" % self.file
323
324    def write_c_wrapper(self):
325        """ Writes the C file to create the python extension class
326            The file is written in C[PYTHONCLASS].c
327        """
[13e46abe]328        file_path = os.path.join(self.c_wrapper_dir,
329                                 "C" + self.pythonClass + '.cpp')
[fd5ac0d]330        file = open(file_path, 'w')
[13e46abe]331
332        template = open(os.path.join(os.path.dirname(__file__),
[fd5ac0d]333                                     "classTemplate.txt"), 'r')
[13e46abe]334
[fd5ac0d]335        tmp_buf = template.read()
336        #tmp_lines = string.split(tmp_buf,'\n')
337        tmp_lines = tmp_buf.split('\n')
[13e46abe]338
[fd5ac0d]339        for tmp_line in tmp_lines:
[13e46abe]340
[fd5ac0d]341            # Catch class name
[13e46abe]342            newline = self.replaceToken(tmp_line,
343                                        "[PYTHONCLASS]", 'C' + self.pythonClass)
[fd5ac0d]344            #Catch model description
345            #newline = self.replaceToken(tmp_line,
346            #                            "[DESCRIPTION]", self.description)
347            # Catch C model name
[13e46abe]348            newline = self.replaceToken(newline,
[fd5ac0d]349                                        "[CMODEL]", self.pythonClass)
[13e46abe]350
[fd5ac0d]351            # Catch class name
[13e46abe]352            newline = self.replaceToken(newline,
[fd5ac0d]353                                        "[MODELSTRUCT]", self.structName)
354
355            # Sort model initialization based on multifunc
[13e46abe]356            if self.is_multifunc:
[fd5ac0d]357                line = "int level = 1;\nPyArg_ParseTuple(args,\"i\",&level);\n"
358                line += "self->model = new " + self.pythonClass + "(level);"
359            else:
360                line = "self->model = new " + self.pythonClass + "();"
[13e46abe]361
362            newline = self.replaceToken(newline, "[INITIALIZE_MODEL]", line)
363
[fd5ac0d]364            # Dictionary initialization
[13e46abe]365            param_str = "// Initialize parameter dictionary\n"
[fd5ac0d]366            for par in self.params:
367                param_str += "        PyDict_SetItemString(self->params,\"%s\",Py_BuildValue(\"d\",%10.12f));\n" % \
368                    (par, self.params[par])
369
[13e46abe]370            if len(self.disp_params) > 0:
[fd5ac0d]371                param_str += "        // Initialize dispersion / averaging parameter dict\n"
372                param_str += "        DispersionVisitor* visitor = new DispersionVisitor();\n"
373                param_str += "        PyObject * disp_dict;\n"
374                for par in self.disp_params:
375                    par = par.strip()
376                    if par == '':
377                        continue
378                    param_str += "        disp_dict = PyDict_New();\n"
379                    param_str += "        self->model->%s.dispersion->accept_as_source(visitor, self->model->%s.dispersion, disp_dict);\n" % (par, par)
380                    param_str += "        PyDict_SetItemString(self->dispersion, \"%s\", disp_dict);\n" % par
[13e46abe]381
[fd5ac0d]382            # Initialize dispersion object dictionnary
383            param_str += "\n"
[13e46abe]384
385
[fd5ac0d]386            newline = self.replaceToken(newline,
387                                        "[INITDICTIONARY]", param_str)
[13e46abe]388
[fd5ac0d]389            # Read dictionary
390            param_str = "    // Reader parameter dictionary\n"
391            for par in self.params:
392                param_str += "    self->model->%s = PyFloat_AsDouble( PyDict_GetItemString(self->params, \"%s\") );\n" % \
393                    (par, par)
[13e46abe]394
395            if len(self.disp_params) > 0:
[fd5ac0d]396                param_str += "    // Read in dispersion parameters\n"
397                param_str += "    PyObject* disp_dict;\n"
398                param_str += "    DispersionVisitor* visitor = new DispersionVisitor();\n"
399                for par in self.disp_params:
400                    par = par.strip()
401                    if par == '':
402                        continue
403                    param_str += "    disp_dict = PyDict_GetItemString(self->dispersion, \"%s\");\n" % par
404                    param_str += "    self->model->%s.dispersion->accept_as_destination(visitor, self->model->%s.dispersion, disp_dict);\n" % (par, par)
[13e46abe]405
[fd5ac0d]406            newline = self.replaceToken(newline, "[READDICTIONARY]", param_str)
[13e46abe]407
[fd5ac0d]408            # Name of .c file
409            #toks = string.split(self.file,'.')
410            basename = os.path.basename(self.file)
411            toks = basename.split('.')
412            newline = self.replaceToken(newline, "[C_FILENAME]", toks[0])
[13e46abe]413
[fd5ac0d]414            # Include file
415            basename = os.path.basename(self.file)
[13e46abe]416            newline = self.replaceToken(newline,
417                                        "[INCLUDE_FILE]", self.file)
[fd5ac0d]418            if self.foundCPP:
[13e46abe]419                newline = self.replaceToken(newline, "[C_INCLUDE_FILE]", "")
420                newline = self.replaceToken(newline,
421                                            "[CPP_INCLUDE_FILE]",
422                                            "#include \"%s\"" % basename)
423            else:
424                newline = self.replaceToken(newline,
425                                            "[C_INCLUDE_FILE]",
426                                            "#include \"%s\"" % basename)
427                newline = self.replaceToken(newline,
428                                            "[CPP_INCLUDE_FILE]",
429                                            "#include \"models.hh\"")
430
[fd5ac0d]431            # Numerical calcs dealloc
432            dealloc_str = "\n"
433            if self.modelCalcFlag:
434                dealloc_str = "    modelcalculations_dealloc(&(self->model_pars.calcPars));\n"
[13e46abe]435            newline = self.replaceToken(newline,
436                                        "[NUMERICAL_DEALLOC]", dealloc_str)
437
[fd5ac0d]438            # Numerical calcs init
439            init_str = "\n"
440            if self.modelCalcFlag:
441                init_str = "        modelcalculations_init(&(self->model_pars.calcPars));\n"
[13e46abe]442            newline = self.replaceToken(newline,
443                                        "[NUMERICAL_INIT]", init_str)
444
[fd5ac0d]445            # Numerical calcs reset
446            reset_str = "\n"
447            if self.modelCalcFlag:
448                reset_str = "modelcalculations_reset(&(self->model_pars.calcPars));\n"
[13e46abe]449            newline = self.replaceToken(newline,
450                                        "[NUMERICAL_RESET]", reset_str)
451
[fd5ac0d]452            # Setting dispsertion weights
453            set_weights = "    // Ugliness necessary to go from python to C\n"
454            set_weights = "    // TODO: refactor this\n"
455            for par in self.disp_params:
456                par = par.strip()
457                if par == '':
458                        continue
459                set_weights += "    if (!strcmp(par_name, \"%s\")) {\n" % par
460                set_weights += "        self->model->%s.dispersion = dispersion;\n" % par
461                set_weights += "    } else"
[13e46abe]462            newline = self.replaceToken(newline,
463                                        "[SET_DISPERSION]", set_weights)
464
[fd5ac0d]465            # Write new line to the wrapper .c file
[13e46abe]466            file.write(newline + '\n')
467
468
[fd5ac0d]469        file.close()
[13e46abe]470
[fd5ac0d]471    def write_python_wrapper(self):
472        """ Writes the python file to create the python extension class
473            The file is written in ../[PYTHONCLASS].py
474        """
[13e46abe]475        file_path = os.path.join(self.output_dir, self.pythonClass + '.py')
[fd5ac0d]476        file = open(file_path, 'w')
[13e46abe]477        template = open(os.path.join(os.path.dirname(__file__),
[fd5ac0d]478                                     "modelTemplate.txt"), 'r')
[13e46abe]479
[fd5ac0d]480        tmp_buf = template.read()
481        tmp_lines = tmp_buf.split('\n')
[13e46abe]482
[fd5ac0d]483        for tmp_line in tmp_lines:
[13e46abe]484
[fd5ac0d]485            # Catch class name
[13e46abe]486            newline = self.replaceToken(tmp_line,
487                                        "[CPYTHONCLASS]",
[fd5ac0d]488                                        'C' + self.pythonClass)
[13e46abe]489
[fd5ac0d]490            # Catch class name
[13e46abe]491            newline = self.replaceToken(newline,
[fd5ac0d]492                                        "[PYTHONCLASS]", self.pythonClass)
[13e46abe]493
[fd5ac0d]494            # Include file
[13e46abe]495            newline = self.replaceToken(newline,
496                                        "[INCLUDE_FILE]", self.file)
497
[fd5ac0d]498            # Include file
[13e46abe]499            newline = self.replaceToken(newline,
[fd5ac0d]500                                        "[DEFAULT_LIST]", self.default_list)
501            # model description
[13e46abe]502            newline = self.replaceToken(newline,
[fd5ac0d]503                                        "[DESCRIPTION]", self.description)
504            # Parameter details
[13e46abe]505            newline = self.replaceToken(newline,
[fd5ac0d]506                                        "[PAR_DETAILS]", self.details)
[13e46abe]507
[fd5ac0d]508            # Call base constructor
509            if self.is_multifunc:
[13e46abe]510                newline = self.replaceToken(newline, "[CALL_CPYTHON_INIT]",
511                                            'C' + self.pythonClass + \
[fd5ac0d]512                    ".__init__(self,multfactor)\n\tself.is_multifunc = True")
[13e46abe]513                newline = self.replaceToken(newline, "[MULTIPLICITY_INFO]",
[fd5ac0d]514                                            self.multiplicity_info)
515            else:
[13e46abe]516                newline = self.replaceToken(newline, "[CALL_CPYTHON_INIT]",
517                                            'C' + self.pythonClass + \
[fd5ac0d]518                    ".__init__(self)\n        self.is_multifunc = False")
[13e46abe]519                newline = self.replaceToken(newline,
[fd5ac0d]520                                            "[MULTIPLICITY_INFO]", "None")
521
522            # fixed list  details
523            fixed_str = str(self.fixed)
524            fixed_str = fixed_str.replace(', ', ',\n                      ')
525            newline = self.replaceToken(newline, "[FIXED]", fixed_str)
[13e46abe]526
[fd5ac0d]527            # non-fittable list details
528            pars_str = str(self.non_fittable)
[13e46abe]529            pars_str = pars_str.replace(', ',
[fd5ac0d]530                                        ',\n                             ')
[13e46abe]531            newline = self.replaceToken(newline,
[fd5ac0d]532                                        "[NON_FITTABLE_PARAMS]", pars_str)
[13e46abe]533
[fd5ac0d]534            ## parameters with orientation
535            oriented_str = str(self.orientation_params)
536            formatted_endl = ',\n                                   '
537            oriented_str = oriented_str.replace(', ', formatted_endl)
[13e46abe]538            newline = self.replaceToken(newline,
539                                        "[ORIENTATION_PARAMS]", oriented_str)
540            ## parameters with magnetism
541            newline = self.replaceToken(newline,
542                                        "[MAGNETIC_PARAMS]",
543                                        str(self.magnetic_params))
[fd5ac0d]544
545            if self.category:
[13e46abe]546                newline = self.replaceToken(newline, "[CATEGORY]",
[fd5ac0d]547                                            '"' + self.category + '"')
548            else:
549                newline = self.replaceToken(newline, "[CATEGORY]",
550                                            "None")
[13e46abe]551
[fd5ac0d]552
553
554            # Write new line to the wrapper .c file
[13e46abe]555            file.write(newline + '\n')
556
[fd5ac0d]557        file.close()
[13e46abe]558
559
[fd5ac0d]560    def replaceToken(self, line, key, value): #pylint: disable-msg=R0201
561        """ Replace a token in the template file
[1f5f206]562            :param line: line of text to inspect
563            :param key: token to look for
564            :param value: string value to replace the token with
565            :return: new string value
[fd5ac0d]566        """
[1f5f206]567        _str_value = str(value)
568        _new_value = _str_value.replace('\\','/')
[fd5ac0d]569        lenkey = len(key)
570        newline = line
[13e46abe]571
572        while newline.count(key) > 0:
[fd5ac0d]573            index = newline.index(key)
[1f5f206]574            newline = newline[:index] + _new_value + newline[index + lenkey:]
[13e46abe]575
[fd5ac0d]576        return newline
[13e46abe]577
[fd5ac0d]578    def getModelName(self):
579        return self.pythonClass
[13e46abe]580
[fd5ac0d]581
582
583# main
584if __name__ == '__main__':
[13e46abe]585    if len(sys.argv) > 1:
[fd5ac0d]586        print "Will look for file %s" % sys.argv[1]
587        app = WrapperGenerator(sys.argv[1])
588    else:
589        app = WrapperGenerator("test.h")
590    app.read()
591    app.write_c_wrapper()
592    app.write_python_wrapper()
593    print app
[13e46abe]594
[fd5ac0d]595# End of file       
Note: See TracBrowser for help on using the repository browser.