]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Fix error handling for callbacks.
[libsigrok.git] / bindings / python / sigrok / core / classes.i
CommitLineData
f7740954
ML
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Martin Ling <martin-sigrok@earth.li>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
6a8c1d68
ML
20%define DOCSTRING
21"@mainpage API Reference
22
23Introduction
24------------
25
26The pysigrok API provides an object-oriented Python interface to the
27functionality in libsigrok. It is built on top of the sigrok++ C++ API.
28
29Getting started
30---------------
31
32Usage of the pysigrok API needs to begin with a call to Context.create().
33This will create the global libsigrok context and returns a Context object.
34Methods on this object provide access to the hardware drivers, input and output
35formats supported by the library, as well as means of creating other objects
36such as sessions and triggers.
37
38Error handling
39--------------
40
41When any libsigrok C API call returns an error, an Error exception is raised,
42which provides access to the error code and description."
43%enddef
44
45%module(docstring=DOCSTRING) classes
f7740954
ML
46
47%{
48#include <pygobject.h>
49
50PyObject *GLib;
51PyTypeObject *IOChannel;
52PyTypeObject *PollFD;
53
0e1a7fe9 54#include "config.h"
abc7146d
ML
55
56#if PYGOBJECT_FLAGS_SIGNED
57typedef gint pyg_flags_type;
58#else
59typedef guint pyg_flags_type;
60#endif
61
f7740954
ML
62%}
63
64%init %{
65 pygobject_init(-1, -1, -1);
66 GLib = PyImport_ImportModule("gi.repository.GLib");
67 IOChannel = (PyTypeObject *) PyObject_GetAttrString(GLib, "IOChannel");
68 PollFD = (PyTypeObject *) PyObject_GetAttrString(GLib, "PollFD");
69%}
70
71/* Map file objects to file descriptors. */
72%typecheck(SWIG_TYPECHECK_POINTER) int fd {
73 $1 = (PyObject_AsFileDescriptor($input) != -1);
74}
75
76%typemap(in) int fd {
77 int fd = PyObject_AsFileDescriptor($input);
78 if (fd == -1)
79 SWIG_exception(SWIG_TypeError,
80 "Expected file object or integer file descriptor");
81 else
82 $1 = fd;
83}
84
85/* Map from Glib::Variant to native Python types. */
86%typemap(out) Glib::VariantBase {
87 GValue *value = g_new0(GValue, 1);
88 g_value_init(value, G_TYPE_VARIANT);
89 g_value_set_variant(value, $1.gobj());
90 PyObject *variant = pyg_value_as_pyobject(value, true);
91 $result = PyObject_CallMethod(variant,
92 const_cast<char *>("unpack"),
93 const_cast<char *>(""), NULL);
94 Py_XDECREF(variant);
95 g_free(value);
96}
97
98/* Map from Glib::IOCondition to GLib.IOCondition. */
99%typecheck(SWIG_TYPECHECK_POINTER) Glib::IOCondition {
abc7146d 100 pyg_flags_type flags;
f7740954
ML
101 $1 = pygobject_check($input, &PyGFlags_Type) &&
102 (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) != -1);
103}
104
105%typemap(in) Glib::IOCondition {
106 if (!pygobject_check($input, &PyGFlags_Type))
107 SWIG_exception(SWIG_TypeError, "Expected GLib.IOCondition value");
abc7146d 108 pyg_flags_type flags;
f7740954
ML
109 if (pyg_flags_get_value(G_TYPE_IO_CONDITION, $input, &flags) == -1)
110 SWIG_exception(SWIG_TypeError, "Not a valid Glib.IOCondition value");
111 $1 = (Glib::IOCondition) flags;
112}
113
114/* And back */
115%typemap(out) Glib::IOCondition {
116 GValue *value = g_new0(GValue, 1);
117 g_value_init(value, G_TYPE_IO_CONDITION);
118 g_value_set_flags(value, &$1);
119 $result = pyg_value_as_pyobject(value, true);
120 g_free(value);
121}
122
123/* Map from GLib.PollFD to Glib::PollFD *. */
124%typecheck(SWIG_TYPECHECK_POINTER) Glib::PollFD {
125 $1 = pygobject_check($input, PollFD);
126}
127
128%typemap(in) Glib::PollFD {
129 if (!pygobject_check($input, PollFD))
130 SWIG_exception(SWIG_TypeError, "Expected GLib.PollFD");
131 PyObject *fd_obj = PyObject_GetAttrString($input, "fd");
132 PyObject *events_obj = PyObject_GetAttrString($input, "events");
abc7146d 133 pyg_flags_type flags;
f7740954
ML
134 pyg_flags_get_value(G_TYPE_IO_CONDITION, events_obj, &flags);
135 int fd = PyInt_AsLong(fd_obj);
136 Glib::IOCondition events = (Glib::IOCondition) flags;
137 $1 = Glib::PollFD(fd, events);
138}
139
140/* Map from GLib.IOChannel to Glib::IOChannel *. */
141%typecheck(SWIG_TYPECHECK_POINTER) Glib::RefPtr<Glib::IOChannel> {
142 $1 = pygobject_check($input, IOChannel);
143}
144
145%typemap(in) Glib::RefPtr<Glib::IOChannel> {
146 if (!pygobject_check($input, IOChannel))
147 SWIG_exception(SWIG_TypeError, "Expected GLib.IOChannel");
148 $1 = Glib::wrap((GIOChannel *) PyObject_Hash($input), true);
149}
150
151/* Map from callable PyObject to SourceCallbackFunction. */
152%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SourceCallbackFunction {
153 $1 = PyCallable_Check($input);
154}
155
156%typemap(in) sigrok::SourceCallbackFunction {
157 if (!PyCallable_Check($input))
158 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
159
160 $1 = [=] (Glib::IOCondition revents) {
161 auto gstate = PyGILState_Ensure();
162
163 GValue *value = g_new0(GValue, 1);
164 g_value_init(value, G_TYPE_IO_CONDITION);
165 g_value_set_flags(value, revents);
166 auto revents_obj = pyg_value_as_pyobject(value, true);
167 g_free(value);
168
169 auto arglist = Py_BuildValue("(O)", revents_obj);
170
171 auto result = PyEval_CallObject($input, arglist);
172
173 Py_XDECREF(arglist);
174 Py_XDECREF(revents_obj);
175
75fb3036
ML
176 bool completed = !PyErr_Occurred();
177
178 if (!completed)
179 PyErr_Print();
180
181 bool valid_result = (completed && PyBool_Check(result));
f7740954 182
75fb3036
ML
183 if (completed && !valid_result)
184 {
185 PyErr_SetString(PyExc_TypeError,
186 "EventSource callback did not return a boolean");
187 PyErr_Print();
188 }
189
190 bool retval = (valid_result && result == Py_True);
f7740954
ML
191
192 Py_XDECREF(result);
193
194 PyGILState_Release(gstate);
195
75fb3036
ML
196 if (!valid_result)
197 throw sigrok::Error(SR_ERR);
198
f7740954
ML
199 return retval;
200 };
201
202 Py_XINCREF($input);
203}
204
205/* Map from callable PyObject to LogCallbackFunction */
206%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
207 $1 = PyCallable_Check($input);
208}
209
210%typemap(in) sigrok::LogCallbackFunction {
211 if (!PyCallable_Check($input))
212 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
213
214 $1 = [=] (const sigrok::LogLevel *loglevel, string message) {
215 auto gstate = PyGILState_Ensure();
216
217 auto log_obj = SWIG_NewPointerObj(
218 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
219
220 auto string_obj = PyString_FromString(message.c_str());
221
222 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
223
224 auto result = PyEval_CallObject($input, arglist);
225
226 Py_XDECREF(arglist);
227 Py_XDECREF(log_obj);
228 Py_XDECREF(string_obj);
75fb3036
ML
229
230 bool completed = !PyErr_Occurred();
231
232 if (!completed)
233 PyErr_Print();
234
235 bool valid_result = (completed && result == Py_None);
236
f7740954
ML
237 Py_XDECREF(result);
238
75fb3036
ML
239 if (completed && !valid_result)
240 {
241 PyErr_SetString(PyExc_TypeError,
242 "Log callback did not return None");
243 PyErr_Print();
244 }
245
f7740954 246 PyGILState_Release(gstate);
75fb3036
ML
247
248 if (!valid_result)
249 throw sigrok::Error(SR_ERR);
f7740954
ML
250 };
251
252 Py_XINCREF($input);
253}
254
255/* Map from callable PyObject to DatafeedCallbackFunction */
256%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
257 $1 = PyCallable_Check($input);
258}
259
260%typemap(in) sigrok::DatafeedCallbackFunction {
261 if (!PyCallable_Check($input))
262 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
263
264 $1 = [=] (std::shared_ptr<sigrok::Device> device,
265 std::shared_ptr<sigrok::Packet> packet) {
266 auto gstate = PyGILState_Ensure();
267
268 auto device_obj = SWIG_NewPointerObj(
269 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
270 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
271
272 auto packet_obj = SWIG_NewPointerObj(
273 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
274 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
275
276 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
277
278 auto result = PyEval_CallObject($input, arglist);
279
280 Py_XDECREF(arglist);
281 Py_XDECREF(device_obj);
282 Py_XDECREF(packet_obj);
75fb3036
ML
283
284 bool completed = !PyErr_Occurred();
285
286 if (!completed)
287 PyErr_Print();
288
289 bool valid_result = (completed && result == Py_None);
290
f7740954
ML
291 Py_XDECREF(result);
292
75fb3036
ML
293 if (completed && !valid_result)
294 {
295 PyErr_SetString(PyExc_TypeError,
296 "Datafeed callback did not return None");
297 PyErr_Print();
298 }
299
f7740954 300 PyGILState_Release(gstate);
75fb3036
ML
301
302 if (!valid_result)
303 throw sigrok::Error(SR_ERR);
f7740954
ML
304 };
305
306 Py_XINCREF($input);
307}
308
309%{
310
311#include "libsigrok/libsigrok.hpp"
312
313/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 314std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
315{
316 if (!PyDict_Check(dict))
317 throw sigrok::Error(SR_ERR_ARG);
318
319 std::map<std::string, std::string> output;
320
321 PyObject *py_key, *py_value;
322 Py_ssize_t pos = 0;
323
324 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
325 if (!PyString_Check(py_key))
326 throw sigrok::Error(SR_ERR_ARG);
327 if (!PyString_Check(py_value))
328 throw sigrok::Error(SR_ERR_ARG);
329 auto key = PyString_AsString(py_key);
330 auto value = PyString_AsString(py_value);
331 output[key] = value;
332 }
333
334 return output;
335}
336
337/* Convert from a Python type to Glib::Variant, according to config key data type. */
338Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
339{
9d229ecb 340 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
341
342 if (type == SR_T_UINT64 && PyInt_Check(input))
343 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
344 if (type == SR_T_UINT64 && PyLong_Check(input))
345 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
346 else if (type == SR_T_STRING && PyString_Check(input))
f90ed2d1 347 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
348 else if (type == SR_T_BOOL && PyBool_Check(input))
349 return Glib::Variant<bool>::create(input == Py_True);
350 else if (type == SR_T_FLOAT && PyFloat_Check(input))
351 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
352 else if (type == SR_T_INT32 && PyInt_Check(input))
353 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
354 else
355 throw sigrok::Error(SR_ERR_ARG);
356}
357
58aa1f83
ML
358/* Convert from a Python type to Glib::Variant, according to Option data type. */
359Glib::VariantBase python_to_variant_by_option(PyObject *input,
360 std::shared_ptr<sigrok::Option> option)
361{
3b161085 362 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
363
364 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
365 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
366 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
367 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
368 else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
f90ed2d1 369 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
370 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
371 return Glib::Variant<bool>::create(input == Py_True);
372 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
373 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
374 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
375 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
376 else
377 throw sigrok::Error(SR_ERR_ARG);
378}
379
380/* Convert from a Python dict to a std::map<std::string, std::string> */
381std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
382 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
383{
384 if (!PyDict_Check(dict))
385 throw sigrok::Error(SR_ERR_ARG);
386
387 std::map<std::string, Glib::VariantBase> output;
388
389 PyObject *py_key, *py_value;
390 Py_ssize_t pos = 0;
391
392 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
393 if (!PyString_Check(py_key))
394 throw sigrok::Error(SR_ERR_ARG);
395 auto key = PyString_AsString(py_key);
396 auto value = python_to_variant_by_option(py_value, options[key]);
397 output[key] = value;
398 }
399
400 return output;
401}
402
f7740954
ML
403%}
404
405/* Ignore these methods, we will override them below. */
406%ignore sigrok::Driver::scan;
ca3291e3 407%ignore sigrok::InputFormat::create_input;
f7740954
ML
408%ignore sigrok::OutputFormat::create_output;
409
bd4fda24
ML
410%include "doc.i"
411
062430a2 412%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
413%rename(_ ## Get) sigrok::Class::Get;
414%extend sigrok::Class
415{
416%pythoncode
417{
418 Name = property(_ ## Get)
419}
420}
062430a2
ML
421%enddef
422
423%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
424%rename(_ ## Get) sigrok::Class::Get;
425%extend sigrok::Class
426{
427%pythoncode
428{
429 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
430}
431}
062430a2
ML
432%enddef
433
7a36ceac 434%define %enumextras(Class)
f0c0dab5
ML
435%extend sigrok::Class
436{
437 long __hash__()
438 {
439 return (long) $self;
440 }
441
442%pythoncode
443{
444 def __eq__(self, other):
445 return (type(self) is type(other) and hash(self) == hash(other))
446
447 def __ne__(self, other):
448 return (type(self) is not type(other) or hash(self) != hash(other))
449}
450}
7a36ceac
ML
451%enddef
452
f7740954
ML
453%include "../../../swig/classes.i"
454
455/* Support Driver.scan() with keyword arguments. */
456%extend sigrok::Driver
457{
458 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
459 {
460 if (!PyDict_Check(dict))
461 throw sigrok::Error(SR_ERR_ARG);
462
463 PyObject *py_key, *py_value;
464 Py_ssize_t pos = 0;
465 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
466
467 while (PyDict_Next(dict, &pos, &py_key, &py_value))
468 {
469 if (!PyString_Check(py_key))
470 throw sigrok::Error(SR_ERR_ARG);
0bc1a761 471 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
472 auto value = python_to_variant_by_key(py_value, key);
473 options[key] = value;
474 }
475
476 return $self->scan(options);
477 }
478}
479
480%pythoncode
481{
482 def _Driver_scan(self, **kwargs):
483 return self._scan_kwargs(kwargs)
484
485 Driver.scan = _Driver_scan
486}
487
ca3291e3 488/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
489%extend sigrok::InputFormat
490{
ca3291e3 491 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 492 {
ca3291e3 493 return $self->create_input(
3b161085 494 dict_to_map_options(dict, $self->options()));
f7740954
ML
495 }
496}
497
498%pythoncode
499{
ca3291e3
ML
500 def _InputFormat_create_input(self, **kwargs):
501 return self._create_input(kwargs)
f7740954 502
ca3291e3 503 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
504}
505
506/* Support OutputFormat.create_output() with keyword arguments. */
507%extend sigrok::OutputFormat
508{
509 std::shared_ptr<sigrok::Output> _create_output_kwargs(
510 std::shared_ptr<sigrok::Device> device, PyObject *dict)
511 {
58aa1f83 512 return $self->create_output(device,
3b161085 513 dict_to_map_options(dict, $self->options()));
f7740954
ML
514 }
515}
516
517%pythoncode
518{
519 def _OutputFormat_create_output(self, device, **kwargs):
520 return self._create_output_kwargs(device, kwargs)
521
522 OutputFormat.create_output = _OutputFormat_create_output
523}
524
525/* Support config_set() with Python input types. */
526%extend sigrok::Configurable
527{
528 void config_set(const ConfigKey *key, PyObject *input)
529 {
530 $self->config_set(key, python_to_variant_by_key(input, key));
531 }
532}