3

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'
1
  • why dont you use config.py Commented Jun 29, 2021 at 8:11

2 Answers 2

2

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)
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much for this, and this worked like a charm! My follow-up question would be the comment that you had left in 'predict.py' regarding modifying the object within app.py. Could you expand on that slightly?
WSGI servers create a lot of threads and even processes which run the same application. Is this technique thread-safe? Is it also process-safe?
@GeorgiosSyngouroglou Probably is not safe not see stackoverflow.com/questions/32815451/…
1

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

1 Comment

Is session size limited for that object? This object may be rather large in size.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.