txdbus
txdbus copied to clipboard
Port to txaio?
Note: opening a new issue to avoid polluting the other one, which is about Python 3 after all.
Over at https://github.com/cocagne/txdbus/issues/11#issuecomment-104372112, 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.
Thanks for the suggestion. I hadn't come across txaio yet and it' certainly worth considering. The prevalence of Deferreds in the txdbus code base means it'd probably require porting one module at a time over to the new API but I don't see any significant barriers in the way. It'd be a relatively straight-forward, if somewhat time-consuming, task.
If you're up to the challenge, I'd happily accept patches on a txaio-specific branch and would be willing to convert the mainline over to the txaio version once all of the unit tests are passing. At the moment I have another side-project that is consuming almost all of my available free time so I probably won't be able to contribute too much code but I'm sure I can find time for a few reviews & merges. Hell, show you're a good developer and I'll add you to the commit list for that matter :)
Thanks for the patch :)
Tom
On Sun, May 29, 2016 at 4:01 PM, Mathieu Bridon [email protected] wrote:
Note: opening a new issue to avoid polluting the other one, which is about Python 3 after all.
Over at #11 (comment) https://github.com/cocagne/txdbus/issues/11#issuecomment-104372112, you mentioned you'd be interested in having txdbus work with both twisted and asyncio.
How about porting txdbus to txaio https://github.com/crossbario/txaio?
That would achieve compatibility with asyncio and twisted.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/cocagne/txdbus/issues/35, or mute the thread https://github.com/notifications/unsubscribe/ABrLfAge8WnPxtrT31WBVDaR-hLwaOQFks5qGf7AgaJpZM4IpYPz .
Co-author of txaio here;)
Using txaio, the txdbus library could be made working on Python 2.7+ for both Twisted and asyncio from one codebase.
txdbus in its implementation would need to stick to:
- no co-routines, only plain Deferreds/Futures (eg
txaio.create_future()
will produce either a Twisted Deferred or an asyncio Future depending on which framework was chosen usingtxaio.use_twisted()
ortxaio.use_asyncio()
) - no use of Deferred chaining (as asyncio Futures don't support that in the way Twisted does)
Further, an internal protocol/factory abstraction is needed. Eg here is AutobahnPython, biggest txaio user:
-
autobahn.websocket.protocol.WebSocketClientProtocol
contains all network framework independent code - then there are 2 classes:
autobahn.twisted.websocket.WebSocketClientProtocol
andautobahn.asyncio.websocket.WebSocketClientProtocol
which have the network framework specific code - these classes are the ones used by users, and they derive from 2 classes: WebSocketAdapterProtocol and the generic WebSocketClientProtocol
- the adapter class member function
WebSocketAdapterProtocol.dataReceived
(Twisted) orWebSocketAdapterProtocol.data_received
(asyncio) then forward that to the genericWebSocketClientProtocol._dataReceived
method
Granted, this is a bit of a tricky design, but it achieves the goal of minimizing network framework specific code, maximize agnostic code, and all from a single code base.
Also important to note: while the above approach puts some burden on the library implementor, the users of the library have maximum freedom and convenience.
Eg it is no problem using the latest Python 3.6 co-routine goodies in app code on top of the library - the resulting app won't run on both Twisted/asyncio then of course, because the app code writer decided. Of course the app code itself could also be written without co-routines/chaining, and then it would run on both (eg allowing to switch framework from a command line option) - but I wouldn't recommend that for apps (only for libs).
The code base seems to be mostly Python 3 compatible, which is great of course:
===============================================================================
[SKIPPED]
Not yet ported to python3
txdbus.test.test_authentication.ServerObjectTester.test_bad_command
txdbus.test.test_authentication.ServerObjectTester.test_bad_mech
txdbus.test.test_authentication.ServerObjectTester.test_bad_mech2
txdbus.test.test_authentication.ServerObjectTester.test_cancel
txdbus.test.test_authentication.ServerObjectTester.test_max_rejects
txdbus.test.test_authentication.ServerObjectTester.test_no_null_byte_at_start
txdbus.test.test_authentication.ServerObjectTester.test_reject
txdbus.test.test_authentication.ServerObjectTester.test_retry
txdbus.test.test_authentication.ServerObjectTester.test_too_long
-------------------------------------------------------------------------------
Ran 255 tests in 1.768s
PASSED (skips=9, successes=246)
(cpy361_7) oberstet@thinkpad-t430s:~/scm/3rdparty/txdbus$
In the meantime, you can use txdbus within an asyncio app using asyncioreactor
and asFuture(loop)
which are now merged in trunk:
import asyncio
from asyncio.tasks import ensure_future
from twisted.internet import asyncioreactor
loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
asyncioreactor.install(eventloop=loop)
from txdbus import error, client
async def show_desktop_notification():
'''
Displays "Hello World!" in a desktop notification window for 3 seconds
'''
con = await client.connect(reactor, 'session').asFuture(loop)
notifier = await con.getRemoteObject('org.freedesktop.Notifications',
'/org/freedesktop/Notifications').asFuture(loop)
nid = await notifier.callRemote('Notify',
'Example Application',
0,
'',
'Tx DBus Example',
'Hello World!',
[], dict(),
3000).asFuture(loop)
ensure_future(show_desktop_notification())
loop.run_forever()
You can also use txdbus as usual (with Deferred objects) within an asyncio loop:
import asyncio
from asyncio.tasks import ensure_future
from twisted.internet import asyncioreactor
loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
asyncioreactor.install(eventloop=loop)
from twisted.internet import reactor, defer, task
from txdbus import error, client
@defer.inlineCallbacks
def show_desktop_notification():
'''
Displays "Hello World!" in a desktop notification window for 3 seconds
'''
con = yield client.connect(reactor, 'session')
notifier = yield con.getRemoteObject('org.freedesktop.Notifications',
'/org/freedesktop/Notifications')
nid = yield notifier.callRemote('Notify',
'Example Application',
0,
'',
'Tx DBus Example',
'Hello World!',
[], dict(),
3000)
reactor.callWhenRunning(show_desktop_notification)
reactor.startRunning()
loop.run_forever()
@DurandA shared a few examples that are possible due to recent Twisted developments, allowing Twisted code to interoperate with asyncio code and vice-versa.
Maybe the docs could include an "asyncio" integration section with these two examples and a link to Twisted's docs about it?
Would you like to create a PR with these examples in the README? 🙂
Just so you know, I just stumbled over this (I guess somewhat experimental) pure-python dbus client implementation that claims to have support for blocking, asyncio & Tornado I/O1 by utilizing an I/O-free core2: https://gitlab.com/takluyver/jeepney
It also has an high-level interface that is slightly more low-level that what txdbus
offers1:
import asyncio
from jeepney import DBusAddress, new_method_call
from jeepney.integrate.asyncio import connect_and_authenticate
notifications = DBusAddress('/org/freedesktop/Notifications',
bus_name='org.freedesktop.Notifications',
interface='org.freedesktop.Notifications')
async def send_notification():
(transport, protocol) = await connect_and_authenticate(bus='SESSION')
msg = new_method_call(notifications, 'Notify', 'susssasa{sv}i',
('jeepney_test', # App name
0, # Not replacing any previous notification
'', # Icon
'Hello, world!', # Summary
'This is an example notification from Jeepney',
[], {}, # Actions, hints
-1, # expire_timeout (-1 = default)
))
# Send the message and await the reply
reply = await protocol.send_message(msg)
print('Notification ID:', reply[0])
loop = asyncio.get_event_loop()
loop.run_until_complete(send_notification())
Building something like pydbus
's API on top this could indeed be a viable alternative?