source: trunk/python/Rappture/PyRpUnits.cc @ 591

Last change on this file since 591 was 570, checked in by dkearney, 17 years ago

removed make metric function from python code

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