11"""Wraps a SQLAlchemy scoped session"""
22
3- import os
4- import sqlite3
5-
63import sqlalchemy
74import sqlalchemy .orm
85
6+ from ._session_util import (
7+ _is_sqlite_url ,
8+ _assert_sqlite_file_exists ,
9+ _create_session ,
10+ )
11+
912
1013class Session :
1114 """Wraps a SQLAlchemy scoped session"""
@@ -23,61 +26,3 @@ def execute(self, statement):
2326
2427 def __getattr__ (self , attr ):
2528 return getattr (self ._session , attr )
26-
27-
28- def _is_sqlite_url (url ):
29- return url .startswith ("sqlite:///" )
30-
31-
32- def _assert_sqlite_file_exists (url ):
33- path = url [len ("sqlite:///" ):]
34- if not os .path .exists (path ):
35- raise RuntimeError (f"does not exist: { path } " )
36- if not os .path .isfile (path ):
37- raise RuntimeError (f"not a file: { path } " )
38-
39-
40- def _create_session (url , ** engine_kwargs ):
41- engine = _create_engine (url , ** engine_kwargs )
42- _setup_on_connect (engine )
43- return _create_scoped_session (engine )
44-
45-
46- def _create_engine (url , ** kwargs ):
47- try :
48- engine = sqlalchemy .create_engine (url , ** kwargs )
49- except sqlalchemy .exc .ArgumentError :
50- raise RuntimeError (f"invalid URL: { url } " ) from None
51-
52- engine .execution_options (autocommit = False )
53- return engine
54-
55-
56- def _setup_on_connect (engine ):
57- def connect (dbapi_connection , _ ):
58- _disable_auto_begin_commit (dbapi_connection )
59- if _is_sqlite_connection (dbapi_connection ):
60- _enable_sqlite_foreign_key_constraints (dbapi_connection )
61-
62- sqlalchemy .event .listen (engine , "connect" , connect )
63-
64-
65- def _create_scoped_session (engine ):
66- session_factory = sqlalchemy .orm .sessionmaker (bind = engine )
67- return sqlalchemy .orm .scoping .scoped_session (session_factory )
68-
69-
70- def _disable_auto_begin_commit (dbapi_connection ):
71- # Disable underlying API's own emitting of BEGIN and COMMIT so we can ourselves
72- # https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#serializable-isolation-savepoints-transactional-ddl
73- dbapi_connection .isolation_level = None
74-
75-
76- def _is_sqlite_connection (dbapi_connection ):
77- return isinstance (dbapi_connection , sqlite3 .Connection )
78-
79-
80- def _enable_sqlite_foreign_key_constraints (dbapi_connection ):
81- cursor = dbapi_connection .cursor ()
82- cursor .execute ("PRAGMA foreign_keys=ON" )
83- cursor .close ()
0 commit comments