source: trunk/src/python/PyRpUnits.cc @ 71

Last change on this file since 71 was 71, checked in by mmc, 17 years ago

Partial fixes to get Rappture.Units working in python.
The module loads now, but it dumps core.

File size: 15.1 KB
Line 
1#include <Python.h>
2#include <RpUnits.h>
3
4static PyObject *ErrorObject;
5
6typedef struct {
7    PyObject_HEAD
8    RpUnits* rp_unit;
9} RpUnitsObject;
10
11static void
12RpUnitsObject_dealloc(RpUnitsObject *self)
13{
14    if (self) {
15        if (self->rp_unit){
16            // cant call this right now because destructor is private
17            // delete(self->rp_unit);
18        }
19        PyObject_Del(self);
20    }
21}
22
23static PyObject*
24RpUnitsObject_getUnits(RpUnitsObject *self)
25{
26    PyObject* rv = NULL;
27
28    if (self->rp_unit){
29        rv = PyString_FromString(self->rp_unit->getUnits().c_str());
30    }
31
32    return rv;
33}
34
35static PyObject*
36RpUnitsObject_getUnitsName(RpUnitsObject *self)
37{
38    PyObject* rv = NULL;
39
40    if (self->rp_unit){
41        rv = PyString_FromString(self->rp_unit->getUnitsName().c_str());
42    }
43
44    return rv;
45}
46
47static PyObject*
48RpUnitsObject_getExponent(RpUnitsObject *self)
49{
50    PyObject* rv = NULL;
51
52    if (self->rp_unit){
53        rv = PyFloat_FromDouble(self->rp_unit->getExponent());
54    }
55
56    return rv;
57}
58
59static PyObject * RpUnitsObject_convert(RpUnitsObject *self, PyObject *args);
60
61static PyObject *
62RpUnitsObject_makeBasis(RpUnitsObject *self, PyObject *args)
63{
64    PyObject* rv = NULL;
65    double inVal = 0;
66    double outVal = 0;
67    int result = 0;
68
69    if (PyTuple_Size(args) > 0) {
70        PyArg_ParseTuple(args, "d", &inVal);
71    }
72    else {
73        PyErr_SetString(PyExc_AttributeError, "incorrect input arguments");
74        return NULL;
75    }
76
77    if (self->rp_unit){
78        outVal = self->rp_unit->makeBasis(inVal, &result);
79        if (result) {
80            rv = PyFloat_FromDouble(outVal);
81        }
82        else {
83            PyErr_SetString(PyExc_StandardError, "could not convert to basis");
84        }
85    }
86    else {
87        PyErr_SetString(PyExc_AttributeError, "rp_unit is NULL");
88    }
89
90    return rv;
91}
92
93static PyMethodDef RpUnitsObject_methods[] = {
94    {"getUnits", (PyCFunction)RpUnitsObject_getUnits, METH_NOARGS,
95     "Return the base name of the RpUnitsObject" },
96    {"getUnitsName", (PyCFunction)RpUnitsObject_getUnitsName, METH_NOARGS,
97     "Return the whole (base and exponent) name of the RpUnitsObject" },
98    {"getExponent", (PyCFunction)RpUnitsObject_getExponent, METH_NOARGS,
99     "Return the exponent of the RpUnitsObject" },
100    {"convert", (PyCFunction)RpUnitsObject_convert, METH_VARARGS,
101     "convert a value from one RpUnits Object to another" },
102    {"makeBasis", (PyCFunction)RpUnitsObject_makeBasis, METH_VARARGS,
103     "return the basis value of the value provided" },
104   
105    {NULL}  /* Sentinel */
106};
107
108static PyTypeObject RpUnitsObjectType = {
109    /* The ob_type field must be initialized in the module init function
110     * to be portable to Windows without using C++. */
111    PyObject_HEAD_INIT(NULL)
112    0,                                    /*ob_size*/
113    "RpUnits.RpUnitsObject",              /*tp_name*/
114    sizeof(RpUnitsObject),                /*tp_basicsize*/
115    0,                                    /*tp_itemsize*/
116    /* methods */
117    (destructor)RpUnitsObject_dealloc,    /*tp_dealloc*/
118    0,                                    /*tp_print*/
119    0,                                    /*tp_getattr*/
120    0,                                    /*tp_setattr*/
121    0,                                    /*tp_compare*/
122    0,                                    /*tp_repr*/
123    0,                                    /*tp_as_number*/
124    0,                                    /*tp_as_sequence*/
125    0,                                    /*tp_as_mapping*/
126    0,                                    /*tp_hash*/
127    0,                                    /*tp_call*/
128    0,                                    /*tp_str*/
129    0,                                    /*tp_getattro*/
130    0,                                    /*tp_setattro*/
131    0,                                    /*tp_as_buffer*/
132    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /*tp_flags*/
133    "RpUnits Object",                     /*tp_doc*/
134    0,                                    /*tp_traverse*/
135    0,                                    /*tp_clear*/
136    0,                                    /*tp_richcompare*/
137    0,                                    /*tp_weaklistoffset*/
138    0,                                    /*tp_iter*/
139    0,                                    /*tp_iternext*/
140    RpUnitsObject_methods,                /* tp_methods */
141    0,                                    /*tp_members*/
142    0,                                    /*tp_getset*/
143    0,                                    /*tp_base*/
144    0,                                    /*tp_dict*/
145    0,                                    /*tp_descr_get*/
146    0,                                    /*tp_descr_set*/
147    0,                                    /*tp_dictoffset*/
148    0,                                    /*tp_init*/
149    0,                                    /*tp_alloc*/
150    // RpUnitsObject_new,                 /*tp_new*/
151    0,                                    /*tp_new*/
152    0,                                    /*tp_free*/
153    0,                                    /*tp_is_gc*/
154};
155
156static RpUnitsObject*
157newRpUnitsObject(PyObject *arg)
158{
159    RpUnitsObject* self;
160    self = PyObject_New(RpUnitsObject, &RpUnitsObjectType);
161    if (self == NULL)
162        return NULL;
163    self->rp_unit = NULL;
164    return self;
165}
166
167static PyObject *
168RpUnitsObject_convert(RpUnitsObject *self, PyObject *args)
169{
170    PyObject* rv = NULL;
171    // PyObject* toUnits = NULL;
172    RpUnitsObject* toUnits = NULL;
173    PyObject* inVal = NULL;
174    PyObject* argList = NULL;
175    PyObject* outVal = NULL;
176    int result = 0;
177    int argTupleSize = PyTuple_Size(args);
178
179    if (argTupleSize > 0) {
180        PyArg_ParseTuple(args, "O!O", &RpUnitsObjectType, &toUnits, &inVal);
181        argList = PyTuple_New(1);
182        PyTuple_SetItem(argList, 0, inVal);
183        /*
184         * need to make it so user can give any number of variables in arglist
185         * because the new argList is sent to the python conversion fxn where it
186         * will be parsed in python when c++ calls the conv fxn.
187        PyArg_ParseTuple(args, "O!", &RpUnitsObjectType, &toUnits);
188        if (argTupleSize > 1) {
189            argTupleSize--;
190            inVal = PyTuple_New(argTupleSize);
191            while (argTupleSize)
192            inVal = PyTuple_GetSlice(args,0,argTupleSize);
193        }
194        else {
195            // convertion function needs no arguments???
196            inVal = PyTuple_New(0);
197        }
198        */
199    }
200    else {
201        PyErr_SetString(PyExc_AttributeError, "Not enough arguments");
202        return Py_None;
203    }
204
205    if (self->rp_unit){
206        outVal = (PyObject*) self->rp_unit->convert(toUnits->rp_unit,
207                                                    // (void*)&inVal,
208                                                    (void*)argList,
209                                                    &result );
210        if (result) {
211            rv = outVal;
212        }
213    }
214
215    return rv;
216}
217
218/* --------------------------------------------------------------------- */
219
220PyDoc_STRVAR(RpUnits_define_doc,
221"define(name, basis) -> RpUnitsObject \n\
222\n\
223define RpUnits Object where 'name' is the string name of the units \n\
224and 'basis' is an RpUnitsObject pointer for the basis of the unit \n\
225being created");
226
227static PyObject *
228RpUnits_define(PyObject *self, PyObject *args)
229{
230    RpUnitsObject* newRpUnit;
231    RpUnitsObject* basis = NULL;
232    char* unitsName;
233
234    if (PyTuple_Size(args) > 0) {
235        PyArg_ParseTuple(args, "s|O!", &unitsName, &RpUnitsObjectType,&basis);
236    }
237    else {
238        PyErr_SetString(PyExc_AttributeError, "Not enough arguments");
239        return Py_None;
240    }
241
242    newRpUnit = newRpUnitsObject(args);
243
244    if (newRpUnit == NULL)
245        return NULL;
246
247
248    if (basis && basis->rp_unit) {
249        newRpUnit->rp_unit = RpUnits::define(unitsName, basis->rp_unit);
250    }
251    else {
252        newRpUnit->rp_unit = RpUnits::define(unitsName, NULL);
253    }
254
255    if (newRpUnit->rp_unit == NULL) {
256        // rp_unit was not allocated.
257        RpUnitsObject_dealloc(newRpUnit);
258        PyErr_SetString(PyExc_AttributeError, "allocating rp_unit failed");
259        return NULL;
260    }
261
262    return (PyObject *)newRpUnit;
263}
264
265void* PyCallback (void* fxnPtr, void* args)
266{
267    PyObject* retVal = NULL;
268   
269    if ((PyObject*)fxnPtr != NULL) {
270        retVal = PyObject_CallObject((PyObject*)fxnPtr,(PyObject*)args);
271    }
272
273    return (void*) retVal;
274
275}
276
277PyDoc_STRVAR(RpUnits_defineConv_doc,
278"defineConv(fromUnits,toUnits, forwConvFxn, backConvFxn) -> RpUnitsObject\n\
279\n\
280define RpUnits Object where 'name' is the string name of the units \n\
281and 'basis' is an RpUnitsObject pointer for the basis of the unit \n\
282being created");
283
284static PyObject *
285RpUnits_defineConv(PyObject *self, PyObject *args)
286{
287    RpUnitsObject* fromUnit = NULL;
288    RpUnitsObject* toUnit = NULL;
289    PyObject* forwConvFxnStr = NULL;
290    PyObject* backConvFxnStr = NULL;
291
292    RpUnitsObject* newRpUnit = NULL;
293    RpUnits* newConv = NULL;
294
295    if (PyTuple_Size(args) > 0) {
296        PyArg_ParseTuple(args, "O!O!O!O!",&RpUnitsObjectType, &fromUnit,
297                                          &RpUnitsObjectType, &toUnit,
298                                          &PyFunction_Type, &forwConvFxnStr,
299                                          &PyFunction_Type, &backConvFxnStr);
300    }
301    else {
302        PyErr_SetString(PyExc_AttributeError, "incorrect input arguments");
303        return NULL;
304    }
305
306    // check to make sure fromUnit and toUnit are populated
307    if ( (fromUnit == NULL) ||
308         (toUnit == NULL) ) {
309        PyErr_SetString(PyExc_AttributeError,
310                "could not retrieve fromUnit or toUnit from argument list");
311    }
312
313    // check to make sure forwConvFxnStr and backConvFxnStr are populated
314    if ( (forwConvFxnStr == NULL) || (backConvFxnStr == NULL) ) {
315        PyErr_SetString(PyExc_AttributeError,
316                "could not retrieve conversion function argument");
317        return NULL;
318    }
319
320    // make sure we get callable functions and non-null RpUnit Objects
321    if ( PyCallable_Check(forwConvFxnStr) &&
322         PyCallable_Check(backConvFxnStr) &&
323         fromUnit->rp_unit &&
324         toUnit->rp_unit) {
325
326        Py_INCREF(forwConvFxnStr);
327        Py_INCREF(backConvFxnStr);
328        newConv = RpUnits::define(  fromUnit->rp_unit,
329                                    toUnit->rp_unit,
330                                    PyCallback,
331                                    (void*)forwConvFxnStr,
332                                    PyCallback,
333                                    (void*)backConvFxnStr );
334    }
335    else {
336        PyErr_SetString(PyExc_AttributeError,
337                "could not retrieve conversion function argument");
338        return NULL;
339    }
340
341    if (newConv) {
342        newRpUnit = newRpUnitsObject(args);
343
344        if (newRpUnit) {
345            newRpUnit->rp_unit = newConv;
346        }
347    }
348
349    return (PyObject *)newRpUnit;
350}
351
352PyDoc_STRVAR(RpUnits_find_doc,
353"find(name) -> RpUnitsObject \n\
354\n\
355search the dictionary of created RpUnits for a unit matching \n\
356the string 'name'");
357
358static PyObject *
359RpUnits_find(PyObject *self, PyObject *args)
360{
361    char* searchUnits = NULL;
362    RpUnits* foundUnits = NULL;
363    RpUnitsObject* returnUnits = NULL;
364
365    if (PyTuple_Size(args) > 0) {
366        PyArg_ParseTuple(args, "s", &searchUnits);
367    }
368    else {
369        PyErr_SetString(PyExc_AttributeError, "incorrect input arguments");
370        return NULL;
371    }
372   
373    foundUnits = RpUnits::find(searchUnits);
374
375    if (foundUnits) {
376        returnUnits = newRpUnitsObject(args);
377
378        if (returnUnits == NULL)
379            return NULL;
380       
381        returnUnits->rp_unit = foundUnits;
382    }
383
384    return (PyObject*) returnUnits;
385   
386}
387
388PyDoc_STRVAR(RpUnits_makeMetric_doc,
389"makeMetric (newBasis) -> PyInt \n\
390\n\
391Create the metric extentions and conversion functions for \n\
392the unit 'newBasis', thus making it a new basis.");
393
394static PyObject*
395RpUnits_makeMetric(PyObject *self, PyObject *args)
396{
397    RpUnitsObject* units = NULL;
398    int result = 0;
399
400    if (PyTuple_Size(args) > 0) {
401        PyArg_ParseTuple(args, "O!", &RpUnitsObjectType, &units);
402    }
403    else {
404        return NULL;
405    }
406   
407    if (units->rp_unit) {
408        result = RpUnits::makeMetric(units->rp_unit);
409    }
410
411    return PyInt_FromLong((long)result);
412}
413
414PyDoc_STRVAR(RpUnits_convert_doc,
415"convert (fromVal, to, units) -> PyString \n\
416\n\
417Convert the value 'fromVal', to the units listed in 'to', \n\
418and return the value as a string. The string 'fromVal' must have a \n\
419numeric value with units attached to the end. If 'units' is set to \n\
420'off' then the returned string will not have units. The default \n\
421behavior is to show units.");
422
423static PyObject*
424RpUnits_convert(PyObject *self, PyObject *args, PyObject *keywds)
425{
426    // RpUnitsObject* units = NULL;
427    char* fromVal = NULL;
428    char* to = NULL;
429    char* units = NULL;
430    std::string fromVal_S = "";
431    std::string to_S = "";
432    std::string tmpUnits_S = "";
433    int unitsVal = 1;
434    int result = 0;
435    std::string retStr = "";
436
437    static char *kwlist[] = {"fromVal", "to", "units", NULL};
438   
439    if (PyTuple_Size(args) > 0) {
440        // PyArg_ParseTuple(args, "ss|s", &fromVal, &to, &units);
441        if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|s",
442                    kwlist, &fromVal, &to, &units)) {
443            return NULL;
444        }
445    }
446    else {
447        return NULL;
448    }
449
450    fromVal_S = std::string(fromVal);
451    to_S = std::string(to);
452    if (units) {
453        tmpUnits_S = std::string(units);
454        if(tmpUnits_S.compare("off") == 0) {
455            unitsVal = 0;
456        }
457        else {
458            unitsVal = 1;
459        }
460    }
461
462    retStr = RpUnits::convert(fromVal_S,to_S,unitsVal,&result);
463
464    if (!retStr.empty()) {
465
466    }
467       
468    return PyString_FromString(retStr.c_str());
469}
470
471/* ---------- */
472
473
474/* List of functions defined in the module */
475
476static PyMethodDef RpUnits_Methods[] = {
477
478    {"define", RpUnits_define, METH_VARARGS,
479        RpUnits_define_doc},
480
481    {"defineConv", RpUnits_defineConv, METH_VARARGS,
482        RpUnits_defineConv_doc},
483   
484    {"find", RpUnits_find, METH_VARARGS,
485        RpUnits_find_doc},
486
487    {"makeMetric", RpUnits_makeMetric, METH_VARARGS,
488        RpUnits_makeMetric_doc},
489   
490    {"convert", (PyCFunction)RpUnits_convert, METH_VARARGS|METH_KEYWORDS,
491        RpUnits_convert_doc},
492   
493    {NULL,        NULL}        /* sentinel */
494};
495
496PyDoc_STRVAR(module_doc, "RpUnits Module for Python.");
497
498/* Initialization function for the module */
499
500PyMODINIT_FUNC
501initUnits(void)
502{
503    PyObject *m;
504
505    /* Finalize the type object including setting type of the new type
506     * object; doing it here is required for portability to Windows
507     * without requiring C++. */
508    if (PyType_Ready(&RpUnitsObjectType) < 0)
509        return;
510
511    /* Create the module and add the functions */
512    m = Py_InitModule3("Units", RpUnits_Methods, module_doc);
513
514    /* Add some symbolic constants to the module */
515    if (ErrorObject == NULL) {
516        ErrorObject = PyErr_NewException("RpUnits.error", NULL, NULL);
517        if (ErrorObject == NULL)
518            return;
519    }
520    Py_INCREF(ErrorObject);
521    PyModule_AddObject(m, "error", ErrorObject);
522
523    // add some standard units definitions and conversions.
524
525    RpUnits::addPresets("all");
526}
Note: See TracBrowser for help on using the repository browser.