Skip to content

Commit 1f62283

Browse files
author
Kareem Zidane
committed
factor out session utility functions
1 parent 32db777 commit 1f62283

File tree

2 files changed

+69
-61
lines changed

2 files changed

+69
-61
lines changed

src/cs50/_session.py

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""Wraps a SQLAlchemy scoped session"""
22

3-
import os
4-
import sqlite3
5-
63
import sqlalchemy
74
import sqlalchemy.orm
85

6+
from ._session_util import (
7+
_is_sqlite_url,
8+
_assert_sqlite_file_exists,
9+
_create_session,
10+
)
11+
912

1013
class 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()

src/cs50/_session_util.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""Utility functions used by _session.py"""
2+
3+
import os
4+
import sqlite3
5+
6+
import sqlalchemy
7+
8+
def _is_sqlite_url(url):
9+
return url.startswith("sqlite:///")
10+
11+
12+
def _assert_sqlite_file_exists(url):
13+
path = url[len("sqlite:///"):]
14+
if not os.path.exists(path):
15+
raise RuntimeError(f"does not exist: {path}")
16+
if not os.path.isfile(path):
17+
raise RuntimeError(f"not a file: {path}")
18+
19+
20+
def _create_session(url, **engine_kwargs):
21+
engine = _create_engine(url, **engine_kwargs)
22+
_setup_on_connect(engine)
23+
return _create_scoped_session(engine)
24+
25+
26+
def _create_engine(url, **kwargs):
27+
try:
28+
engine = sqlalchemy.create_engine(url, **kwargs)
29+
except sqlalchemy.exc.ArgumentError:
30+
raise RuntimeError(f"invalid URL: {url}") from None
31+
32+
engine.execution_options(autocommit=False)
33+
return engine
34+
35+
36+
def _setup_on_connect(engine):
37+
def connect(dbapi_connection, _):
38+
_disable_auto_begin_commit(dbapi_connection)
39+
if _is_sqlite_connection(dbapi_connection):
40+
_enable_sqlite_foreign_key_constraints(dbapi_connection)
41+
42+
sqlalchemy.event.listen(engine, "connect", connect)
43+
44+
45+
def _create_scoped_session(engine):
46+
session_factory = sqlalchemy.orm.sessionmaker(bind=engine)
47+
return sqlalchemy.orm.scoping.scoped_session(session_factory)
48+
49+
50+
def _disable_auto_begin_commit(dbapi_connection):
51+
# Disable underlying API's own emitting of BEGIN and COMMIT so we can ourselves
52+
# https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#serializable-isolation-savepoints-transactional-ddl
53+
dbapi_connection.isolation_level = None
54+
55+
56+
def _is_sqlite_connection(dbapi_connection):
57+
return isinstance(dbapi_connection, sqlite3.Connection)
58+
59+
60+
def _enable_sqlite_foreign_key_constraints(dbapi_connection):
61+
cursor = dbapi_connection.cursor()
62+
cursor.execute("PRAGMA foreign_keys=ON")
63+
cursor.close()

0 commit comments

Comments
 (0)