Brian
Brian

Reputation: 427

(Twisted-Autobahn) exceptions.AttributeError: 'WsProtocol' object has no attribute 'factory'

Currently I am getting the following error as the title suggests. My code for a Web Socket using Autobahn's twisted library is below. When I instantiate the WsProtocolFactory, I want to set the protocol to WsProtocol and initialize the factory with a defaultdict for topics to subscribe to.

My initial thought was to add a factory argument to the WsProtocol __init_, but have not been able to fix the error.

Any help would be greatly appreciated.

Thank you!

EDIT: added traceback error

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 1074, in doRead
    protocol.makeConnection(transport)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/protocol.py", line 494, in makeConnection
    self.connectionMade()
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 95, in connectionMade
    self._connectionMade()
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 2426, in _connectionMade
    WebSocketProtocol._connectionMade(self)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 962, in _connectionMade
    setattr(self, configAttr, getattr(self.factory, configAttr))
exceptions.AttributeError: 'WsProtocol' object has no attribute 'factory'

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 209, in doRead
    return self._dataReceived(data)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 215, in _dataReceived
    rval = self.protocol.dataReceived(data)
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 132, in dataReceived
    self._dataReceived(data)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 1175, in _dataReceived
    if self.state == WebSocketProtocol.STATE_OPEN:
exceptions.AttributeError: 'WsProtocol' object has no attribute 'state'

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/internet/task.py", line 936, in react
    _reactor.run()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 1194, in run
    self.mainLoop()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 1206, in mainLoop
    self.doIteration(t)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/epollreactor.py", line 396, in doPoll
    log.callWithLogger(selectable, _drdw, selectable, fd, event)
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 610, in _doReadOrWrite
    self._disconnectSelectable(selectable, why, inRead)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 258, in _disconnectSelectable
    selectable.connectionLost(failure.Failure(why))
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 293, in connectionLost
    protocol.connectionLost(reason)
  File "web_autobahn.py", line 77, in connectionLost
    WebSocketServerProtocol.connectionLost(self, reason)
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 129, in connectionLost
    self._connectionLost(reason)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 2437, in _connectionLost
    WebSocketProtocol._connectionLost(self, reason)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 1075, in _connectionLost
    if not self.factory.isServer and self.serverConnectionDropTimeoutCall is not None:
exceptions.AttributeError: 'WsProtocol' object has no attribute 'factory'

Here is my code

from datetime import datetime
from collections import defaultdict

from twisted.web import resource, server
from twisted.internet.task import react
from twisted.internet import reactor
from twisted.internet.defer import DeferredList, Deferred
from twisted.internet.endpoints import TCP4ServerEndpoint
from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory
from schema import schema
import json
import os
import sys
from twisted.python import log

def log(msg):
    print("{}: {}".format(str(datetime.now()), msg))


class WsProtocol(WebSocketServerProtocol):
    """Dummy websocket protocol"""
    def __init__(self, topics):
        super(WsProtocol, self).__init__()
        self.topics = topics
        self.subscribed_topic = None
        log("WS protocol init")

    def onConnect(self, request):
        print("WebSocket connected.")

    def onOpen(self):
        print("WebSocket connection open.")

    def onMessage(self, payload, isBinary):
        log(payload)
        self.sendMessage("Message received")        

    def onClose(self, wasClean, code, reason):
        print("WebSocket connection closed: {}".format(reason))

    def connectionLost(self, reason):
        WebSocketServerProtocol.connectionLost(self, reason)
        log("Connection closed: Reason is {}".format(reason))

class WsProtocolFactory(WebSocketServerFactory):

    def __init__(self):
        self.topics = defaultdict(set)

    def buildProtocol(self, *args, **kwargs):
        return WsProtocol(self.topics)

def setup_protocols(reactor):
    factories = {
        WsProtocolFactory: 9001,
    }

    for factory, port in factories.items():
        endpoint = TCP4ServerEndpoint(reactor, port)
        endpoint.listen(factory())
        log("Bound port {} to protocol {}".format(str(port), factory))
    return Deferred()



if __name__ == '__main__':
    react(setup_protocols)

EDIT: New traceback

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 1074, in doRead
    protocol.makeConnection(transport)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/protocol.py", line 494, in makeConnection
    self.connectionMade()
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 95, in connectionMade
    self._connectionMade()
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 2426, in _connectionMade
    WebSocketProtocol._connectionMade(self)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 962, in _connectionMade
    setattr(self, configAttr, getattr(self.factory, configAttr))
exceptions.AttributeError: 'WsProtocolFactory' object has no attribute 'logOctets'

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
    why = selectable.doRead()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 209, in doRead
    return self._dataReceived(data)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 215, in _dataReceived
    rval = self.protocol.dataReceived(data)
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 132, in dataReceived
    self._dataReceived(data)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 1175, in _dataReceived
    if self.state == WebSocketProtocol.STATE_OPEN:
exceptions.AttributeError: 'WsProtocol' object has no attribute 'state'

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/twisted/internet/task.py", line 936, in react
    _reactor.run()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 1194, in run
    self.mainLoop()
  File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 1206, in mainLoop
    self.doIteration(t)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/epollreactor.py", line 396, in doPoll
    log.callWithLogger(selectable, _drdw, selectable, fd, event)
--- <exception caught here> ---
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 101, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/log.py", line 84, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 610, in _doReadOrWrite
    self._disconnectSelectable(selectable, why, inRead)
  File "/usr/lib64/python2.7/site-packages/twisted/internet/posixbase.py", line 258, in _disconnectSelectable
    selectable.connectionLost(failure.Failure(why))
  File "/usr/lib64/python2.7/site-packages/twisted/internet/tcp.py", line 293, in connectionLost
    protocol.connectionLost(reason)
  File "web_autobahn.py", line 77, in connectionLost
    WebSocketServerProtocol.connectionLost(self, reason)
  File "/usr/lib/python2.7/site-packages/autobahn/twisted/websocket.py", line 129, in connectionLost
    self._connectionLost(reason)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 2437, in _connectionLost
    WebSocketProtocol._connectionLost(self, reason)
  File "/usr/lib/python2.7/site-packages/autobahn/websocket/protocol.py", line 1082, in _connectionLost
    if self.autoPingPendingCall:
exceptions.AttributeError: 'WsProtocol' object has no attribute 'autoPingPendingCall'

EDIT: Correct code that works

from datetime import datetime
from collections import defaultdict

from twisted.web import resource, server
from twisted.internet.task import react
from twisted.internet import reactor
from twisted.internet.defer import DeferredList, Deferred
from twisted.internet.endpoints import TCP4ServerEndpoint
from autobahn.twisted.websocket import WebSocketServerProtocol, WebSocketServerFactory
from schema import schema
import json
import os
import sys
from twisted.python import log

def log(msg):
    print("{}: {}".format(str(datetime.now()), msg))


class WsProtocol(WebSocketServerProtocol):
    """Dummy websocket protocol"""
    def __init__(self, topics):
        super(WsProtocol, self).__init__()
        self.topics = topics
        self.subscribed_topic = None
        log("WS protocol init")

    def onConnect(self, request):
        print("WebSocket connected.")

    def onOpen(self):
        print("WebSocket connection open.")

    def onMessage(self, payload, isBinary):
        log(payload)
        self.sendMessage("Message received")        

    def onClose(self, wasClean, code, reason):
        print("WebSocket connection closed: {}".format(reason))

    def connectionLost(self, reason):
        WebSocketServerProtocol.connectionLost(self, reason)
        log("Connection closed: Reason is {}".format(reason))

class WsProtocolFactory(WebSocketServerFactory):

    def __init__(self):
        super(WsProtocolFactory, self).__init__()
        self.topics = defaultdict(set)

    def buildProtocol(self, *args, **kwargs):
        protocol = WsProtocol(self.topics)
        protocol.factory = self
        return protocol

def setup_protocols(reactor):
    factories = {
        WsProtocolFactory: 9001,
    }

    for factory, port in factories.items():
        endpoint = TCP4ServerEndpoint(reactor, port)
        endpoint.listen(factory())
        log("Bound port {} to protocol {}".format(str(port), factory))
    return Deferred()



if __name__ == '__main__':
    react(setup_protocols)

Upvotes: 0

Views: 1384

Answers (1)

Jean-Paul Calderone
Jean-Paul Calderone

Reputation: 48325

Define your factory's buildProtocol so it gives the protocols it builds a factory attribute:

def buildProtocol(self, *args, **kwargs):
    protocol = WsProtocol(self.topics)
    protocol.factory = self
    return protocol

Setting the factory this way is a widespread convention assumed by a lot of different Twisted-using code.

I'm not sure what logOctets is but my guess is that this is caused by a similar issue.

Let's look at buildProtocol again. Your class overrides the base implementation of buildProtocol which does something like:

def buildProtocol(self, *args, **kwargs):
    protocol = self.protocol()
    protocol.factory = self
    return protocol

Your version caused the first AttributeError (for factory) by not re-implementing quite all of this behavior and the fix was to update your version so it was closer to the original.

My guess is that WebSocketServerFactory.__init__ has some additional behavior and your subclass's __init__ has clobbered that. The fix is either to replicate it or (better) call the base implementation.

Upvotes: 1

Related Questions