Skip to content

Commit 5472755

Browse files
committed
added lazy loading of cs50.SQL, added comments
1 parent d7ec5e6 commit 5472755

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

src/__init__.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,24 @@
1+
import imp
2+
import sys
3+
14
from .cs50 import *
2-
from .sql import *
5+
6+
class CustomImporter(object):
7+
"""
8+
Import cs50.SQL lazily so that rest of library can be used without SQLAlchemy installed.
9+
10+
https://docs.python.org/3/library/imp.html
11+
http://xion.org.pl/2012/05/06/hacking-python-imports/
12+
http://dangerontheranger.blogspot.com/2012/07/how-to-use-sysmetapath-with-python.html
13+
"""
14+
def find_module(self, fullname, path=None):
15+
if fullname == "cs50.SQL":
16+
return self
17+
return None
18+
def load_module(self, name):
19+
if name in sys.modules:
20+
return sys.modules[name]
21+
from .sql import SQL
22+
sys.modules[name] = SQL
23+
return SQL
24+
sys.meta_path.append(CustomImporter())

src/sql.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,52 @@
11
import sqlalchemy
22

33
class SQL(object):
4-
"""TODO"""
4+
"""Wrap SQLAlchemy to provide a simple SQL API."""
55

66
def __init__(self, url):
7-
"""TODO"""
7+
"""
8+
Create instance of sqlalchemy.engine.Engine.
9+
10+
URL should be a string that indicates database dialect and connection arguments.
11+
12+
http://docs.sqlalchemy.org/en/latest/core/engines.html#sqlalchemy.create_engine
13+
"""
814
try:
915
self.engine = sqlalchemy.create_engine(url)
1016
except Exception as e:
1117
raise RuntimeError(e)
1218

1319
def execute(self, text, *multiparams, **params):
14-
"""TODO"""
20+
"""
21+
Execute a SQL statement.
22+
"""
1523
try:
1624

25+
# bind parameters before statement reaches database, so that bound parameters appear in exceptions
1726
# http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.text
1827
# https://groups.google.com/forum/#!topic/sqlalchemy/FfLwKT1yQlg
1928
# http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute
2029
# http://docs.sqlalchemy.org/en/latest/faq/sqlexpressions.html#how-do-i-render-sql-expressions-as-strings-possibly-with-bound-parameters-inlined
2130
statement = sqlalchemy.text(text).bindparams(*multiparams, **params)
2231
result = self.engine.execute(str(statement.compile(compile_kwargs={"literal_binds": True})))
2332

24-
# SELECT
33+
# if SELECT (or INSERT with RETURNING), return result set as list of dict objects
2534
if result.returns_rows:
2635
rows = result.fetchall()
2736
return [dict(row) for row in rows]
2837

29-
# INSERT
38+
# if INSERT, return primary key value for a newly inserted row
3039
elif result.lastrowid is not None:
3140
return result.lastrowid
3241

33-
# DELETE, UPDATE
42+
# if DELETE or UPDATE, return number of rows matched
3443
else:
3544
return result.rowcount
3645

46+
# if constraint violated, return None
3747
except sqlalchemy.exc.IntegrityError:
3848
return None
3949

50+
# else raise error
4051
except Exception as e:
4152
raise RuntimeError(e)
42-
43-

0 commit comments

Comments
 (0)