Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
slib_python.cc
1/*************************************************************************/
2/* */
3/* Language Technologies Institute */
4/* Carnegie Mellon University */
5/* Copyright (c) 2013 */
6/* All Rights Reserved. */
7/* */
8/* Permission is hereby granted, free of charge, to use and distribute */
9/* this software and its documentation without restriction, including */
10/* without limitation the rights to use, copy, modify, merge, publish, */
11/* distribute, sublicense, and/or sell copies of this work, and to */
12/* permit persons to whom this work is furnished to do so, subject to */
13/* the following conditions: */
14/* 1. The code must retain the above copyright notice, this list of */
15/* conditions and the following disclaimer. */
16/* 2. Any modifications must be clearly marked as such. */
17/* 3. Original authors' names are not deleted. */
18/* 4. The authors' names are not used to endorse or promote products */
19/* derived from this software without specific prior written */
20/* permission. */
21/* */
22/* CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK */
23/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25/* SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE */
26/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30/* THIS SOFTWARE. */
31/* */
32/*************************************************************************/
33/* Author: Alok Parlikar (aup@cs.cmu.edu) */
34/* Date: April 2013 */
35/*************************************************************************/
36/*
37 Support to call Python Functions from SIOD
38*/
39
40#ifdef EST_SIOD_ENABLE_PYTHON
41#include "slib_python.h"
42#include "siod.h"
43
44#include "Python.h"
45
46// The following are the types for Python objects in LISP, they are
47// set when the objects are registered. These are not required
48// outside this file, hence static.
49static int tc_pyobject = -1;
50
51// Check if a LISP object stores reference to PyObject
52int pyobject_p(LISP x) {
53 if (TYPEP(x, tc_pyobject))
54 return TRUE;
55 return FALSE;
56}
57
59 if (pyobject_p(x))
60 return truth;
61 return NIL;
62}
63
64// This always returns a new reference to PyObject
65// If it already stores a reference to a PyObject
66// This increments its count.
68 if (TYPEP(x, tc_pyobject)) {
69 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(x));
70 Py_XINCREF(p);
71 return p;
72 }
73
74 if (NULLP(x))
76
77 if (numberp(x))
78 return PyFloat_FromDouble(get_c_double(x));
79
80 if (TYPEP(x, tc_string))
81 return PyUnicode_FromString(get_c_string(x));
82
83 if (consp(x)) {
84 int num_items = siod_llength(x);
86 LISP ptr;
87 int i;
88 for (ptr = x, i = 0;
89 NNULLP(ptr);
90 ptr = cdr(ptr), i++) {
91 PyList_SetItem(pList, i, get_c_pyobject(car(ptr)));
92 }
93 return pList;
94 }
95
96 err("wrong type of argument to get_c_pyobject", x);
97 return NULL; // err doesn't return but compilers don't know that
98}
99
101 if (pyobj == NULL || pyobj == Py_None)
102 return NIL;
103
105 return flocons(PyFloat_AsDouble(pyobj));
106
107 if (PyBool_Check(pyobj))
108 return PyObject_IsTrue(pyobj)? truth : NIL;
109
110 if (PyUnicode_Check(pyobj)) {
112 LISP ret;
114 if (pBytes == NULL)
115 return NIL;
116
117 ret = strcons(PyBytes_Size(pBytes),
120 return ret;
121 }
122
124 LISP ret = NIL;
125 int size = PySequence_Size(pyobj);
126 if (size <= 0)
127 return NIL;
128 for (int i = size - 1; i >= 0; i--)
130 ret);
131 return ret;
132 }
133
134 // Bytes, Dict, or Other Objects are stored as Python Objects.
136 return siod_make_typed_cell(tc_pyobject, pyobj);
137}
138
139static void pyobject_free(LISP x) {
140 // Decrement refcount if x stores a PyObject;
141 if (TYPEP(x, tc_pyobject)) {
142 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(x));
143 Py_XDECREF(p);
144 }
145}
146
147static void pyobject_prin1(LISP v, FILE *fp) {
148 if (TYPEP(v, tc_pyobject)) {
149 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(v));
151 }
152}
153
154static void pyobject_print_string(LISP v, char *tkbuffer) {
155 if (TYPEP(v, tc_pyobject)) {
156 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(v));
158 if (pRepr == NULL) {
159 snprintf(tkbuffer, 1024, "#<UnknownPythonObject %p>", p); // NOLINT
160 return;
161 }
162
164 snprintf(tkbuffer, 1024, "PyObject %s", get_c_string(repr)); // NOLINT
166 return;
167 }
168 snprintf(tkbuffer, 1024, "#<UnknownObject>"); // NOLINT
169}
170
171static LISP python_syspath_append(LISP path) {
172 if (!TYPEP(path, tc_string)) {
173 err("Invalid Path", path);
174 return NIL;
175 }
176
178 int ret = PyList_Append(sysPath, PyUnicode_FromString(get_c_string(path)));
179 if (ret == 0) {
180 // Success
181 return truth;
182 }
183 return NIL;
184}
185
188 LISP ret;
189
190 if (!TYPEP(modulename, tc_string)) {
191 err("Invalid module name (expecting string)", modulename);
192 return NIL;
193 }
194
195 pName = PyUnicode_FromString(get_c_string(modulename));
198
199 if (pModule == NULL) {
200 if (PyErr_Occurred()) {
201 PyErr_Print();
202 PyErr_Clear();
203 }
204 err("Failed to load module", modulename);
205 return NIL;
206 }
209 return ret;
210}
211
213 if (!TYPEP(lpobj, tc_pyobject)) {
214 err("Invalid Object for python_attr_get", lpobj);
215 return NIL;
216 }
217
218 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(lpobj));
219
220 if (!TYPEP(attrname, tc_string)) {
221 err("Invalid Attribute Name (expecting string)", attrname);
222 return NIL;
223 }
224
225 PyObject *pAttr = PyObject_GetAttrString(p, get_c_string(attrname));
226 if (pAttr == NULL) {
227 if (PyErr_Occurred()) {
228 PyErr_Print();
229 PyErr_Clear();
230 }
231 }
234 return ret;
235}
236
238 if (!TYPEP(lpobj, tc_pyobject)) {
239 err("Invalid Object for python_attr_set", lpobj);
240 return NIL;
241 }
242
243 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(lpobj));
244
245 if (!TYPEP(attrname, tc_string)) {
246 err("Invalid Attribute Name (expecting string)", attrname);
247 return NIL;
248 }
249
251 if (pValue == NULL) {
252 if (PyErr_Occurred()) {
253 PyErr_Print();
254 PyErr_Clear();
255 }
256 err("Invalid Value for python_attr_set", value);
257 return NIL;
258 }
259
260 int result = PyObject_SetAttrString(p, get_c_string(attrname), pValue);
262
263 if (result == -1) {
264 err("Failed to set value", value);
265 return NIL;
266 }
267 return truth;
268}
269
270static LISP python_call_object(LISP fpobj, LISP args) {
271 if (!TYPEP(fpobj, tc_pyobject)) {
272 err("Invalid Object for python_callfunction", fpobj);
273 return NIL;
274 }
275
276 PyObject *p = reinterpret_cast<PyObject *>(USERVAL(fpobj));
277
278 if (p == NULL || !PyCallable_Check(p)) {
279 err("Not a callable object", fpobj);
280 return NIL;
281 }
282
284 if (args == NIL) {
285 pArgs = NULL;
286 } else {
287 if (!consp(args)) {
288 err("Invalid argument (expecting list)", args);
289 return NIL;
290 }
291
292 pArgs = get_c_pyobject(args);
293 if (pArgs == NULL) {
294 err("Could not convert arguments", args);
295 return NIL;
296 }
297 }
298
299 PyObject *pArgsTuple = NULL;
300 if (pArgs != NULL) {
303 }
304
307
308 if (pValue == NULL) {
309 if (PyErr_Occurred()) {
310 PyErr_Print();
311 PyErr_Clear();
312 }
313 err("Could not call object", fpobj);
314 return NIL;
315 }
318 return ret;
319}
320
323 return python_call_object(callable, args);
324}
325
326void init_subrs_python(void) {
328
329 long kind; // NOLINT
330
331 tc_pyobject = siod_register_user_type("PyObject");
332 set_gc_hooks(tc_pyobject, 0, NULL, NULL, NULL, pyobject_free, NULL, &kind);
334
335 // Add CWD to PythonPath
338
339 init_subr_1("pyobjectp", pyobjectp,
340 "(pyobjectp obj)\n"
341 "Checks if obj is a Python Object");
342
343
344 init_subr_1("python_syspath_append", python_syspath_append,
345 "(python_addpath path)\n"
346 "Appends path (string) to sys.path");
347
348 init_subr_1("python_import", python_import,
349 "(python_import modulename)\n"
350 "Imports specified module and returns it");
351
352 init_subr_2("python_attr_get", python_attr_get,
353 "(python_attr_get object attrname)\n"
354 "Returns the specified attribute of the given PyObject");
355
356 init_subr_3("python_attr_set", python_attr_set,
357 "(python_attr_set object attrname value)\n"
358 "Set value of the given attribute of the given PyObject");
359
360 init_subr_3("python_call_method", python_call_method,
361 "(python_call_method object methodname args)\n"
362 "Calls object.methodname(args)\n"
363 "object is a PyObject, methodname is string. args is a list.");
364
365 init_subr_2("python_call_object", python_call_object,
366 "(python_call_object object args)\n"
367 "Calls object(args)\n"
368 "object is a callable PyObject, args is a list");
369}
370
371void python_tidy_up(void) {
372 Py_Finalize();
373}
374#else // No python support
375
376/* So there is a symbol in here even if there is no python support */
377int est_no_python_support = 1;
378
379#endif // EST_SIOD_ENABLE_PYTHON