diff options
| author | Hongxu Jia <hongxu.jia@windriver.com> | 2018-08-14 00:22:16 +0800 |
|---|---|---|
| committer | Khem Raj <raj.khem@gmail.com> | 2018-08-15 08:20:06 -0700 |
| commit | c67f65f4fa05f23bf3b187b51ffdb0c3b9052232 (patch) | |
| tree | d2976be4da5ac47f0e44d92ac7818d3acd7d11f0 | |
| parent | dccb790e187f3b6f06d53b000a9ffd0687d78876 (diff) | |
| download | meta-openembedded-c67f65f4fa05f23bf3b187b51ffdb0c3b9052232.tar.gz | |
python3-pydbus: cherry-pick patches from fedora
Fedora enhanced python3-pydbus:
- Support asynchronous calls
- Support transformation between D-Bus errors and
exceptions.
https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
Signed-off-by: Khem Raj <raj.khem@gmail.com>
3 files changed, 300 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/0001-Support-asynchronous-calls-58.patch b/meta-python/recipes-devtools/python/python3-pydbus/0001-Support-asynchronous-calls-58.patch new file mode 100644 index 0000000000..c5cb9a8780 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pydbus/0001-Support-asynchronous-calls-58.patch | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | From 39a7d79ee6c548902fbac8b95c934af7e4c69260 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Vendula Poncova <vponcova@redhat.com> | ||
| 3 | Date: Thu, 2 Aug 2018 15:30:45 +0800 | ||
| 4 | Subject: [PATCH 1/2] Support asynchronous calls (#58) | ||
| 5 | |||
| 6 | Added support for asynchronous calls of methods. A method is called | ||
| 7 | synchronously unless its callback parameter is specified. A callback | ||
| 8 | is a function f(*args, returned=None, error=None), where args is | ||
| 9 | callback_args specified in the method call, returned is a return | ||
| 10 | value of the method and error is an exception raised by the method. | ||
| 11 | |||
| 12 | Example of an asynchronous call: | ||
| 13 | |||
| 14 | def func(x, y, returned=None, error=None): | ||
| 15 | pass | ||
| 16 | |||
| 17 | proxy.Method(a, b, callback=func, callback_args=(x, y)) | ||
| 18 | |||
| 19 | Upstream-Status: Cherry-pick [https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/] | ||
| 20 | |||
| 21 | Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> | ||
| 22 | --- | ||
| 23 | pydbus/proxy_method.py | 44 ++++++++++++++++++++++++++++++++++++++------ | ||
| 24 | 1 file changed, 38 insertions(+), 6 deletions(-) | ||
| 25 | |||
| 26 | diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py | ||
| 27 | index 8798edd..4ea4304 100644 | ||
| 28 | --- a/pydbus/proxy_method.py | ||
| 29 | +++ b/pydbus/proxy_method.py | ||
| 30 | @@ -65,15 +65,34 @@ class ProxyMethod(object): | ||
| 31 | |||
| 32 | # Python 2 sux | ||
| 33 | for kwarg in kwargs: | ||
| 34 | - if kwarg not in ("timeout",): | ||
| 35 | + if kwarg not in ("timeout", "callback", "callback_args"): | ||
| 36 | raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg)) | ||
| 37 | timeout = kwargs.get("timeout", None) | ||
| 38 | + callback = kwargs.get("callback", None) | ||
| 39 | + callback_args = kwargs.get("callback_args", tuple()) | ||
| 40 | + | ||
| 41 | + call_args = ( | ||
| 42 | + instance._bus_name, | ||
| 43 | + instance._path, | ||
| 44 | + self._iface_name, | ||
| 45 | + self.__name__, | ||
| 46 | + GLib.Variant(self._sinargs, args), | ||
| 47 | + GLib.VariantType.new(self._soutargs), | ||
| 48 | + 0, | ||
| 49 | + timeout_to_glib(timeout), | ||
| 50 | + None | ||
| 51 | + ) | ||
| 52 | + | ||
| 53 | + if callback: | ||
| 54 | + call_args += (self._finish_async_call, (callback, callback_args)) | ||
| 55 | + instance._bus.con.call(*call_args) | ||
| 56 | + return None | ||
| 57 | + else: | ||
| 58 | + ret = instance._bus.con.call_sync(*call_args) | ||
| 59 | + return self._unpack_return(ret) | ||
| 60 | |||
| 61 | - ret = instance._bus.con.call_sync( | ||
| 62 | - instance._bus_name, instance._path, | ||
| 63 | - self._iface_name, self.__name__, GLib.Variant(self._sinargs, args), GLib.VariantType.new(self._soutargs), | ||
| 64 | - 0, timeout_to_glib(timeout), None).unpack() | ||
| 65 | - | ||
| 66 | + def _unpack_return(self, values): | ||
| 67 | + ret = values.unpack() | ||
| 68 | if len(self._outargs) == 0: | ||
| 69 | return None | ||
| 70 | elif len(self._outargs) == 1: | ||
| 71 | @@ -81,6 +100,19 @@ class ProxyMethod(object): | ||
| 72 | else: | ||
| 73 | return ret | ||
| 74 | |||
| 75 | + def _finish_async_call(self, source, result, user_data): | ||
| 76 | + error = None | ||
| 77 | + return_args = None | ||
| 78 | + | ||
| 79 | + try: | ||
| 80 | + ret = source.call_finish(result) | ||
| 81 | + return_args = self._unpack_return(ret) | ||
| 82 | + except Exception as err: | ||
| 83 | + error = err | ||
| 84 | + | ||
| 85 | + callback, callback_args = user_data | ||
| 86 | + callback(*callback_args, returned=return_args, error=error) | ||
| 87 | + | ||
| 88 | def __get__(self, instance, owner): | ||
| 89 | if instance is None: | ||
| 90 | return self | ||
| 91 | -- | ||
| 92 | 2.7.4 | ||
| 93 | |||
diff --git a/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-transformation-between-D-Bus-errors-and-exce.patch b/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-transformation-between-D-Bus-errors-and-exce.patch new file mode 100644 index 0000000000..f5c0390c54 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pydbus/0002-Support-transformation-between-D-Bus-errors-and-exce.patch | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | From 69968dec867053e38de0b91d76ac41d5a5735e36 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Vendula Poncova <vponcova@redhat.com> | ||
| 3 | Date: Thu, 2 Aug 2018 15:31:56 +0800 | ||
| 4 | Subject: [PATCH 2/2] Support transformation between D-Bus errors and | ||
| 5 | exceptions. | ||
| 6 | |||
| 7 | Exceptions can be registered with decorators, raised in a remote | ||
| 8 | method and recreated after return from the remote call. | ||
| 9 | |||
| 10 | Upstream-Status: Cherry-pick [https://src.fedoraproject.org/cgit/rpms/python-pydbus.git/] | ||
| 11 | |||
| 12 | Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com> | ||
| 13 | --- | ||
| 14 | pydbus/error.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
| 15 | pydbus/proxy_method.py | 18 ++++++++-- | ||
| 16 | pydbus/registration.py | 16 ++++++--- | ||
| 17 | 3 files changed, 123 insertions(+), 8 deletions(-) | ||
| 18 | create mode 100644 pydbus/error.py | ||
| 19 | |||
| 20 | diff --git a/pydbus/error.py b/pydbus/error.py | ||
| 21 | new file mode 100644 | ||
| 22 | index 0000000..aaa3510 | ||
| 23 | --- /dev/null | ||
| 24 | +++ b/pydbus/error.py | ||
| 25 | @@ -0,0 +1,97 @@ | ||
| 26 | +from gi.repository import GLib, Gio | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +def register_error(name, domain, code): | ||
| 30 | + """Register and map decorated exception class to a DBus error.""" | ||
| 31 | + def decorated(cls): | ||
| 32 | + error_registration.register_error(cls, name, domain, code) | ||
| 33 | + return cls | ||
| 34 | + | ||
| 35 | + return decorated | ||
| 36 | + | ||
| 37 | + | ||
| 38 | +def map_error(error_name): | ||
| 39 | + """Map decorated exception class to a DBus error.""" | ||
| 40 | + def decorated(cls): | ||
| 41 | + error_registration.map_error(cls, error_name) | ||
| 42 | + return cls | ||
| 43 | + | ||
| 44 | + return decorated | ||
| 45 | + | ||
| 46 | + | ||
| 47 | +def map_by_default(cls): | ||
| 48 | + """Map decorated exception class to all unknown DBus errors.""" | ||
| 49 | + error_registration.map_by_default(cls) | ||
| 50 | + return cls | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +class ErrorRegistration(object): | ||
| 54 | + """Class for mapping exceptions to DBus errors.""" | ||
| 55 | + | ||
| 56 | + _default = None | ||
| 57 | + _map = dict() | ||
| 58 | + _reversed_map = dict() | ||
| 59 | + | ||
| 60 | + def map_by_default(self, exception_cls): | ||
| 61 | + """Set the exception class as a default.""" | ||
| 62 | + self._default = exception_cls | ||
| 63 | + | ||
| 64 | + def map_error(self, exception_cls, name): | ||
| 65 | + """Map the exception class to a DBus name.""" | ||
| 66 | + self._map[name] = exception_cls | ||
| 67 | + self._reversed_map[exception_cls] = name | ||
| 68 | + | ||
| 69 | + def register_error(self, exception_cls, name, domain, code): | ||
| 70 | + """Map and register the exception class to a DBus name.""" | ||
| 71 | + self.map_error(exception_cls, name) | ||
| 72 | + return Gio.DBusError.register_error(domain, code, name) | ||
| 73 | + | ||
| 74 | + def is_registered_exception(self, obj): | ||
| 75 | + """Is the exception registered?""" | ||
| 76 | + return obj.__class__ in self._reversed_map | ||
| 77 | + | ||
| 78 | + def get_dbus_name(self, obj): | ||
| 79 | + """Get the DBus name of the exception.""" | ||
| 80 | + return self._reversed_map.get(obj.__class__) | ||
| 81 | + | ||
| 82 | + def get_exception_class(self, name): | ||
| 83 | + """Get the exception class mapped to the DBus name.""" | ||
| 84 | + return self._map.get(name, self._default) | ||
| 85 | + | ||
| 86 | + def transform_message(self, name, message): | ||
| 87 | + """Transform the message of the exception.""" | ||
| 88 | + prefix = "{}:{}: ".format("GDBus.Error", name) | ||
| 89 | + | ||
| 90 | + if message.startswith(prefix): | ||
| 91 | + return message[len(prefix):] | ||
| 92 | + | ||
| 93 | + return message | ||
| 94 | + | ||
| 95 | + def transform_exception(self, e): | ||
| 96 | + """Transform the remote error to the exception.""" | ||
| 97 | + if not isinstance(e, GLib.Error): | ||
| 98 | + return e | ||
| 99 | + | ||
| 100 | + if not Gio.DBusError.is_remote_error(e): | ||
| 101 | + return e | ||
| 102 | + | ||
| 103 | + # Get DBus name of the error. | ||
| 104 | + name = Gio.DBusError.get_remote_error(e) | ||
| 105 | + # Get the exception class. | ||
| 106 | + exception_cls = self.get_exception_class(name) | ||
| 107 | + | ||
| 108 | + # Return the original exception. | ||
| 109 | + if not exception_cls: | ||
| 110 | + return e | ||
| 111 | + | ||
| 112 | + # Return new exception. | ||
| 113 | + message = self.transform_message(name, e.message) | ||
| 114 | + exception = exception_cls(message) | ||
| 115 | + exception.dbus_name = name | ||
| 116 | + exception.dbus_domain = e.domain | ||
| 117 | + exception.dbus_code = e.code | ||
| 118 | + return exception | ||
| 119 | + | ||
| 120 | + | ||
| 121 | +# Default error registration. | ||
| 122 | +error_registration = ErrorRegistration() | ||
| 123 | diff --git a/pydbus/proxy_method.py b/pydbus/proxy_method.py | ||
| 124 | index 4ea4304..e9496f5 100644 | ||
| 125 | --- a/pydbus/proxy_method.py | ||
| 126 | +++ b/pydbus/proxy_method.py | ||
| 127 | @@ -2,6 +2,7 @@ from gi.repository import GLib | ||
| 128 | from .generic import bound_method | ||
| 129 | from .identifier import filter_identifier | ||
| 130 | from .timeout import timeout_to_glib | ||
| 131 | +from .error import error_registration | ||
| 132 | |||
| 133 | try: | ||
| 134 | from inspect import Signature, Parameter | ||
| 135 | @@ -87,9 +88,20 @@ class ProxyMethod(object): | ||
| 136 | call_args += (self._finish_async_call, (callback, callback_args)) | ||
| 137 | instance._bus.con.call(*call_args) | ||
| 138 | return None | ||
| 139 | + | ||
| 140 | else: | ||
| 141 | - ret = instance._bus.con.call_sync(*call_args) | ||
| 142 | - return self._unpack_return(ret) | ||
| 143 | + result = None | ||
| 144 | + error = None | ||
| 145 | + | ||
| 146 | + try: | ||
| 147 | + result = instance._bus.con.call_sync(*call_args) | ||
| 148 | + except Exception as e: | ||
| 149 | + error = error_registration.transform_exception(e) | ||
| 150 | + | ||
| 151 | + if error: | ||
| 152 | + raise error | ||
| 153 | + | ||
| 154 | + return self._unpack_return(result) | ||
| 155 | |||
| 156 | def _unpack_return(self, values): | ||
| 157 | ret = values.unpack() | ||
| 158 | @@ -108,7 +120,7 @@ class ProxyMethod(object): | ||
| 159 | ret = source.call_finish(result) | ||
| 160 | return_args = self._unpack_return(ret) | ||
| 161 | except Exception as err: | ||
| 162 | - error = err | ||
| 163 | + error = error_registration.transform_exception(err) | ||
| 164 | |||
| 165 | callback, callback_args = user_data | ||
| 166 | callback(*callback_args, returned=return_args, error=error) | ||
| 167 | diff --git a/pydbus/registration.py b/pydbus/registration.py | ||
| 168 | index f531539..1d2cbcb 100644 | ||
| 169 | --- a/pydbus/registration.py | ||
| 170 | +++ b/pydbus/registration.py | ||
| 171 | @@ -5,6 +5,7 @@ from . import generic | ||
| 172 | from .exitable import ExitableWithAliases | ||
| 173 | from functools import partial | ||
| 174 | from .method_call_context import MethodCallContext | ||
| 175 | +from .error import error_registration | ||
| 176 | import logging | ||
| 177 | |||
| 178 | try: | ||
| 179 | @@ -91,11 +92,16 @@ class ObjectWrapper(ExitableWithAliases("unwrap")): | ||
| 180 | logger = logging.getLogger(__name__) | ||
| 181 | logger.exception("Exception while handling %s.%s()", interface_name, method_name) | ||
| 182 | |||
| 183 | - #TODO Think of a better way to translate Python exception types to DBus error types. | ||
| 184 | - e_type = type(e).__name__ | ||
| 185 | - if not "." in e_type: | ||
| 186 | - e_type = "unknown." + e_type | ||
| 187 | - invocation.return_dbus_error(e_type, str(e)) | ||
| 188 | + if error_registration.is_registered_exception(e): | ||
| 189 | + name = error_registration.get_dbus_name(e) | ||
| 190 | + invocation.return_dbus_error(name, str(e)) | ||
| 191 | + else: | ||
| 192 | + logger.info("name is not registered") | ||
| 193 | + e_type = type(e).__name__ | ||
| 194 | + if not "." in e_type: | ||
| 195 | + e_type = "unknown." + e_type | ||
| 196 | + | ||
| 197 | + invocation.return_dbus_error(e_type, str(e)) | ||
| 198 | |||
| 199 | def Get(self, interface_name, property_name): | ||
| 200 | type = self.readable_properties[interface_name + "." + property_name] | ||
| 201 | -- | ||
| 202 | 2.7.4 | ||
| 203 | |||
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 index 7ed1c63b63..adaa86d5a2 100644 --- a/meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb +++ b/meta-python/recipes-devtools/python/python3-pydbus_0.6.0.bb | |||
| @@ -1,2 +1,6 @@ | |||
| 1 | require python-pydbus.inc | 1 | require python-pydbus.inc |
| 2 | inherit pypi setuptools3 | 2 | inherit pypi setuptools3 |
| 3 | |||
| 4 | SRC_URI += "file://0001-Support-asynchronous-calls-58.patch \ | ||
| 5 | file://0002-Support-transformation-between-D-Bus-errors-and-exce.patch \ | ||
| 6 | " | ||
