From a4ed8e7fa514031d24abdcd512fedc4a8a9fa6ea Mon Sep 17 00:00:00 2001 From: David Beniamine <david.beniamine@tetras-libre.fr> Date: Tue, 21 Feb 2023 00:08:21 +0100 Subject: [PATCH] =?UTF-8?q?WIP=C2=A0trying=20to=20setup=20dependency=20inj?= =?UTF-8?q?ection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mirador_backend/app.py | 35 ++++++++++++++++++----------- Mirador_backend/models.py | 22 +++++++++++++----- Mirador_backend/resources/base.py | 3 --- Mirador_backend/tests/tester.py | 7 +++--- Mirador_backend/utils/app.py | 9 -------- Mirador_backend/utils/config.py | 16 +++++-------- Mirador_backend/utils/containers.py | 14 ++++++++++++ Mirador_backend/utils/database.py | 6 ++--- setup.py | 1 + 9 files changed, 66 insertions(+), 47 deletions(-) delete mode 100644 Mirador_backend/utils/app.py create mode 100644 Mirador_backend/utils/containers.py diff --git a/Mirador_backend/app.py b/Mirador_backend/app.py index 9ac4c93..f8e1395 100644 --- a/Mirador_backend/app.py +++ b/Mirador_backend/app.py @@ -4,25 +4,34 @@ from flask_restful_swagger import swagger from flask_apispec.extension import FlaskApiSpec from Mirador_backend.routes import v1 -from Mirador_backend.utils.config import ConfigFactory +from Mirador_backend.utils.containers import Container from Mirador_backend.utils.database import db -from Mirador_backend.utils.app import setApp +from Mirador_backend.utils.config import Config +from dependency_injector import providers +from dependency_injector.wiring import Provide, inject -app = Flask(__name__) -setApp(app) -api = Api(app) -docs = FlaskApiSpec(app) -app.config.from_object(ConfigFactory()) -app.db = db(app.config['DB'], app.config['DEBUG']) +@inject +def shutdown_session(db: db = Provide[Container.db], exception=None): + db.close() -v1.register_routes(api, docs) +@inject +def do_create_app(config: Config = Provide[Container.config]) -> Flask: + app = Flask(__name__) + app.container = Container() + app.config = config + app.teardown_appcontext(shutdown_session) + api = Api(app) + docs = FlaskApiSpec(app) + v1.register_routes(api, docs) + return app -@app.teardown_appcontext -def shutdown_session(exception=None): - app.db.close() + +# Just for flask resolver +def create_app(): + return do_create_app() if __name__ == '__main__': - app.run() + create_app().run() diff --git a/Mirador_backend/models.py b/Mirador_backend/models.py index e6e15a9..260868d 100644 --- a/Mirador_backend/models.py +++ b/Mirador_backend/models.py @@ -4,8 +4,10 @@ from sqlalchemy.orm import mapped_column from sqlalchemy import Integer, JSON from sqlalchemy import select from sqlalchemy.exc import NoResultFound +from Mirador_backend.utils.containers import Container +from Mirador_backend.utils.database import db +from dependency_injector.wiring import Provide, inject import json -from Mirador_backend.utils.app import getApp class NotFound(NoResultFound): @@ -16,10 +18,10 @@ class BaseModel(DeclarativeBase): """A generic model class """ - session = getApp().db.session + session = None """Access the db session""" - engine = getApp().db.engine + engine = None """Access the db session""" fillable = ['id'] @@ -33,13 +35,21 @@ class BaseModel(DeclarativeBase): } """Actual data fields""" - def create_all(): + @inject + def __init__(self, db: db = Provide[Container.db]): + super().__init__() + if db is None: + raise Exception('DB must be set') + self.session = db.session + self.engine = db.engine + + def create_all(self): """Creates all tables for all models""" - BaseModel.metadata.create_all(getApp().db.engine) + BaseModel.metadata.create_all(self.engine) def drop_all(): """drop all tables for all models""" - BaseModel.metadata.drop_all(getApp().db.engine) + BaseModel.metadata.drop_all(self.engine) @classmethod def query(cls, stmt): diff --git a/Mirador_backend/resources/base.py b/Mirador_backend/resources/base.py index e264ec2..945ceae 100644 --- a/Mirador_backend/resources/base.py +++ b/Mirador_backend/resources/base.py @@ -10,9 +10,6 @@ from flask_apispec import doc from flask_restful import marshal, fields from Mirador_backend.models import BaseModel, NotFound -from Mirador_backend.utils.app import getApp - -logger = getApp().logger class ResourceGroup(MethodResource, Resource): diff --git a/Mirador_backend/tests/tester.py b/Mirador_backend/tests/tester.py index f2f6882..2a1d61a 100644 --- a/Mirador_backend/tests/tester.py +++ b/Mirador_backend/tests/tester.py @@ -3,14 +3,15 @@ import json from os.path import dirname, abspath from flask_fixtures import FixturesMixin -from Mirador_backend.app import app +from Mirador_backend.app import create_app from Mirador_backend.models import BaseModel class TestCase(unittest.TestCase, FixturesMixin): fixtures = ['test.json'] - app = app - db = BaseModel + + app = create_app() + db = BaseModel() def setUp(self): self.base = 'v1/mirador_resource' diff --git a/Mirador_backend/utils/app.py b/Mirador_backend/utils/app.py deleted file mode 100644 index 71f6b56..0000000 --- a/Mirador_backend/utils/app.py +++ /dev/null @@ -1,9 +0,0 @@ -def getApp(): - return getApp.app - - -getApp.app = None - - -def setApp(app): - getApp.app = app diff --git a/Mirador_backend/utils/config.py b/Mirador_backend/utils/config.py index 002af56..23e4297 100644 --- a/Mirador_backend/utils/config.py +++ b/Mirador_backend/utils/config.py @@ -23,13 +23,9 @@ class Config(object): 'BASE': getenv('MYSQL_DATABASE', 'base'), } - -class TestingConfig(Config): - TESTING = True - DEBUG = True - DB = None - FIXTURES_DIRS = ['tests/fixtures'] - - -def ConfigFactory(): - return TestingConfig if getenv('ENV', 'dev') == 'test' else Config + def __init__(): + if getenv('ENV', 'dev') == 'test': + self.TESTING = True + self.DEBUG = True + self.DB = None + self.FIXTURES_DIRS = ['tests/fixtures'] diff --git a/Mirador_backend/utils/containers.py b/Mirador_backend/utils/containers.py new file mode 100644 index 0000000..624b421 --- /dev/null +++ b/Mirador_backend/utils/containers.py @@ -0,0 +1,14 @@ +from dependency_injector import containers, providers +from Mirador_backend.utils.config import Config +from Mirador_backend.utils.database import db + + +class Container(containers.DeclarativeContainer): + wiring_config = containers.WiringConfiguration(modules=[ + "Mirador_backend.app", + "Mirador_backend.models", + "Mirador_backend.resources.base", + "Mirador_backend.tests.tester" + ]) + config = providers.Factory(Config) + db = providers.Factory(db, config=config) diff --git a/Mirador_backend/utils/database.py b/Mirador_backend/utils/database.py index 8d35a0d..5f7c4ee 100644 --- a/Mirador_backend/utils/database.py +++ b/Mirador_backend/utils/database.py @@ -9,9 +9,9 @@ class db(): return 'sqlite://' return f'{params["TYPE"]}://{params["USER"]}:{params["PASSWORD"]}@{params["HOST"]}/{params["BASE"]}' - def __init__(self, config, debug): - self.config = config - self.engine = create_engine(self.__getDBUri(), echo=debug) + def __init__(self, config): + self.config = config['DB'] + self.engine = create_engine(self.__getDBUri(), echo=config['DEBUG']) self.session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=self.engine)) diff --git a/setup.py b/setup.py index 5cfd0c1..c939828 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ setup( # 1.1.x is incompatible with mariadb connector already in python:3.10 docker image "mariadb>=1.0.11,<1.1.0", "python-dotenv", + "dependency-injector", ], extras_require={ -- GitLab