/[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 875 - (show 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 /* 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
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 #include <compiler/extfunc.h>
32
33 #include <Python.h>
34
35 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 /*------------------------------------------------------------------------------
66 PYTHON METHOD INVOKER
67 */
68
69 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 PyObject *fn, *arglist, *result;
81 PyObject *pycontext;
82 /* cast user data to PyObject pointer */
83
84 CONSOLE_DEBUG("USER_DATA IS AT %p",user_data);
85
86 fn = (PyObject *) user_data;
87
88 ERROR_REPORTER_HERE(ASC_USER_NOTE,"RUNNING PYTHON METHOD");
89 CONSOLE_DEBUG("RUNNING PYTHON METHOD...");
90
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 /*
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 arglist = Py_BuildValue("(i)", 666);
108 CONSOLE_DEBUG("BUILDING ARGLIST FOR PYTHON METHOD");
109
110 CONSOLE_DEBUG("CALLING PYTHON");
111 result = PyEval_CallObject(fn, arglist);
112 CONSOLE_DEBUG("DONE CALLING PYTHON");
113 Py_DECREF(arglist);
114
115 if(PyErr_Occurred()){
116 PyErr_Print();
117 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed running python method (see console)");
118 return 1;
119 }
120
121 return 0;
122 }
123
124 /*------------------------------------------------------------------------------
125 'EXTPY' PYTHON STATIC MODULE
126 */
127
128 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 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 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
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 static PyMethodDef extpymethods[] = {
189 {"getbrowser", extpy_getbrowser, METH_NOARGS,"Retrieve browser pointer"}
190 ,{"registermethod", extpy_registermethod, METH_VARARGS,"Register a python method as an ASCEND script method"}
191 ,{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 /**
204 Create a filename base on a partial filename. In that case of python, this
205 just means adding '.py' to the end.
206
207 @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
218 len = strlen(partialname);
219 name = ASC_NEW_ARRAY_CLEAR(char,len+4);
220 strcpy(name,partialname);
221 strcat(name,".py");
222 CONSOLE_DEBUG("New filename is '%s'",name);
223 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 int extpy_import(const struct FilePath *fp, const char *initfunc, const char *partialpath){
232 char *name;
233 name = ospath_str(fp);
234 FILE *f;
235 PyObject *pyfile;
236
237 CONSOLE_DEBUG("Importing Python script %s",name);
238 if(Py_IsInitialized()){
239 CONSOLE_DEBUG("Python was already initialised");
240 }else{
241 CONSOLE_DEBUG("INITIALISING PYTHON");
242 Py_Initialize();
243 CONSOLE_DEBUG("COMPLETED ATTEMPT TO INITIALISE PYTHON");
244 }
245
246 if(!Py_IsInitialized()){
247 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to initialise Python");
248 CONSOLE_DEBUG("UNABLE TO INITIALIZE PYTHON");
249 ASC_FREE(name);
250 return 1;
251 }
252
253 initextpy();
254
255 if(PyRun_SimpleString("import ascpy")){
256 CONSOLE_DEBUG("Failed importing 'ascpy'");
257 return 1;
258 }
259
260 pyfile = PyFile_FromString(name,"r");
261 if(pyfile==NULL){
262 CONSOLE_DEBUG("Failed opening script");
263 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to open '%s' (%s)",partialpath,name);
264 ASC_FREE(name);
265 return 1;
266 }
267
268 f = PyFile_AsFile(pyfile);
269 if(f==NULL){
270 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to cast PyObject to FILE*");
271 ASC_FREE(name);
272 return 1;
273 }
274
275 PyRun_AnyFileEx(f,name,1);
276 /*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
283 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Imported python script '%s' (check console for errors)",partialpath);
284
285 ASC_FREE(name);
286 return 0;
287 }
288

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