[Twisted-Python] PyObjC and Twisted command line script

David Bolen db3l.net at gmail.com
Sun Nov 1 20:00:16 EST 2009


Jonathan Stoppani <jonathan at garetjax.info> writes:

> Hi Ronald,
> thanks for the response. I already saw the examples on the pyobjc
> website, but they (two) are all using Cocoa to do some GUI related
> work.
>
> I don't have a gui and I use the console loop instead.
>
> I'm now trying to use the code attached to this ticket and it seems to
> work, but I have to test it a little more.

Not sure which ticket is being referenced but which Twisted reactor
are you using?  I've had very good luck with the threadedselect
reactor, which shouldn't care if your main loop is a GUI or not.  You
interleave with AppHelper.callAfter, which I think should work fine
with both runConsoleEventLoopas well as the GUI runEventLoop

For my part, any OSX console apps I've had to do could just be pure
Twisted, with no need to integrate with an NSRunLoop, so I'm not that
familiar with how you best track startup/shutdown in those cases.

But fundamentally, you install the threadedselect reactor (do that
before any other code uses "from twisted.internet import reactor"),
then use "reactor.interleave(AppHelper.callAfter)" to tie the reactor
in to the normal event loop.  In the Cocoa/NSApplication scenario, I
use the applicationDidFinishLaunching notification to trigger this.

During shutdown, wait for the reactor to perform its shutdown so it
can close things down cleanly, using a reactor trigger to finalize the
event loop with "AppHelper.stopEventLoop".  Again, presumably you'll
have some way to determine when this is appropriate in your console
event loop - in a Cocoa/NSApplication scenario, I use the
applicationShouldTerminate notification.  (I've tended to install the
trigger right at that point too, although it could also be done
earlier)

Here's a trivial example, where I kluge a startup event.  Presumably
the reason you are using runConsoleEventLoop is to use other native
event/input sources based operations, so you might have a more logical
place or event to identify when to start the twisted integration - all
that's required is that it be done after the main event loop is
running.  If not, while I chose a 1s startup delay in this example, it
was mostly to see the difference in timestamps - you can make the
initial callLater a timeout of 0, and it'll just run as soon as the
event loop gets started.

This example also just terminates after two Twisted-based delayed
events, but that would also be determined by your own application:

    """Test console event loop app with Twisted threadedselect reactor"""

    import time

    from PyObjCTools import AppHelper

    from twisted.internet._threadedselect import install
    reactor = install()

    class Main(object):

        def startup(self):
            print time.ctime(), 'Main starting'
            reactor.callLater(1, self.callback)
            reactor.interleave(AppHelper.callAfter)

        def terminate(self):
            print time.ctime(), 'Shutting down reactor'
            reactor.addSystemEventTrigger('after', 'shutdown',
                                          AppHelper.stopEventLoop)
            reactor.stop()

        def callback(self):
            print time.ctime(), 'I was called by the reactor'
            reactor.callLater(1, self.terminate)


    if __name__ == "__main__":

        main = Main()
        AppHelper.callLater(1, main.startup)

        print time.ctime(), 'Starting Event Loop'
        AppHelper.runConsoleEventLoop()
        print time.ctime(), 'Terminating'

When running, this produces:

    Sun Nov  1 19:53:16 2009 Starting Event Loop
    Sun Nov  1 19:53:17 2009 Main starting
    Sun Nov  1 19:53:18 2009 I was called by the reactor
    Sun Nov  1 19:53:19 2009 Shutting down reactor
    Sun Nov  1 19:53:19 2009 Terminating

-- David




More information about the Twisted-Python mailing list