pythonflaskflask-socketiopython-socketio

Accessing Flask application context within python-socketio Client()'s event handler


I am trying to access Flask application context inside the python-socketio's event handler on_tick(), and I am presented with error -

(...)
 File "H:\Python\autotrader2\venv\lib\site-packages\werkzeug\local.py", line 316, in __get__
    obj = instance._get_current_object()  # type: ignore[misc]
  File "H:\Python\autotrader2\venv\lib\site-packages\werkzeug\local.py", line 513, in _get_current_object
    raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.

Tried to extract a self sufficient miniature version of a larger program -

import socketio
from flask import current_app

class MySocketIOClient:
    def __init__(self):
        self.sio = socketio.Client()
        self.sio.connect("https://feeds.sio.server",
                         headers={"User-Agent": "python-socketio[client]/socket"},
                         auth={"user": "user_id", "token": "session_token"},
                         transports="websocket")

    def execute(self):
        # with current_app.app_context():  # Does not work
        with current_app.test_request_context('/'):  # Does not work
            self.sio.on('update', self.on_tick)
            # self.sio.wait()  # Does not work either

    def on_tick(self, tick):
        print(tick)
        # Error: working outside application context
        print("APP_TIMEZONE={}".format(current_app.config.get('APP_TIMEZONE')))  

if __name__ == '__main__':
    MySocketIOClient().execute()

How to access Flask's application context (or request context) in the event handler?


Solution

  • current_app only works when there is already an app context installed, so it is not useful in your case.

    For this you need to import your application instance:

    from x import app
    
    class MySocketIOClient:
        # ...
    
        def on_tick(self, tick):
            print("APP_TIMEZONE={}".format(app.config.get('APP_TIMEZONE')))  
    

    Here I'm using x as a placeholder for the module that has your Flask application instance.