Skip to content

Instantly share code, notes, and snippets.

@alexa-infra
Last active May 22, 2020 21:33
Show Gist options
  • Save alexa-infra/2bfb56e0ae79689433b0e365bc3f7926 to your computer and use it in GitHub Desktop.
Save alexa-infra/2bfb56e0ae79689433b0e365bc3f7926 to your computer and use it in GitHub Desktop.
Minimal flask-sqlalchemy integration, which allows you to keep models independent of flask
from typing import TYPE_CHECKING
from sqlalchemy import create_engine
if TYPE_CHECKING:
from flask import Flask
from sqlalchemy.orm import scoped_session
class FlaskSQLAlchemy:
def __init__(self, app: 'Flask' = None, db: 'scoped_session' = None) -> None:
self.engine = None
if app and db:
self.init_app(app, db)
def init_app(self, app: 'Flask', db: 'scoped_session') -> None:
if not app or not db:
raise ValueError
app.extensions['sqlalchemy'] = self
uri = app.config.setdefault('SQLALCHEMY_DATABASE_URI', 'sqlite:///:memory:')
options = app.config.setdefault('SQLALCHEMY_ENGINE_OPTIONS', {})
self.engine = engine = create_engine(uri, **options)
db.configure(bind=engine)
# pylint: disable=unused-variable
@app.teardown_appcontext
def shutdown_session(response_or_exc):
db.remove()
return response_or_exc
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
session_factory = sessionmaker()
db = scoped_session(session_factory)
Model = declarative_base()
metadata = Model.metadata
from .mymodel import MyModel
from sqlalchemy import Column, Integer, Text
from .models import Model
class MyModel(Model):
__tablename__ = 'my_model'
id = Column(Integer, primary_key=True)
name = Column(Text, nullable=False)
import pytest
from .models import db, metadata
from .mymodel import MyModel
@pytest.fixture
def with_flask():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
sa = FlaskSQLAlchemy()
sa.init_app(app, db)
with app.app_context() as ctx:
metadata.create_all(sa.engine)
yield
@pytest.fixture
def without_flask():
engine = create_engine('sqlite:///:memory:')
db.configure(bind=engine)
try:
metadata.create_all(engine)
yield
finally:
db.remove()
@pytest.mark.usefixtures('with_flask')
def test_simple():
item = MyModel(name='hello')
db.add(item)
db.commit()
item = db.query(MyModel).filter_by(name='hello').first()
assert item.name == 'hello'
@pytest.mark.usefixtures('without_flask')
def test_simple2():
item = MyModel(name='world')
db.add(item)
db.commit()
item = db.query(MyModel).filter_by(name='world').first()
assert item.name == 'world'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment