SQLAlchemy 1.4 support

This commit is contained in:
Parnassius 2021-12-11 01:37:10 +01:00
parent cc483e1877
commit 2d545de5bf
2 changed files with 34 additions and 11 deletions

View file

@ -10,6 +10,18 @@ from sqlalchemy.types import Integer
from pokedex.db import markdown from pokedex.db import markdown
# Decide which method to use for the default value of the parameter _default_language_id
_MULTILANG_SESSION_USE_EVENT = False
try:
from sqlalchemy.orm import SessionEvents
except ImportError:
pass
else:
if hasattr(SessionEvents, 'do_orm_execute'):
# SQLAlchemy 1.4+
from sqlalchemy import event
_MULTILANG_SESSION_USE_EVENT = True
class LocalAssociationProxy(AssociationProxy, ColumnOperators): class LocalAssociationProxy(AssociationProxy, ColumnOperators):
"""An association proxy for names in the default language """An association proxy for names in the default language
@ -168,7 +180,7 @@ def create_translation_table(_table_name, foreign_class, relation_name,
primaryjoin=and_( primaryjoin=and_(
Translations.foreign_id == foreign_class.id, Translations.foreign_id == foreign_class.id,
Translations.local_language_id == bindparam('_default_language_id', Translations.local_language_id == bindparam('_default_language_id',
value='dummy', type_=Integer, required=True), value='dummy', type_=Integer),
), ),
foreign_keys=[Translations.foreign_id, Translations.local_language_id], foreign_keys=[Translations.foreign_id, Translations.local_language_id],
uselist=False, uselist=False,
@ -206,14 +218,16 @@ def create_translation_table(_table_name, foreign_class, relation_name,
# Done # Done
return Translations return Translations
class MultilangQuery(Query): if not _MULTILANG_SESSION_USE_EVENT:
def _execute_and_instances(self, *args, **kwargs): # SQLAlchemy 1.4 no longer supports Query._execute_and_instances
# Set _default_language_id param if it hasn't been set by the time the query is executed. class MultilangQuery(Query):
# XXX This is really hacky and we should figure out a cleaner method. def _execute_and_instances(self, *args, **kwargs):
if '_default_language_id' not in self._params or self._params['_default_language_id'] == 'dummy': # Set _default_language_id param if it hasn't been set by the time the query is executed.
self._params = self._params.copy() # XXX This is really hacky and we should figure out a cleaner method.
self._params['_default_language_id'] = self.session.default_language_id if '_default_language_id' not in self._params or self._params['_default_language_id'] == 'dummy':
return super(MultilangQuery, self)._execute_and_instances(*args, **kwargs) self._params = self._params.copy()
self._params['_default_language_id'] = self.session.default_language_id
return super(MultilangQuery, self)._execute_and_instances(*args, **kwargs)
class MultilangSession(Session): class MultilangSession(Session):
"""A tiny Session subclass that adds support for a default language. """A tiny Session subclass that adds support for a default language.
@ -232,10 +246,19 @@ class MultilangSession(Session):
self.markdown_extension = markdown_extension_class(self) self.markdown_extension = markdown_extension_class(self)
kwargs.setdefault('query_cls', MultilangQuery) if not _MULTILANG_SESSION_USE_EVENT:
kwargs.setdefault('query_cls', MultilangQuery)
super(MultilangSession, self).__init__(*args, **kwargs) super(MultilangSession, self).__init__(*args, **kwargs)
if _MULTILANG_SESSION_USE_EVENT:
@event.listens_for(MultilangSession, 'do_orm_execute')
def receive_do_orm_execute(state):
# Set _default_language_id param if it hasn't been set by the time the query is executed.
# The same hack as above, but for SQLAlchemy 1.4+
if state.is_select and state.parameters.get('_default_language_id', 'dummy') == 'dummy':
return state.invoke_statement(params={'_default_language_id': state.session.default_language_id})
class MultilangScopedSession(ScopedSession): class MultilangScopedSession(ScopedSession):
"""Dispatches language selection to the attached Session.""" """Dispatches language selection to the attached Session."""

View file

@ -9,7 +9,7 @@ setup(
'pokedex': ['data/csv/*.csv'] 'pokedex': ['data/csv/*.csv']
}, },
install_requires=[ install_requires=[
'SQLAlchemy>=1.0,<1.4', 'SQLAlchemy>=1.0,<2.0',
'whoosh>=2.5,<2.7', 'whoosh>=2.5,<2.7',
'markdown>=2.4.1,<=2.6.11', 'markdown>=2.4.1,<=2.6.11',
'construct==2.5.3', 'construct==2.5.3',