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

Last change on this file since 27 was 20, checked in by dkearney, 17 years ago

initial submission of the Rappture Core components and language bindings

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