Open micolous opened 10 years ago
Michael,
You are quite correct that callRemote could be eliminated in favor of providing wrapper objects that simulate native object usage. It was, however, an intentional design decision to not do this. There are two primary reasons for not doing so in txdbus. First is that I was attempting to provide an interface similar to that of Twisted's long-standing Perspective Broker API. The second, and more important reason, is that I agree with Perspective Broker's rationale for intentionally avoiding the native-looking APIs for remote objects.
Remote methods do not behave in the same manner as native methods. If nothing else, network connection failures can occur at any time and robust code must account for the fact that all remote calls can fail with TimeOuts and/or ConnectionLost exceptions. The visual distinction between "o.callRemote('foo', 1,2,3)" and "o.foo(1,2,3)" helps to remind readers of your code that you're dealing with remote objects and that the rules are different. Admittedly, it's somewhat less convenient during the initial implementation but the maintenance benefits, in my opinion, more than make up for it.
Cheers,
Tom
On Sat, Apr 26, 2014 at 1:25 AM, Michael Farrell notifications@github.comwrote:
I was thinking it may be better to eliminate the use of callRemote in txdbus. This would mean that D-Bus remote objects are first-class Python objects, which makes RPC interfaces much simpler, and don't need any glue to talk over the D-Bus.
How I've implemented this in my own code is with something like this:
class DBusRemoteWrapperMethod(object): """ Wrapper for methods for interface.callRemote """ def init(self, obj, methname): self._obj = obj self._methname = methname
def __call__(self, *args, **kwargs): return self._obj.callRemote(self._methname, *args, **kwargs)
class DBusRemoteWrapper(object): """ Wrapper for interfaces that makes everything a callRemote. """ def init(self, obj): self._obj = obj
def __getattr__(self, name): return DBusRemoteWrapperMethod(self._obj, name)
(setup reactor here, omitted for simplicity)
@defer.inlineCallbacksdef main(): conn = yield client.connect(reactor, 'session') obj = yield conn.getRemoteObject(DBUS_SERVICE, DBUS_PATH)
# Add callRemote wrapper api = DBusRemoteWrapper(obj) # Now we can execute methods directly on the DBus object as if it was # a normal Python class... yield api.my_method() result = yield api.do_other_things('bar', 123)
There's a some limitations to my implementation as it stands:
- Members are generated dynamically, and it does not check or expose the org.freedesktop.DBus.Introspection interface in order to be smart about this (and populate things like all.
- This doesn't support wrapping org.freedesktop.DBus.Properties to Python properties.
- This doesn't support handling other interfaces of the object.
There's one major limitation to my implementation as it stands is that it can't handle org.freedesktop.DBus.Properties interface wrapping to a Python property. This would require a little bit more glue in order to handle this.
With o.fd.DB.Properties implementation, it would allow even more interaction like a normal Python object:
api.MyProperty = 6while api.BottleCount > 0: api.BottleCount -= 1
This would make txdbus work a little more like python-dbus, and other RPC mechanisms like Python's XMLRPC module in the standard library ( ServiceProxy).
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/txdbus/issues/10 .
@micolous, you may simplify your code using return functools.partial(self._obj.callRemote, name)
instead of return DBusRemoteWrapperMethod(self._obj, name)
and also I recommend you to check name.startswith('_')
and raise appropriate error
I was thinking it may be better to eliminate the use of
callRemote
in txdbus. This would mean that D-Bus remote objects are first-class Python objects, which makes RPC interfaces much simpler, and don't need any glue to talk over the D-Bus.How I've implemented this in my own code is with something like this:
There's a some limitations to my implementation as it stands:
org.freedesktop.DBus.Introspection
interface in order to be smart about this (and populate things like__all__
.org.freedesktop.DBus.Properties
to Python properties.There's one major limitation to my implementation as it stands is that it can't handle org.freedesktop.DBus.Properties interface wrapping to a Python property. This would require a little bit more glue in order to handle this.
With
o.fd.DB.Properties
implementation, it would allow even more interaction like a normal Python object:This would make
txdbus
work a little more likepython-dbus
, and other RPC mechanisms like Python's XMLRPC module in the standard library (ServiceProxy
).