xref: /petsc/src/sys/python/pythonsys.c (revision 974168fd257f7d46d6154b41c32c6c92a7381a1f)
1 #include <petsc/private/petscimpl.h>       /*I "petscsys.h" I*/
2 
3 /* ---------------------------------------------------------------- */
4 
5 #if !defined(PETSC_PYTHON_EXE)
6 #define PETSC_PYTHON_EXE "python"
7 #endif
8 
9 static PetscErrorCode PetscPythonFindExecutable(char pythonexe[PETSC_MAX_PATH_LEN])
10 {
11   PetscBool      flag;
12   PetscErrorCode ierr;
13 
14   PetscFunctionBegin;
15   /* get the path for the Python interpreter executable */
16   ierr = PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
17   ierr = PetscOptionsGetString(NULL,NULL,"-python",pythonexe,PETSC_MAX_PATH_LEN,&flag);CHKERRQ(ierr);
18   if (!flag || pythonexe[0]==0) {
19     ierr = PetscStrncpy(pythonexe,PETSC_PYTHON_EXE,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
20   }
21   PetscFunctionReturn(0);
22 }
23 
24 static PetscErrorCode PetscPythonFindLibrary(const char pythonexe[PETSC_MAX_PATH_LEN],char pythonlib[PETSC_MAX_PATH_LEN])
25 {
26   const char     cmdline[] = "-c 'from distutils import sysconfig; print(sysconfig.get_config_var('LIBPYTHON'))'";
27   char           command[PETSC_MAX_PATH_LEN+1+sizeof(cmdline)+1],*eol;
28   FILE           *fp = NULL;
29   PetscBool      found = PETSC_FALSE;
30   PetscErrorCode ierr;
31 
32   PetscFunctionBegin;
33 #if defined(PETSC_PYTHON_LIB)
34   ierr = PetscStrcpy(pythonlib,PETSC_PYTHON_LIB);CHKERRQ(ierr);
35   PetscFunctionReturn(0);
36 #endif
37 
38   /* call Python to find out the name of the Python dynamic library */
39   ierr = PetscStrncpy(command,pythonexe,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
40   ierr = PetscStrcat(command," ");CHKERRQ(ierr);
41   ierr = PetscStrcat(command,cmdline);CHKERRQ(ierr);
42 #if defined(PETSC_HAVE_POPEN)
43   ierr = PetscPOpen(PETSC_COMM_SELF,NULL,command,"r",&fp);CHKERRQ(ierr);
44   if (!fgets(pythonlib,PETSC_MAX_PATH_LEN,fp)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: bad output from executable: %s",pythonexe);
45   ierr = PetscPClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
46 #else
47   SETERRQ(PETSC_COMM_SELF,1,"Python: Aborted due to missing popen()");
48 #endif
49   /* remove newlines */
50   ierr = PetscStrchr(pythonlib,'\n',&eol);CHKERRQ(ierr);
51   if (eol) eol[0] = 0;
52   ierr = PetscTestFile(pythonlib,'r',&found);CHKERRQ(ierr);
53   ierr = PetscInfo2(0,"Python library  %s found %d\n",pythonlib,found);CHKERRQ(ierr);
54   PetscFunctionReturn(0);
55 }
56 
57 /* ---------------------------------------------------------------- */
58 
59 typedef struct _Py_object_t PyObject; /* fake definition */
60 
61 static PyObject* Py_None = 0;
62 
63 static const char* (*Py_GetVersion)(void);
64 
65 static int       (*Py_IsInitialized)(void);
66 static void      (*Py_InitializeEx)(int);
67 static void      (*Py_Finalize)(void);
68 
69 static void      (*PySys_SetArgv)(int,char**);
70 static PyObject* (*PySys_GetObject)(const char*);
71 static PyObject* (*PyObject_CallMethod)(PyObject*,const char*, const char*, ...);
72 static PyObject* (*PyImport_ImportModule)(const char*);
73 
74 static void      (*Py_IncRef)(PyObject*);
75 static void      (*Py_DecRef)(PyObject*);
76 
77 static void      (*PyErr_Clear)(void);
78 static PyObject* (*PyErr_Occurred)(void);
79 static void      (*PyErr_Fetch)(PyObject**,PyObject**,PyObject**);
80 static void      (*PyErr_NormalizeException)(PyObject**,PyObject**, PyObject**);
81 static void      (*PyErr_Display)(PyObject*,PyObject*,PyObject*);
82 static void      (*PyErr_Restore)(PyObject*,PyObject*,PyObject*);
83 
84 
85 #define PetscDLPyLibOpen(libname) \
86   PetscDLLibraryAppend(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,libname)
87 #define PetscDLPyLibSym(symbol, value) \
88   PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,symbol,(void**)value)
89 #define PetscDLPyLibClose(comm) \
90   do { } while (0)
91 
92 static PetscErrorCode PetscPythonLoadLibrary(const char pythonlib[])
93 {
94   PetscErrorCode ierr;
95 
96   PetscFunctionBegin;
97   /* open the Python dynamic library */
98   ierr = PetscDLPyLibOpen(pythonlib);CHKERRQ(ierr);
99   ierr = PetscInfo1(0,"Python: loaded dynamic library %s\n", pythonlib);CHKERRQ(ierr);
100   /* look required symbols from the Python C-API */
101   ierr = PetscDLPyLibSym("_Py_NoneStruct"        , &Py_None               );CHKERRQ(ierr);
102   ierr = PetscDLPyLibSym("Py_GetVersion"         , &Py_GetVersion         );CHKERRQ(ierr);
103   ierr = PetscDLPyLibSym("Py_IsInitialized"      , &Py_IsInitialized      );CHKERRQ(ierr);
104   ierr = PetscDLPyLibSym("Py_InitializeEx"       , &Py_InitializeEx       );CHKERRQ(ierr);
105   ierr = PetscDLPyLibSym("Py_Finalize"           , &Py_Finalize           );CHKERRQ(ierr);
106   ierr = PetscDLPyLibSym("PySys_GetObject"       , &PySys_GetObject       );CHKERRQ(ierr);
107   ierr = PetscDLPyLibSym("PySys_SetArgv"         , &PySys_SetArgv         );CHKERRQ(ierr);
108   ierr = PetscDLPyLibSym("PyObject_CallMethod"   , &PyObject_CallMethod   );CHKERRQ(ierr);
109   ierr = PetscDLPyLibSym("PyImport_ImportModule" , &PyImport_ImportModule );CHKERRQ(ierr);
110   ierr = PetscDLPyLibSym("Py_IncRef"             , &Py_IncRef             );CHKERRQ(ierr);
111   ierr = PetscDLPyLibSym("Py_DecRef"             , &Py_DecRef             );CHKERRQ(ierr);
112   ierr = PetscDLPyLibSym("PyErr_Clear"           , &PyErr_Clear           );CHKERRQ(ierr);
113   ierr = PetscDLPyLibSym("PyErr_Occurred"        , &PyErr_Occurred        );CHKERRQ(ierr);
114   ierr = PetscDLPyLibSym("PyErr_Fetch"             , &PyErr_Fetch             );CHKERRQ(ierr);
115   ierr = PetscDLPyLibSym("PyErr_NormalizeException", &PyErr_NormalizeException);CHKERRQ(ierr);
116   ierr = PetscDLPyLibSym("PyErr_Display",            &PyErr_Display           );CHKERRQ(ierr);
117   ierr = PetscDLPyLibSym("PyErr_Restore",            &PyErr_Restore           );CHKERRQ(ierr);
118   /* XXX TODO: check that ALL symbols were there !!! */
119   if (!Py_None)          SETERRQ(PETSC_COMM_SELF,1,"Python: failed to load symbols from dynamic library");
120   if (!Py_GetVersion)    SETERRQ(PETSC_COMM_SELF,1,"Python: failed to load symbols from dynamic library");
121   if (!Py_IsInitialized) SETERRQ(PETSC_COMM_SELF,1,"Python: failed to load symbols from dynamic library");
122   if (!Py_InitializeEx)  SETERRQ(PETSC_COMM_SELF,1,"Python: failed to load symbols from dynamic library");
123   if (!Py_Finalize)      SETERRQ(PETSC_COMM_SELF,1,"Python: failed to load symbols from dynamic library");
124   ierr = PetscInfo(0,"Python: all required symbols loaded from Python dynamic library\n");CHKERRQ(ierr);
125   PetscFunctionReturn(0);
126 }
127 
128 /* ---------------------------------------------------------------- */
129 
130 static char      PetscPythonExe[PETSC_MAX_PATH_LEN] = { 0 };
131 static char      PetscPythonLib[PETSC_MAX_PATH_LEN] = { 0 };
132 static PetscBool PetscBeganPython = PETSC_FALSE;
133 
134 /*@C
135   PetscPythonFinalize - Finalize Python.
136 
137   Level: intermediate
138 
139 .keywords: Python
140 @*/
141 PetscErrorCode  PetscPythonFinalize(void)
142 {
143   PetscFunctionBegin;
144   if (PetscBeganPython) { if (Py_IsInitialized()) Py_Finalize(); }
145   PetscBeganPython = PETSC_FALSE;
146   PetscFunctionReturn(0);
147 }
148 
149 /*@C
150   PetscPythonInitialize - Initialize Python and import petsc4py.
151 
152    Input Parameter:
153 +  pyexe - path to the Python interpreter executable, or NULL.
154 -  pylib - full path to the Python dynamic library, or NULL.
155 
156   Level: intermediate
157 
158 .keywords: Python
159 
160 @*/
161 PetscErrorCode  PetscPythonInitialize(const char pyexe[],const char pylib[])
162 {
163   PyObject       *module = 0;
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167   if (PetscBeganPython) PetscFunctionReturn(0);
168   /* Python executable */
169   if (pyexe && pyexe[0] != 0) {
170     ierr = PetscStrncpy(PetscPythonExe,pyexe,sizeof(PetscPythonExe));CHKERRQ(ierr);
171   } else {
172     ierr = PetscPythonFindExecutable(PetscPythonExe);CHKERRQ(ierr);
173   }
174   /* Python dynamic library */
175   if (pylib && pylib[0] != 0) {
176     ierr = PetscStrncpy(PetscPythonLib,pylib,sizeof(PetscPythonLib));CHKERRQ(ierr);
177   } else {
178     ierr = PetscPythonFindLibrary(PetscPythonExe,PetscPythonLib);CHKERRQ(ierr);
179   }
180   /* dynamically load Python library */
181   ierr = PetscPythonLoadLibrary(PetscPythonLib);CHKERRQ(ierr);
182   /* initialize Python */
183   PetscBeganPython = PETSC_FALSE;
184   if (!Py_IsInitialized()) {
185     static PetscBool registered = PETSC_FALSE;
186     const char       *py_version;
187     PyObject         *sys_path;
188     char             path[PETSC_MAX_PATH_LEN] = { 0 };
189 
190     /* initialize Python */
191     Py_InitializeEx(0); /* 0: do not install signal handlers */
192     /*  build 'sys.argv' list */
193     py_version = Py_GetVersion();
194     if (py_version[0] == '2') {
195       int argc = 0; char **argv = 0;
196       ierr = PetscGetArgs(&argc,&argv);CHKERRQ(ierr);
197       PySys_SetArgv(argc,argv);
198     }
199     if (py_version[0] == '3') {
200       /* XXX 'argv' is type 'wchar_t**' */
201       PySys_SetArgv(0,NULL);
202     }
203     /* add PETSC_LIB_DIR in front of 'sys.path' */
204     sys_path = PySys_GetObject("path");
205     if (sys_path) {
206       ierr = PetscStrreplace(PETSC_COMM_SELF,"${PETSC_LIB_DIR}",path,sizeof(path));CHKERRQ(ierr);
207       Py_DecRef(PyObject_CallMethod(sys_path,"insert","is",(int)0,(char*)path));
208     }
209     /* register finalizer */
210     if (!registered) {
211       ierr = PetscRegisterFinalize(PetscPythonFinalize);CHKERRQ(ierr);
212 
213       registered = PETSC_TRUE;
214     }
215     PetscBeganPython = PETSC_TRUE;
216   }
217   /* import 'petsc4py.PETSc' module */
218   module = PyImport_ImportModule("petsc4py.PETSc");
219   if (module) {
220     ierr = PetscInfo(0,"Python: successfully imported  module 'petsc4py.PETSc'\n");CHKERRQ(ierr);
221 
222     Py_DecRef(module); module = 0;
223   } else {
224     PetscPythonPrintError();
225     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Python: could not import module 'petsc4py.PETSc', perhaps your PYTHONPATH does not contain it\n");
226   }
227   PetscFunctionReturn(0);
228 }
229 
230 /*@C
231   PetscPythonPrintError - Print Python errors.
232 
233   Level: developer
234 
235 .keywords: Python
236 
237 @*/
238 PetscErrorCode  PetscPythonPrintError(void)
239 {
240   PyObject *exc=0, *val=0, *tb=0;
241 
242   PetscFunctionBegin;
243   if (!PetscBeganPython) PetscFunctionReturn(0);
244   if (!PyErr_Occurred()) PetscFunctionReturn(0);
245   PyErr_Fetch(&exc,&val,&tb);
246   PyErr_NormalizeException(&exc,&val,&tb);
247   PyErr_Display(exc ? exc : Py_None,
248                 val ? val : Py_None,
249                 tb  ? tb  : Py_None);
250   PyErr_Restore(exc,val,tb);
251   PetscFunctionReturn(0);
252 }
253 
254 /* ---------------------------------------------------------------- */
255 
256 PETSC_EXTERN PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]);
257 PetscErrorCode (*PetscPythonMonitorSet_C)(PetscObject,const char[]) = NULL;
258 
259 /*@C
260   PetscPythonMonitorSet - Set Python monitor
261 
262   Level: developer
263 
264 .keywords: Python
265 
266 @*/
267 PetscErrorCode PetscPythonMonitorSet(PetscObject obj, const char url[])
268 {
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   PetscValidHeader(obj,1);
273   PetscValidCharPointer(url,2);
274   if (!PetscPythonMonitorSet_C) {
275     ierr = PetscPythonInitialize(NULL,NULL);CHKERRQ(ierr);
276     if (!PetscPythonMonitorSet_C) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Couldn't initialize Python support for monitors");
277   }
278   ierr = PetscPythonMonitorSet_C(obj,url);CHKERRQ(ierr);
279   PetscFunctionReturn(0);
280 }
281 
282 /* ---------------------------------------------------------------- */
283