cocagne / txdbus Goto Github PK
View Code? Open in Web Editor NEWNative Python implementation of DBus for Twisted
License: MIT License
Native Python implementation of DBus for Twisted
License: MIT License
Split out from #11
The way the type checking is done in the code base problematic. Take this line:
if not isinstance(var, six.string_types):
raise MarshallingError('Required string. Received: ' + repr(var))
The problem is, on Python 2 this will always evaluate to False
! For both bytes and unicode strings.
(cpy361_7) oberstet@thinkpad-t430s:~/scm/crossbario/crossbar-fabric-device-agent$ python2
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import six
>>> six.text_type
<type 'unicode'>
>>> six.binary_type
<type 'str'>
>>> type(b'hello') == six.binary_type
True
>>> type(b'hello') == six.text_type
False
>>> six.string_types
(<type 'basestring'>,)
>>> isinstance(u'hello', six.string_types)
True
>>> isinstance(b'hello', six.string_types)
True
>>>
(cpy361_7) oberstet@thinkpad-t430s:~/scm/crossbario/crossbar-fabric-device-agent$ python
Python 3.6.1 (default, Apr 2 2017, 18:19:20)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import six
>>> six.text_type
<class 'str'>
>>> six.binary_type
<class 'bytes'>
>>> type(b'hello') == six.binary_type
True
>>> type(b'hello') == six.text_type
False
>>> six.string_types
(<class 'str'>,)
>>> isinstance(u'hello', six.string_types)
True
>>> isinstance(b'hello', six.string_types)
False
>>>
The reason is, that on Python 2, both str (bytes) and unicode derive of basestring (https://pythonhosted.org/six/#six.string_types, https://docs.python.org/2/library/functions.html#basestring).
The right way to check is via six.text_type
and six.binary_type
. See above.
Hello
I noticed that you updated to version 1.1.0 on PyPI, but not in the git repository. Can you add a release tag for this? This is important for us because we build from source.
Thanks!
Brecht
When a method is called with annotated variables, then the following error message is returned:
org.txdbus.PythonException.ValueError: Function has keyword-only arguments or annotations, use getfullargspec() API which can support them
This is because getargspec does not support the new signature formats of keyword-only arguments and annotations. This issue is easily fixed:
In file txdbus/objects.py line 488 replace
def _set_method_flags(self, method_obj):
"""
Sets the \"_dbusCaller\" boolean on the \"dbus_*\" methods. This
is a one-time operation used to flag each method with a boolean
indicating whether or not they accept the \"dbusCaller\" keyword
argument
"""
args = inspect.getargspec(method_obj)[0]
needs_caller = False
if len(args) >= 1 and args[-1] == 'dbusCaller':
needs_caller = True
method_obj.__func__._dbusCaller = needs_caller
by:
def _set_method_flags(self, method_obj):
"""
Sets the \"_dbusCaller\" boolean on the \"dbus_*\" methods. This
is a one-time operation used to flag each method with a boolean
indicating whether or not they accept the \"dbusCaller\" keyword
argument
"""
try:
args = inspect.getfullargspec(method_obj)[0]
except AttributeError:
args = inspect.getargspec(method_obj)[0]
needs_caller = False
if len(args) >= 1 and args[-1] == 'dbusCaller':
needs_caller = True
method_obj.__func__._dbusCaller = needs_caller
This maintains backwards compatibility with python2 and supports the new signatures introduced in python3.
DBusObject
methods with object path return type doesn't allow returning a DBusObject
subclass. It would be very nice to support this, as subclasses of DBusObject
are initialized with its path.
The example code in doc/examples/avahi_browse
fails to notice some of the early dbus signals.
When I first start avahi_browse
and then avahi_publish
, everything works fine.
The browser correctly receives the ItemNew
signal sent by the Avahi server.
When I first start avahi_publish
and then avahi_browse
, then the browser does not recognize the ItemNew
signal.
The ItemNew
signal is however sent by the Avahi server, as one can detect by monitoring the system bus.
I suspect a race condition here: When a new ServiceBrowser is created by calling ServiceBrowserNew
, ItemNew
is sent by Avahi before we can set the callback via
self.browser.notifyOnSignal('ItemNew', self.new_service)
So, in general, how do I catch all of the signals of a remote object after creating that object?
I wrote two scripts which publish one object each on a session-bus with bus name "de.test.objectbus".
When I execute one of the scripts the objects are perfectly published and I can execute all of the remote methods specified by the interfaces. The interfaces have different names and the object have different object-paths.
My question: Is it possible to publish an remote object on a session-bus which has already been created with the reactor running? Or do I have to publish all objects on that bus before I start the reactor?
I am running on a centos 5 system and python 2.6.8 (python26) and dbus authentication does not work smoothly. In particular mechanism EXTERNAL never succeeds. It appears the root cause is the client and server not being in sync early in the auth sequence, and EXTERNAL being first in the order gets discarded.
After brief investigation it appears the ClientAuthenticator implementation might not be ideal. It might benefit from sending an empty AUTH which should give a server response listing mechanisms, and get client and server in sync right away.
The dbus server on this centos 5 system rejects the first auth attempt from txdbus which by default tries EXTERNAL. Seeing errors returned like "Not currently in an auth conversation" is a key diagnostic.
I got it to work by adding a second EXTERNAL after the first in the 'preference' member variable. Not a preferred solution, but it is diagnostic.
At least, in python2 (where isinstance(True, int)
is True
) If I try to serialize {1: True, 2:False}
as DBUS's variant, it is really serialized as {1: 1, 2:0}
.
And also txdbus allows mix of types in such dicts., for example, {1:'s', 'd': True}
Hi
Browsing to the code, it looks like Method interface is not complete. In ur code u have implemented
Method('exampleMethod', arguments='s', returns='s' )
So it takes arguments and returns only...
But the original package is
http://dbus.freedesktop.org/doc/dbus-python/api/dbus.decorators-module.html
We have decorators which takes many additional param.
For example I need async_callback to be added and I would implement what would happen if the remote call lead to error.
In normal python package, I do
<
@method(MY_INTFACE, in_signature='', out_signature='', async_callbacks=('async_cb', 'async_eb'))
def DoSomething(self, async_cb, async_eb):
"""Do Something"""
d = self.remote.doSomething()
return self.add_callbacks(d, async_cb, async_eb)
/>
How can I achieve similar thing in tx_dbus.
class MyObj (objects.DBusObject):
iface = DBusInterface('org.example.MyIFace',
Method('exampleMethod', arguments='s', returns='s' )) --> Here I cant add async_callback param which I can pass
Split out from #11
I only have sketchy knowledge about dbus and stuff, haven't looked deeply enough into the txdbus
codebase, but are the unit tests actually talk to a real dbus? and if so, are there tests that
What I meant with round-tripping is between different Python versions.
Like have a procedure implemented in Python 3, exposed via Dbus, and being called from Python 2.
Where the procedure name is a fancy Unicode name, and/or the procedure takes an Unicode argument (and the test actually uses non-US-ASCII characters) and/or the procedure takes a binary argument (and the test actually uses a binary value which isn't valid UTF8).
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.inlineCallbacks
def 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:
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:
api.MyProperty = 6
while 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
).
Suppose this:
...
Method('structMethod', arguments='(si)', returns='(is)')
...
def dbus_structMethod(self, arg):
print 'swapping and returning swapped struct'
return (arg[1], arg[0])
When I call it:
res = yield qwe.callRemote('structMethod', ('x', 69))
I expect [69, 'x']
in res
, but actually I see [[69, 'x']]
Note: opening a new issue to avoid polluting the other one, which is about Python 3 after all.
Over at #11 (comment), you mentioned you'd be interested in having txdbus work with both twisted and asyncio.
How about porting txdbus to txaio?
That would achieve compatibility with asyncio and twisted.
I'm trying to call SetProperty
of a connman service, and it works fine if params are ok, when I use invalid params txdbus client apparently disconnects cleanly
I've defined a custom datatype:
class VariantList(list):
dbusSignature = 'a(v)'
here is the debug log:
2017-05-22T18:06:38+0200 [twisted.internet.defer#critical] Unhandled error in Deferred:
2017-05-22T18:06:38+0200 [twisted.internet.defer#critical] (debug: C: Deferred was created:
C: File "/root/venv/bin/twistd", line 18, in <module>
C: run()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/twistd.py", line 29, in run
C: app.run(runApp, ServerOptions)
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 643, in run
C: runApp(config)
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/twistd.py", line 25, in runApp
C: _SomeApplicationRunner(config).run()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 378, in run
C: self.postApplication()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/_twistd_unix.py", line 222, in postApplication
C: self.startReactor(None, self.oldstdout, self.oldstderr)
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 390, in startReactor
C: self.config, oldstdout, oldstderr, self.profiler, reactor)
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 311, in runReactorWithLogging
C: reactor.run()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1194, in run
C: self.mainLoop()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1203, in mainLoop
C: self.runUntilCurrent()
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 825, in runUntilCurrent
C: call.func(*call.args, **call.kw)
C: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1274, in unwindGenerator
C: return _inlineCallbacks(None, gen, Deferred())
I: First Invoker was:
I: File "/root/venv/bin/twistd", line 18, in <module>
I: run()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/twistd.py", line 29, in run
I: app.run(runApp, ServerOptions)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 643, in run
I: runApp(config)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/twistd.py", line 25, in runApp
I: _SomeApplicationRunner(config).run()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 378, in run
I: self.postApplication()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/scripts/_twistd_unix.py", line 222, in postApplication
I: self.startReactor(None, self.oldstdout, self.oldstderr)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 390, in startReactor
I: self.config, oldstdout, oldstderr, self.profiler, reactor)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/application/app.py", line 311, in runReactorWithLogging
I: reactor.run()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1194, in run
I: self.mainLoop()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/base.py", line 1206, in mainLoop
I: self.doIteration(t)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/epollreactor.py", line 396, in doPoll
I: log.callWithLogger(selectable, _drdw, selectable, fd, event)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
I: return callWithContext({"system": lp}, func, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
I: return context.call({ILogContext: newCtx}, func, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
I: return self.currentContext().callWithContext(ctx, func, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
I: return func(*args,**kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 610, in _doReadOrWrite
I: self._disconnectSelectable(selectable, why, inRead)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 252, in _disconnectSelectable
I: selectable.readConnectionLost(f)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 273, in readConnectionLost
I: self.connectionLost(reason)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 479, in connectionLost
I: self._commonConnection.connectionLost(self, reason)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/tcp.py", line 293, in connectionLost
I: protocol.connectionLost(reason)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/endpoints.py", line 129, in connectionLost
I: return self._wrappedProtocol.connectionLost(reason)
I: File "/root/venv/local/lib/python2.7/site-packages/txdbus/client.py", line 105, in connectionLost
I: d.errback(reason)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 434, in errback
I: self._startRunCallbacks(fail)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 501, in _startRunCallbacks
I: self._runCallbacks()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 588, in _runCallbacks
I: current.result = callback(current.result, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1184, in gotResult
I: _inlineCallbacks(r, g, deferred)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1174, in _inlineCallbacks
I: deferred.errback()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 434, in errback
I: self._startRunCallbacks(fail)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 501, in _startRunCallbacks
I: self._runCallbacks()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 588, in _runCallbacks
I: current.result = callback(current.result, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1184, in gotResult
I: _inlineCallbacks(r, g, deferred)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1174, in _inlineCallbacks
I: deferred.errback()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 434, in errback
I: self._startRunCallbacks(fail)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 501, in _startRunCallbacks
I: self._runCallbacks()
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 588, in _runCallbacks
I: current.result = callback(current.result, *args, **kw)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1184, in gotResult
I: _inlineCallbacks(r, g, deferred)
I: File "/root/venv/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1174, in _inlineCallbacks
I: deferred.errback()
)
Traceback (most recent call last):
Failure: twisted.internet.error.ConnectionDone: Connection was closed cleanly.
2017-05-22T18:06:38+0200 [txdbus.client.DBusClientFactory#info] Stopping factory <txdbus.client.DBusClientFactory instance at 0x7f87a0690368>
and the dbus monitor output:
method call sender=:1.35 -> dest=net.connman serial=37 path=/net/connman/service/ethernet_080027b88135_cable; interface=org.freedesktop.DBus.Introspectable; member=Introspect
method return sender=:1.2 -> dest=:1.35 reply_serial=37
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg name="xml" type="s" direction="out"/>
</method></interface><interface name="net.connman.Service"><method name="GetProperties"><arg name="properties" type="a{sv}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/></method><method name="SetProperty"><arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method><method name="ClearProperty"><arg name="name" type="s" direction="in"/>
</method><method name="Connect"></method><method name="Disconnect"></method><method name="Remove"></method><method name="MoveBefore"><arg name="service" type="o" direction="in"/>
</method><method name="MoveAfter"><arg name="service" type="o" direction="in"/>
</method><method name="ResetCounters"></method><signal name="PropertyChanged"><arg name="name" type="s"/>
<arg name="value" type="v"/>
</signal>
</interface></node>"
method call sender=:1.35 -> dest=net.connman serial=38 path=/net/connman/service/ethernet_080027b88135_cable; interface=net.connman.Service; member=SetProperty
string "Domains.Configuration"
variant array [
struct {
variant string "n"
}
]
signal sender=:1.2 -> dest=(null destination) serial=683 path=/net/connman/service/ethernet_080027b88135_cable; interface=net.connman.Service; member=PropertyChanged
string "Domains.Configuration"
variant array [
]
signal sender=:1.2 -> dest=(null destination) serial=684 path=/net/connman/service/ethernet_080027b88135_cable; interface=net.connman.Service; member=PropertyChanged
string "Domains"
variant array [
]
method return sender=:1.2 -> dest=:1.35 reply_serial=38
method call sender=:1.35 -> dest=net.connman serial=39 path=/net/connman/service/ethernet_080027b88135_cable; interface=org.freedesktop.DBus.Introspectable; member=Introspect
method return sender=:1.2 -> dest=:1.35 reply_serial=39
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node><interface name="org.freedesktop.DBus.Introspectable"><method name="Introspect"><arg name="xml" type="s" direction="out"/>
</method></interface><interface name="net.connman.Service"><method name="GetProperties"><arg name="properties" type="a{sv}" direction="out"/>
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/></method><method name="SetProperty"><arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method><method name="ClearProperty"><arg name="name" type="s" direction="in"/>
</method><method name="Connect"></method><method name="Disconnect"></method><method name="Remove"></method><method name="MoveBefore"><arg name="service" type="o" direction="in"/>
</method><method name="MoveAfter"><arg name="service" type="o" direction="in"/>
</method><method name="ResetCounters"></method><signal name="PropertyChanged"><arg name="name" type="s"/>
<arg name="value" type="v"/>
</signal>
</interface></node>"
For logs, crash reports and version specific workarounds it would be nice to have the "standard" txdbus.__version__
variable. Could get it from $ pip3 show txdbus | grep Version
but it is less pretty.
This is most common in a requirements file, from chris|
on #twisted irc:
"before installing, pip runs egg_info on all packages and txdbus decides it is a good thing to just SystemExit() the setup if twisted is not there, even if it is not even needed"
Ideally twisted would be declared as a dependency correctly in the setup() call.
Cheers!
Latest release on PyPI is lacking the latest improvements, including Python 3 support and support for UNIX_FD function/method arguments, probably among others.
See #11 (comment) and #24 (comment).
Per those discussions, this should move forward once #61 is fixed which, in turn, declares #11 ready for release -- for the time being. :)
Not sure about the release numbering policy, any pointers?
See https://github.com/cocagne/txdbus/blob/master/txdbus/objects.py#L712 - to me it looks like this line should instead be:
del self.exports[ objectPath ]
With the current code, it doesn't seem possible to unexport an object while continuing to use other exported objects with the same bus name.
Sorry if this is stupid question, but could not bytes
be added to the following tuple of supported types?
Line 525 in 17b620d
Currently this raises txdbus.error.MarshallingError: List, Tuple, Bytearray, or Dictionary required for DBus array
if bytes
are used.
Attempting to construct a UInt64(2 ** 64 - 1)
fails with an OverflowError. I think Int64 and UInt64 should be be based on long, not int, as the latter is only guaranteed to fit 32 bits, signed. Even on x86_64 the signedness prevents its use for UInt64.
I have several dbus client programs that connect to the same dbus server(implemented with txdbus). These client programs are written in different programming languages and I noticed java client uses big endian, and all others use little endian.
Using both big and little endian dbus clients to the same txdbus server at the same time cuases dbus service hang, and I resolved the issue as follow;
diff --git a/txdbus/protocol.py b/txdbus/protocol.py
index 946b652..db92340 100644
--- a/txdbus/protocol.py
+++ b/txdbus/protocol.py
@@ -112,6 +112,8 @@ class BasicDBusProtocol(protocol.Protocol):
if self._nextMsgLen == 0 and buffer_len >= 16:
if self._buffer[:1] != b'l':
self._endian = '>'
+ else:
+ self._endian = '<'
body_len = struct.unpack(self._endian + 'I', self._buffer[4:8] )[0]
harr_len = struct.unpack(self._endian + 'I', self._buffer[12:16])[0]
Please review it and apply to upstream..
Thanks,
split out from #11
(cpy361_7) oberstet@thinkpad-t430s:~/scm/3rdparty/txdbus$ flake8 --select=F821 --show-source .
./txdbus/test/test_marshal.py:39:20: F821 undefined name 'long'
self.t(long(1),'x')
^
here:
(cpy361_7) oberstet@thinkpad-t430s:~/scm/crossbario/crossbario-organize/fibu$ python
Python 3.6.1 (default, Apr 2 2017, 18:19:20)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import six
>>> six.integer_types
(<class 'int'>,)
>>>
(cpy361_7) oberstet@thinkpad-t430s:~/scm/crossbario/crossbario-organize/fibu$ python2
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import six
>>> six.integer_types
(<type 'int'>, <type 'long'>)
>>>
KeyboardInterrupt
>>>
It would be good if at least parts of txdbus would work on Python 3.x. It makes integrating txdbus into my "gruvi" project easier. And I'd expect it'd be useful for the asyncio folks as well (And hopefully at some point Twisted will support Python 3 as well.)
I'm happy to contribute patches. However, the best way to support both Python 2.x and 3.x (which is generally accepted now in the Python community), is to have a single-source project that supports 2.6, 2.7 and 3.3+ (3.2 is possible as well but 3.3+ is easier).
So the question is... are you currently supporting Python 2.5 and if so are you willing to give up on that?
See #11 from #11 (comment) onwards.
I'd start with running a linter on CI but not failing on errors. From there, individual issues / PRs can be created and addressed with a somewhat narrow-focus (example: one issue fixes E111 indentation not a multiple of 4, etc.)
Once we get the "good enough" results (up to discussion?), then maybe linter failures could prevent PR merges.
Thoughts welcome.
This is kinda hard to reproduce, since this test only fails sometimes (I'm guessing race condition or something alike).
It's txdbus.test.test_client_against_native_bus.SignalTester.test_shared_signal
.
The easiest way to reproduce is running trial -u txdbus
, which will run all tests in a loop, forever, until failure (it eventually fails).
Tags for versions published on PyPi after v1.0.6 haven't been publish. Do you mind pushing these to github?
Since this method calls conn.sendMessage()
internally, this method may block.
Moreover. Library should expect that socket write function may (!) block! So, whole chain of calls should implement deffered semantics.
Creating this ticket as a follow-up of a not 100% clear matter identified in #65 (comment).
Facts:
What I'm trying to account for:
Maybe this is all correct, maybe not. Just leaving this here for future reference and to be checked by someone (me, who knows?) in the future.
Plan:
Maybe this could be done via CI, just in case any API changes, etc (I guess we'd have to make the examples a package?).
While exploring tox and testing in general, I found out that one particular test was failing unpredictably on my dev system, under Python 2.7.
I found a way of reproducing it by passing in a particular value for PYTHONHASHSEED.
I run the test with trial txdbus.test.test_client_against_native_bus.InterfaceTester.test_get_all_properties
which will only run if a DBUS session is up. So, on my dev VM with no GUI, I actually run dbus-run-session trial txdbus.test.test_client_against_native_bus.InterfaceTester.test_get_all_properties
. This runs successfully most of the time.
To force a failure, I need to set PYTHONHASHSEED to 3475844530 by running PYTHONHASHSEED=3475844530 dbus-run-session trial txdbus.test.test_client_against_native_bus.InterfaceTester.test_get_all_properties
which consistently fails for me.
Taking a quick peek at the test itself, in txdbus/test/client_tests.py
...
def test_get_all_properties(self):
def got_object(ro):
return ro.callRemote('GetAll', '')
def got_reply(reply):
self.assertEquals(reply, {'common' : 'common1',
'prop1' : 'foobar',
'prop2' : 5,
'prop_if1' : 'pif1',
'pwrite' : 'orig'})
return self.proxy_chain(got_object, got_reply)
...it is calling the GetAll
method with an empty interface argument. Not being familiar with DBUS specifics, the behavior seems to be returning a "merged" result of two interfaces in TestClass
at around line 1388: these are org.txdbus.trial.IFace1
and org.txdbus.trial.IFace2
.
Given that both interfaces expose/declare a property named common
, respectively supported by the common1
and common2
attributes in the class, it seems that for most cases of the test run, common1
's value is returned, but for the particular PYTHONHASHSEED mentioned above, common2
's value is returned and the test fails.
Questions on my mind at that point:
GetAll
when an empty interface argument is passed in? Is it supposed to merge/combine the existing interfaces? If so how?GetAll
should return a merged/combined list of all existing interfaces, and assuming that somehow order is important when facing overlapping names, then the current implementation needs fixing.GetAll
exists -- and, say, the result may be arbitrary (again, I have no idea) -- then the test may need to be adapted to account for that possibility.Then I skimmed through https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties which apparently states that:
An empty string may be provided for the interface name; in this case, if there are multiple properties on an object with the same name, the results are undefined (picking one by according to an arbitrary deterministic rule, or returning an error, are the reasonable possibilities).
So, it seems 3. above is the case -- unless txdbus wants to be stricter in this scenario, of course. :)
Running tox -e py27
passes, but there's lots of test failures. Looks like the script that runs the tests returns 0
, even if tests failed:
$ tox -e py27
GLOB sdist-make: /home/hugo/workspace/Forks/txdbus/setup.py
py27 inst-nodeps: /home/hugo/workspace/Forks/txdbus/.tox/dist/txdbus-1.0.12.zip
py27 installed: appdirs==1.4.3,attrs==17.2.0,Automat==0.6.0,constantly==15.1.0,incremental==17.5.0,packaging==16.8,pyparsing==2.2.0,six==1.10.0,Twisted==17.1.0,txdbus==1.0.12,zope.interface==4.4.1
py27 runtests: PYTHONHASHSEED='61129722'
py27 runtests: commands[0] | python runtests.py
Internal bus tests are currently broken... skipping
.....................................EEEEEEEE.........................EUnhandled error in Deferred:
E..Unhandled Error
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/python/log.py", line 103, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/python/log.py", line 86, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/python/context.py", line 122, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/python/context.py", line 85, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
why = selectable.doRead()
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/unix.py", line 193, in doRead
return self._dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/tcp.py", line 214, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/endpoints.py", line 119, in dataReceived
return self._wrappedProtocol.dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 387, in dataReceived
self.gotMessage(line)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 531, in recv1
self.send('AUTH DBUS_COOKIE_SHA1 ' + binascii.hexlify(get_username()))
exceptions.TypeError: b2a_hex() argument 1 must be string or buffer, not None
FE........................................................................................
======================================================================
ERROR: test_launchd_address (txdbus.test.test_endpoints.EndpointsTester)
test_launchd_address
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_multiple_addresses (txdbus.test.test_endpoints.EndpointsTester)
test_multiple_addresses
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_no_session (txdbus.test.test_endpoints.EndpointsTester)
test_no_session
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_nonce_tcp_address (txdbus.test.test_endpoints.EndpointsTester)
test_nonce_tcp_address
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_session (txdbus.test.test_endpoints.EndpointsTester)
test_session
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_system (txdbus.test.test_endpoints.EndpointsTester)
test_system
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_tcp_address (txdbus.test.test_endpoints.EndpointsTester)
test_tcp_address
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_unix_address (txdbus.test.test_endpoints.EndpointsTester)
test_unix_address
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_endpoints.py", line 13, in setUp
self.pre_ses = os.environ['DBUS_SESSION_BUS_ADDRESS']
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/UserDict.py", line 40, in __getitem__
raise KeyError(key)
KeyError: 'DBUS_SESSION_BUS_ADDRESS'
======================================================================
ERROR: test_cancel (txdbus.test.test_authentication.ServerObjectTester)
test_cancel
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 662, in test_cancel
return self.conn.test_cancel()
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 541, in test_cancel
self.send('AUTH DBUS_COOKIE_SHA1 '+ binascii.hexlify(get_username()))
TypeError: b2a_hex() argument 1 must be string or buffer, not None
======================================================================
ERROR: test_max_rejects (txdbus.test.test_authentication.ServerObjectTester)
test_max_rejects
----------------------------------------------------------------------
FailTest: Connection unexpectedly dropped
======================================================================
ERROR: test_retry (txdbus.test.test_authentication.ServerObjectTester)
test_retry
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
why = selectable.doRead()
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/unix.py", line 193, in doRead
return self._dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/tcp.py", line 214, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/.tox/py27/lib/python2.7/site-packages/twisted/internet/endpoints.py", line 119, in dataReceived
return self._wrappedProtocol.dataReceived(data)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 387, in dataReceived
self.gotMessage(line)
File "/home/hugo/workspace/Forks/txdbus/txdbus/test/test_authentication.py", line 531, in recv1
self.send('AUTH DBUS_COOKIE_SHA1 ' + binascii.hexlify(get_username()))
TypeError: b2a_hex() argument 1 must be string or buffer, not None
======================================================================
FAIL: test_retry (txdbus.test.test_authentication.ServerObjectTester)
test_retry
----------------------------------------------------------------------
FailTest: Connection unexpectedly dropped
----------------------------------------------------------------------
Ran 163 tests in 0.073s
FAILED (failures=1, errors=11)
_____________________________________________________________________________________ summary _____________________________________________________________________________________
py27: commands succeeded
congratulations :)
Also reproduced here.
This test is a no-op on Python 3. Passing is misleading, it should be skipped instead.
See #11 (comment) in #11.
Hello,
if I try to stress the dbus Interface, I get an error, too many open files.
Maybe I'm doing something wrong.
After 1024 requests, the server stops.
I have attached the error as an example.
I exported two object with one blocking method each. I would like to use the threads.deferToThread() method from twisted, in order to make the blocking methods non-blocking. I don't understand, how to use this method together with inline callbacks. Does a solution for this problem exist?
Identified in #11 (comment), this really looks like a typo of some-kind, ready to fail once the code is hit.
Split out from #11
Looking at the example on the frontpage, I'm a bit puzzled that none of the arguments there is using explicit b'..'
or u'...'
. So the arguments will be bytes on Py2 and unicode on Py3. Are the arguments auto-coerced under the hood?
Take
notifier = yield con.getRemoteObject('org.freedesktop.Notifications',
'/org/freedesktop/Notifications')
Does getRemoteObject
take bytes or strings? If the latter, then the example code should read:
notifier = yield con.getRemoteObject(u'org.freedesktop.Notifications',
u'/org/freedesktop/Notifications')
This code then works on both Python 2 and 3.
Hi,
Is it mandatory to specify "Method" in interface explicitly?
=== Not working===
I tried following to call a remote method I wrote "ActivateConnection", passed the argument using following piece of code:
dialer_iface = DBusInterface(DIALUP_INTFACE)
self.dobj= yield self.mdmModel.bus.getRemoteObject(DIALUP_SERVICE, DIALUP_OBJECT,dialer_iface)
self.path = yield self.dobj.callRemote('ActivateConnection',self.mdmModel.device_opath,
timeout=80)
--> This gives an error that Remote Object doesnt have ActivateConnection in any of interfaces --->
=== working===
Then I tried explicitly specifying the method in interface
dialer_iface = DBusInterface(DIALUP_INTFACE,
Method('ActivateConnection', 'o',returns=''))
self.dobj= yield self.mdmModel.bus.getRemoteObject(DIALUP_SERVICE, DIALUP_OBJECT,dialer_iface)
self.path = yield self.dobj.callRemote('ActivateConnection',self.mdmModel.device_opath,
timeout=80)
It works fine.. here, am I missing something?
Hello,
and first of all thanks for your work!
This repository has not seen any update for 2 years, is it still maintained? Do you have any plan to update it?
If not, could be nice to specify it in the README and/or archive the repos.
Thanks!
The introspection of txdbus does not handle correctly objects whose path has a prefix in common.
Just having any parts in common causes every entry to be duplicated in the generated XML.
Example:
from twisted.internet import reactor, defer
from txdbus import client
from txdbus.objects import DBusObject
@defer.inlineCallbacks
def main():
conn = yield client.connect(reactor)
conn.exportObject(DBusObject('/org/example/ObjPath'))
conn.exportObject(DBusObject('/org/example/ObjPath2'))
yield conn.requestBusName('org.example')
reactor.callWhenRunning(main)
reactor.run()
Introspection XML for path /
:
<node name="/">
<node name="org"/>
<node name="org"/>
</node>
Introspection XML for path /org/
:
<node name="/org/">
<node name="example"/>
<node name="example"/>
</node>
Having one object whose path is "under" another object's path excludes the former from the introspection.
from twisted.internet import reactor, defer
from txdbus import client
from txdbus.objects import DBusObject
@defer.inlineCallbacks
def main():
conn = yield client.connect(reactor)
conn.exportObject(DBusObject('/org/example/ObjPath'))
conn.exportObject(DBusObject('/org/example/ObjPath/more_path'))
yield conn.requestBusName('org.example')
reactor.callWhenRunning(main)
reactor.run()
Introspection XML for path /org/example/ObjPath
: (Snipped for brevity; the issue is that it should have had a <node name="more_path"/>
under the root element.)
<node name="/org/example/ObjPath">
<interface name="org.freedesktop.DBus.Properties">
[...]
</interface>
<interface name="org.freedesktop.DBus.Introspectable">
[...]
</interface>
<interface name="org.freedesktop.DBus.Peer">
[...]
</interface>
<interface name="org.freedesktop.DBus.ObjectManager">
[...]
</interface>
</node>
If fixes are welcome, I can make a pull request.
It seems calling client.connect()
creates a new connection to DBus, and I have to call disconnct()
to prevent DBus connection leaking in my program. My program is a daemon process and uses @defer.inlineCallbacks
pattern to call dbus method calls.
Not sure it's possible, but it would be convenient if the connection is reused if client.connect()
is called multiple times.
When implementing, we should return file objects os.fdopen(received_fd)
in order not to lost FD on, say, exception. If someone wants to use file with another parameters, please use .fileno()
.
One thing. CLOEXEC. https://sourceware.org/bugzilla/show_bug.cgi?id=12539 . This should be set by default as I think.
Also, suppose code:
with open(...) as f:
# suppose f.fileno() = 42
yield xxx.callRemote(f)
# (B)
f2 = open(...)
# f2.fileno() == 42 too
Due to #20 in some situations, we may go to point (B)
while message is not sent actually (just buffered in twisted). But file f
already closed. And more over, another file may be opened under the same descriptor. So, we should guarantee to wait for sendmsg()
syscall in ANY cases.
There is a good chance I am missing something here as I am new to Twisted and TxDBus but I am truly stumped. I am writing a program that can connect with Spotify onmy desktop and control it from a remote computer.
I've been testing it in Eclipse and everything has been working great but when I run the same module in Terminal I get an error saying,
File "/usr/local/lib/python2.7/dist-packages/txdbus/client.py", line 653, in connect
eplist = endpoints.getDBusEndpoints(reactor, busAddress)
File "/usr/local/lib/python2.7/dist-packages/txdbus/endpoints.py", line 48, in getDBusEndpoints
raise Exception('DBus Session environment variable not set')
exceptions.Exception: DBus Session environment variable not set
I went to the source to try and figure things out. I noticed in endpoints.getDBusEndPoints() that I can pass it the actual Bus address from os.environ instead of it trying to find it. So I did just that. I opened terminal, ran python, typed
import os
os.environ.get("DBUS_SESSION_BUS_ADDRESS", None)
and it returned
unix:abstract=/tmp/dbus-viyOLeetrg
Then in my code I replaced,
cli = yield client.connect(reactor, 'session')
with
cli = yield client.connect(reactor, 'unix:abstract=/tmp/dbus-viyOLeetrg')
It worked perfectly again in Eclipse but not in Terminal. Although this time in Terminal it didn't throw that error like it did before.
I'm sorry if this isn't a bug and I am missing something but it feels like a bug to me.
Thanks for your time,
Snortoise
DBusClientConnection's delMatch should remove rules from the bus by calling RemoveMatch with the original rule string. Otherwise, they can keep accumulating until the bus refuses to add any more rules.
This does not work (prints None) silently and does not even say that something wrong.
class MyObj(objects.DBusObject):
...
@defer.inlineCallbacks
def dbus_identTest(self, dbusCaller=None):
print 'Caller:', dbusCaller
In the Tx DBus Tutorial it's described how one could send a structure using dbusOrder class variable. I would like to have convenient way of unmarshalling such structure on the receiving side. As of now I presumably invented the wheel with the from_marshalled method:
class SensorDescription(object):
dbusOrder = ['name', 'parameter', 'type']
def __init__(self, sensor = None):
if sensor != None:
self.name = sensor.name
self.parameter = sensor.parameter
self.type = sensor.type
@classmethod
def from_marshalled(cls, marshalled_item):
assert isinstance(marshalled_item, list)
assert len(marshalled_item) == len(SensorDescription.dbusOrder)
result = cls()
for i in range(0, len(SensorDescription.dbusOrder)):
setattr(result, SensorDescription.dbusOrder[i], marshalled_item[i])
return result
Does txdbus have some way of automatic structure unmarshalling? Maybe I could register my structure on the client side for unmarshalling and txdbus would do for me the same as the code in the from_marshalled class method above?
I have noticed several errors when I try to return a large int from a dbus method who's return signature is a variant or dictionary of variants. Python ints are C longs, and can contain larger values than will fit in 'i'. A simple size check for integers in sigFromPy would be easy to implement and solve this problem. A less elegant solution would be to change the default assignment to 'x', but that would result in larger messages in many cases.
I want to become familiar with txdbus, which is a native dbus implementation that uses twisted. I want to export an simple object in order to remotely call its only method with python 2.7. The example given at http://pythonhosted.org/txdbus/ works properly.
I changed the example_method a little bit. Now it takes an integer, instead of a string, like the original example method does. I took this into account when specifying the interface.
Server:
from twisted.internet import reactor, defer
from txdbus import client, objects, error
from txdbus.interface import DBusInterface, Method
import time
class MyObj (objects.DBusObject):
iface = DBusInterface('org.example.MyIFace',
Method('exampleMethod', arguments='i', returns='s'))
dbusInterfaces = [iface]
def __init__(self, objectPath):
super(MyObj, self).__init__(objectPath)
def dbus_exampleMethod(self, arg):
time.sleep(arg)
return 'success'
@defer.inlineCallbacks
def main():
try:
conn = yield client.connect(reactor)
conn.exportObject( MyObj('/MyObjPath') )
yield conn.requestBusName('org.example')
print 'Object exported on bus name "org.example" with path /MyObjPath'
except error.DBusException, e:
print 'Failed to export object: ', e
reactor.stop()
reactor.callWhenRunning( main )
reactor.run()
The client calls the example method exactly as in the original example client but with an integer instead of a string.
Client:
from twisted.internet import reactor, defer
from txdbus import client, error
@defer.inlineCallbacks
def main():
try:
cli = yield client.connect(reactor)
robj = yield cli.getRemoteObject( 'org.example', '/MyObjPath' )
reply = yield robj.callRemote('exampleMethod', 2)
print 'Reply from server: ', reply
except error.DBusException, e:
print 'DBus Error:', e
reactor.stop()
reactor.callWhenRunning(main)
reactor.run()
Executing both the server and the client yields the error message:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1184, in gotResult
_inlineCallbacks(r, g, deferred)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 1128, in _inlineCallbacks
result = g.send(result)
File "tx_example_client.py", line 16, in main
reply = yield robj.callRemote('exampleMethod', 'Hello World!')
File "/usr/local/lib/python2.7/dist-packages/txdbus/objects.py", line 284, in callRemote
returnSignature = m.sigOut )
--- <exception caught here> ---
File "/usr/local/lib/python2.7/dist-packages/txdbus/client.py", line 519, in callRemote
autoStart = autoStart )
File "/usr/local/lib/python2.7/dist-packages/txdbus/message.py", line 190, in __init__
self._marshal()
File "/usr/local/lib/python2.7/dist-packages/txdbus/message.py", line 103, in _marshal
binBody = b''.join( marshal.marshal( self.signature, self.body )[1] )
File "/usr/local/lib/python2.7/dist-packages/txdbus/marshal.py", line 612, in marshal
nbytes, vchunks = marshallers[ tcode ]( ct, var, startByte, lendian )
File "/usr/local/lib/python2.7/dist-packages/txdbus/marshal.py", line 405, in marshal_int32
return 4, [ struct.pack( lendian and '<i' or '>i', var) ]
struct.error: cannot convert argument to integer
What am I doing wrong? It would be great if someone could help me with this issue. It would be the coolest, if someone could explain to me what the error means.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.