Skip to content

Commit 4ca473b

Browse files
authored
[REF] upgrade to using sqlalchemy 2.0 (neurosynth_compose) (#1126)
* upgrade to using sqlalchemy 2.0 * ignore selectin spelling * remove leading db. where appropriate * remove fallbacks for what should be failures
1 parent 0148864 commit 4ca473b

File tree

18 files changed

+618
-343
lines changed

18 files changed

+618
-343
lines changed

.codespellrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
skip = .git,*.pdf,*.svg,*.ts,*.tsx,package-lock.json,data-*vocabulary.txt,sample_*.csv,CHANGELOG.rst,ingest_neurovault.yml,./compose/neurosynth-frontend/cypress/fixtures
33
# regexes
44
ignore-regex = r"\(\?i\).*\\\\1
5-
ignore-words-list = te,fwe,connexion,zoon,covert,rime
5+
ignore-words-list = te,fwe,connexion,zoon,covert,rime,selectin

compose/backend/neurosynth_compose/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import connexion
77
from connexion.resolver import MethodViewResolver
88

9-
from .database import db
10-
119

1210
def create_app():
1311
connexion_app = connexion.FlaskApp(
@@ -44,8 +42,10 @@ def create_app():
4442
},
4543
)
4644

47-
# initialize db
48-
db.init_app(app)
45+
# initialize db (ensure models register against the app-bound registry)
46+
from .database import init_db
47+
48+
init_db(app)
4949

5050
# setup authentication
5151
# jwt = JWTManager(app)
Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,42 @@
1-
from sqlalchemy.ext.declarative import declarative_base
1+
import logging
2+
from sqlalchemy.orm import DeclarativeBase
23
from flask_sqlalchemy import SQLAlchemy
34

5+
logging.basicConfig(level=logging.INFO)
6+
logger = logging.getLogger(__name__)
7+
8+
9+
class Base(DeclarativeBase):
10+
# Allow existing 1.4-style declarative mappings without
11+
# requiring explicit typing with Mapped[] annotations.
12+
__allow_unmapped__ = True
13+
14+
15+
# Defer assigning the model class so models are registered after app init
416
db = SQLAlchemy()
517

6-
Base = declarative_base()
18+
19+
def commit_session(session=None):
20+
"""Commit the provided session or the default db.session, rolling back on error."""
21+
sess = session or db.session
22+
try:
23+
sess.commit()
24+
except Exception:
25+
sess.rollback()
26+
logger.exception("Session commit failed, rolling back.")
727

828

929
def init_db(app):
10-
# Make Flask-Security, Flask-SQLAlchemy, and Graphene all play nice.
11-
# See https://github.com/mattupstate/flask-security/issues/766#issuecomment-393567456
30+
"""Initialize Flask-SQLAlchemy with the Flask app and register models.
31+
32+
This sets the declarative base class on the SQLAlchemy object and imports
33+
the models so they register against the same registry only once.
34+
"""
35+
# Attach the DeclarativeBase as the model base
36+
db.Model = Base
1237
with app.app_context():
13-
db.app = app
1438
db.init_app(app)
15-
Base.metadata.bind = db.engine
16-
Base.query = db.session.query_property()
39+
# Import models after db is initialized so mappings bind to this registry
40+
# Importing here avoids duplicate mapper registration during test collection.
41+
from . import models # noqa: F401
1742
return db

compose/backend/neurosynth_compose/ingest/neurostore.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
StudysetReference,
1313
AnnotationReference,
1414
)
15-
from ..database import db
15+
from ..database import db, commit_session
16+
from sqlalchemy import select
1617

1718

1819
def ingest_neurostore(
@@ -28,9 +29,9 @@ def ingest_neurostore(
2829
to_commit = []
2930
with db.session.no_autoflush:
3031
for studyset in studysets:
31-
ss_ref = StudysetReference.query.filter_by(
32-
id=studyset["id"]
33-
).one_or_none() or StudysetReference(id=studyset["id"])
32+
ss_ref = db.session.execute(
33+
select(StudysetReference).where(StudysetReference.id == studyset["id"])
34+
).scalar_one_or_none() or StudysetReference(id=studyset["id"])
3435
ss = Studyset(studyset_reference=ss_ref)
3536
to_commit.append(ss)
3637
# only ingest annotations for smaller studysets now.
@@ -39,9 +40,11 @@ def ingest_neurostore(
3940
f"{url}/api/annotations/?studyset_id={studyset['id']}"
4041
).json()["results"]
4142
for annot in annotations:
42-
annot_ref = AnnotationReference.query.filter_by(
43-
id=annot["id"]
44-
).one_or_none() or AnnotationReference(id=annot["id"])
43+
annot_ref = db.session.execute(
44+
select(AnnotationReference).where(
45+
AnnotationReference.id == annot["id"]
46+
)
47+
).scalar_one_or_none() or AnnotationReference(id=annot["id"])
4548
to_commit.append(
4649
Annotation(
4750
studyset=ss,
@@ -50,12 +53,12 @@ def ingest_neurostore(
5053
)
5154

5255
db.session.add_all(to_commit)
53-
db.session.commit()
56+
commit_session()
5457

5558

5659
def create_meta_analyses(url="https://neurostore.org", n_studysets=None):
5760
ingest_neurostore(url, n_studysets)
58-
stdsts = Studyset.query.all()
61+
stdsts = db.session.execute(select(Studyset)).scalars().all()
5962
to_commit = []
6063
with db.session.no_autoflush:
6164
for ss in stdsts:
@@ -80,4 +83,4 @@ def create_meta_analyses(url="https://neurostore.org", n_studysets=None):
8083
)
8184

8285
db.session.add_all(to_commit)
83-
db.session.commit()
86+
commit_session()

0 commit comments

Comments
 (0)