[Twisted-Python] Question about ReconnectingClientFactory and conch StatefulTelnetProtocol

Lucas Taylor ltaylor.volks at gmail.com
Fri Feb 5 20:04:03 EST 2010


On 2/5/10 5:23 PM, Mark Bailey wrote:
> Good day, everyone:
> 
> Continuing my effort to learn Python and Twisted, I need to create
> several Telnet clients and somehow send two arguments to each and
> receive data from each.
> 
> I tried the same pattern that I used with the Telnet server and created
> a Factory, actually a ReconnectingClientFactory.  It doesn't work.  My
> source and the error (no attribute 'factory') are below.
> 
> Do the "conch" protocols not support a factory?  Is there an alternative
> that provides a Telnet client with a lineReceived method?
> 
> What am I doing wrong?  :-)  I suppose I could pass arguments to
> ClusterClient by overriding __init__, but that seems inelegant.
> 
> Thanks for your help.
> 
> Mark
>
> ----------
> 
> from twisted.internet.protocol import Protocol, ReconnectingClientFactory
> from sys import stdout
> 
> from twisted.internet import reactor
> 
> from twisted.conch.telnet import StatefulTelnetProtocol
> 
> class ClusterClient(StatefulTelnetProtocol):
> 
>     def lineReceived(self, data):
>         print self.factory.prompt, self.factory.call
>         print data
> 
> class ClusterClientFactory(ReconnectingClientFactory):
> 
>     protocol = ClusterClient
> 
>     def __init__(self):
>         self.prompt = "call:"
>         self.call = "kd4d"
> 
>     def startedConnecting(self, connector):
>         print 'Started to connect.'
> 
>     def buildProtocol(self, addr):
>         print 'Connected.'
>         self.resetDelay()
>         return ClusterClient()
> 
>     def clientConnectionLost(self, connector, reason):
>         print 'Lost connection.  Reason:', reason
>         ReconnectingClientFactory.clientConnectionLost(self, connector,
> reason)
> 
>     def clientConnectionFailed(self, connector, reason):
>         print 'Connection failed. Reason:', reason
>         ReconnectingClientFactory.clientConnectionFailed(self, connector,
>                                                          reason)
> if __name__ == '__main__':
>     factory = ClusterClientFactory()
>     factory.maxDelay = 120  #  two minutes
>     print factory.prompt, factory.call
>     reactor.connectTCP("localhost", 8023, factory)
> 
> 
>     reactor.run()
> 
> -----------------
> 
>   File "ClusterClient.py", line 11, in lineReceived
>     print self.factory.prompt, self.factory.call
> exceptions.AttributeError: ClusterClient instance has no attribute 'factory'
> Lost connection.  Reason: [Failure instance: Traceback (failure with no
> frames):
>  <type 'exceptions.AttributeError'>: ClusterClient instance has no
> attribute 'fa
> ctory'
> ]
> 



Hi Mark,

The problem is that you have overridden buildProtocol in your Factory
and not set the factory attribute on the protocol instance
(ClusterClient instance has no attribute 'factory').

buildProtocol is responsible for creating the protocol instance and the
default implementation takes care of assigning the factory to the protocol.

see the source for Factory and buildProtocol...it's very concise:

http://twistedmatrix.com/trac/browser/tags/releases/twisted-9.0.0/twisted/internet/protocol.py#L87
http://twistedmatrix.com/documents/9.0.0/api/twisted.internet.protocol.Factory.html#buildProtocol


So something like this should work in your case:

    def buildProtocol(self, addr):
        print 'Connected.'
        self.resetDelay()
        p = self.protocol()
        p.factory = self
	return p


This doc is also helpful for understanding the relationship between
Protocols and Factories:
http://twistedmatrix.com/documents/current/core/howto/servers.html

It may be worth emphasizing that there's no real magic going on
here...you're just assigning a python object as an attribute of the
protocol instance.


Lucas




More information about the Twisted-Python mailing list