/[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 874 - (show annotations) (download) (as text)
Thu Oct 5 15:13:22 2006 UTC (14 years ago) by johnpye
File MIME type: text/x-csrc
File size: 7433 byte(s)
Can now access python methods from ASCEND. Still can't access the 'SELF' instance: that's the next thing to do.
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 CONSOLE_DEBUG("Hello...");
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 /* cast user data to PyObject pointer */
84
85 CONSOLE_DEBUG("USER_DATA IS AT %p",user_data);
86
87 fn = (PyObject *) user_data;
88
89 ERROR_REPORTER_HERE(ASC_USER_NOTE,"RUNNING PYTHON METHOD");
90 CONSOLE_DEBUG("RUNNING PYTHON METHOD...");
91
92 PyErr_Clear();
93
94 if(!PyCallable_Check(fn)){
95 ERROR_REPORTER_HERE(ASC_PROG_ERR,"user_data is not a PyCallable");
96 return 1;
97 }
98
99 arglist = Py_BuildValue("(i)", 666);
100 result = PyEval_CallObject(fn, arglist);
101 Py_DECREF(arglist);
102 if(PyErr_Occurred()){
103 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed running python method");
104 return 1;
105 }
106
107 return 0;
108 }
109
110 /*------------------------------------------------------------------------------
111 'EXTPY' PYTHON STATIC MODULE
112 */
113
114 static PyObject *extpy_getbrowser(PyObject *self, PyObject *args){
115 PyObject *browser;
116 if(args!=NULL){
117 ERROR_REPORTER_HERE(ASC_PROG_ERR,"args is not NULL?!");
118 }
119 browser = (PyObject *)importhandler_getsharedpointer("browser");
120 return Py_BuildValue("O",browser);
121 }
122
123 static PyObject *extpy_registermethod(PyObject *self, PyObject *args){
124 PyObject *fn, *name, *docstring;
125 const char *cname, *cdocstring;
126 int res;
127 int nargs = 1;
128
129 PyArg_ParseTuple(args,"O:registermethod", &fn);
130 if(!PyCallable_Check(fn)){
131 PyErr_SetString(PyExc_TypeError,"parameter must be callable");
132 return NULL;
133 }
134
135 CONSOLE_DEBUG("FOUND FN=%p",fn);
136
137 name = PyObject_GetAttr(fn,PyString_FromString("__name__"));
138 if(name==NULL){
139 CONSOLE_DEBUG("No __name__ attribute");
140 PyErr_SetString(PyExc_TypeError,"No __name__ attribute");
141 return NULL;
142 }
143 cname = PyString_AsString(name);
144
145 CONSOLE_DEBUG("REGISTERED METHOD '%s' HAS %d ARGS",cname,nargs);
146
147 docstring = PyObject_GetAttr(fn,PyString_FromString("func_doc"));
148 cdocstring = "(no help)";
149 if(name!=NULL){
150 cdocstring = PyString_AsString(docstring);
151 CONSOLE_DEBUG("DOCSTRING: %s",cdocstring);
152 }
153
154 res = CreateUserFunctionMethod(cname,extpy_invokemethod,nargs,cdocstring,(void *)fn);
155 CONSOLE_DEBUG("PYTHON FUNCTION IS AT %p",fn);
156 Py_INCREF(fn);
157 CONSOLE_DEBUG("PYTHON FUNCTION IS AT %p",fn);
158
159 CONSOLE_DEBUG("EXTPY INVOKER IS AT %p",extpy_invokemethod);
160
161 if(res){
162 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Problem registering external script method (%d)",res);
163 PyErr_SetString(PyExc_Exception,"unable to register script method");
164 return NULL;
165 }
166
167 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Registered python method '%s'",cname);
168
169 /* nothing gets returned (but possibly an exception) */
170 Py_INCREF(Py_None);
171 return Py_None;
172 }
173
174 static PyMethodDef extpymethods[] = {
175 {"getbrowser", extpy_getbrowser, METH_NOARGS,"Retrieve browser pointer"}
176 ,{"registermethod", extpy_registermethod, METH_VARARGS,"Register a python method as an ASCEND script method"}
177 ,{NULL,NULL,0,NULL}
178 };
179
180 PyMODINIT_FUNC initextpy(void){
181 PyObject *obj;
182 obj = Py_InitModule3("extpy", extpymethods,"Module for accessing shared ASCEND pointers from python");
183 }
184
185 /*------------------------------------------------------------------------------
186 STANDARD IMPORT HANDLER ROUTINES
187 */
188
189 /**
190 Create a filename base on a partial filename. In that case of python, this
191 just means adding '.py' to the end.
192
193 @param partialname the filename without suffix, as specified in the user's "IMPORT" command
194 @return new filename, or NULL on failure
195 */
196 char *extpy_filename(const char *partialname){
197 char *name;
198 int len;
199 if(partialname==NULL){
200 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Partial name is NULL, can't work out filename");
201 return NULL;
202 }
203
204 len = strlen(partialname);
205 name = ASC_NEW_ARRAY_CLEAR(char,len+4);
206 strcpy(name,partialname);
207 strcat(name,".py");
208 CONSOLE_DEBUG("New filename is '%s'",name);
209 return name;
210 }
211
212 /**
213 Import a python script located at the path indicated.
214
215 @return 0 on success, else error codes (TBD)
216 */
217 int extpy_import(const struct FilePath *fp, const char *initfunc, const char *partialpath){
218 char *name;
219 name = ospath_str(fp);
220 FILE *f;
221 PyObject *pyfile;
222
223 CONSOLE_DEBUG("Importing Python script %s",name);
224 if(Py_IsInitialized()){
225 CONSOLE_DEBUG("Python was already initialised");
226 }else{
227 CONSOLE_DEBUG("INITIALISING PYTHON");
228 Py_Initialize();
229 CONSOLE_DEBUG("COMPLETED ATTEMPT TO INITIALISE PYTHON");
230 }
231
232 if(!Py_IsInitialized()){
233 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to initialise Python");
234 CONSOLE_DEBUG("UNABLE TO INITIALIZE PYTHON");
235 ASC_FREE(name);
236 return 1;
237 }
238
239 initextpy();
240
241 pyfile = PyFile_FromString(name,"r");
242 if(pyfile==NULL){
243 CONSOLE_DEBUG("Failed opening script");
244 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to open '%s' (%s)",partialpath,name);
245 ASC_FREE(name);
246 return 1;
247 }
248
249 f = PyFile_AsFile(pyfile);
250 if(f==NULL){
251 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to cast PyObject to FILE*");
252 ASC_FREE(name);
253 return 1;
254 }
255
256 PyRun_AnyFileEx(f,name,1);
257 /*if(PyErr_Occurred()){
258 ERROR_REPORTER_HERE(ASC_PROG_ERR,"An error occurred in the python script '%s'. Check the console for details");
259 PyErr_Print();
260 PyErr_Clear();
261 return 1;
262 }*/
263
264 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Imported python script '%s' (check console for errors)",partialpath);
265
266 ASC_FREE(name);
267 return 0;
268 }
269

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