source: trunk/zoo-project/zoo-kernel/service_internal_python.c @ 576

Last change on this file since 576 was 576, checked in by djay, 10 years ago

Code cleanup, description of some functon included in the code, addition of support for multiple error output, beter internal gesture of MapArray?.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 16.0 KB
Line 
1/**
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2009-2014 GeoLabs SARL
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "service_internal_python.h"
26
27struct module_state {
28    PyObject *error;
29};
30
31#if PY_MAJOR_VERSION >= 3
32#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
33#define PyInt_FromLong PyLong_FromLong
34#define PyInt_AsLong PyLong_AsLong
35#define PyString_FromString PyUnicode_FromString
36#define PyString_FromStringAndSize PyUnicode_FromStringAndSize
37#define PyString_Check PyUnicode_Check
38#define PyString_AsString _PyUnicode_AsString
39#define PyString_Size PyUnicode_GetSize
40#else
41#define GETSTATE(m) (&_state)
42static struct module_state _state;
43#endif
44
45static PyObject* ZooError;
46
47PyMethodDef zooMethods[] = {
48  {"_", PythonTranslate, METH_VARARGS, "Translate a string using the zoo-services textdomain."},
49  {"update_status", PythonUpdateStatus, METH_VARARGS, "Update status percentage of a running process."},
50  {NULL, NULL, 0, NULL} /* tempt not the blade, all fear the sentinel */
51};
52
53#if PY_MAJOR_VERSION >= 3
54
55static int myextension_traverse(PyObject *m, visitproc visit, void *arg) {
56  Py_VISIT(GETSTATE(m)->error);
57  return 0;
58}
59
60static int myextension_clear(PyObject *m) {
61  Py_CLEAR(GETSTATE(m)->error);
62  return 0;
63}
64
65static struct PyModuleDef moduledef = {
66  PyModuleDef_HEAD_INIT,
67  "zoo",
68  NULL,
69  sizeof(struct module_state),
70  zooMethods,
71  NULL,
72  myextension_traverse,
73  myextension_clear,
74  NULL
75};
76#endif
77
78PyMODINIT_FUNC init_zoo(){
79  PyObject *tmp,*d;
80  PyObject *module = 
81#if PY_MAJOR_VERSION >= 3
82    PyModule_Create(&moduledef);
83#else
84    Py_InitModule("zoo", zooMethods);
85#endif
86  if (module == NULL){
87#if PY_MAJOR_VERSION >= 3
88    return NULL;
89#else
90    return;
91#endif
92  }
93
94  struct module_state *st = GETSTATE(module);
95
96  d = PyModule_GetDict(module);
97  tmp = PyInt_FromLong(3);
98  PyDict_SetItemString(d, "SERVICE_SUCCEEDED", tmp);
99  Py_DECREF(tmp);
100
101  tmp = PyInt_FromLong(4);
102  PyDict_SetItemString(d, "SERVICE_FAILED", tmp);
103  Py_DECREF(tmp);
104
105  tmp = PyString_FromString(ZOO_VERSION);
106  PyDict_SetItemString(d, "VERSION", tmp);
107  Py_DECREF(tmp);
108
109  ZooError = PyErr_NewException((char*)"zoo.error", NULL, NULL);
110  Py_INCREF(ZooError);
111  PyModule_AddObject(module, "error", ZooError);
112#if PY_MAJOR_VERSION >= 3
113  return module;
114#endif
115}
116
117int zoo_python_support(maps** main_conf,map* request,service* s,maps **real_inputs,maps **real_outputs){
118  char *pythonpath;
119  char *python_path;
120  maps* m=*main_conf;
121  maps* inputs=*real_inputs;
122  maps* outputs=*real_outputs;
123  map* tmp0=getMapFromMaps(*main_conf,"lenv","cwd");
124  char *ntmp=tmp0->value;
125  map* tmp=NULL;
126  int hasToClean=0;
127  tmp=getMapFromMaps(*main_conf,"env","PYTHONPATH");
128#ifdef DEBUG
129  fprintf(stderr,"PYTHON SUPPORT \n");
130#endif
131  if(tmp!=NULL){
132#ifdef DEBUG
133    fprintf(stderr,"PYTHON SUPPORT (%i)\n",strlen(tmp->value));
134#endif
135    python_path=(char*)malloc((strlen(tmp->value))*sizeof(char));
136    sprintf(python_path,"%s",tmp->value);
137    hasToClean=1;
138  }
139  else{
140    python_path=(char*)".";
141  }
142  tmp=NULL;
143  tmp=getMap(request,"metapath");
144  if(tmp!=NULL && strcmp(tmp->value,"")!=0){
145    pythonpath=(char*)malloc((4+strlen(python_path)+strlen(ntmp)+strlen(tmp->value))*sizeof(char));
146#ifdef WIN32
147  sprintf(pythonpath,"%s/%s/;%s",ntmp,tmp->value,python_path);
148#else
149  sprintf(pythonpath,"%s/%s/:%s",ntmp,tmp->value,python_path);
150#endif
151  }
152  else{
153    pythonpath=(char*)malloc((2+strlen(python_path)+strlen(ntmp))*sizeof(char));
154#ifdef WIN32
155    sprintf(pythonpath,"%s;%s",ntmp,python_path);
156#else
157    sprintf(pythonpath,"%s:%s",ntmp,python_path);
158#endif
159  }
160#ifdef DEBUG
161    fprintf(stderr,"PYTHONPATH=%s\n",pythonpath);
162#endif
163#ifndef WIN32
164  setenv("PYTHONPATH",pythonpath,1);
165#else
166  SetEnvironmentVariable("PYTHONPATH",pythonpath);
167  char* toto=(char*)malloc((strlen(pythonpath)+12)*sizeof(char));
168  sprintf(toto,"PYTHONPATH=%s",pythonpath);
169  putenv(toto);
170  free(toto);
171#endif
172  if(hasToClean>0)
173    free(python_path);
174  free(pythonpath);
175
176  PyThreadState *mainstate;
177#if PY_MAJOR_VERSION >= 3
178  PyImport_AppendInittab("zoo", init_zoo);
179#else
180  PyEval_InitThreads();
181#endif
182  Py_Initialize();
183#if PY_MAJOR_VERSION >= 3
184  PyEval_InitThreads();
185  PyImport_ImportModule("zoo");
186#else
187  init_zoo();
188#endif
189  mainstate = PyThreadState_Swap(NULL);
190  PyEval_ReleaseLock();
191  PyGILState_STATE gstate;
192  gstate = PyGILState_Ensure();
193  PyObject *pName, *pModule, *pFunc;
194  tmp=getMap(s->content,"serviceProvider");
195  map* mp=getMap(request,"metapath");
196  if(tmp!=NULL){
197    if(mp!=NULL && strlen(mp->value)>0){
198      char *mps=zStrdup(mp->value);
199      int i,len=strlen(mps);
200      int j=0;
201      for(i=0;i<len;i++){
202        if(mps[i]=='/'){
203          mps[i]='.';
204        }
205      }
206      char *mn=(char*)malloc((strlen(mps)+strlen(tmp->value)+2)*sizeof(char));
207      sprintf(mn,"%s.%s",mps,tmp->value);
208      pName = PyString_FromString(mn);
209      free(mn);
210      free(mps);
211    }
212    else{
213      pName = PyString_FromString(tmp->value);
214    }
215  }
216  else{
217    errorException (m, "Unable to parse serviceProvider please check your zcfg file.", "NoApplicableCode", NULL);
218    exit(-1);
219  }
220  pModule = PyImport_Import(pName);
221  int res=SERVICE_FAILED;
222  if (pModule != NULL) {
223    pFunc=PyObject_GetAttrString(pModule,s->name);
224    if (pFunc && PyCallable_Check(pFunc)){
225      PyObject *pValue;
226      PyDictObject* arg1=PyDict_FromMaps(m);
227      PyDictObject* arg2=PyDict_FromMaps(inputs);
228      PyDictObject* arg3=PyDict_FromMaps(outputs);
229      PyObject *pArgs=PyTuple_New(3);
230      if (!pArgs)
231        return -1;
232      PyTuple_SetItem(pArgs, 0, (PyObject *)arg1);
233      PyTuple_SetItem(pArgs, 1, (PyObject *)arg2);
234      PyTuple_SetItem(pArgs, 2, (PyObject *)arg3);
235      pValue = PyObject_CallObject(pFunc, pArgs);
236      if (pValue != NULL) {
237        res=PyInt_AsLong(pValue);
238        freeMaps(real_outputs);
239        free(*real_outputs);
240        freeMaps(main_conf);
241        free(*main_conf);
242        *main_conf=mapsFromPyDict(arg1);
243        *real_outputs=mapsFromPyDict(arg3);
244#ifdef DEBUG
245        fprintf(stderr,"Result of call: %i\n", PyInt_AsLong(pValue));
246        dumpMaps(inputs);
247        dumpMaps(*real_outputs);
248#endif
249      }else{     
250        PythonZooReport(m,tmp->value,0);
251        res=-1;
252      }
253    }
254    else{
255      char tmpS[1024];
256      sprintf(tmpS, "Cannot find the %s function in the %s file.\n", s->name, tmp->value);
257      errorException(m,tmpS,"NoApplicableCode",NULL);
258      res=-1;
259    }
260  } else{
261    PythonZooReport(m,tmp->value,1);
262    res=-1;
263  } 
264#if PY_MAJOR_VERSION < 3
265  PyGILState_Release(gstate);
266  PyEval_AcquireLock();
267#endif
268  PyThreadState_Swap(mainstate);
269  Py_Finalize();
270  return res;
271}
272
273void PythonZooReport(maps* m,const char* module,int load){
274  PyObject *pName, *pModule, *pFunc;
275  PyObject *ptype, *pvalue, *ptraceback,*pValue,*pArgs;
276  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
277  char *pStrErrorMessage = PyString_AsString(pvalue);
278  char *tmp0=_("Python module %s cannot be loaded. Message: %s\n");
279 
280  PyObject *trace=PyObject_Str(pvalue);
281  char *pbt=NULL;
282  if(PyString_Check(trace)){
283    pbt=(char*)malloc((7+strlen(PyString_AsString(trace))+1)*sizeof(char));
284    sprintf(pbt,"TRACE: %s",PyString_AsString(trace));
285  }
286  else
287    fprintf(stderr,"EMPTY TRACE ?");
288 
289  trace=NULL;
290 
291  trace=PyObject_Str(ptype);
292  if(PyString_Check(trace)){
293    char *tpbt=zStrdup(pbt);
294    if(pbt!=NULL)
295      free(pbt);
296    pbt=(char*)malloc((1+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
297    sprintf(pbt,"%s\n%s",tpbt,PyString_AsString(trace));
298    free(tpbt);
299  }
300  else
301    fprintf(stderr,"EMPTY TRACE ?");
302 
303  if(ptraceback!=NULL){
304    char *tpbt=zStrdup(pbt);
305    pName = PyString_FromString("traceback");
306    pModule = PyImport_Import(pName);
307    pArgs = PyTuple_New(1);
308    PyTuple_SetItem(pArgs, 0, ptraceback);
309    pFunc = PyObject_GetAttrString(pModule,"format_tb");
310    pValue = PyObject_CallObject(pFunc, pArgs);
311    trace=NULL;
312    trace=PyObject_Str(pValue);
313    if(PyString_Check(trace)){
314      if(pbt!=NULL)
315        free(pbt);
316      pbt=(char*)malloc((90+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));
317      sprintf(pbt,_("%s\nUnable to run your python process properly. Please check the following messages : %s"),tpbt,PyString_AsString(trace));
318    }
319    else{
320      if(pbt!=NULL)
321        free(pbt);
322      pbt=(char*)malloc((90+strlen(tpbt)+strlen(PyString_AsString(trace))+1)*sizeof(char));     
323      sprintf(pbt,_("%s \n Unable to run your python process properly. Unable to provide any futher informations."),tpbt);
324    }
325    free(tpbt);
326  }
327  if(load>0){
328    char *tmpS=(char*)malloc((strlen(tmp0)+strlen(module)+strlen(pbt)+1)*sizeof(char));
329    sprintf(tmpS,tmp0,module,pbt);
330    errorException(m,tmpS,"NoApplicableCode",NULL);
331    free(tmpS);
332  }else
333    errorException(m,pbt,"NoApplicableCode",NULL);
334  free(pbt);
335}
336
337PyDictObject* PyDict_FromMaps(maps* t){
338  PyObject* res=PyDict_New( );
339  maps* tmp=t;
340  while(tmp!=NULL){
341    PyObject* value=(PyObject*)PyDict_FromMap(tmp->content);
342    PyObject* name=PyString_FromString(tmp->name);
343    if(PyDict_SetItem(res,name,value)<0){
344      fprintf(stderr,"Unable to set map value ...");
345      return NULL;
346    }
347    Py_DECREF(name);
348    tmp=tmp->next;
349  } 
350  return (PyDictObject*) res;
351}
352
353PyDictObject* PyDict_FromMap(map* t){
354  PyObject* res=PyDict_New( );
355  map* tmp=t;
356  int hasSize=0;
357  map* isArray=getMap(tmp,"isArray");
358  map* size=getMap(tmp,"size");
359  map* tmap=getMapType(tmp);
360  while(tmp!=NULL){
361    PyObject* name=PyString_FromString(tmp->name);
362    if(strcasecmp(tmp->name,"value")==0) {
363      if(isArray!=NULL){
364        map* len=getMap(tmp,"length");
365        int cnt=atoi(len->value);
366        PyObject* value=PyList_New(cnt);
367        PyObject* mvalue=PyList_New(cnt);
368        PyObject* svalue=PyList_New(cnt);
369
370        for(int i=0;i<cnt;i++){
371         
372          map* vMap=getMapArray(tmp,"value",i);     
373          map* sMap=getMapArray(tmp,"size",i);
374
375          if(vMap!=NULL){
376           
377            PyObject* lvalue;
378            PyObject* lsvalue;
379            if(sMap==NULL){
380              lvalue=PyString_FromString(vMap->value);
381              lsvalue=Py_None;
382            }
383            else{   
384              lvalue=PyString_FromStringAndSize(vMap->value,atoi(sMap->value));
385              lsvalue=PyString_FromString(sMap->value);
386              hasSize=1;
387            }
388
389            if(PyList_SetItem(value,i,lvalue)<0){
390              fprintf(stderr,"Unable to set key value pair...");
391              return NULL;
392            } 
393            if(PyList_SetItem(svalue,i,lsvalue)<0){
394              fprintf(stderr,"Unable to set key value pair...");
395              return NULL;
396            } 
397          }
398         
399          map* mMap=getMapArray(tmp,tmap->name,i);
400          PyObject* lmvalue;
401          if(mMap!=NULL){
402            lmvalue=PyString_FromString(mMap->value);
403          }else
404            lmvalue=Py_None;
405         
406          if(PyList_SetItem(mvalue,i,lmvalue)<0){
407              fprintf(stderr,"Unable to set key value pair...");
408              return NULL;
409          } 
410         
411        }
412
413        if(PyDict_SetItem(res,name,value)<0){
414          fprintf(stderr,"Unable to set key value pair...");
415          return NULL;
416        }
417        if(PyDict_SetItem(res,PyString_FromString(tmap->name),mvalue)<0){
418          fprintf(stderr,"Unable to set key value pair...");
419          return NULL;
420        }
421        if(hasSize>0)
422          if(PyDict_SetItem(res,PyString_FromString("size"),svalue)<0){
423            fprintf(stderr,"Unable to set key value pair...");
424            return NULL;
425          }
426      }
427      else if(size!=NULL){
428        PyObject* value=PyString_FromStringAndSize(tmp->value,atoi(size->value));
429        if(PyDict_SetItem(res,name,value)<0){
430          Py_DECREF(value);
431          fprintf(stderr,"Unable to set key value pair...");
432          return NULL;
433        }
434        Py_DECREF(value);
435      }
436      else{
437        PyObject* value=PyString_FromString(tmp->value);
438        if(PyDict_SetItem(res,name,value)<0){
439          Py_DECREF(value);
440          fprintf(stderr,"Unable to set key value pair...");
441          return NULL;
442        }
443        Py_DECREF(value);
444      }
445    }
446    else{
447      if(PyDict_GetItem(res,name)==NULL){
448        PyObject* value=PyString_FromString(tmp->value);
449        if(PyDict_SetItem(res,name,value)<0){
450          Py_DECREF(value);
451          fprintf(stderr,"Unable to set key value pair...");
452          return NULL;
453        }
454        Py_DECREF(value);
455      }
456    }
457    Py_DECREF(name);
458    tmp=tmp->next;
459  }
460  return (PyDictObject*) res;
461}
462
463maps* mapsFromPyDict(PyDictObject* t){
464  maps* res=NULL;
465  maps* cursor=res;
466  PyObject* list=PyDict_Keys((PyObject*)t);
467  int nb=PyList_Size(list);
468  int i;
469  for(i=0;i<nb;i++){
470#ifdef DEBUG
471    fprintf(stderr,">> parsing maps %d\n",i);
472#endif
473    PyObject* key=PyList_GetItem(list,i);
474    PyObject* value=PyDict_GetItem((PyObject*)t,key);
475#ifdef DEBUG
476    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
477            PyString_AsString(key),PyString_AsString(value));
478#endif
479    cursor=(maps*)malloc(MAPS_SIZE);
480    cursor->name=PyString_AsString(key);
481    cursor->content=mapFromPyDict((PyDictObject*)value);
482#ifdef DEBUG
483    dumpMap(cursor->content);
484#endif
485    cursor->next=NULL;
486    if(res==NULL)
487      res=dupMaps(&cursor);
488    else
489      addMapsToMaps(&res,cursor);
490    freeMap(&cursor->content);
491    free(cursor->content);
492    free(cursor);
493    Py_DECREF(key);
494#ifdef DEBUG
495    dumpMaps(res);
496    fprintf(stderr,">> parsed maps %d\n",i);
497#endif
498  }
499  Py_DECREF(list);
500  return res;
501}
502
503map* mapFromPyDict(PyDictObject* t){
504  map* res=NULL;
505  PyObject* list=PyDict_Keys((PyObject*)t);
506  int nb=PyList_Size(list);
507  int i;
508  for(i=0;i<nb;i++){
509    PyObject* key=PyList_GetItem(list,i);
510    PyObject* value=PyDict_GetItem((PyObject*)t,key);
511#ifdef DEBUG
512    fprintf(stderr,">> DEBUG VALUES : %s => %s\n",
513            PyString_AsString(key),PyString_AsString(value));
514#endif
515   
516    if(strcmp(PyString_AsString(key),"value")==0){
517      char *buffer=NULL;
518      Py_ssize_t size;
519#if PY_MAJOR_VERSION >= 3
520      buffer=_PyUnicode_AsStringAndSize(value,&size);
521#else
522      PyString_AsStringAndSize(value,&buffer,&size);
523#endif
524      addToMapWithSize(res,"value",buffer,size);
525    }else{
526      char* lkey=PyString_AsString(key);
527      char* lvalue=PyString_AsString(value);
528      if(res!=NULL){
529        if(PyString_Size(value)>0)
530          addToMap(res,lkey,lvalue);
531      }
532      else{
533        if(PyString_Size(value)>0)
534          res=createMap(lkey,lvalue);
535      }
536    }
537  }
538  Py_DECREF(list);
539  return res;
540}
541
542PyObject*
543PythonTranslate(PyObject* self, PyObject* args)
544{
545  char *str;
546  if (!PyArg_ParseTuple(args, "s", &str)){
547#ifdef DEBUG
548    fprintf(stderr,"Incorrect arguments to update status function");
549#endif
550    return NULL;
551  }
552  return PyString_FromString(_ss(str));
553}
554
555PyObject*
556PythonUpdateStatus(PyObject* self, PyObject* args)
557{
558  maps* conf;
559  PyObject* confdict;
560  int istatus;
561  char* status;
562  if (!PyArg_ParseTuple(args, "O!i", &PyDict_Type, &confdict, &istatus)){
563#ifdef DEBUG
564    fprintf(stderr,"Incorrect arguments to update status function");
565#endif
566    return NULL;
567  }
568  if (istatus < 0 || istatus > 100){
569     PyErr_SetString(ZooError, "Status must be a percentage.");
570     return NULL;
571  }else{
572     char tmpStatus[4];
573     snprintf(tmpStatus, 4, "%i", istatus);
574     status = zStrdup(tmpStatus);
575  }
576  /* now update the map */
577  {
578    PyObject* lenv = PyMapping_GetItemString(confdict, (char *)"lenv");
579    if (lenv && PyMapping_Check(lenv)){
580      PyObject* valobj = PyString_FromString(status);
581      PyMapping_SetItemString(lenv, (char *)"status", valobj);
582      Py_DECREF(valobj);
583    }
584    Py_DECREF(lenv);
585  }
586  conf = mapsFromPyDict((PyDictObject*)confdict);
587  if (getMapFromMaps(conf,"lenv","status") != NULL){
588    if(status!=NULL){
589      setMapInMaps(conf,"lenv","status",status);
590      free(status);
591    }
592    else
593      setMapInMaps(conf,"lenv","status","15");
594    _updateStatus(conf);
595  }
596  freeMaps(&conf);
597  free(conf);
598  Py_RETURN_NONE;
599}
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png