Skip to content

Commit 55ba0f0

Browse files
API: SQL class definitions renaming
- renaming of PandasSQLAlchemy to SQLDatabase and PandasSQLTable to SQLTable - renaming of SQLDatabase.read_sql to read_query (to be consistent with read_query/read_table) - legacy -> fallback
1 parent 2b389b4 commit 55ba0f0

File tree

2 files changed

+177
-51
lines changed

2 files changed

+177
-51
lines changed

pandas/io/sql.py

+156-30
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def read_sql_table(table_name, con, schema=None, index_col=None,
315315
except sqlalchemy.exc.InvalidRequestError:
316316
raise ValueError("Table %s not found" % table_name)
317317

318-
pandas_sql = PandasSQLAlchemy(con, meta=meta)
318+
pandas_sql = SQLDatabase(con, meta=meta)
319319
table = pandas_sql.read_table(
320320
table_name, index_col=index_col, coerce_float=coerce_float,
321321
parse_dates=parse_dates, columns=columns)
@@ -374,7 +374,7 @@ def read_sql_query(sql, con, index_col=None, coerce_float=True, params=None,
374374
375375
"""
376376
pandas_sql = pandasSQL_builder(con)
377-
return pandas_sql.read_sql(
377+
return pandas_sql.read_query(
378378
sql, index_col=index_col, params=params, coerce_float=coerce_float,
379379
parse_dates=parse_dates)
380380

@@ -388,7 +388,7 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
388388
----------
389389
sql : string
390390
SQL query to be executed or database table name.
391-
con : SQLAlchemy engine or DBAPI2 connection (legacy mode)
391+
con : SQLAlchemy engine or DBAPI2 connection (fallback mode)
392392
Using SQLAlchemy makes it possible to use any DB supported by that
393393
library.
394394
If a DBAPI2 object, only sqlite3 is supported.
@@ -435,8 +435,8 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
435435
"""
436436
pandas_sql = pandasSQL_builder(con)
437437

438-
if isinstance(pandas_sql, PandasSQLLegacy):
439-
return pandas_sql.read_sql(
438+
if isinstance(pandas_sql, SQLiteDatabase):
439+
return pandas_sql.read_query(
440440
sql, index_col=index_col, params=params,
441441
coerce_float=coerce_float, parse_dates=parse_dates)
442442

@@ -451,7 +451,7 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
451451
sql, index_col=index_col, coerce_float=coerce_float,
452452
parse_dates=parse_dates, columns=columns)
453453
else:
454-
return pandas_sql.read_sql(
454+
return pandas_sql.read_query(
455455
sql, index_col=index_col, params=params,
456456
coerce_float=coerce_float, parse_dates=parse_dates)
457457

@@ -551,14 +551,14 @@ def pandasSQL_builder(con, flavor=None, schema=None, meta=None,
551551
# When support for DBAPI connections is removed,
552552
# is_cursor should not be necessary.
553553
if _is_sqlalchemy_engine(con):
554-
return PandasSQLAlchemy(con, schema=schema, meta=meta)
554+
return SQLDatabase(con, schema=schema, meta=meta)
555555
else:
556556
if flavor == 'mysql':
557557
warnings.warn(_MYSQL_WARNING, FutureWarning)
558-
return PandasSQLLegacy(con, flavor, is_cursor=is_cursor)
558+
return SQLiteDatabase(con, flavor, is_cursor=is_cursor)
559559

560560

561-
class PandasSQLTable(PandasObject):
561+
class SQLTable(PandasObject):
562562
"""
563563
For mapping Pandas tables to SQL tables.
564564
Uses fact that table is reflected by SQLAlchemy to
@@ -890,10 +890,24 @@ def to_sql(self, *args, **kwargs):
890890
" or connection+sql flavor")
891891

892892

893-
class PandasSQLAlchemy(PandasSQL):
893+
class SQLDatabase(PandasSQL):
894894
"""
895895
This class enables convertion between DataFrame and SQL databases
896896
using SQLAlchemy to handle DataBase abstraction
897+
898+
Parameters
899+
----------
900+
engine : SQLAlchemy engine
901+
Engine to connect with the database. Using SQLAlchemy makes it possible to use any DB supported by that
902+
library.
903+
schema : string, default None
904+
Name of SQL schema in database to write to (if database flavor
905+
supports this). If None, use default schema (default).
906+
meta : SQLAlchemy MetaData object, default None
907+
If provided, this MetaData object is used instead of a newly
908+
created. This allows to specify database flavor specific
909+
arguments in the MetaData object.
910+
897911
"""
898912

899913
def __init__(self, engine, schema=None, meta=None):
@@ -913,13 +927,86 @@ def execute(self, *args, **kwargs):
913927

914928
def read_table(self, table_name, index_col=None, coerce_float=True,
915929
parse_dates=None, columns=None, schema=None):
916-
table = PandasSQLTable(
917-
table_name, self, index=index_col, schema=schema)
930+
"""Read SQL database table into a DataFrame.
931+
932+
Parameters
933+
----------
934+
table_name : string
935+
Name of SQL table in database
936+
index_col : string, optional
937+
Column to set as index
938+
coerce_float : boolean, default True
939+
Attempt to convert values to non-string, non-numeric objects (like
940+
decimal.Decimal) to floating point. Can result in loss of Precision.
941+
parse_dates : list or dict
942+
- List of column names to parse as dates
943+
- Dict of ``{column_name: format string}`` where format string is
944+
strftime compatible in case of parsing string times or is one of
945+
(D, s, ns, ms, us) in case of parsing integer timestamps
946+
- Dict of ``{column_name: arg dict}``, where the arg dict corresponds
947+
to the keyword arguments of :func:`pandas.to_datetime`
948+
Especially useful with databases without native Datetime support,
949+
such as SQLite
950+
columns : list
951+
List of column names to select from sql table
952+
schema : string, default None
953+
Name of SQL schema in database to query (if database flavor
954+
supports this). If specified, this overwrites the default
955+
schema of the SQLDatabase object.
956+
957+
Returns
958+
-------
959+
DataFrame
960+
961+
See also
962+
--------
963+
pandas.read_sql_table
964+
SQLDatabase.read_query
965+
966+
"""
967+
table = SQLTable(table_name, self, index=index_col, schema=schema)
918968
return table.read(coerce_float=coerce_float,
919969
parse_dates=parse_dates, columns=columns)
920-
921-
def read_sql(self, sql, index_col=None, coerce_float=True,
970+
971+
def read_query(self, sql, index_col=None, coerce_float=True,
922972
parse_dates=None, params=None):
973+
"""Read SQL query into a DataFrame.
974+
975+
Parameters
976+
----------
977+
sql : string
978+
SQL query to be executed
979+
index_col : string, optional
980+
Column name to use as index for the returned DataFrame object.
981+
coerce_float : boolean, default True
982+
Attempt to convert values to non-string, non-numeric objects (like
983+
decimal.Decimal) to floating point, useful for SQL result sets
984+
params : list, tuple or dict, optional
985+
List of parameters to pass to execute method. The syntax used
986+
to pass parameters is database driver dependent. Check your
987+
database driver documentation for which of the five syntax styles,
988+
described in PEP 249's paramstyle, is supported.
989+
Eg. for psycopg2, uses %(name)s so use params={'name' : 'value'}
990+
parse_dates : list or dict
991+
- List of column names to parse as dates
992+
- Dict of ``{column_name: format string}`` where format string is
993+
strftime compatible in case of parsing string times or is one of
994+
(D, s, ns, ms, us) in case of parsing integer timestamps
995+
- Dict of ``{column_name: arg dict}``, where the arg dict corresponds
996+
to the keyword arguments of :func:`pandas.to_datetime`
997+
Especially useful with databases without native Datetime support,
998+
such as SQLite
999+
1000+
Returns
1001+
-------
1002+
DataFrame
1003+
1004+
See also
1005+
--------
1006+
read_sql_table : Read SQL database table into a DataFrame
1007+
read_sql
1008+
1009+
"""
9231010
args = _convert_params(sql, params)
9241011

9251012
result = self.execute(*args)
@@ -935,12 +1022,41 @@ def read_sql(self, sql, index_col=None, coerce_float=True,
9351022
data_frame.set_index(index_col, inplace=True)
9361023

9371024
return data_frame
1025+
1026+
read_sql = read_query
9381027

9391028
def to_sql(self, frame, name, if_exists='fail', index=True,
9401029
index_label=None, schema=None, chunksize=None):
941-
table = PandasSQLTable(
942-
name, self, frame=frame, index=index, if_exists=if_exists,
943-
index_label=index_label, schema=schema)
1030+
"""
1031+
Write records stored in a DataFrame to a SQL database.
1032+
1033+
Parameters
1034+
----------
1035+
frame : DataFrame
1036+
name : string
1037+
Name of SQL table
1038+
if_exists : {'fail', 'replace', 'append'}, default 'fail'
1039+
- fail: If table exists, do nothing.
1040+
- replace: If table exists, drop it, recreate it, and insert data.
1041+
- append: If table exists, insert data. Create if does not exist.
1042+
index : boolean, default True
1043+
Write DataFrame index as a column
1044+
index_label : string or sequence, default None
1045+
Column label for index column(s). If None is given (default) and
1046+
`index` is True, then the index names are used.
1047+
A sequence should be given if the DataFrame uses MultiIndex.
1048+
schema : string, default None
1049+
Name of SQL schema in database to write to (if database flavor
1050+
supports this). If specified, this overwrites the default
1051+
schema of the SQLDatabase object.
1052+
chunksize : int, default None
1053+
If not None, then rows will be written in batches of this size at a
1054+
time. If None, all rows will be written at once.
1055+
1056+
"""
1057+
table = SQLTable(name, self, frame=frame, index=index,
1058+
if_exists=if_exists, index_label=index_label,
1059+
schema=schema)
9441060
table.create()
9451061
table.insert(chunksize)
9461062
# check for potentially case sensitivity issues (GH7815)
@@ -972,8 +1088,7 @@ def drop_table(self, table_name, schema=None):
9721088
self.meta.clear()
9731089

9741090
def _create_sql_schema(self, frame, table_name, keys=None):
975-
table = PandasSQLTable(table_name, self, frame=frame, index=False,
976-
keys=keys)
1091+
table = SQLTable(table_name, self, frame=frame, index=False, keys=keys)
9771092
return str(table.sql_schema())
9781093

9791094

@@ -1032,9 +1147,9 @@ def _create_sql_schema(self, frame, table_name, keys=None):
10321147
"underscores.")
10331148

10341149

1035-
class PandasSQLTableLegacy(PandasSQLTable):
1150+
class SQLiteTable(SQLTable):
10361151
"""
1037-
Patch the PandasSQLTable for legacy support.
1152+
Patch the SQLTable for fallback support.
10381153
Instead of a table variable just use the Create Table statement.
10391154
"""
10401155

@@ -1135,7 +1250,19 @@ def _sql_type_name(self, col):
11351250
return _SQL_TYPES[pytype_name][self.pd_sql.flavor]
11361251

11371252

1138-
class PandasSQLLegacy(PandasSQL):
1253+
class SQLiteDatabase(PandasSQL):
1254+
"""
1255+
Version of SQLDatabase to support sqlite connections (fallback without
1256+
sqlalchemy). This should only be used internally.
1257+
1258+
For now still supports `flavor` argument to deal with 'mysql' database
1259+
for backwards compatibility, but this will be removed in future versions.
1260+
1261+
Parameters
1262+
----------
1263+
con : sqlite connection object
1264+
1265+
"""
11391266

11401267
def __init__(self, con, flavor, is_cursor=False):
11411268
self.is_cursor = is_cursor
@@ -1180,7 +1307,7 @@ def execute(self, *args, **kwargs):
11801307
ex = DatabaseError("Execution failed on sql '%s': %s" % (args[0], exc))
11811308
raise_with_traceback(ex)
11821309

1183-
def read_sql(self, sql, index_col=None, coerce_float=True, params=None,
1310+
def read_query(self, sql, index_col=None, coerce_float=True, params=None,
11841311
parse_dates=None):
11851312
args = _convert_params(sql, params)
11861313
cursor = self.execute(*args)
@@ -1196,7 +1323,7 @@ def read_sql(self, sql, index_col=None, coerce_float=True, params=None,
11961323
if index_col is not None:
11971324
data_frame.set_index(index_col, inplace=True)
11981325
return data_frame
1199-
1326+
12001327
def _fetchall_as_list(self, cur):
12011328
result = cur.fetchall()
12021329
if not isinstance(result, list):
@@ -1230,9 +1357,8 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
12301357
size at a time. If None, all rows will be written at once.
12311358
12321359
"""
1233-
table = PandasSQLTableLegacy(
1234-
name, self, frame=frame, index=index, if_exists=if_exists,
1235-
index_label=index_label)
1360+
table = SQLiteTable(name, self, frame=frame, index=index,
1361+
if_exists=if_exists, index_label=index_label)
12361362
table.create()
12371363
table.insert(chunksize)
12381364

@@ -1246,15 +1372,15 @@ def has_table(self, name, schema=None):
12461372
return len(self.execute(query).fetchall()) > 0
12471373

12481374
def get_table(self, table_name, schema=None):
1249-
return None # not supported in Legacy mode
1375+
return None # not supported in fallback mode
12501376

12511377
def drop_table(self, name, schema=None):
12521378
drop_sql = "DROP TABLE %s" % name
12531379
self.execute(drop_sql)
12541380

12551381
def _create_sql_schema(self, frame, table_name, keys=None):
1256-
table = PandasSQLTableLegacy(table_name, self, frame=frame,
1257-
index=False, keys=keys)
1382+
table = SQLiteTable(table_name, self, frame=frame, index=False,
1383+
keys=keys)
12581384
return str(table.sql_schema())
12591385

12601386

0 commit comments

Comments
 (0)