Its Andrew
Its Andrew

Reputation: 155

Flask - Application wide global variable

Good afternoon. I am attempting to create a 'dpt_manager' singleton object during the Flask app instantiation where this manager object should be accessible throughout the application and requests. I am aware of the application context to where what is created within my app factory will only be available during a request / cli however I am unable to access this variable when a request comes in (http://0.0.0.0:5000/getSampleResponse). I am also open to learning better ways to achieve a flask global variable if my implementation is not ideal.

run.py:

from app import create_app

app = create_app()

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)

init.py:

from flask_api import FlaskAPI

from app.config import Config
from app.main.dpt_manager import DPTManager


def create_app():
    app = FlaskAPI(__name__)
    app.config.from_object(Config)

    from app.api.casify_service.authorization import auth
    from app.api.casify_service.predict import predict

    app.register_blueprint(auth)
    app.register_blueprint(predict)

    # instantiate DPTManager instance
    dpt_manager = DPTManager()  # <-- here is where I'm hoping to instantiate the object

    return app

DPTManager Class:

from app.main.data_set import DataSet
from app.main.pickle import Pickle
from app.config import Config


class DPTManager:
    # TODO: singleton implementation goes here

    def __init__(self):
        self._model_retrain_freq = 30
        self._is_model_persistent = True

    def __str__(self):
        return f"""
        Model retrain frequency: {self._model_retrain_freq}
        Model persistent state: {self._is_model_persistent}
    """

predict.py:

from flask import jsonify, current_app
from flask import Blueprint, request
from http import HTTPStatus

from app.util.auth import build_cors_preflight_response, corsify_response
from app.util.response import internal_server_error, successful_response
from app.util.decorators import token_required
import app.main.api_exceptions as err


predict = Blueprint("predict", __name__)    

@predict.route("/getSampleResponse", methods=["GET", "OPTIONS"])
@token_required
def get_sample_response():
    """Returns a sample response"""
    if request.method == "GET":
        sampleResponse = {"someKey": "someValue", "anotherKey": "anotherValue"}

        print(current_app.dpt_manager) # <-- this doesn't work

        # perform business logic here and build the response
        response = jsonify(sampleData=sampleResponse)

        return successful_response(response)

stack trace:

127.0.0.1 - - [28/Jun/2021 16:49:47] "GET /getSampleResponse HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/user/Documents/environments/casify-service/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/user/Documents/environments/casify-service/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/user/Documents/projects/casify_autoescalation/casify/casify-service/app/util/decorators.py", line 34, in decorated
    return f(*args, **kwargs)
  File "/Users/user/Documents/projects/casify_autoescalation/casify/casify-service/app/api/casify_service/predict.py", line 23, in get_sample_response
    print(current_app.dpt_manager)
  File "/Users/user/Documents/environments/casify-service/lib/python3.9/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: 'FlaskAPI' object has no attribute 'dpt_manager'

Upvotes: 3

Views: 4948

Answers (2)

Bao Tran
Bao Tran

Reputation: 636

I recommend using new file extensions.py

  1. Create new file under app folder, name it extensions.py
from app.main.dpt_manager import DPTManager
        
dpt_manager = DPTManager()# init the instance here so we can import later 
  1. init.py

from flask_api import FlaskAPI
    
from app.config import Config
from app.extensions import dpt_manager 

def create_app():
    app = FlaskAPI(__name__)
    app.config.from_object(Config)

    from app.api.casify_service.authorization import auth
    from app.api.casify_service.predict import predict

    app.register_blueprint(auth)
    app.register_blueprint(predict)

    print(dpt_manager) ## let print out to check

    return app
  1. Then in your predict.py , let import dpt_manager and use it
from flask import jsonify, current_app
from flask import Blueprint, request
from http import HTTPStatus

from app.util.auth import build_cors_preflight_response, corsify_response
from app.util.response import internal_server_error, successful_response
from app.util.decorators import token_required
from app.extensions import dpt_manager 
import app.main.api_exceptions as err


predict = Blueprint("predict", __name__)    

@predict.route("/getSampleResponse", methods=["GET", "OPTIONS"])
@token_required
def get_sample_response():
    """Returns a sample response"""
    if request.method == "GET":
        sampleResponse = {"someKey": "someValue", "anotherKey": "anotherValue"}

        print(dpt_manager) # your instance 

        # perform business logic here and build the response
        response = jsonify(sampleData=sampleResponse)

        return successful_response(response)

Upvotes: 2

Confucius Cat
Confucius Cat

Reputation: 108

You can try storing that object you need to access globally in session data, which is syntactically similar to a Python dictionary.

To store it:

from flask import session
session['dpt_manager'] = dpt_manager

To retrieve it somewhere else:

from flask import session
dpt_manager = session.get('dpt_manager') 

Note that session.get('dpt_manager') will return None if 'dpt_manager' is not in session, better to use this than session['dpt_manager'] right away

Upvotes: 1

Related Questions