/[ascend]/trunk/models/johnpye/extpy/extpy.c
ViewVC logotype

Annotation of /trunk/models/johnpye/extpy/extpy.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 875 - (hide annotations) (download) (as text)
Sat Oct 7 06:26:34 2006 UTC (14 years ago) by johnpye
File MIME type: text/x-csrc
File size: 8108 byte(s)
Can now access the ASCEND model from an external python script method. The API is not at all nice, but it's basically working now.
1 johnpye 862 /* ASCEND modelling environment
2     Copyright (C) 2006 Carnegie Mellon University
3    
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2, or (at your option)
7     any later version.
8    
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     GNU General Public License for more details.
13    
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place - Suite 330,
17     Boston, MA 02111-1307, USA.
18 johnpye 869 *//**
19     @file
20     Import handler to provide external python script functionality for ASCEND.
21 johnpye 862 */
22    
23     #include <stdio.h>
24     #include <string.h>
25    
26     #include <utilities/ascConfig.h>
27     #include <utilities/error.h>
28     #include <general/ospath.h>
29    
30     #include <compiler/importhandler.h>
31 johnpye 873 #include <compiler/extfunc.h>
32 johnpye 862
33 johnpye 865 #include <Python.h>
34    
35 johnpye 862 ImportHandlerCreateFilenameFn extpy_filename;
36     ImportHandlerImportFn extpy_import;
37    
38     #ifndef ASC_EXPORT
39     # error "Where is ASC_EXPORT?"
40     #endif
41    
42     /**
43     This is the function called from "IMPORT extpy"
44    
45     It sets up the functions in this external function library
46     */
47     extern ASC_EXPORT(int) extpy_register(){
48     int result = 0;
49    
50     struct ImportHandler *handler;
51     handler = ASC_NEW(struct ImportHandler);
52    
53     handler->name = "extpy";
54     handler->filenamefn = extpy_filename;
55     handler->importfn = extpy_import;
56    
57     result = importhandler_add(handler);
58    
59     if(result){
60     ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to register import handler (error = %d)",result);
61     }
62     return result;
63     }
64    
65 johnpye 869 /*------------------------------------------------------------------------------
66 johnpye 873 PYTHON METHOD INVOKER
67 johnpye 869 */
68    
69 johnpye 873 ExtMethodRun extpy_invokemethod;
70    
71     /** Method invoker. extpy will supply a pointer to this function whenever it
72     registers a python function as an external script method. This function will
73     then dereference the user_data field into a python function, and execute that
74     python function.
75    
76     One difficult aspect is the question of how to usefully pass the 'context'
77     argument to Python?
78     */
79     int extpy_invokemethod(struct Instance *context, struct gl_list_t *args, void *user_data){
80 johnpye 874 PyObject *fn, *arglist, *result;
81 johnpye 875 PyObject *pycontext;
82 johnpye 873 /* cast user data to PyObject pointer */
83 johnpye 874
84     CONSOLE_DEBUG("USER_DATA IS AT %p",user_data);
85    
86 johnpye 873 fn = (PyObject *) user_data;
87    
88     ERROR_REPORTER_HERE(ASC_USER_NOTE,"RUNNING PYTHON METHOD");
89     CONSOLE_DEBUG("RUNNING PYTHON METHOD...");
90 johnpye 874
91     PyErr_Clear();
92    
93     if(!PyCallable_Check(fn)){
94     ERROR_REPORTER_HERE(ASC_PROG_ERR,"user_data is not a PyCallable");
95     return 1;
96     }
97    
98 johnpye 875 /*
99     We need to be able to convert C 'struct Instance' pointers to Python 'Instance' objects.
100     This functionality is implemented in 'ascpy' but we're not going to link to that here,
101     so we will use the importhandler 'getsharedpointer' trick to get hold of the
102     casting function, then run it here.
103     */
104     CONSOLE_DEBUG("ADDING 'context' AS SHARED POINTER");
105     importhandler_setsharedpointer("context",(void *)context);
106    
107 johnpye 874 arglist = Py_BuildValue("(i)", 666);
108 johnpye 875 CONSOLE_DEBUG("BUILDING ARGLIST FOR PYTHON METHOD");
109    
110     CONSOLE_DEBUG("CALLING PYTHON");
111 johnpye 874 result = PyEval_CallObject(fn, arglist);
112 johnpye 875 CONSOLE_DEBUG("DONE CALLING PYTHON");
113 johnpye 874 Py_DECREF(arglist);
114 johnpye 875
115 johnpye 874 if(PyErr_Occurred()){
116 johnpye 875 PyErr_Print();
117     ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed running python method (see console)");
118 johnpye 874 return 1;
119     }
120    
121     return 0;
122 johnpye 873 }
123    
124     /*------------------------------------------------------------------------------
125     'EXTPY' PYTHON STATIC MODULE
126     */
127    
128 johnpye 869 static PyObject *extpy_getbrowser(PyObject *self, PyObject *args){
129     PyObject *browser;
130     if(args!=NULL){
131     ERROR_REPORTER_HERE(ASC_PROG_ERR,"args is not NULL?!");
132     }
133     browser = (PyObject *)importhandler_getsharedpointer("browser");
134     return Py_BuildValue("O",browser);
135     }
136    
137 johnpye 873 static PyObject *extpy_registermethod(PyObject *self, PyObject *args){
138     PyObject *fn, *name, *docstring;
139     const char *cname, *cdocstring;
140     int res;
141     int nargs = 1;
142    
143     PyArg_ParseTuple(args,"O:registermethod", &fn);
144     if(!PyCallable_Check(fn)){
145     PyErr_SetString(PyExc_TypeError,"parameter must be callable");
146     return NULL;
147     }
148    
149     CONSOLE_DEBUG("FOUND FN=%p",fn);
150    
151     name = PyObject_GetAttr(fn,PyString_FromString("__name__"));
152     if(name==NULL){
153     CONSOLE_DEBUG("No __name__ attribute");
154     PyErr_SetString(PyExc_TypeError,"No __name__ attribute");
155     return NULL;
156     }
157     cname = PyString_AsString(name);
158    
159     CONSOLE_DEBUG("REGISTERED METHOD '%s' HAS %d ARGS",cname,nargs);
160    
161     docstring = PyObject_GetAttr(fn,PyString_FromString("func_doc"));
162     cdocstring = "(no help)";
163     if(name!=NULL){
164     cdocstring = PyString_AsString(docstring);
165     CONSOLE_DEBUG("DOCSTRING: %s",cdocstring);
166     }
167    
168 johnpye 874 res = CreateUserFunctionMethod(cname,extpy_invokemethod,nargs,cdocstring,(void *)fn);
169     CONSOLE_DEBUG("PYTHON FUNCTION IS AT %p",fn);
170     Py_INCREF(fn);
171     CONSOLE_DEBUG("PYTHON FUNCTION IS AT %p",fn);
172 johnpye 873
173     CONSOLE_DEBUG("EXTPY INVOKER IS AT %p",extpy_invokemethod);
174    
175     if(res){
176     ERROR_REPORTER_HERE(ASC_PROG_ERR,"Problem registering external script method (%d)",res);
177     PyErr_SetString(PyExc_Exception,"unable to register script method");
178     return NULL;
179     }
180    
181     ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Registered python method '%s'",cname);
182    
183     /* nothing gets returned (but possibly an exception) */
184     Py_INCREF(Py_None);
185     return Py_None;
186     }
187    
188 johnpye 869 static PyMethodDef extpymethods[] = {
189     {"getbrowser", extpy_getbrowser, METH_NOARGS,"Retrieve browser pointer"}
190 johnpye 873 ,{"registermethod", extpy_registermethod, METH_VARARGS,"Register a python method as an ASCEND script method"}
191 johnpye 869 ,{NULL,NULL,0,NULL}
192     };
193    
194     PyMODINIT_FUNC initextpy(void){
195     PyObject *obj;
196     obj = Py_InitModule3("extpy", extpymethods,"Module for accessing shared ASCEND pointers from python");
197     }
198    
199     /*------------------------------------------------------------------------------
200     STANDARD IMPORT HANDLER ROUTINES
201     */
202    
203 johnpye 862 /**
204     Create a filename base on a partial filename. In that case of python, this
205     just means adding '.py' to the end.
206 johnpye 867
207 johnpye 862 @param partialname the filename without suffix, as specified in the user's "IMPORT" command
208     @return new filename, or NULL on failure
209     */
210     char *extpy_filename(const char *partialname){
211     char *name;
212     int len;
213     if(partialname==NULL){
214     ERROR_REPORTER_HERE(ASC_PROG_ERR,"Partial name is NULL, can't work out filename");
215     return NULL;
216     }
217 johnpye 867
218 johnpye 862 len = strlen(partialname);
219     name = ASC_NEW_ARRAY_CLEAR(char,len+4);
220     strcpy(name,partialname);
221     strcat(name,".py");
222 johnpye 865 CONSOLE_DEBUG("New filename is '%s'",name);
223 johnpye 862 return name;
224     }
225    
226     /**
227     Import a python script located at the path indicated.
228    
229     @return 0 on success, else error codes (TBD)
230     */
231 johnpye 864 int extpy_import(const struct FilePath *fp, const char *initfunc, const char *partialpath){
232 johnpye 862 char *name;
233     name = ospath_str(fp);
234 johnpye 865 FILE *f;
235 johnpye 872 PyObject *pyfile;
236 johnpye 865
237 johnpye 873 CONSOLE_DEBUG("Importing Python script %s",name);
238 johnpye 865 if(Py_IsInitialized()){
239 johnpye 873 CONSOLE_DEBUG("Python was already initialised");
240 johnpye 865 }else{
241     CONSOLE_DEBUG("INITIALISING PYTHON");
242     Py_Initialize();
243 johnpye 867 CONSOLE_DEBUG("COMPLETED ATTEMPT TO INITIALISE PYTHON");
244 johnpye 865 }
245    
246 johnpye 867 if(!Py_IsInitialized()){
247 johnpye 873 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to initialise Python");
248 johnpye 867 CONSOLE_DEBUG("UNABLE TO INITIALIZE PYTHON");
249 johnpye 873 ASC_FREE(name);
250 johnpye 867 return 1;
251     }
252    
253 johnpye 869 initextpy();
254    
255 johnpye 875 if(PyRun_SimpleString("import ascpy")){
256     CONSOLE_DEBUG("Failed importing 'ascpy'");
257     return 1;
258     }
259    
260 johnpye 872 pyfile = PyFile_FromString(name,"r");
261     if(pyfile==NULL){
262 johnpye 871 CONSOLE_DEBUG("Failed opening script");
263 johnpye 873 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to open '%s' (%s)",partialpath,name);
264     ASC_FREE(name);
265 johnpye 871 return 1;
266     }
267 johnpye 872
268     f = PyFile_AsFile(pyfile);
269     if(f==NULL){
270 johnpye 873 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to cast PyObject to FILE*");
271     ASC_FREE(name);
272 johnpye 872 return 1;
273     }
274 johnpye 873
275 johnpye 872 PyRun_AnyFileEx(f,name,1);
276 johnpye 873 /*if(PyErr_Occurred()){
277     ERROR_REPORTER_HERE(ASC_PROG_ERR,"An error occurred in the python script '%s'. Check the console for details");
278     PyErr_Print();
279     PyErr_Clear();
280     return 1;
281     }*/
282 johnpye 871
283 johnpye 873 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Imported python script '%s' (check console for errors)",partialpath);
284    
285 johnpye 862 ASC_FREE(name);
286 johnpye 873 return 0;
287 johnpye 862 }
288    

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22