from gi.repository import GLib
from .generic import bound_method
from .identifier import filter_identifier
from .timeout import timeout_to_glib
from .error import error_registration
try:
from inspect import Signature, Parameter
put_signature_in_doc = False
except:
from ._inspect3 import Signature, Parameter
put_signature_in_doc = True
class DBUSSignature(Signature):
def __str__(self):
result = []
for param in self.parameters.values():
p = param.name if not param.name.startswith("arg") else ""
if type(param.annotation) == str:
p += ":" + param.annotation
result.append(p)
rendered = '({})'.format(', '.join(result))
if self.return_annotation is not Signature.empty:
rendered += ' -> {}'.format(self.return_annotation)
return rendered
class ProxyMethod(object):
def __init__(self, iface_name, method):
self._iface_name = iface_name
self.__name__ = method.attrib["name"]
self.__qualname__ = self._iface_name + "." + self.__name__
self._inargs = [(arg.attrib.get("name", ""), arg.attrib["type"]) for arg in method if arg.tag == "arg" and arg.attrib.get("direction", "in") == "in"]
self._outargs = [arg.attrib["type"] for arg in method if arg.tag == "arg" and arg.attrib.get("direction", "in") == "out"]
self._sinargs = "(" + "".join(x[1] for x in self._inargs) + ")"
self._soutargs = "(" + "".join(self._outargs) + ")"
self_param = Parameter("self", Parameter.POSITIONAL_ONLY)
pos_params = []
for i, a in enumerate(self._inargs):
name = filter_identifier(a[0])
if not name:
name = "arg" + str(i)
param = Parameter(name, Parameter.POSITIONAL_ONLY, annotation=a[1])
pos_params.append(param)
ret_type = Signature.empty if len(self._outargs) == 0 else self._outargs[0] if len(self._outargs) == 1 else "(" + ", ".join(self._outargs) + ")"
self.__signature__ = DBUSSignature([self_param] + pos_params, return_annotation=ret_type)
if put_signature_in_doc:
self.__doc__ = self.__name__ + str(self.__signature__)
def __call__(self, instance, *args, **kwargs):
argdiff = len(args) - len(self._inargs)
if argdiff < 0:
raise TypeError(self.__qualname__ + " missing {} required positional argument(s)".format(-argdiff))
elif argdiff > 0:
raise TypeError(self.__qualname__ + " takes {} positional argument(s) but {} was/were given".format(len(self._inargs), len(args)))
# Python 2 sux
for kwarg in kwargs:
if kwarg not in ("timeout", "callback", "callback_args"):
raise TypeError(self.__qualname__ + " got an unexpected keyword argument '{}'".format(kwarg))
timeout = kwargs.get("timeout", None)
callback = kwargs.get("callback", None)
callback_args = kwargs.get("callback_args", tuple())
call_args = (
instance._bus_name,
instance._path,
self._iface_name,
self.__name__,
GLib.Variant(self._sinargs, args),
GLib.VariantType.new(self._soutargs),
0,
timeout_to_glib(timeout),
None
)
if callback:
call_args += (self._finish_async_call, (callback, callback_args))
instance._bus.con.call(*call_args)
return None
else:
result = None
error = None
try:
result = instance._bus.con.call_sync(*call_args)
except Exception as e:
error = error_registration.transform_exception(e)
if error:
raise error
return self._unpack_return(result)
def _unpack_return(self, values):
ret = values.unpack()
if len(self._outargs) == 0:
return None
elif len(self._outargs) == 1:
return ret[0]
else:
return ret
def _finish_async_call(self, source, result, user_data):
error = None
return_args = None
try:
ret = source.call_finish(result)
return_args = self._unpack_return(ret)
except Exception as err:
error = error_registration.transform_exception(err)
callback, callback_args = user_data
callback(*callback_args, returned=return_args, error=error)
def __get__(self, instance, owner):
if instance is None:
return self
return bound_method(self, instance)
def __repr__(self):
return "<function " + self.__qualname__ + " at 0x" + format(id(self), "x") + ">"