[Twisted-Python] in a factory: assert not self.usedUp

exarkun at twistedmatrix.com exarkun at twistedmatrix.com
Wed Jun 23 13:06:11 MDT 2010


On 04:23 pm, jeandaniel.browne at gmail.com wrote:
>Hello,
>
>I have three questions on a code examples, and actually I have seen
>this pattern in several places in Twisted. The code are copied from
>twisted/doc/mail/examples/imap4client.py
>
>1. In the code below, what is the purpose of an assert checking that
>the member attribute promptDeferred is empty in the prompt method? Is
>this some kind of documentation saying "the attribute is ALWAYS empty
>when this function is called"?

It's a safeguard against the method being called a second time before 
the response to the first call has been received.  Imagine code using 
the function like this if the assert weren't there:

    d1 = prompter.prompt("Answer this")
    d2 = prompter.prompt("Now answer this")
>
>2. It seems that there is the protocol's deferred and the protocol are
>unlinked before the deferred is fired. What would happen if the
>defered was fired while it is still held in an attribute of the
>protocol?

Consider what would happen if there were a callback on `promptDeferred` 
which called the `prompt` method.
>
>class TrivialPrompter(basic.LineReceiver):
>
>    from os import linesep as delimiter
>
>    promptDeferred = None
>
>    def prompt(self, msg):
>
>        assert self.promptDeferred is None    #  1.
>        self.display(msg)
>        self.promptDeferred = defer.Deferred()
>        return self.promptDeferred
>
>    def display(self,msg):
>        self.transport.write(msg)
>
>    def lineReceived(self, line):
>        if self.promptDeferred is None:
>            return
>        d, self.promptDeferred = self.promptDeferred, None     # 2.
>        d.callback(line)
>
>
>3. Third question, in the factory below, there is an attribute usedUp
>set at False by default and set to True late in the buildprotocol
>method. There is an assert making sure the factory is only used once,
>checking that usedUp is False at the beginning of buildprotocol(). Why
>it is so important that the factory must be used only once? What would
>happens otherwise?
>
>class SimpleIMAP4ClientFactory(protocol.ClientFactory):
>    usedUp = False
>
>    protocol = SimpleIMAP4Client
>
>    def __init__(self, username, onConn):
>        self.ctx = ssl.ClientContextFactory()
>
>        self.username = username
>        self.onConn = onConn
>
>    def buildProtocol(self, addr):
>        assert not self.usedUp           # 3.
>        self.usedUp = True
>
>        p = self.protocol(self.ctx)
>        p.factory = self
>        p.greetDeferred = self.onConn
>
>        auth = imap4.CramMD5ClientAuthenticator(self.username)
>        p.registerAuthenticator(auth)
>
>        return p

There's only one Deferred referenced by `self.onConn`.  If you ever got 
to a second connection, the Deferred would have its `callback` method 
invoked a second time which would raise an exception.
>
>Thanks for your help,

You're welcome.

Jean-Paul




More information about the Twisted-Python mailing list