Skip to content

Commit 46aeb6b

Browse files
authoredFeb 25, 2017
Merge pull request #5 from cs50/import-hooking
adds lazy loading of cs50.SQL
2 parents 5f87e64 + bbcff41 commit 46aeb6b

File tree

7 files changed

+48
-13
lines changed

7 files changed

+48
-13
lines changed
 

‎Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ DESCRIPTION = CS50 Library for Python
33
MAINTAINER = CS50 <sysadmins@cs50.harvard.edu>
44
NAME = python-cs50
55
OLD_NAME = lib50-python
6-
VERSION = 1.2.4
6+
VERSION = 1.3.0
77

88
.PHONY: bash
99
bash:

‎README.md

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ Requires [Docker Engine](https://docs.docker.com/engine/installation/).
3131
## TODO
3232

3333
* Add install target to Makefile.
34-
* Add comments.
3534
* Conditionally install for Python 2 and/or Python 3.
3635
* Add targets for `pacman`, `rpm`.
3736
* Add tests.

‎after-install.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/bash
22

3+
pip2 install SQLAlchemy
34
pip3 install SQLAlchemy
45

56
chmod -R a+rX /usr/lib/python2.7/dist-packages/cs50

‎src/__init__.py

+23-1
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

+17-8
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 (or INSERT without RETURNING), 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-

‎test/python2.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import cs50
22

3+
from cs50 import SQL
4+
35
l = cs50.get_long()
46
print(l)

‎test/python3.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import cs50
2+
from cs50 import SQL
3+
4+
i = cs50.get_int()
5+
print(i)
26

3-
l = cs50.get_long()
4-
print(l)

0 commit comments

Comments
 (0)
Please sign in to comment.