From 62b4d6405c21cfd74b4e9e00c298648d6b2e2e82 Mon Sep 17 00:00:00 2001 From: Guillaume Poulin Date: Wed, 26 Mar 2014 10:22:05 +0800 Subject: [PATCH 1/2] Fix SQLLegacy to allow parameters as mapping --- pandas/io/sql.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index fa89cf488125a..ac90555526a5e 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -31,7 +31,10 @@ def _convert_params(sql, params): """convert sql and params args to DBAPI2.0 compliant format""" args = [sql] if params is not None: - args += list(params) + if hasattr(params, 'keys'): # test if params is a mapping + args += [params] + else: + args += [list(params)] return args @@ -200,7 +203,7 @@ def read_sql(sql, con, index_col=None, flavor='sqlite', coerce_float=True, Attempt to convert values to non-string, non-numeric objects (like decimal.Decimal) to floating point, useful for SQL result sets cur : depreciated, cursor is obtained from connection - params : list or tuple, optional + params : list, tuple or dict, optional List of parameters to pass to execute method. parse_dates : list or dict - List of column names to parse as dates From 4cf59fe6952f2d38bc016e3324856dd26e87c84b Mon Sep 17 00:00:00 2001 From: Guillaume Poulin Date: Sun, 30 Mar 2014 19:08:22 +0800 Subject: [PATCH 2/2] Add SQL read_parameters tests --- pandas/io/tests/test_sql.py | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pandas/io/tests/test_sql.py b/pandas/io/tests/test_sql.py index 2f9323e50c9e2..80da7ae6bf391 100644 --- a/pandas/io/tests/test_sql.py +++ b/pandas/io/tests/test_sql.py @@ -95,6 +95,24 @@ INSERT INTO types_test_data VALUES(%s, %s, %s, %s, %s, %s, %s, %s) """ + }, + 'read_parameters': { + 'sqlite': "SELECT * FROM iris WHERE Name=? AND SepalLength=?", + 'mysql': 'SELECT * FROM iris WHERE `Name`="%s" AND `SepalLength`=%s', + 'postgresql': 'SELECT * FROM iris WHERE "Name"=%s AND "SepalLength"=%s' + }, + 'read_named_parameters': { + 'sqlite': """ + SELECT * FROM iris WHERE Name=:name AND SepalLength=:length + """, + 'mysql': """ + SELECT * FROM iris WHERE + `Name`="%(name)s" AND `SepalLength`=%(length)s + """, + 'postgresql': """ + SELECT * FROM iris WHERE + "Name"=%(name)s AND "SepalLength"=%(length)s + """ } } @@ -168,6 +186,18 @@ def _read_sql_iris(self): iris_frame = self.pandasSQL.read_sql("SELECT * FROM iris") self._check_iris_loaded_frame(iris_frame) + def _read_sql_iris_parameter(self): + query = SQL_STRINGS['read_parameters'][self.flavor] + params = ['Iris-setosa', 5.1] + iris_frame = self.pandasSQL.read_sql(query, params=params) + self._check_iris_loaded_frame(iris_frame) + + def _read_sql_iris_named_parameter(self): + query = SQL_STRINGS['read_named_parameters'][self.flavor] + params = {'name': 'Iris-setosa', 'length': 5.1} + iris_frame = self.pandasSQL.read_sql(query, params=params) + self._check_iris_loaded_frame(iris_frame) + def _to_sql(self): self.drop_table('test_frame1') @@ -491,6 +521,12 @@ class _TestSQLAlchemy(PandasSQLTest): def test_read_sql(self): self._read_sql_iris() + def test_read_sql_parameter(self): + self._read_sql_iris_parameter() + + def test_read_sql_named_parameter(self): + self._read_sql_iris_named_parameter() + def test_to_sql(self): self._to_sql() @@ -703,6 +739,12 @@ def test_invalid_flavor(self): def test_read_sql(self): self._read_sql_iris() + def test_read_sql_parameter(self): + self._read_sql_iris_parameter() + + def test_read_sql_named_parameter(self): + self._read_sql_iris_named_parameter() + def test_to_sql(self): self._to_sql()