15
15
from flask .signals import Namespace
16
16
from sqlalchemy import event , inspect , orm
17
17
from sqlalchemy .engine .url import make_url
18
- from sqlalchemy .ext .declarative import DeclarativeMeta , declarative_base
19
18
from sqlalchemy .orm .exc import UnmappedClassError
20
19
from sqlalchemy .orm .session import Session as SessionBase
21
20
22
- from flask_sqlalchemy .model import Model
23
21
from ._compat import itervalues , string_types , xrange
24
22
from .model import DefaultMeta
23
+ from .model import Model
25
24
from . import utils
26
25
26
+ try :
27
+ from sqlalchemy .orm import declarative_base
28
+ from sqlalchemy .orm import DeclarativeMeta
29
+ except ImportError :
30
+ # SQLAlchemy <= 1.3
31
+ from sqlalchemy .ext .declarative import declarative_base
32
+ from sqlalchemy .ext .declarative import DeclarativeMeta
33
+
27
34
__version__ = "2.4.4"
28
35
29
36
# the best timer function for the platform
40
47
before_models_committed = _signals .signal ('before-models-committed' )
41
48
42
49
50
+ def _sa_url_set (url , ** kwargs ):
51
+ try :
52
+ url = url .set (** kwargs )
53
+ except AttributeError :
54
+ # SQLAlchemy <= 1.3
55
+ for key , value in kwargs .items ():
56
+ setattr (url , key , value )
57
+
58
+ return url
59
+
60
+
61
+ def _sa_url_query_setdefault (url , ** kwargs ):
62
+ query = dict (url .query )
63
+
64
+ for key , value in kwargs .items ():
65
+ query .setdefault (key , value )
66
+
67
+ return _sa_url_set (url , query = query )
68
+
69
+
43
70
def _make_table (db ):
44
71
def _make_table (* args , ** kwargs ):
45
72
if len (args ) > 1 and isinstance (args [1 ], db .Column ):
@@ -552,7 +579,7 @@ def get_engine(self):
552
579
return self ._engine
553
580
554
581
sa_url = make_url (uri )
555
- options = self .get_options (sa_url , echo )
582
+ sa_url , options = self .get_options (sa_url , echo )
556
583
self ._engine = rv = self ._sa .create_engine (sa_url , options )
557
584
558
585
if _record_queries (self ._app ):
@@ -566,8 +593,9 @@ def get_engine(self):
566
593
def get_options (self , sa_url , echo ):
567
594
options = {}
568
595
569
- self ._sa .apply_pool_defaults (self ._app , options )
570
- self ._sa .apply_driver_hacks (self ._app , sa_url , options )
596
+ options = self ._sa .apply_pool_defaults (self ._app , options )
597
+ sa_url , options = self ._sa .apply_driver_hacks (self ._app , sa_url , options )
598
+
571
599
if echo :
572
600
options ['echo' ] = echo
573
601
@@ -578,7 +606,7 @@ def get_options(self, sa_url, echo):
578
606
# Give options set in SQLAlchemy.__init__() ultimate priority
579
607
options .update (self ._sa ._engine_options )
580
608
581
- return options
609
+ return sa_url , options
582
610
583
611
584
612
def get_state (app ):
@@ -861,6 +889,11 @@ def shutdown_session(response_or_exc):
861
889
return response_or_exc
862
890
863
891
def apply_pool_defaults (self , app , options ):
892
+ """
893
+ .. versionchanged:: 2.5
894
+ Returns the ``options`` dict, for consistency with
895
+ :meth:`apply_driver_hacks`.
896
+ """
864
897
def _setdefault (optionkey , configkey ):
865
898
value = app .config [configkey ]
866
899
if value is not None :
@@ -869,6 +902,7 @@ def _setdefault(optionkey, configkey):
869
902
_setdefault ('pool_timeout' , 'SQLALCHEMY_POOL_TIMEOUT' )
870
903
_setdefault ('pool_recycle' , 'SQLALCHEMY_POOL_RECYCLE' )
871
904
_setdefault ('max_overflow' , 'SQLALCHEMY_MAX_OVERFLOW' )
905
+ return options
872
906
873
907
def apply_driver_hacks (self , app , sa_url , options ):
874
908
"""This method is called before engine creation and used to inject
@@ -879,9 +913,15 @@ def apply_driver_hacks(self, app, sa_url, options):
879
913
The default implementation provides some saner defaults for things
880
914
like pool sizes for MySQL and sqlite. Also it injects the setting of
881
915
`SQLALCHEMY_NATIVE_UNICODE`.
916
+
917
+ .. versionchanged:: 2.5
918
+ Returns ``(sa_url, options)``. SQLAlchemy 1.4 made the URL
919
+ immutable, so any changes to it must now be passed back up
920
+ to the original caller.
882
921
"""
883
922
if sa_url .drivername .startswith ('mysql' ):
884
- sa_url .query .setdefault ('charset' , 'utf8' )
923
+ sa_url = _sa_url_query_setdefault (sa_url , charset = "utf8" )
924
+
885
925
if sa_url .drivername != 'mysql+gaerdbms' :
886
926
options .setdefault ('pool_size' , 10 )
887
927
options .setdefault ('pool_recycle' , 7200 )
@@ -911,7 +951,9 @@ def apply_driver_hacks(self, app, sa_url, options):
911
951
912
952
# if it's not an in memory database we make the path absolute.
913
953
if not detected_in_memory :
914
- sa_url .database = os .path .join (app .root_path , sa_url .database )
954
+ sa_url = _sa_url_set (
955
+ sa_url , database = os .path .join (app .root_path , sa_url .database )
956
+ )
915
957
916
958
unu = app .config ['SQLALCHEMY_NATIVE_UNICODE' ]
917
959
if unu is None :
@@ -932,6 +974,8 @@ def apply_driver_hacks(self, app, sa_url, options):
932
974
DeprecationWarning
933
975
)
934
976
977
+ return sa_url , options
978
+
935
979
@property
936
980
def engine (self ):
937
981
"""Gives access to the engine. If the database configuration is bound
0 commit comments