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