txdbus icon indicating copy to clipboard operation
txdbus copied to clipboard

Port to txaio?

Open bochecha opened this issue 8 years ago • 7 comments

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.

bochecha avatar May 29 '16 21:05 bochecha

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 .

cocagne avatar May 31 '16 01:05 cocagne

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:

  1. 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 using txaio.use_twisted() or txaio.use_asyncio())
  2. 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 and autobahn.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) or WebSocketAdapterProtocol.data_received (asyncio) then forward that to the generic WebSocketClientProtocol._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$ 

oberstet avatar Jun 05 '17 13:06 oberstet

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()

DurandA avatar Jun 12 '17 14:06 DurandA

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 avatar Jun 13 '17 09:06 DurandA

@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?

exvito avatar Jun 13 '17 13:06 exvito

Would you like to create a PR with these examples in the README? 🙂

WhyNotHugo avatar Jun 15 '17 01:06 WhyNotHugo

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?

ntninja avatar Jun 24 '17 12:06 ntninja