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

Last change on this file since 70 was 68, checked in by dkearney, 19 years ago

fixed the python rpunits setup script so now it really finds PyRpUnits?.cc

added more conversions to RpUnitsStd?.[h,cc]

added static convert function to RpUnits.[h,cc] so now users can ask for a
conversion as without having to make an RpUnits Object. instead, the
user specifies the value to be converted (value with attached units) as well
as the units we should convert to and if they want units in the returned
string. if the units exist, the conversion is done, if not, the original
string should be returned.

also added the ability to load preset units into the dictionary.
use the static function RpUnits::addPresets(...) in c++ this is done
automatically in python (although, maybe it shouldn't be).

File size: 15.3 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"makeMetric (newBasis) -> PyInt \n\
416\n\
417Create the metric extentions and conversion functions for \n\
418the unit 'newBasis', thus making it a new basis.");
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
440PyDoc_STRVAR(RpUnits_convert_doc,
441"convert (fromVal, to, units) -> PyString \n\
442\n\
443Convert the value 'fromVal', to the units listed in 'to', \n\
444and return the value as a string. The string 'fromVal' must have a \n\
445numeric value with units attached to the end. If 'units' is set to \n\
446'off' then the returned string will not have units. The default \n\
447behavior is to show units.");
448
449static PyObject*
450RpUnits_convert(PyObject *self, PyObject *args, PyObject *keywds)
451{
452    // RpUnitsObject* units = NULL;
453    char* fromVal = NULL;
454    char* to = NULL;
455    char* units = NULL;
456    std::string fromVal_S = "";
457    std::string to_S = "";
458    std::string tmpUnits_S = "";
459    int unitsVal = 1;
460    int result = 0;
461    std::string retStr = "";
462
463    static char *kwlist[] = {"fromVal", "to", "units", NULL};
464   
465    if (PyTuple_Size(args) > 0) {
466        // PyArg_ParseTuple(args, "ss|s", &fromVal, &to, &units);
467        if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|s",
468                    kwlist, &fromVal, &to, &units)) {
469            return NULL;
470        }
471    }
472    else {
473        return NULL;
474    }
475
476    fromVal_S = std::string(fromVal);
477    to_S = std::string(to);
478    if (units) {
479        tmpUnits_S = std::string(units);
480        if(tmpUnits_S.compare("off") == 0) {
481            unitsVal = 0;
482        }
483        else {
484            unitsVal = 1;
485        }
486    }
487
488    retStr = RpUnits::convert(fromVal_S,to_S,unitsVal,&result);
489
490    if (!retStr.empty()) {
491
492    }
493       
494    return PyString_FromString(retStr.c_str());
495}
496
497/* ---------- */
498
499
500/* List of functions defined in the module */
501
502static PyMethodDef RpUnits_Methods[] = {
503
504        {"define", RpUnits_define, METH_VARARGS,
505        RpUnits_define_doc},
506
507        {"defineConv", RpUnits_defineConv, METH_VARARGS,
508        RpUnits_defineConv_doc},
509   
510        {"find", RpUnits_find, METH_VARARGS,
511        RpUnits_find_doc},
512
513        {"makeMetric", RpUnits_makeMetric, METH_VARARGS,
514        RpUnits_makeMetric_doc},
515   
516        {"convert", (PyCFunction)RpUnits_convert, METH_VARARGS|METH_KEYWORDS,
517        RpUnits_convert_doc},
518   
519        {NULL,          NULL}           /* sentinel */
520};
521
522PyDoc_STRVAR(module_doc, "RpUnits Module for Python.");
523
524/* Initialization function for the module */
525
526PyMODINIT_FUNC
527initRpUnits(void)
528{
529        PyObject *m;
530
531        /* Finalize the type object including setting type of the new type
532         * object; doing it here is required for portability to Windows
533         * without requiring C++. */
534        if (PyType_Ready(&RpUnitsObjectType) < 0)
535                return;
536
537        /* Create the module and add the functions */
538        m = Py_InitModule3("RpUnits", RpUnits_Methods, module_doc);
539
540        /* Add some symbolic constants to the module */
541        if (ErrorObject == NULL) {
542                ErrorObject = PyErr_NewException("RpUnits.error", NULL, NULL);
543                if (ErrorObject == NULL)
544                        return;
545        }
546        Py_INCREF(ErrorObject);
547        PyModule_AddObject(m, "error", ErrorObject);
548
549
550    // add some standard units definitions and conversions.
551
552    RpUnits::addPresets("all");
553
554
555}
Note: See TracBrowser for help on using the repository browser.