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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 880 - (show annotations) (download) (as text)
Sun Oct 8 23:38:31 2006 UTC (13 years, 11 months ago) by johnpye
File MIME type: text/x-csrc
File size: 8374 byte(s)
bumping versions to 0.9.5.101
1 /* 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 *//**
19 @file
20 Import handler to provide external python script functionality for ASCEND.
21 *//*
22 by John Pye, Oct 2006
23 */
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 #include <compiler/extfunc.h>
34
35 #include <Python.h>
36
37 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 /*------------------------------------------------------------------------------
68 PYTHON METHOD INVOKER
69 */
70
71 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 PyObject *fn, *arglist, *result;
83 PyObject *pycontext;
84 /* cast user data to PyObject pointer */
85
86 CONSOLE_DEBUG("USER_DATA IS AT %p",user_data);
87
88 fn = (PyObject *) user_data;
89
90 ERROR_REPORTER_HERE(ASC_USER_NOTE,"RUNNING PYTHON METHOD");
91 CONSOLE_DEBUG("RUNNING PYTHON METHOD...");
92
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 /*
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 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 */
107 importhandler_setsharedpointer("context",(void *)context);
108
109 /*
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 arglist = Py_BuildValue("(i)", 666);
114
115 CONSOLE_DEBUG("CALLING PYTHON");
116 result = PyEval_CallObject(fn, arglist);
117 CONSOLE_DEBUG("DONE CALLING PYTHON");
118 Py_DECREF(arglist);
119
120 if(PyErr_Occurred()){
121 /** @TODO we really want to capture these error messages and output them to the GUI, instead of outputting them to the console */
122 PyErr_Print();
123 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed running python method (see console)");
124 return 1;
125 }
126
127 return 0;
128 }
129
130 /*------------------------------------------------------------------------------
131 'EXTPY' PYTHON STATIC MODULE
132 */
133
134 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 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 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
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 return Py_None;
192 }
193
194 static PyMethodDef extpymethods[] = {
195 {"getbrowser", extpy_getbrowser, METH_NOARGS,"Retrieve browser pointer"}
196 ,{"registermethod", extpy_registermethod, METH_VARARGS,"Register a python method as an ASCEND script method"}
197 ,{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 /**
210 Create a filename base on a partial filename. In that case of python, this
211 just means adding '.py' to the end.
212
213 @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
224 len = strlen(partialname);
225 name = ASC_NEW_ARRAY_CLEAR(char,len+4);
226 strcpy(name,partialname);
227 strcat(name,".py");
228 CONSOLE_DEBUG("New filename is '%s'",name);
229 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 int extpy_import(const struct FilePath *fp, const char *initfunc, const char *partialpath){
238 char *name;
239 name = ospath_str(fp);
240 FILE *f;
241 PyObject *pyfile;
242
243 CONSOLE_DEBUG("Importing Python script %s",name);
244 if(Py_IsInitialized()){
245 CONSOLE_DEBUG("Python was already initialised");
246 }else{
247 CONSOLE_DEBUG("INITIALISING PYTHON");
248 Py_Initialize();
249 CONSOLE_DEBUG("COMPLETED ATTEMPT TO INITIALISE PYTHON");
250 }
251
252 if(!Py_IsInitialized()){
253 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to initialise Python");
254 CONSOLE_DEBUG("UNABLE TO INITIALIZE PYTHON");
255 ASC_FREE(name);
256 return 1;
257 }
258
259 initextpy();
260
261 if(PyRun_SimpleString("import ascpy")){
262 CONSOLE_DEBUG("Failed importing 'ascpy'");
263 return 1;
264 }
265
266 pyfile = PyFile_FromString(name,"r");
267 if(pyfile==NULL){
268 CONSOLE_DEBUG("Failed opening script");
269 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to open '%s' (%s)",partialpath,name);
270 ASC_FREE(name);
271 return 1;
272 }
273
274 f = PyFile_AsFile(pyfile);
275 if(f==NULL){
276 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to cast PyObject to FILE*");
277 ASC_FREE(name);
278 return 1;
279 }
280
281 PyRun_AnyFileEx(f,name,1);
282 /*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
289 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Imported python script '%s' (check console for errors)",partialpath);
290
291 ASC_FREE(name);
292 return 0;
293 }
294

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