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

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