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.
49
static
int
tc_pyobject
= -1;
50
51
// Check if a LISP object stores reference to PyObject
52
int
pyobject_p
(
LISP
x
) {
53
if
(TYPEP(
x
,
tc_pyobject
))
54
return
TRUE;
55
return
FALSE;
56
}
57
58
LISP
pyobjectp
(
LISP
x
) {
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.
67
static
PyObject
*
get_c_pyobject
(
LISP
x
) {
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
))
75
Py_RETURN_NONE
;
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
);
85
PyObject
*
pList
=
PyList_New
(
num_items
);
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
100
static
LISP
siod_make_pyobject
(
PyObject
*
pyobj
) {
101
if
(
pyobj
== NULL ||
pyobj
==
Py_None
)
102
return
NIL;
103
104
if
(
PyLong_Check
(
pyobj
) ||
PyFloat_Check
(
pyobj
))
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
)) {
111
PyObject
*
pBytes
;
112
LISP
ret
;
113
pBytes
=
PyUnicode_AsUTF8String
(
pyobj
);
114
if
(
pBytes
== NULL)
115
return
NIL;
116
117
ret
= strcons(
PyBytes_Size
(
pBytes
),
118
PyBytes_AsString
(
pBytes
));
119
Py_DECREF
(
pBytes
);
120
return
ret
;
121
}
122
123
if
(
PyTuple_Check
(
pyobj
) ||
PyList_Check
(
pyobj
)) {
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--)
129
ret
= cons(
siod_make_pyobject
(
PySequence_GetItem
(
pyobj
, i)),
130
ret
);
131
return
ret
;
132
}
133
134
// Bytes, Dict, or Other Objects are stored as Python Objects.
135
Py_XINCREF
(
pyobj
);
136
return
siod_make_typed_cell(
tc_pyobject
,
pyobj
);
137
}
138
139
static
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
147
static
void
pyobject_prin1
(
LISP
v,
FILE
*fp) {
148
if
(TYPEP(v,
tc_pyobject
)) {
149
PyObject
*p =
reinterpret_cast<
PyObject
*
>
(USERVAL(v));
150
PyObject_Print
(p, fp,
Py_PRINT_RAW
);
151
}
152
}
153
154
static
void
pyobject_print_string
(
LISP
v,
char
*tkbuffer) {
155
if
(TYPEP(v,
tc_pyobject
)) {
156
PyObject
*p =
reinterpret_cast<
PyObject
*
>
(USERVAL(v));
157
PyObject
*
pRepr
=
PyObject_Str
(p);
158
if
(
pRepr
== NULL) {
159
snprintf
(tkbuffer, 1024,
"#<UnknownPythonObject %p>"
, p);
// NOLINT
160
return
;
161
}
162
163
LISP
repr
=
siod_make_pyobject
(
pRepr
);
164
snprintf
(tkbuffer, 1024,
"PyObject %s"
, get_c_string(
repr
));
// NOLINT
165
Py_DECREF
(
pRepr
);
166
return
;
167
}
168
snprintf
(tkbuffer, 1024,
"#<UnknownObject>"
);
// NOLINT
169
}
170
171
static
LISP
python_syspath_append
(
LISP
path) {
172
if
(!TYPEP(path, tc_string)) {
173
err(
"Invalid Path"
, path);
174
return
NIL;
175
}
176
177
PyObject
*
sysPath
=
PySys_GetObject
(
"path"
);
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
186
static
LISP
python_import
(
LISP
modulename
) {
187
PyObject
*
pName
, *
pModule
;
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
));
196
pModule
=
PyImport_Import
(
pName
);
197
Py_XDECREF
(
pName
);
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
}
207
ret
=
siod_make_pyobject
(
pModule
);
208
Py_DECREF
(
pModule
);
209
return
ret
;
210
}
211
212
static
LISP
python_attr_get
(
LISP
lpobj
,
LISP
attrname
) {
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
}
232
LISP
ret
=
siod_make_pyobject
(
pAttr
);
233
Py_XDECREF
(
pAttr
);
234
return
ret
;
235
}
236
237
static
LISP
python_attr_set
(
LISP
lpobj
,
LISP
attrname
,
LISP
value) {
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
250
PyObject
*
pValue
=
get_c_pyobject
(value);
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
);
261
Py_DECREF
(
pValue
);
262
263
if
(result == -1) {
264
err(
"Failed to set value"
, value);
265
return
NIL;
266
}
267
return
truth;
268
}
269
270
static
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
283
PyObject
*
pArgs
;
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) {
301
pArgsTuple
=
PyList_AsTuple
(
pArgs
);
302
Py_XDECREF
(
pArgs
);
303
}
304
305
PyObject
*
pValue
=
PyObject_CallObject
(p,
pArgsTuple
);
306
Py_XDECREF
(
pArgsTuple
);
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
}
316
LISP
ret
=
siod_make_pyobject
(
pValue
);
317
Py_DECREF
(
pValue
);
318
return
ret
;
319
}
320
321
static
LISP
python_call_method
(
LISP
lpobj
,
LISP
methodname
,
LISP
args) {
322
LISP
callable
=
python_attr_get
(
lpobj
,
methodname
);
323
return
python_call_object
(
callable
, args);
324
}
325
326
void
init_subrs_python
(
void
) {
327
Py_Initialize
();
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
);
333
set_print_hooks(
tc_pyobject
,
pyobject_prin1
,
pyobject_print_string
);
334
335
// Add CWD to PythonPath
336
PyObject
*
sysPath
=
PySys_GetObject
(
"path"
);
337
PyList_Append
(
sysPath
,
PyUnicode_FromString
(
"."
));
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
371
void
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 */
377
int
est_no_python_support = 1;
378
379
#endif
// EST_SIOD_ENABLE_PYTHON
EST_Hash_Pair
Definition
EST_THash.h:75
siod
slib_python.cc
Generated on Sun Jan 1 2023 21:50:01 for Edinburgh Speech Tools by
1.9.8