]> sigrok.org Git - libsigrok.git/blame - bindings/python/sigrok/core/classes.i
python: Fix PyObject_CallMethod() arguments
[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
52ff4f6a 27functionality in libsigrok. It is built on top of the libsigrokcxx C++ API.
6a8c1d68
ML
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%{
aae2273b 48#include <stdio.h>
f7740954 49#include <pygobject.h>
ed6b4c47 50#include <numpy/arrayobject.h>
f7740954 51
aae2273b 52PyObject *PyGObject_lib;
f7740954 53PyObject *GLib;
f7740954 54
0e1a7fe9 55#include "config.h"
abc7146d
ML
56
57#if PYGOBJECT_FLAGS_SIGNED
58typedef gint pyg_flags_type;
59#else
60typedef guint pyg_flags_type;
61#endif
62
f7740954
ML
63%}
64
65%init %{
aae2273b
AG
66 PyGObject_lib = pygobject_init(-1, -1, -1);
67 if (!PyGObject_lib)
68 fprintf(stderr, "pygobject initialization failed.\n");
f7740954 69 GLib = PyImport_ImportModule("gi.repository.GLib");
aae2273b
AG
70 /*
71 * This check can't save us if the import fails, but at least it gives us
72 * a starting point to trace the issue versus straight out crashing.
73 */
74 if (!GLib) {
75 fprintf(stderr, "Import of gi.repository.GLib failed.\n");
a2e4d882 76#if PY_VERSION_HEX >= 0x03000000
fa72105f 77 return nullptr;
a2e4d882 78#else
aae2273b 79 return;
a2e4d882 80#endif
aae2273b 81 }
ed6b4c47 82 import_array();
f7740954
ML
83%}
84
85/* Map file objects to file descriptors. */
86%typecheck(SWIG_TYPECHECK_POINTER) int fd {
87 $1 = (PyObject_AsFileDescriptor($input) != -1);
88}
89
f7740954
ML
90/* Map from Glib::Variant to native Python types. */
91%typemap(out) Glib::VariantBase {
92 GValue *value = g_new0(GValue, 1);
93 g_value_init(value, G_TYPE_VARIANT);
94 g_value_set_variant(value, $1.gobj());
95 PyObject *variant = pyg_value_as_pyobject(value, true);
96 $result = PyObject_CallMethod(variant,
fa72105f 97 const_cast<char *>("unpack"), nullptr);
f7740954
ML
98 Py_XDECREF(variant);
99 g_free(value);
100}
101
f7740954
ML
102/* Map from callable PyObject to LogCallbackFunction */
103%typecheck(SWIG_TYPECHECK_POINTER) sigrok::LogCallbackFunction {
104 $1 = PyCallable_Check($input);
105}
106
107%typemap(in) sigrok::LogCallbackFunction {
108 if (!PyCallable_Check($input))
109 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
110
682fb08c 111 $1 = [=] (const sigrok::LogLevel *loglevel, std::string message) {
f7740954
ML
112 auto gstate = PyGILState_Ensure();
113
114 auto log_obj = SWIG_NewPointerObj(
115 SWIG_as_voidptr(loglevel), SWIGTYPE_p_sigrok__LogLevel, 0);
116
117 auto string_obj = PyString_FromString(message.c_str());
118
119 auto arglist = Py_BuildValue("(OO)", log_obj, string_obj);
120
121 auto result = PyEval_CallObject($input, arglist);
122
123 Py_XDECREF(arglist);
124 Py_XDECREF(log_obj);
125 Py_XDECREF(string_obj);
75fb3036
ML
126
127 bool completed = !PyErr_Occurred();
128
129 if (!completed)
130 PyErr_Print();
131
132 bool valid_result = (completed && result == Py_None);
133
f7740954
ML
134 Py_XDECREF(result);
135
75fb3036
ML
136 if (completed && !valid_result)
137 {
138 PyErr_SetString(PyExc_TypeError,
139 "Log callback did not return None");
140 PyErr_Print();
141 }
142
f7740954 143 PyGILState_Release(gstate);
75fb3036
ML
144
145 if (!valid_result)
146 throw sigrok::Error(SR_ERR);
f7740954
ML
147 };
148
149 Py_XINCREF($input);
150}
151
2c3c9b99
DE
152/* Map from callable PyObject to SessionStoppedCallback */
153%typecheck(SWIG_TYPECHECK_POINTER) sigrok::SessionStoppedCallback {
154 $1 = PyCallable_Check($input);
155}
156
157%typemap(in) sigrok::SessionStoppedCallback {
158 if (!PyCallable_Check($input))
159 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
160
161 $1 = [=] () {
162 const auto gstate = PyGILState_Ensure();
163
164 const auto result = PyEval_CallObject($input, nullptr);
165 const bool completed = !PyErr_Occurred();
166 const bool valid_result = (completed && result == Py_None);
167
168 if (completed && !valid_result) {
169 PyErr_SetString(PyExc_TypeError,
170 "Session stop callback did not return None");
171 }
172 if (!valid_result)
173 PyErr_Print();
174
175 Py_XDECREF(result);
176 PyGILState_Release(gstate);
177
178 if (!valid_result)
179 throw sigrok::Error(SR_ERR);
180 };
181
182 Py_XINCREF($input);
183}
184
f7740954
ML
185/* Map from callable PyObject to DatafeedCallbackFunction */
186%typecheck(SWIG_TYPECHECK_POINTER) sigrok::DatafeedCallbackFunction {
187 $1 = PyCallable_Check($input);
188}
189
190%typemap(in) sigrok::DatafeedCallbackFunction {
191 if (!PyCallable_Check($input))
192 SWIG_exception(SWIG_TypeError, "Expected a callable Python object");
193
194 $1 = [=] (std::shared_ptr<sigrok::Device> device,
195 std::shared_ptr<sigrok::Packet> packet) {
196 auto gstate = PyGILState_Ensure();
197
198 auto device_obj = SWIG_NewPointerObj(
199 SWIG_as_voidptr(new std::shared_ptr<sigrok::Device>(device)),
200 SWIGTYPE_p_std__shared_ptrT_sigrok__Device_t, SWIG_POINTER_OWN);
201
202 auto packet_obj = SWIG_NewPointerObj(
203 SWIG_as_voidptr(new std::shared_ptr<sigrok::Packet>(packet)),
204 SWIGTYPE_p_std__shared_ptrT_sigrok__Packet_t, SWIG_POINTER_OWN);
205
206 auto arglist = Py_BuildValue("(OO)", device_obj, packet_obj);
207
208 auto result = PyEval_CallObject($input, arglist);
209
210 Py_XDECREF(arglist);
211 Py_XDECREF(device_obj);
212 Py_XDECREF(packet_obj);
75fb3036
ML
213
214 bool completed = !PyErr_Occurred();
215
216 if (!completed)
217 PyErr_Print();
218
219 bool valid_result = (completed && result == Py_None);
220
f7740954
ML
221 Py_XDECREF(result);
222
75fb3036
ML
223 if (completed && !valid_result)
224 {
225 PyErr_SetString(PyExc_TypeError,
226 "Datafeed callback did not return None");
227 PyErr_Print();
228 }
229
f7740954 230 PyGILState_Release(gstate);
75fb3036
ML
231
232 if (!valid_result)
233 throw sigrok::Error(SR_ERR);
f7740954
ML
234 };
235
236 Py_XINCREF($input);
237}
238
ea22dc10
ML
239/* Cast PacketPayload pointers to correct subclass type. */
240%ignore sigrok::Packet::payload;
241
242%extend sigrok::Packet
243{
244 std::shared_ptr<sigrok::Header> _payload_header()
245 {
246 return dynamic_pointer_cast<sigrok::Header>($self->payload());
247 }
248 std::shared_ptr<sigrok::Meta> _payload_meta()
249 {
250 return dynamic_pointer_cast<sigrok::Meta>($self->payload());
251 }
252 std::shared_ptr<sigrok::Analog> _payload_analog()
253 {
254 return dynamic_pointer_cast<sigrok::Analog>($self->payload());
255 }
256 std::shared_ptr<sigrok::Logic> _payload_logic()
257 {
258 return dynamic_pointer_cast<sigrok::Logic>($self->payload());
259 }
260}
261
262%extend sigrok::Packet
263{
264%pythoncode
265{
266 def _payload(self):
267 if self.type == PacketType.HEADER:
268 return self._payload_header()
269 elif self.type == PacketType.META:
270 return self._payload_meta()
271 elif self.type == PacketType.LOGIC:
272 return self._payload_logic()
273 elif self.type == PacketType.ANALOG:
274 return self._payload_analog()
275 else:
276 return None
277
278 payload = property(_payload)
279}
280}
281
f7740954
ML
282%{
283
161dc24d 284#include "libsigrokcxx/libsigrokcxx.hpp"
f7740954
ML
285
286/* Convert from a Python dict to a std::map<std::string, std::string> */
58aa1f83 287std::map<std::string, std::string> dict_to_map_string(PyObject *dict)
f7740954
ML
288{
289 if (!PyDict_Check(dict))
290 throw sigrok::Error(SR_ERR_ARG);
291
292 std::map<std::string, std::string> output;
293
294 PyObject *py_key, *py_value;
295 Py_ssize_t pos = 0;
296
297 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
298 if (!PyString_Check(py_key))
299 throw sigrok::Error(SR_ERR_ARG);
300 if (!PyString_Check(py_value))
301 throw sigrok::Error(SR_ERR_ARG);
302 auto key = PyString_AsString(py_key);
303 auto value = PyString_AsString(py_value);
304 output[key] = value;
305 }
306
307 return output;
308}
309
310/* Convert from a Python type to Glib::Variant, according to config key data type. */
311Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::ConfigKey *key)
312{
9d229ecb 313 enum sr_datatype type = (enum sr_datatype) key->data_type()->id();
f7740954
ML
314
315 if (type == SR_T_UINT64 && PyInt_Check(input))
316 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
317 if (type == SR_T_UINT64 && PyLong_Check(input))
318 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
319 else if (type == SR_T_STRING && PyString_Check(input))
f90ed2d1 320 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
f7740954
ML
321 else if (type == SR_T_BOOL && PyBool_Check(input))
322 return Glib::Variant<bool>::create(input == Py_True);
323 else if (type == SR_T_FLOAT && PyFloat_Check(input))
324 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
325 else if (type == SR_T_INT32 && PyInt_Check(input))
326 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
327 else
328 throw sigrok::Error(SR_ERR_ARG);
329}
330
58aa1f83
ML
331/* Convert from a Python type to Glib::Variant, according to Option data type. */
332Glib::VariantBase python_to_variant_by_option(PyObject *input,
333 std::shared_ptr<sigrok::Option> option)
334{
3b161085 335 GVariantType *type = option->default_value().get_type().gobj();
58aa1f83
ML
336
337 if (type == G_VARIANT_TYPE_UINT64 && PyInt_Check(input))
338 return Glib::Variant<guint64>::create(PyInt_AsLong(input));
339 if (type == G_VARIANT_TYPE_UINT64 && PyLong_Check(input))
340 return Glib::Variant<guint64>::create(PyLong_AsLong(input));
341 else if (type == G_VARIANT_TYPE_STRING && PyString_Check(input))
f90ed2d1 342 return Glib::Variant<Glib::ustring>::create(PyString_AsString(input));
58aa1f83
ML
343 else if (type == G_VARIANT_TYPE_BOOLEAN && PyBool_Check(input))
344 return Glib::Variant<bool>::create(input == Py_True);
345 else if (type == G_VARIANT_TYPE_DOUBLE && PyFloat_Check(input))
346 return Glib::Variant<double>::create(PyFloat_AsDouble(input));
347 else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
348 return Glib::Variant<gint32>::create(PyInt_AsLong(input));
349 else
350 throw sigrok::Error(SR_ERR_ARG);
351}
352
353/* Convert from a Python dict to a std::map<std::string, std::string> */
354std::map<std::string, Glib::VariantBase> dict_to_map_options(PyObject *dict,
355 std::map<std::string, std::shared_ptr<sigrok::Option> > options)
356{
357 if (!PyDict_Check(dict))
358 throw sigrok::Error(SR_ERR_ARG);
359
360 std::map<std::string, Glib::VariantBase> output;
361
362 PyObject *py_key, *py_value;
363 Py_ssize_t pos = 0;
364
365 while (PyDict_Next(dict, &pos, &py_key, &py_value)) {
366 if (!PyString_Check(py_key))
367 throw sigrok::Error(SR_ERR_ARG);
368 auto key = PyString_AsString(py_key);
369 auto value = python_to_variant_by_option(py_value, options[key]);
370 output[key] = value;
371 }
372
373 return output;
374}
375
f7740954
ML
376%}
377
378/* Ignore these methods, we will override them below. */
ed6b4c47 379%ignore sigrok::Analog::data;
f7740954 380%ignore sigrok::Driver::scan;
ca3291e3 381%ignore sigrok::InputFormat::create_input;
f7740954
ML
382%ignore sigrok::OutputFormat::create_output;
383
bd4fda24
ML
384%include "doc.i"
385
062430a2 386%define %attributevector(Class, Type, Name, Get)
444d6a39
ML
387%rename(_ ## Get) sigrok::Class::Get;
388%extend sigrok::Class
389{
390%pythoncode
391{
392 Name = property(_ ## Get)
393}
394}
062430a2
ML
395%enddef
396
397%define %attributemap(Class, Type, Name, Get)
444d6a39
ML
398%rename(_ ## Get) sigrok::Class::Get;
399%extend sigrok::Class
400{
401%pythoncode
402{
403 Name = property(fget = lambda x: x._ ## Get().asdict(), doc=_ ## Get.__doc__)
404}
405}
062430a2
ML
406%enddef
407
7a36ceac 408%define %enumextras(Class)
f0c0dab5
ML
409%extend sigrok::Class
410{
411 long __hash__()
412 {
413 return (long) $self;
414 }
415
416%pythoncode
417{
418 def __eq__(self, other):
419 return (type(self) is type(other) and hash(self) == hash(other))
420
421 def __ne__(self, other):
422 return (type(self) is not type(other) or hash(self) != hash(other))
423}
424}
7a36ceac
ML
425%enddef
426
f7740954
ML
427%include "../../../swig/classes.i"
428
429/* Support Driver.scan() with keyword arguments. */
430%extend sigrok::Driver
431{
432 std::vector<std::shared_ptr<sigrok::HardwareDevice> > _scan_kwargs(PyObject *dict)
433 {
434 if (!PyDict_Check(dict))
435 throw sigrok::Error(SR_ERR_ARG);
436
437 PyObject *py_key, *py_value;
438 Py_ssize_t pos = 0;
439 std::map<const sigrok::ConfigKey *, Glib::VariantBase> options;
440
441 while (PyDict_Next(dict, &pos, &py_key, &py_value))
442 {
443 if (!PyString_Check(py_key))
444 throw sigrok::Error(SR_ERR_ARG);
0bc1a761 445 auto key = sigrok::ConfigKey::get_by_identifier(PyString_AsString(py_key));
f7740954
ML
446 auto value = python_to_variant_by_key(py_value, key);
447 options[key] = value;
448 }
449
450 return $self->scan(options);
451 }
452}
453
454%pythoncode
455{
456 def _Driver_scan(self, **kwargs):
457 return self._scan_kwargs(kwargs)
458
459 Driver.scan = _Driver_scan
460}
461
ca3291e3 462/* Support InputFormat.create_input() with keyword arguments. */
f7740954
ML
463%extend sigrok::InputFormat
464{
ca3291e3 465 std::shared_ptr<sigrok::Input> _create_input_kwargs(PyObject *dict)
f7740954 466 {
ca3291e3 467 return $self->create_input(
3b161085 468 dict_to_map_options(dict, $self->options()));
f7740954
ML
469 }
470}
471
472%pythoncode
473{
ca3291e3
ML
474 def _InputFormat_create_input(self, **kwargs):
475 return self._create_input(kwargs)
f7740954 476
ca3291e3 477 InputFormat.create_input = _InputFormat_create_input
f7740954
ML
478}
479
480/* Support OutputFormat.create_output() with keyword arguments. */
481%extend sigrok::OutputFormat
482{
483 std::shared_ptr<sigrok::Output> _create_output_kwargs(
484 std::shared_ptr<sigrok::Device> device, PyObject *dict)
485 {
58aa1f83 486 return $self->create_output(device,
3b161085 487 dict_to_map_options(dict, $self->options()));
f7740954
ML
488 }
489}
490
491%pythoncode
492{
493 def _OutputFormat_create_output(self, device, **kwargs):
494 return self._create_output_kwargs(device, kwargs)
495
496 OutputFormat.create_output = _OutputFormat_create_output
497}
498
499/* Support config_set() with Python input types. */
500%extend sigrok::Configurable
501{
502 void config_set(const ConfigKey *key, PyObject *input)
503 {
504 $self->config_set(key, python_to_variant_by_key(input, key));
505 }
506}
ed6b4c47
ML
507
508/* Return NumPy array from Analog::data(). */
509%extend sigrok::Analog
510{
511 PyObject * _data()
512 {
513 int nd = 2;
514 npy_intp dims[2];
515 dims[0] = $self->channels().size();
516 dims[1] = $self->num_samples();
517 int typenum = NPY_FLOAT;
518 void *data = $self->data_pointer();
519 return PyArray_SimpleNewFromData(nd, dims, typenum, data);
520 }
521
522%pythoncode
523{
524 data = property(_data)
525}
526}