[Twisted-Python] Foolscap-0.0.5 released (aka newpb)

Brian Warner warner at lothar.com
Sun Nov 5 03:37:50 EST 2006

I've uploaded another release of Foolscap, the next-generation remote-object
communication system for Twisted. (actually I've uploaded two, but 0.0.4 had
a brown-paper-bag bug and so it never got announced).

The new release makes all Referenceable objects "giftable" by default, making
it easier to share objects among multiple machines. There is a new
"Reconnector" with which you can announce your intention to connect to a
given target and have the Tub perform exponential-backoff retry attempts
whenever the connection is lost. Also, notifyOnDisconnect() now accepts args
and kwargs to be passed to the disconnect handler callback.

This release also adds support for making debian packages, for sid, sarge,
and dapper. Just type 'make debian-sid' (etc) to get an installable .deb
package in the parent directory.

The full list of user-visible changes is attached below. No wire-level
compatibility changes were introduced in this release, but there will be some
in the future.

Please see http://twistedmatrix.com/trac/wiki/FoolsCap for complete
information about Foolscap. The 0.0.5 release tarball is available from
http://twistedmatrix.com/~warner/Foolscap/ .

share and enjoy,

User visible changes in Foolscap (aka newpb/pb2).

* Release 0.0.5 (04 Nov 2006)

** add Tub.setOption, add logRemoteFailures and logLocalFailures

These options control whether we log exceptions (to the standard twisted log)
that occur on other systems in response to messages that we've sent, and that
occur on our system in response to messages that we've received
(respectively). These may be useful while developing a distributed
application. All such log messages have each line of the stack trace prefixed
by REMOTE: or LOCAL: to make it clear where the exception is happening.

** add sarge packaging, improve dependencies for sid and dapper .debs

** fix typo that prevented Reconnector from actually reconnecting

* Release 0.0.4 (26 Oct 2006)

** API Changes

*** notifyOnDisconnect() takes args/kwargs

RemoteReference.notifyOnDisconnect(), which registers a callback to be fired
when the connection to this RemoteReference is lost, now accepts args and
kwargs to be passed to the callback function. Without this, application code
needed to use inner functions or bound methods to close over any additional
state you wanted to get into the disconnect handler.

notifyOnDisconnect() returns a "marker", an opaque values that should be
passed into the corresponding dontNotifyOnDisconnect() function to deregister
the callback. (previously dontNotifyOnDisconnect just took the same argument
as notifyOnDisconnect).

For example:

class Foo:
    def _disconnect(self, who, reason):
        print "%s left us, because of %s" % (who, reason)
    def connect(self, url, why):
        d = self.tub.getReference(url)
        def _connected(rref):
            self.rref = rref
            m = rref.notifyOnDisconnect(self._disconnect, who, reason=why)
            self.marker = m
    def stop_caring(self):

*** Reconnector / Tub.connectTo()

There is a new connection API for applications that want to connect to a
target and to reconnect to it if/when that connection is lost. This is like
ReconnectingClientFactory, but at a higher layer. You give it a URL to
connect to, and a callback (plus args/kwargs) that should be called each time
a connection is established. Your callback should use notifyOnDisconnect() to
find out when it is disconnected. Reconnection attempts use exponential
backoff to limit the retry rate, and you can shut off reconnection attempts
when you no longer want to maintain a connection.

Use it something like this:

class Foo:
    def __init__(self, tub, url):
        self.tub = tub
        self.reconnector = tub.connectTo(url, self._connected, "arg")
    def _connected(self, rref, arg):
        print "connected"
        assert arg == "arg"
        self.rref = rref
        self.rref.notifyOnDisconnect(self._disconnected, "blag")
    def _disconnected(self, blag):
        print "disconnected"
        assert blag == "blag"
        self.rref = None
    def shutdown(self):

Code which uses this pattern will see "connected" events strictly interleaved
with "disconnected" events (i.e. it will never see two "connected" events in
a row, nor two "disconnected" events).

The basic idea is that each time your _connected() method is called, it
should re-initialize all your state by making method calls to the remote
side. When the connection is lost, all that state goes away (since you have
no way to know what is happening until you reconnect).

** Behavioral Changes

*** All Referenceable object are now implicitly "giftable"

In 0.0.3, for a Referenceable to be "giftable" (i.e. useable as the payload
of an introduction), two conditions had to be satisfied. #1: the object must
be published through a Tub with Tub.registerReference(obj). #2: that Tub must
have a location set (with Tub.setLocation). Once those conditions were met,
if the object was sent over a wire from this Tub to another one, the
recipient of the corresponding RemoteReference could pass it on to a third
party. Another side effect of calling registerReference() is that the Tub
retains a strongref to the object, keeping it alive (with respect to gc)
until either the Tub is shut down or the object is explicitly de-registered
with unregisterReference().

Starting in 0.0.4, the first condition has been removed. All objects which
pass through a setLocation'ed Tub will be usable as gifts. This makes it much
more convenient to use third-party references.

Note that the Tub will *not* retain a strongref to these objects (merely a
weakref), so such objects might disappear before the recipient has had a
chance to claim it. The lifecycle of gifts is a subject of much research. The
hope is that, for reasonably punctual recipients, the gift will be kept alive
until they claim it. The whole gift/introduction mechanism is likely to
change in the near future, so this lifetime issue will be revisited in a
later release.

** Build Changes

The source tree now has some support for making debian-style packages (for
both sid and dapper). 'make debian-sid' and 'make debian-dapper' ought to
create a .deb package.

More information about the Twisted-Python mailing list