From 5d8006478bae052ba4db013b653992bb09ae50a7 Mon Sep 17 00:00:00 2001 From: "David J. Malan" <malan@harvard.edu> Date: Sat, 27 May 2017 10:45:22 -0400 Subject: [PATCH 1/5] disabled logging, removed temporary prints --- tests/sqltests.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/sqltests.py b/tests/sqltests.py index 8e518b4..5d3e336 100644 --- a/tests/sqltests.py +++ b/tests/sqltests.py @@ -1,8 +1,10 @@ -from cs50.sql import SQL +import logging import sys import unittest import warnings +from cs50.sql import SQL + class SQLTests(unittest.TestCase): def multi_inserts_enabled(self): return True @@ -15,11 +17,6 @@ def test_delete_returns_affected_rows(self): ] for row in rows: self.db.execute("INSERT INTO cs50(val) VALUES(:val);", val=row["val"]) - - print(self.db.execute("DELETE FROM cs50 WHERE id = :id", id=rows[0]["id"])) - print(self.db.execute("SELECT * FROM cs50")) - return - self.assertEqual(self.db.execute("DELETE FROM cs50 WHERE id = :id", id=rows[0]["id"]), 1) self.assertEqual(self.db.execute("DELETE FROM cs50 WHERE id = :a or id = :b", a=rows[1]["id"], b=rows[2]["id"]), 2) self.assertEqual(self.db.execute("DELETE FROM cs50 WHERE id = -50"), 0) @@ -122,5 +119,5 @@ def multi_inserts_enabled(self): unittest.TestLoader().loadTestsFromTestCase(MySQLTests), unittest.TestLoader().loadTestsFromTestCase(PostgresTests) ]) - + logging.getLogger("cs50.sql").disabled = True sys.exit(not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful()) From 3faee867b56785c61905e5e634b1ae6cc56af039 Mon Sep 17 00:00:00 2001 From: Kareem Zidane <kzidane@cs50.harvard.edu> Date: Sat, 27 May 2017 22:46:20 +0200 Subject: [PATCH 2/5] deploying once after tests succeed --- .travis.yml | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index a20df42..2a946b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,18 +15,23 @@ before_script: - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' - psql -c 'create database test;' -U postgres script: python tests/sqltests.py -deploy: -- provider: script - script: 'curl --fail --data "{ \"tag_name\": \"v$(python setup.py --version)\", - \"target_commitish\": \"$TRAVIS_COMMIT\", \"name\": \"v$(python setup.py --version)\" - }" --user bot50:$GITHUB_TOKEN https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases' - on: - branch: master -- provider: pypi - user: "$PYPI_USERNAME" - password: "$PYPI_PASSWORD" - on: - branch: master +jobs: + include: + - stage: deploy + python: '3.4' + script: skip + deploy: + - provider: script + script: 'curl --fail --data "{ \"tag_name\": \"v$(python setup.py --version)\", + \"target_commitish\": \"$TRAVIS_COMMIT\", \"name\": \"v$(python setup.py --version)\" + }" --user bot50:$GITHUB_TOKEN https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases' + on: + branch: master + - provider: pypi + user: "$PYPI_USERNAME" + password: "$PYPI_PASSWORD" + on: + branch: master notifications: slack: secure: lJklhcBVjDT6KzUNa3RFHXdXSeH7ytuuGrkZ5ZcR72CXMoTf2pMJTzPwRLWOp6lCSdDC9Y8MWLrcg/e33dJga4Jlp9alOmWqeqesaFjfee4st8vAsgNbv8/RajPH1gD2bnkt8oIwUzdHItdb5AucKFYjbH2g0d8ndoqYqUeBLrnsT1AP5G/Vi9OHC9OWNpR0FKaZIJE0Wt52vkPMH3sV2mFeIskByPB+56U5y547mualKxn61IVR/dhYBEtZQJuSvnwKHPOn9Pkk7cCa+SSSeTJ4w5LboY8T17otaYNauXo46i1bKIoGiBcCcrJyQHHiPQmcq/YU540MC5Wzt9YXUycmJzRi347oyQeDee27wV3XJlWMXuuhbtJiKCFny7BTQ160VATlj/dbwIzN99Ra6/BtTumv/6LyTdKIuVjdAkcN8dtdDW1nlrQ29zuPNCcXXzJ7zX7kQaOCUV1c2OrsbiH/0fE9nknUORn97txqhlYVi0QMS7764wFo6kg0vpmFQRkkQySsJl+TmgcZ01AlsJc2EMMWVuaj9Af9JU4/4yalqDiXIh1fOYYUZnLfOfWS+MsnI+/oLfqJFyMbrsQQTIjs+kTzbiEdhd2R4EZgusU/xRFWokS2NAvahexrRhRQ6tpAI+LezPrkNOR3aHiykBf+P9BkUa0wPp6V2Ayc6q0= From fdfbd4bcfb271bb5ac1caf7a168860625d050aec Mon Sep 17 00:00:00 2001 From: Kareem Zidane <kzidane@cs50.harvard.edu> Date: Sat, 27 May 2017 22:58:26 +0200 Subject: [PATCH 3/5] skipped install and before_script in deploy stage --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a946b4..b8504fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,8 @@ jobs: include: - stage: deploy python: '3.4' + install: skip + before_script: skip script: skip deploy: - provider: script From 24634ad9b4c678042b2424ce9f951689825d7e32 Mon Sep 17 00:00:00 2001 From: "David J. Malan" <malan@harvard.edu> Date: Thu, 6 Jul 2017 09:11:28 -0400 Subject: [PATCH 4/5] fixed get_backend_name bug --- src/cs50/sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cs50/sql.py b/src/cs50/sql.py index bfa79f0..5d8e345 100644 --- a/src/cs50/sql.py +++ b/src/cs50/sql.py @@ -123,7 +123,7 @@ def process(value): # if INSERT, return primary key value for a newly inserted row elif re.search(r"^\s*INSERT\s+", statement, re.I): - if self.engine.url.get_backend_name() == "postgresql": + if self.engine.url.get_backend_name() in ["postgres", "postgresql"]: result = self.engine.execute(sqlalchemy.text("SELECT LASTVAL()")) return result.first()[0] else: From 893cb90efe3509cfcf9ad0ab83463c63c89432b9 Mon Sep 17 00:00:00 2001 From: "David J. Malan" <malan@harvard.edu> Date: Mon, 3 Jul 2017 18:28:54 +0000 Subject: [PATCH 5/5] removed support for multiple statements so all behavior is well-defined --- setup.py | 4 ++-- src/cs50/sql.py | 5 +++++ tests/sqltests.py | 7 +++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 8440a86..8e6ee91 100644 --- a/setup.py +++ b/setup.py @@ -10,11 +10,11 @@ "Topic :: Software Development :: Libraries :: Python Modules" ], description="CS50 library for Python", - install_requires=["SQLAlchemy"], + install_requires=["SQLAlchemy", "sqlparse"], keywords="cs50", name="cs50", package_dir={"": "src"}, packages=["cs50"], url="https://github.com/cs50/python-cs50", - version="2.0.0" + version="2.1.0" ) diff --git a/src/cs50/sql.py b/src/cs50/sql.py index 5d8e345..4cfbd78 100644 --- a/src/cs50/sql.py +++ b/src/cs50/sql.py @@ -3,6 +3,7 @@ import logging import re import sqlalchemy +import sqlparse import sys import warnings @@ -86,6 +87,10 @@ def process(value): else: return process(value) + # allow only one statement at a time + if len(sqlparse.split(text)) > 1: + raise RuntimeError("too many statements at once") + # raise exceptions for warnings warnings.filterwarnings("error") diff --git a/tests/sqltests.py b/tests/sqltests.py index 5d3e336..c1f3c0e 100644 --- a/tests/sqltests.py +++ b/tests/sqltests.py @@ -6,8 +6,9 @@ from cs50.sql import SQL class SQLTests(unittest.TestCase): - def multi_inserts_enabled(self): - return True + + def test_multiple_statements(self): + self.assertRaises(RuntimeError, self.db.execute, "INSERT INTO cs50(val) VALUES('baz'); INSERT INTO cs50(val) VALUES('qux')") def test_delete_returns_affected_rows(self): rows = [ @@ -24,8 +25,6 @@ def test_delete_returns_affected_rows(self): def test_insert_returns_last_row_id(self): self.assertEqual(self.db.execute("INSERT INTO cs50(val) VALUES('foo')"), 1) self.assertEqual(self.db.execute("INSERT INTO cs50(val) VALUES('bar')"), 2) - if self.multi_inserts_enabled(): - self.assertEqual(self.db.execute("INSERT INTO cs50(val) VALUES('baz'); INSERT INTO cs50(val) VALUES('qux')"), 4) def test_select_all(self): self.assertEqual(self.db.execute("SELECT * FROM cs50"), [])