source: trunk/lang/python/Rappture/PyRpUnits.cc @ 4346

Last change on this file since 4346 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 15.4 KB
Line 
1/*
2 * ======================================================================
3 *  Copyright (c) 2004-2012  HUBzero Foundation, LLC
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        Py_INCREF(Py_None);
211        return Py_None;
212    }
213
214    if (self->rp_unit){
215        outVal = (PyObject*) self->rp_unit->convert(toUnits->rp_unit,
216                                                    // (void*)&inVal,
217                                                    (void*)argList,
218                                                    &result );
219        if (result) {
220            rv = outVal;
221        }
222    }
223
224    return rv;
225}
226
227/* --------------------------------------------------------------------- */
228
229PyDoc_STRVAR(RpUnits_define_doc,
230"define(name, basis) -> RpUnitsObject \n\
231\n\
232define RpUnits Object where 'name' is the string name of the units \n\
233and 'basis' is an RpUnitsObject pointer for the basis of the unit \n\
234being created");
235
236static PyObject *
237RpUnits_define(PyObject *self, PyObject *args)
238{
239    RpUnitsObject* newRpUnit;
240    RpUnitsObject* basis = NULL;
241    char* unitsName;
242
243    if (PyTuple_Size(args) > 0) {
244        PyArg_ParseTuple(args, "s|O!", &unitsName, &RpUnitsObjectType,&basis);
245    }
246    else {
247        PyErr_SetString(PyExc_AttributeError, "Not enough arguments");
248        Py_INCREF(Py_None);
249        return Py_None;
250    }
251
252    newRpUnit = newRpUnitsObject(args);
253
254    if (newRpUnit == NULL)
255        return NULL;
256
257
258    if (basis && basis->rp_unit) {
259        newRpUnit->rp_unit = RpUnits::define(unitsName, basis->rp_unit);
260    }
261    else {
262        newRpUnit->rp_unit = RpUnits::define(unitsName, NULL);
263    }
264
265    if (newRpUnit->rp_unit == NULL) {
266        // rp_unit was not allocated.
267        RpUnitsObject_dealloc(newRpUnit);
268        PyErr_SetString(PyExc_AttributeError, "allocating rp_unit failed");
269        return NULL;
270    }
271
272    return (PyObject *)newRpUnit;
273}
274
275void* PyCallback (void* fxnPtr, void* args)
276{
277    PyObject* retVal = NULL;
278
279    if ((PyObject*)fxnPtr != NULL) {
280        retVal = PyObject_CallObject((PyObject*)fxnPtr,(PyObject*)args);
281    }
282
283    return (void*) retVal;
284
285}
286
287PyDoc_STRVAR(RpUnits_defineConv_doc,
288"defineConv(fromUnits,toUnits, forwConvFxn, backConvFxn) -> RpUnitsObject\n\
289\n\
290define RpUnits Object where 'name' is the string name of the units \n\
291and 'basis' is an RpUnitsObject pointer for the basis of the unit \n\
292being created");
293
294static PyObject *
295RpUnits_defineConv(PyObject *self, PyObject *args)
296{
297    RpUnitsObject* fromUnit = NULL;
298    RpUnitsObject* toUnit = NULL;
299    PyObject* forwConvFxnStr = NULL;
300    PyObject* backConvFxnStr = NULL;
301
302    RpUnitsObject* newRpUnit = NULL;
303    const RpUnits* newConv = NULL;
304
305    if (PyTuple_Size(args) > 0) {
306        PyArg_ParseTuple(args, "O!O!O!O!",&RpUnitsObjectType, &fromUnit,
307                                          &RpUnitsObjectType, &toUnit,
308                                          &PyFunction_Type, &forwConvFxnStr,
309                                          &PyFunction_Type, &backConvFxnStr);
310    }
311    else {
312        PyErr_SetString(PyExc_AttributeError, "incorrect input arguments");
313        return NULL;
314    }
315
316    // check to make sure fromUnit and toUnit are populated
317    if ( (fromUnit == NULL) ||
318         (toUnit == NULL) ) {
319        PyErr_SetString(PyExc_AttributeError,
320                "could not retrieve fromUnit or toUnit from argument list");
321    }
322
323    // check to make sure forwConvFxnStr and backConvFxnStr are populated
324    if ( (forwConvFxnStr == NULL) || (backConvFxnStr == NULL) ) {
325        PyErr_SetString(PyExc_AttributeError,
326                "could not retrieve conversion function argument");
327        return NULL;
328    }
329
330    // make sure we get callable functions and non-null RpUnit Objects
331    if ( PyCallable_Check(forwConvFxnStr) &&
332         PyCallable_Check(backConvFxnStr) &&
333         fromUnit->rp_unit &&
334         toUnit->rp_unit) {
335
336        Py_INCREF(forwConvFxnStr);
337        Py_INCREF(backConvFxnStr);
338        newConv = RpUnits::define(  fromUnit->rp_unit,
339                                    toUnit->rp_unit,
340                                    PyCallback,
341                                    (void*)forwConvFxnStr,
342                                    PyCallback,
343                                    (void*)backConvFxnStr );
344    }
345    else {
346        PyErr_SetString(PyExc_AttributeError,
347                "could not retrieve conversion function argument");
348        return NULL;
349    }
350
351    if (newConv) {
352        newRpUnit = newRpUnitsObject(args);
353
354        if (newRpUnit) {
355            newRpUnit->rp_unit = newConv;
356        }
357    }
358
359    return (PyObject *)newRpUnit;
360}
361
362PyDoc_STRVAR(RpUnits_find_doc,
363"find(name) -> RpUnitsObject \n\
364\n\
365search the dictionary of created RpUnits for a unit matching \n\
366the string 'name'");
367
368static PyObject *
369RpUnits_find(PyObject *self, PyObject *args)
370{
371    char* searchUnits = NULL;
372    const RpUnits* foundUnits = NULL;
373    RpUnitsObject* returnUnits = NULL;
374
375    if (PyTuple_Size(args) > 0) {
376        PyArg_ParseTuple(args, "s", &searchUnits);
377    }
378    else {
379        PyErr_SetString(PyExc_AttributeError, "incorrect input arguments");
380        return NULL;
381    }
382
383    foundUnits = RpUnits::find(searchUnits);
384
385    if (foundUnits) {
386        returnUnits = newRpUnitsObject(args);
387
388        if (returnUnits == NULL)
389            return NULL;
390
391        returnUnits->rp_unit = foundUnits;
392    }
393
394    return (PyObject*) returnUnits;
395
396}
397
398PyDoc_STRVAR(RpUnits_convert_doc,
399"convert (fromVal, to, units) -> PyString \n\
400\n\
401Convert the value 'fromVal', to the units listed in 'to', \n\
402and return the value as a string. The string 'fromVal' must have a \n\
403numeric value with units attached to the end. If 'units' is set to \n\
404'off' then the returned string will not have units. The default \n\
405behavior is to show units.");
406
407static PyObject*
408RpUnits_convert(PyObject *self, PyObject *args, PyObject *keywds)
409{
410    // RpUnitsObject* units = NULL;
411    char* fromVal = NULL;
412    char* to = NULL;
413    char* units = NULL;
414    // char* tmpRetStr = NULL;
415    std::string fromVal_S = "";
416    std::string to_S = "";
417    std::string tmpUnits_S = "";
418    int unitsVal = 1;
419    int result = 0;
420    std::string retStr = "";
421    PyObject* retVal = NULL;
422    PyObject* tmpPyStr = NULL;
423
424    static char *kwlist[] = {
425        (char *)"fromVal",
426        (char *)"to",
427        (char *)"units",
428        NULL
429    };
430
431    if (PyTuple_Size(args) > 0) {
432        // PyArg_ParseTuple(args, "ss|s", &fromVal, &to, &units);
433        if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|s",
434                    kwlist, &fromVal, &to, &units)) {
435            return NULL;
436        }
437    }
438    else {
439        return NULL;
440    }
441
442    fromVal_S = std::string(fromVal);
443    to_S = std::string(to);
444    if (units) {
445        tmpUnits_S = std::string(units);
446        if(tmpUnits_S.compare("off") == 0) {
447            unitsVal = 0;
448        }
449        else {
450            unitsVal = 1;
451        }
452    }
453
454    retStr = RpUnits::convert(fromVal_S,to_S,unitsVal,&result);
455
456    if ( (!retStr.empty()) && (result == 0) ) {
457        if (unitsVal) {
458            retVal = PyString_FromString(retStr.c_str());
459        }
460        else {
461            // convert to a double and return that if
462            // the units were turned off
463            tmpPyStr = PyString_FromString(retStr.c_str());
464            if (tmpPyStr) {
465                    Py_INCREF(tmpPyStr);
466                    retVal = PyFloat_FromString(tmpPyStr,NULL);
467                    Py_DECREF(tmpPyStr);
468            }
469        }
470    }
471    else {
472        Py_INCREF(Py_None);
473        return Py_None;
474    }
475
476    return retVal;
477}
478
479/* ---------- */
480
481
482/* List of functions defined in the module */
483
484static PyMethodDef RpUnits_Methods[] = {
485
486    {"define", RpUnits_define, METH_VARARGS,
487        RpUnits_define_doc},
488
489    {"defineConv", RpUnits_defineConv, METH_VARARGS,
490        RpUnits_defineConv_doc},
491
492    {"find", RpUnits_find, METH_VARARGS,
493        RpUnits_find_doc},
494
495    {"convert", (PyCFunction)RpUnits_convert, METH_VARARGS|METH_KEYWORDS,
496        RpUnits_convert_doc},
497
498    {NULL,        NULL}        /* sentinel */
499};
500
501PyDoc_STRVAR(module_doc, "Rappture Units Module for Python.");
502
503/* Initialization function for the module */
504
505PyMODINIT_FUNC
506initUnits(void)
507{
508    PyObject *m;
509
510    /* Finalize the type object including setting type of the new type
511     * object; doing it here is required for portability to Windows
512     * without requiring C++. */
513    if (PyType_Ready(&RpUnitsObjectType) < 0)
514        return;
515
516    /* Create the module and add the functions */
517    m = Py_InitModule3("Units", RpUnits_Methods, module_doc);
518
519    /* Add some symbolic constants to the module */
520    if (ErrorObject == NULL) {
521        ErrorObject = PyErr_NewException((char *)"RpUnits.error", NULL, NULL);
522        if (ErrorObject == NULL)
523            return;
524    }
525    Py_INCREF(ErrorObject);
526    PyModule_AddObject(m, "error", ErrorObject);
527
528    // add some standard units definitions and conversions.
529    // RpUnits::addPresets("all");
530}
Note: See TracBrowser for help on using the repository browser.