summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python
diff options
context:
space:
mode:
Diffstat (limited to 'meta-python/recipes-devtools/python')
-rw-r--r--meta-python/recipes-devtools/python/python3-pydbus/0001-make-direction-attribute-conforming-to-introspect.dt.patch40
-rw-r--r--meta-python/recipes-devtools/python/python3-pydbus/0002-Support-asynchronous-calls-58.patch206
-rw-r--r--meta-python/recipes-devtools/python/python3-pydbus/0003-Support-transformation-between-D-Bus-errors-and-exce.patch495
-rw-r--r--meta-python/recipes-devtools/python/python3-pydbus/run-ptest15
-rw-r--r--meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb26
5 files changed, 782 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/0001-make-direction-attribute-conforming-to-introspect.dt.patch b/meta-python/recipes-devtools/python/python3-pydbus/0001-make-direction-attribute-conforming-to-introspect.dt.patch
new file mode 100644
index 0000000000..1bd17986e6
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pydbus/0001-make-direction-attribute-conforming-to-introspect.dt.patch
@@ -0,0 +1,40 @@
1From 5fe65a35e0e7106347639f0258206fadb451c439 Mon Sep 17 00:00:00 2001
2From: Hiroaki KAWAI <hiroaki.kawai@gmail.com>
3Date: Wed, 1 Feb 2017 18:00:33 +0900
4Subject: [PATCH 1/3] make direction attribute conforming to introspect.dtd
5
6direction attribute defaults to "in" as
7in the DTD(*1), direction attribute is defined as following:
8
9```
10<!ATTRLIST arg direction (in|out) "in">
11```
12
13*1) http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd
14
15Adapted from Fedora [https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/]
16
17Upstream-Status: Inactive-Upstream (Last release 12/18/2016; Last commit 05/6/2018)
18
19Signed-off-by: Derek Straka <derek@asterius.io>
20---
21 pydbus/proxy_method.py | 4 ++--
22 1 file changed, 2 insertions(+), 2 deletions(-)
23
24diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py
25index 8798edd..3e6e6ee 100644
26--- a/pydbus/proxy_method.py
27+++ b/pydbus/proxy_method.py
28@@ -33,8 +33,8 @@ class ProxyMethod(object):
29 self.__name__ = method.attrib["name"]
30 self.__qualname__ = self._iface_name + "." + self.__name__
31
32- self._inargs = [(arg.attrib.get("name", ""), arg.attrib["type"]) for arg in method if arg.tag == "arg" and arg.attrib["direction"] == "in"]
33- self._outargs = [arg.attrib["type"] for arg in method if arg.tag == "arg" and arg.attrib["direction"] == "out"]
34+ self._inargs = [(arg.attrib.get("name", ""), arg.attrib["type"]) for arg in method if arg.tag == "arg" and arg.attrib.get("direction", "in") == "in"]
35+ self._outargs = [arg.attrib["type"] for arg in method if arg.tag == "arg" and arg.attrib.get("direction", "in") == "out"]
36 self._sinargs = "(" + "".join(x[1] for x in self._inargs) + ")"
37 self._soutargs = "(" + "".join(self._outargs) + ")"
38
39--
402.13.5
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-asynchronous-calls-58.patch b/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-asynchronous-calls-58.patch
new file mode 100644
index 0000000000..b3c57edade
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-asynchronous-calls-58.patch
@@ -0,0 +1,206 @@
1From 31d6dd7893a5e1bb9eb14bfcee861a5b62f64960 Mon Sep 17 00:00:00 2001
2From: Vendula Poncova <vponcova@redhat.com>
3Date: Thu, 27 Jul 2017 18:41:29 +0200
4Subject: [PATCH 2/3] Support asynchronous calls (#58)
5
6Added support for asynchronous calls of methods. A method is called
7synchronously unless its callback parameter is specified. A callback
8is a function f(*args, returned=None, error=None), where args is
9callback_args specified in the method call, returned is a return
10value of the method and error is an exception raised by the method.
11
12Example of an asynchronous call:
13
14def func(x, y, returned=None, error=None):
15 pass
16
17proxy.Method(a, b, callback=func, callback_args=(x, y))
18
19Adapted from Fedora [https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/]
20
21Upstream-Status: Inactive-Upstream (Last release 12/18/2016; Last commit 05/6/2018)
22
23Signed-off-by: Derek Straka <derek@asterius.io>
24---
25 doc/tutorial.rst | 11 ++++++++-
26 pydbus/proxy_method.py | 44 ++++++++++++++++++++++++++++++-----
27 tests/publish_async.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
28 tests/run.sh | 1 +
29 4 files changed, 112 insertions(+), 7 deletions(-)
30 create mode 100644 tests/publish_async.py
31
32diff --git a/doc/tutorial.rst b/doc/tutorial.rst
33index 7474de3..b8479cf 100644
34--- a/doc/tutorial.rst
35+++ b/doc/tutorial.rst
36@@ -84,7 +84,8 @@ All objects have methods, properties and signals.
37 Setting up an event loop
38 ========================
39
40-To handle signals emitted by exported objects, or to export your own objects, you need to setup an event loop.
41+To handle signals emitted by exported objects, to asynchronously call methods
42+or to export your own objects, you need to setup an event loop.
43
44 The only main loop supported by ``pydbus`` is GLib.MainLoop.
45
46@@ -156,6 +157,14 @@ To call a method::
47
48 dev.Disconnect()
49
50+To asynchronously call a method::
51+
52+ def print_result(returned=None, error=None):
53+ print(returned, error)
54+
55+ dev.GetAppliedConnection(0, callback=print_result)
56+ loop.run()
57+
58 To read a property::
59
60 print(dev.Autoconnect)
61diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py
62index 3e6e6ee..442fe07 100644
63--- a/pydbus/proxy_method.py
64+++ b/pydbus/proxy_method.py
65@@ -65,15 +65,34 @@ class ProxyMethod(object):
66
67 # Python 2 sux
68 for kwarg in kwargs:
69- if kwarg not in ("timeout",):
70+ if kwarg not in ("timeout", "callback", "callback_args"):
71 raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg))
72 timeout = kwargs.get("timeout", None)
73+ callback = kwargs.get("callback", None)
74+ callback_args = kwargs.get("callback_args", tuple())
75+
76+ call_args = (
77+ instance._bus_name,
78+ instance._path,
79+ self._iface_name,
80+ self.__name__,
81+ GLib.Variant(self._sinargs, args),
82+ GLib.VariantType.new(self._soutargs),
83+ 0,
84+ timeout_to_glib(timeout),
85+ None
86+ )
87+
88+ if callback:
89+ call_args += (self._finish_async_call, (callback, callback_args))
90+ instance._bus.con.call(*call_args)
91+ return None
92+ else:
93+ ret = instance._bus.con.call_sync(*call_args)
94+ return self._unpack_return(ret)
95
96- ret = instance._bus.con.call_sync(
97- instance._bus_name, instance._path,
98- self._iface_name, self.__name__, GLib.Variant(self._sinargs, args), GLib.VariantType.new(self._soutargs),
99- 0, timeout_to_glib(timeout), None).unpack()
100-
101+ def _unpack_return(self, values):
102+ ret = values.unpack()
103 if len(self._outargs) == 0:
104 return None
105 elif len(self._outargs) == 1:
106@@ -81,6 +100,19 @@ class ProxyMethod(object):
107 else:
108 return ret
109
110+ def _finish_async_call(self, source, result, user_data):
111+ error = None
112+ return_args = None
113+
114+ try:
115+ ret = source.call_finish(result)
116+ return_args = self._unpack_return(ret)
117+ except Exception as err:
118+ error = err
119+
120+ callback, callback_args = user_data
121+ callback(*callback_args, returned=return_args, error=error)
122+
123 def __get__(self, instance, owner):
124 if instance is None:
125 return self
126diff --git a/tests/publish_async.py b/tests/publish_async.py
127new file mode 100644
128index 0000000..3f79b62
129--- /dev/null
130+++ b/tests/publish_async.py
131@@ -0,0 +1,63 @@
132+from pydbus import SessionBus
133+from gi.repository import GLib
134+from threading import Thread
135+import sys
136+
137+done = 0
138+loop = GLib.MainLoop()
139+
140+class TestObject(object):
141+ '''
142+<node>
143+ <interface name='net.lew21.pydbus.tests.publish_async'>
144+ <method name='HelloWorld'>
145+ <arg type='i' name='x' direction='in'/>
146+ <arg type='s' name='response' direction='out'/>
147+ </method>
148+ </interface>
149+</node>
150+ '''
151+ def __init__(self, id):
152+ self.id = id
153+
154+ def HelloWorld(self, x):
155+ res = self.id + ": " + str(x)
156+ print(res)
157+ return res
158+
159+bus = SessionBus()
160+
161+with bus.publish("net.lew21.pydbus.tests.publish_async", TestObject("Obj")):
162+ remote = bus.get("net.lew21.pydbus.tests.publish_async")
163+
164+ def callback(x, returned=None, error=None):
165+ print("asyn: " + returned)
166+ assert (returned is not None)
167+ assert(error is None)
168+ assert(x == int(returned.split()[1]))
169+
170+ global done
171+ done += 1
172+ if done == 3:
173+ loop.quit()
174+
175+ def t1_func():
176+ remote.HelloWorld(1, callback=callback, callback_args=(1,))
177+ remote.HelloWorld(2, callback=callback, callback_args=(2,))
178+ print("sync: " + remote.HelloWorld(3))
179+ remote.HelloWorld(4, callback=callback, callback_args=(4,))
180+
181+ t1 = Thread(None, t1_func)
182+ t1.daemon = True
183+
184+ def handle_timeout():
185+ print("ERROR: Timeout.")
186+ sys.exit(1)
187+
188+ GLib.timeout_add_seconds(2, handle_timeout)
189+
190+ t1.start()
191+
192+ loop.run()
193+
194+ t1.join()
195diff --git a/tests/run.sh b/tests/run.sh
196index 8d93644..271c58a 100755
197--- a/tests/run.sh
198+++ b/tests/run.sh
199@@ -15,4 +15,5 @@ then
200 "$PYTHON" $TESTS_DIR/publish.py
201 "$PYTHON" $TESTS_DIR/publish_properties.py
202 "$PYTHON" $TESTS_DIR/publish_multiface.py
203+ "$PYTHON" $TESTS_DIR/publish_async.py
204 fi
205--
2062.13.5
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/0003-Support-transformation-between-D-Bus-errors-and-exce.patch b/meta-python/recipes-devtools/python/python3-pydbus/0003-Support-transformation-between-D-Bus-errors-and-exce.patch
new file mode 100644
index 0000000000..a1b8a6c38c
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pydbus/0003-Support-transformation-between-D-Bus-errors-and-exce.patch
@@ -0,0 +1,495 @@
1From 773858e1afd21cdf3ceef2cd35509f0b4882bf16 Mon Sep 17 00:00:00 2001
2From: Vendula Poncova <vponcova@redhat.com>
3Date: Tue, 1 Aug 2017 16:54:24 +0200
4Subject: [PATCH 3/3] Support transformation between D-Bus errors and
5 exceptions.
6
7Exceptions can be registered with decorators, raised in a remote
8method and recreated after return from the remote call.
9
10Adapted from Fedora [https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/]
11
12Upstream-Status: Inactive-Upstream (Last release 12/18/2016; Last commit 05/6/2018)
13
14Signed-off-by: Derek Straka <derek@asterius.io>
15---
16 doc/tutorial.rst | 47 ++++++++++++++++++
17 pydbus/error.py | 97 ++++++++++++++++++++++++++++++++++++
18 pydbus/proxy_method.py | 18 +++++--
19 pydbus/registration.py | 16 ++++--
20 tests/error.py | 67 +++++++++++++++++++++++++
21 tests/publish_error.py | 132 +++++++++++++++++++++++++++++++++++++++++++++++++
22 tests/run.sh | 2 +
23 7 files changed, 371 insertions(+), 8 deletions(-)
24 create mode 100644 pydbus/error.py
25 create mode 100644 tests/error.py
26 create mode 100644 tests/publish_error.py
27
28diff --git a/doc/tutorial.rst b/doc/tutorial.rst
29index b8479cf..7fe55e1 100644
30--- a/doc/tutorial.rst
31+++ b/doc/tutorial.rst
32@@ -341,6 +341,53 @@ See ``help(bus.request_name)`` and ``help(bus.register_object)`` for details.
33
34 .. --------------------------------------------------------------------
35
36+Error handling
37+==============
38+
39+You can map D-Bus errors to your exception classes for better error handling.
40+To handle D-Bus errors, use the ``@map_error`` decorator::
41+
42+ from pydbus.error import map_error
43+
44+ @map_error("org.freedesktop.DBus.Error.InvalidArgs")
45+ class InvalidArgsException(Exception):
46+ pass
47+
48+ try:
49+ ...
50+ catch InvalidArgsException as e:
51+ print(e)
52+
53+To register new D-Bus errors, use the ``@register_error`` decorator::
54+
55+ from pydbus.error import register_error
56+
57+ @map_error("net.lew21.pydbus.TutorialExample.MyError", MY_DOMAIN, MY_EXCEPTION_CODE)
58+ class MyException(Exception):
59+ pass
60+
61+Then you can raise ``MyException`` from the D-Bus method of the remote object::
62+
63+ def Method():
64+ raise MyException("Message")
65+
66+And catch the same exception on the client side::
67+
68+ try:
69+ proxy.Method()
70+ catch MyException as e:
71+ print(e)
72+
73+To handle all unknown D-Bus errors, use the ``@map_by_default`` decorator to specify the default exception::
74+
75+ from pydbus.error import map_by_default
76+
77+ @map_by_default
78+ class DefaultException(Exception):
79+ pass
80+
81+.. --------------------------------------------------------------------
82+
83 Data types
84 ==========
85
86diff --git a/pydbus/error.py b/pydbus/error.py
87new file mode 100644
88index 0000000..aaa3510
89--- /dev/null
90+++ b/pydbus/error.py
91@@ -0,0 +1,97 @@
92+from gi.repository import GLib, Gio
93+
94+
95+def register_error(name, domain, code):
96+ """Register and map decorated exception class to a DBus error."""
97+ def decorated(cls):
98+ error_registration.register_error(cls, name, domain, code)
99+ return cls
100+
101+ return decorated
102+
103+
104+def map_error(error_name):
105+ """Map decorated exception class to a DBus error."""
106+ def decorated(cls):
107+ error_registration.map_error(cls, error_name)
108+ return cls
109+
110+ return decorated
111+
112+
113+def map_by_default(cls):
114+ """Map decorated exception class to all unknown DBus errors."""
115+ error_registration.map_by_default(cls)
116+ return cls
117+
118+
119+class ErrorRegistration(object):
120+ """Class for mapping exceptions to DBus errors."""
121+
122+ _default = None
123+ _map = dict()
124+ _reversed_map = dict()
125+
126+ def map_by_default(self, exception_cls):
127+ """Set the exception class as a default."""
128+ self._default = exception_cls
129+
130+ def map_error(self, exception_cls, name):
131+ """Map the exception class to a DBus name."""
132+ self._map[name] = exception_cls
133+ self._reversed_map[exception_cls] = name
134+
135+ def register_error(self, exception_cls, name, domain, code):
136+ """Map and register the exception class to a DBus name."""
137+ self.map_error(exception_cls, name)
138+ return Gio.DBusError.register_error(domain, code, name)
139+
140+ def is_registered_exception(self, obj):
141+ """Is the exception registered?"""
142+ return obj.__class__ in self._reversed_map
143+
144+ def get_dbus_name(self, obj):
145+ """Get the DBus name of the exception."""
146+ return self._reversed_map.get(obj.__class__)
147+
148+ def get_exception_class(self, name):
149+ """Get the exception class mapped to the DBus name."""
150+ return self._map.get(name, self._default)
151+
152+ def transform_message(self, name, message):
153+ """Transform the message of the exception."""
154+ prefix = "{}:{}: ".format("GDBus.Error", name)
155+
156+ if message.startswith(prefix):
157+ return message[len(prefix):]
158+
159+ return message
160+
161+ def transform_exception(self, e):
162+ """Transform the remote error to the exception."""
163+ if not isinstance(e, GLib.Error):
164+ return e
165+
166+ if not Gio.DBusError.is_remote_error(e):
167+ return e
168+
169+ # Get DBus name of the error.
170+ name = Gio.DBusError.get_remote_error(e)
171+ # Get the exception class.
172+ exception_cls = self.get_exception_class(name)
173+
174+ # Return the original exception.
175+ if not exception_cls:
176+ return e
177+
178+ # Return new exception.
179+ message = self.transform_message(name, e.message)
180+ exception = exception_cls(message)
181+ exception.dbus_name = name
182+ exception.dbus_domain = e.domain
183+ exception.dbus_code = e.code
184+ return exception
185+
186+
187+# Default error registration.
188+error_registration = ErrorRegistration()
189diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py
190index 442fe07..a73f9eb 100644
191--- a/pydbus/proxy_method.py
192+++ b/pydbus/proxy_method.py
193@@ -2,6 +2,7 @@ from gi.repository import GLib
194 from .generic import bound_method
195 from .identifier import filter_identifier
196 from .timeout import timeout_to_glib
197+from .error import error_registration
198
199 try:
200 from inspect import Signature, Parameter
201@@ -87,9 +88,20 @@ class ProxyMethod(object):
202 call_args += (self._finish_async_call, (callback, callback_args))
203 instance._bus.con.call(*call_args)
204 return None
205+
206 else:
207- ret = instance._bus.con.call_sync(*call_args)
208- return self._unpack_return(ret)
209+ result = None
210+ error = None
211+
212+ try:
213+ result = instance._bus.con.call_sync(*call_args)
214+ except Exception as e:
215+ error = error_registration.transform_exception(e)
216+
217+ if error:
218+ raise error
219+
220+ return self._unpack_return(result)
221
222 def _unpack_return(self, values):
223 ret = values.unpack()
224@@ -108,7 +120,7 @@ class ProxyMethod(object):
225 ret = source.call_finish(result)
226 return_args = self._unpack_return(ret)
227 except Exception as err:
228- error = err
229+ error = error_registration.transform_exception(err)
230
231 callback, callback_args = user_data
232 callback(*callback_args, returned=return_args, error=error)
233diff --git a/pydbus/registration.py b/pydbus/registration.py
234index f531539..1d2cbcb 100644
235--- a/pydbus/registration.py
236+++ b/pydbus/registration.py
237@@ -5,6 +5,7 @@ from . import generic
238 from .exitable import ExitableWithAliases
239 from functools import partial
240 from .method_call_context import MethodCallContext
241+from .error import error_registration
242 import logging
243
244 try:
245@@ -91,11 +92,16 @@ class ObjectWrapper(ExitableWithAliases("unwrap")):
246 logger = logging.getLogger(__name__)
247 logger.exception("Exception while handling %s.%s()", interface_name, method_name)
248
249- #TODO Think of a better way to translate Python exception types to DBus error types.
250- e_type = type(e).__name__
251- if not "." in e_type:
252- e_type = "unknown." + e_type
253- invocation.return_dbus_error(e_type, str(e))
254+ if error_registration.is_registered_exception(e):
255+ name = error_registration.get_dbus_name(e)
256+ invocation.return_dbus_error(name, str(e))
257+ else:
258+ logger.info("name is not registered")
259+ e_type = type(e).__name__
260+ if not "." in e_type:
261+ e_type = "unknown." + e_type
262+
263+ invocation.return_dbus_error(e_type, str(e))
264
265 def Get(self, interface_name, property_name):
266 type = self.readable_properties[interface_name + "." + property_name]
267diff --git a/tests/error.py b/tests/error.py
268new file mode 100644
269index 0000000..3ec507d
270--- /dev/null
271+++ b/tests/error.py
272@@ -0,0 +1,67 @@
273+from pydbus.error import ErrorRegistration
274+
275+
276+class ExceptionA(Exception):
277+ pass
278+
279+
280+class ExceptionB(Exception):
281+ pass
282+
283+
284+class ExceptionC(Exception):
285+ pass
286+
287+
288+class ExceptionD(Exception):
289+ pass
290+
291+
292+class ExceptionE(Exception):
293+ pass
294+
295+
296+def test_error_mapping():
297+ r = ErrorRegistration()
298+ r.map_error(ExceptionA, "net.lew21.pydbus.tests.ErrorA")
299+ r.map_error(ExceptionB, "net.lew21.pydbus.tests.ErrorB")
300+ r.map_error(ExceptionC, "net.lew21.pydbus.tests.ErrorC")
301+
302+ assert r.is_registered_exception(ExceptionA("Test"))
303+ assert r.is_registered_exception(ExceptionB("Test"))
304+ assert r.is_registered_exception(ExceptionC("Test"))
305+ assert not r.is_registered_exception(ExceptionD("Test"))
306+ assert not r.is_registered_exception(ExceptionE("Test"))
307+
308+ assert r.get_dbus_name(ExceptionA("Test")) == "net.lew21.pydbus.tests.ErrorA"
309+ assert r.get_dbus_name(ExceptionB("Test")) == "net.lew21.pydbus.tests.ErrorB"
310+ assert r.get_dbus_name(ExceptionC("Test")) == "net.lew21.pydbus.tests.ErrorC"
311+
312+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorA") == ExceptionA
313+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorB") == ExceptionB
314+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorC") == ExceptionC
315+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorD") is None
316+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorE") is None
317+
318+ r.map_by_default(ExceptionD)
319+ assert not r.is_registered_exception(ExceptionD("Test"))
320+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorD") == ExceptionD
321+ assert r.get_exception_class("net.lew21.pydbus.tests.ErrorE") == ExceptionD
322+
323+
324+def test_transform_message():
325+ r = ErrorRegistration()
326+ n1 = "net.lew21.pydbus.tests.ErrorA"
327+ m1 = "GDBus.Error:net.lew21.pydbus.tests.ErrorA: Message1"
328+
329+ n2 = "net.lew21.pydbus.tests.ErrorB"
330+ m2 = "GDBus.Error:net.lew21.pydbus.tests.ErrorB: Message2"
331+
332+ assert r.transform_message(n1, m1) == "Message1"
333+ assert r.transform_message(n2, m2) == "Message2"
334+ assert r.transform_message(n1, m2) == m2
335+ assert r.transform_message(n2, m1) == m1
336+
337+
338+test_error_mapping()
339+test_transform_message()
340diff --git a/tests/publish_error.py b/tests/publish_error.py
341new file mode 100644
342index 0000000..aa8a18a
343--- /dev/null
344+++ b/tests/publish_error.py
345@@ -0,0 +1,132 @@
346+import sys
347+from threading import Thread
348+from gi.repository import GLib, Gio
349+from pydbus import SessionBus
350+from pydbus.error import register_error, map_error, map_by_default, error_registration
351+
352+import logging
353+logger = logging.getLogger('pydbus.registration')
354+logger.disabled = True
355+
356+loop = GLib.MainLoop()
357+DOMAIN = Gio.DBusError.quark() # TODO: Register new domain.
358+
359+
360+@register_error("net.lew21.pydbus.tests.ErrorA", DOMAIN, 1000)
361+class ExceptionA(Exception):
362+ pass
363+
364+
365+@register_error("net.lew21.pydbus.tests.ErrorB", DOMAIN, 2000)
366+class ExceptionB(Exception):
367+ pass
368+
369+
370+@map_error("org.freedesktop.DBus.Error.InvalidArgs")
371+class ExceptionC(Exception):
372+ pass
373+
374+
375+@map_by_default
376+class ExceptionD(Exception):
377+ pass
378+
379+
380+class ExceptionE(Exception):
381+ pass
382+
383+
384+class TestObject(object):
385+ '''
386+<node>
387+ <interface name='net.lew21.pydbus.tests.TestInterface'>
388+ <method name='RaiseA'>
389+ <arg type='s' name='msg' direction='in'/>
390+ </method>
391+ <method name='RaiseB'>
392+ <arg type='s' name='msg' direction='in'/>
393+ </method>
394+ <method name='RaiseD'>
395+ <arg type='s' name='msg' direction='in'/>
396+ </method>
397+ <method name='RaiseE'>
398+ <arg type='s' name='msg' direction='in'/>
399+ </method>
400+ </interface>
401+</node>
402+ '''
403+
404+ def RaiseA(self, msg):
405+ raise ExceptionA(msg)
406+
407+ def RaiseB(self, msg):
408+ raise ExceptionB(msg)
409+
410+ def RaiseD(self, msg):
411+ raise ExceptionD(msg)
412+
413+ def RaiseE(self, msg):
414+ raise ExceptionE(msg)
415+
416+bus = SessionBus()
417+
418+with bus.publish("net.lew21.pydbus.tests.Test", TestObject()):
419+ remote = bus.get("net.lew21.pydbus.tests.Test")
420+
421+ def t_func():
422+ # Test new registered errors.
423+ try:
424+ remote.RaiseA("Test A")
425+ except ExceptionA as e:
426+ assert str(e) == "Test A"
427+
428+ try:
429+ remote.RaiseB("Test B")
430+ except ExceptionB as e:
431+ assert str(e) == "Test B"
432+
433+ # Test mapped errors.
434+ try:
435+ remote.Get("net.lew21.pydbus.tests.TestInterface", "Foo")
436+ except ExceptionC as e:
437+ assert str(e) == "No such property 'Foo'"
438+
439+ # Test default errors.
440+ try:
441+ remote.RaiseD("Test D")
442+ except ExceptionD as e:
443+ assert str(e) == "Test D"
444+
445+ try:
446+ remote.RaiseE("Test E")
447+ except ExceptionD as e:
448+ assert str(e) == "Test E"
449+
450+ # Test with no default errors.
451+ error_registration.map_by_default(None)
452+
453+ try:
454+ remote.RaiseD("Test D")
455+ except Exception as e:
456+ assert not isinstance(e, ExceptionD)
457+
458+ try:
459+ remote.RaiseE("Test E")
460+ except Exception as e:
461+ assert not isinstance(e, ExceptionD)
462+ assert not isinstance(e, ExceptionE)
463+
464+ loop.quit()
465+
466+ t = Thread(None, t_func)
467+ t.daemon = True
468+
469+ def handle_timeout():
470+ print("ERROR: Timeout.")
471+ sys.exit(1)
472+
473+ GLib.timeout_add_seconds(4, handle_timeout)
474+
475+ t.start()
476+ loop.run()
477+ t.join()
478diff --git a/tests/run.sh b/tests/run.sh
479index 271c58a..a08baf8 100755
480--- a/tests/run.sh
481+++ b/tests/run.sh
482@@ -10,10 +10,11 @@ PYTHON=${1:-python}
483
484 "$PYTHON" $TESTS_DIR/context.py
485 "$PYTHON" $TESTS_DIR/identifier.py
486+"$PYTHON" $TESTS_DIR/error.py
487 if [ "$2" != "dontpublish" ]
488 then
489 "$PYTHON" $TESTS_DIR/publish.py
490 "$PYTHON" $TESTS_DIR/publish_properties.py
491 "$PYTHON" $TESTS_DIR/publish_multiface.py
492 "$PYTHON" $TESTS_DIR/publish_async.py
493 fi
494--
4952.13.5
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/run-ptest b/meta-python/recipes-devtools/python/python3-pydbus/run-ptest
new file mode 100644
index 0000000000..782ceed3bb
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pydbus/run-ptest
@@ -0,0 +1,15 @@
1#!/bin/sh
2
3for case in `find tests -type f -name '*.sh'`; do
4 bash $case python3 >$case.output 2>&1
5 ret=$?
6 if [ $ret -ne 0 ]; then
7 cat $case.output
8 echo "FAIL: ${case}"
9 elif grep -i 'SKIP' $case.output; then
10 echo "SKIP: ${case}"
11 else
12 echo "PASS: ${case}"
13 fi
14 rm -f $case.output
15done \ No newline at end of file
diff --git a/meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb b/meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb
new file mode 100644
index 0000000000..ac9b8e8aba
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb
@@ -0,0 +1,26 @@
1DESCRIPTION = "Pythonic DBus library"
2HOMEPAGE = "https://pypi.python.org/pypi/pydbus/"
3LICENSE = "LGPL-2.1-only"
4LIC_FILES_CHKSUM = "file://LICENSE;md5=a916467b91076e631dd8edb7424769c7"
5
6SRCREV = "f2e6355a88351e7d644ccb2b4d67b19305507312"
7SRC_URI = " \
8 git://github.com/LEW21/pydbus.git;protocol=https;branch=master \
9 file://0001-make-direction-attribute-conforming-to-introspect.dt.patch \
10 file://0002-Support-asynchronous-calls-58.patch \
11 file://0003-Support-transformation-between-D-Bus-errors-and-exce.patch \
12 file://run-ptest \
13"
14
15inherit ptest setuptools3
16
17S = "${WORKDIR}/git"
18
19RDEPENDS:${PN} = "${PYTHON_PN}-pygobject \
20 ${PYTHON_PN}-io \
21 ${PYTHON_PN}-logging"
22
23do_install_ptest() {
24 install -d ${D}${PTEST_PATH}/tests
25 cp -rf ${S}/tests/* ${D}${PTEST_PATH}/tests/
26} \ No newline at end of file