Search code examples
flaskwebsockettwistedautobahn

Flask to autobahn and twisted: RuntimeError: working outside of request context


I would like to send session data from the Flask part to the Websocket part of my app. A simplified example is:

from flask import session

class EchoServerProtocol(WebSocketServerProtocol):
    def __init__(self):
        self.user= session.get('user')

    def onMessage(self, payload, isBinary):
        _user=self.user

        self.sendMessage(payload, isBinary, _user)

app = Flask(__name__)

app.secret_key = str(uuid.uuid4())

@app.route('/')
def page_home():
    return render_template('index.html')

(adapted from here).

I received the error:

File "app.py", line 171, in __init__
    if session.get('user'):
  File "/usr/local/lib/python2.7/dist-packages/werkzeug/local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/usr/local/lib/python2.7/dist-packages/werkzeug/local.py", line 297, in _get_current_object
    return self.__local()
  File "/usr/local/lib/python2.7/dist-packages/flask/globals.py", line 20, in _lookup_req_object
    raise RuntimeError('working outside of request context')
exceptions.RuntimeError: working outside of request context

Solution

  • The temporary solution I found was to save the user name as a pickle object in the Flask part, and to load the pickle object in the websocket part, like:

    from flask import session
    import pickle
    
    class EchoServerProtocol(WebSocketServerProtocol):
        def __init__(self):
            self.user=  pickle.load(open('../static/uploads/userfile.p', 'rb'))
    
        def onMessage(self, payload, isBinary):
            _user=self.user
    
            self.sendMessage(payload, isBinary, _user)
    
    app = Flask(__name__)
    
    app.secret_key = str(uuid.uuid4())
    
    @app.route('/')
    def page_home():
        _user=session.get('user')
    
        pickle.dump(_user, open('../static/uploads/userfile.p', 'wb'))
    
        return render_template('index.html')