@@ -41,6 +41,24 @@ class DatabaseError(IOError):
41
41
_SQLALCHEMY_INSTALLED = None
42
42
43
43
44
+ def _validate_flavor_parameter (flavor ):
45
+ """
46
+ Checks whether a database 'flavor' was specified.
47
+ If not None, produces FutureWarning if 'sqlite' and
48
+ raises a ValueError if anything else.
49
+ """
50
+ if flavor is not None :
51
+ if flavor == 'sqlite' :
52
+ warnings .warn ("the 'flavor' parameter is deprecated "
53
+ "and will be removed in a future version, "
54
+ "as 'sqlite' is the only supported option "
55
+ "when SQLAlchemy is not installed." ,
56
+ FutureWarning , stacklevel = 2 )
57
+ else :
58
+ raise ValueError ("database flavor {flavor} is not "
59
+ "supported" .format (flavor = flavor ))
60
+
61
+
44
62
def _is_sqlalchemy_connectable (con ):
45
63
global _SQLALCHEMY_INSTALLED
46
64
if _SQLALCHEMY_INSTALLED is None :
@@ -517,7 +535,7 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
517
535
chunksize = chunksize )
518
536
519
537
520
- def to_sql (frame , name , con , flavor = 'sqlite' , schema = None , if_exists = 'fail' ,
538
+ def to_sql (frame , name , con , flavor = None , schema = None , if_exists = 'fail' ,
521
539
index = True , index_label = None , chunksize = None , dtype = None ):
522
540
"""
523
541
Write records stored in a DataFrame to a SQL database.
@@ -532,10 +550,8 @@ def to_sql(frame, name, con, flavor='sqlite', schema=None, if_exists='fail',
532
550
Using SQLAlchemy makes it possible to use any DB supported by that
533
551
library.
534
552
If a DBAPI2 object, only sqlite3 is supported.
535
- flavor : {'sqlite', 'mysql'}, default 'sqlite'
536
- The flavor of SQL to use. Ignored when using SQLAlchemy connectable.
537
- 'mysql' is deprecated and will be removed in future versions, but it
538
- will be further supported through SQLAlchemy connectables.
553
+ flavor : 'sqlite', default None
554
+ DEPRECATED: this parameter will be removed in a future version
539
555
schema : string, default None
540
556
Name of SQL schema in database to write to (if database flavor
541
557
supports this). If None, use default schema (default).
@@ -573,7 +589,7 @@ def to_sql(frame, name, con, flavor='sqlite', schema=None, if_exists='fail',
573
589
chunksize = chunksize , dtype = dtype )
574
590
575
591
576
- def has_table (table_name , con , flavor = 'sqlite' , schema = None ):
592
+ def has_table (table_name , con , flavor = None , schema = None ):
577
593
"""
578
594
Check if DataBase has named table.
579
595
@@ -585,10 +601,8 @@ def has_table(table_name, con, flavor='sqlite', schema=None):
585
601
Using SQLAlchemy makes it possible to use any DB supported by that
586
602
library.
587
603
If a DBAPI2 object, only sqlite3 is supported.
588
- flavor: {'sqlite', 'mysql'}, default 'sqlite'
589
- The flavor of SQL to use. Ignored when using SQLAlchemy connectable.
590
- 'mysql' is deprecated and will be removed in future versions, but it
591
- will be further supported through SQLAlchemy connectables.
604
+ flavor : 'sqlite', default None
605
+ DEPRECATED: this parameter will be removed in a future version
592
606
schema : string, default None
593
607
Name of SQL schema in database to write to (if database flavor supports
594
608
this). If None, use default schema (default).
@@ -603,12 +617,6 @@ def has_table(table_name, con, flavor='sqlite', schema=None):
603
617
table_exists = has_table
604
618
605
619
606
- _MYSQL_WARNING = ("The 'mysql' flavor with DBAPI connection is deprecated "
607
- "and will be removed in future versions. "
608
- "MySQL will be further supported with SQLAlchemy "
609
- "connectables." )
610
-
611
-
612
620
def _engine_builder (con ):
613
621
"""
614
622
Returns a SQLAlchemy engine from a URI (if con is a string)
@@ -632,15 +640,15 @@ def pandasSQL_builder(con, flavor=None, schema=None, meta=None,
632
640
Convenience function to return the correct PandasSQL subclass based on the
633
641
provided parameters
634
642
"""
643
+ _validate_flavor_parameter (flavor )
644
+
635
645
# When support for DBAPI connections is removed,
636
646
# is_cursor should not be necessary.
637
647
con = _engine_builder (con )
638
648
if _is_sqlalchemy_connectable (con ):
639
649
return SQLDatabase (con , schema = schema , meta = meta )
640
650
else :
641
- if flavor == 'mysql' :
642
- warnings .warn (_MYSQL_WARNING , FutureWarning , stacklevel = 3 )
643
- return SQLiteDatabase (con , flavor , is_cursor = is_cursor )
651
+ return SQLiteDatabase (con , is_cursor = is_cursor )
644
652
645
653
646
654
class SQLTable (PandasObject ):
@@ -1035,11 +1043,11 @@ class PandasSQL(PandasObject):
1035
1043
1036
1044
def read_sql (self , * args , ** kwargs ):
1037
1045
raise ValueError ("PandasSQL must be created with an SQLAlchemy "
1038
- "connectable or connection+sql flavor " )
1046
+ "connectable or sqlite connection " )
1039
1047
1040
1048
def to_sql (self , * args , ** kwargs ):
1041
1049
raise ValueError ("PandasSQL must be created with an SQLAlchemy "
1042
- "connectable or connection+sql flavor " )
1050
+ "connectable or sqlite connection " )
1043
1051
1044
1052
1045
1053
class SQLDatabase (PandasSQL ):
@@ -1308,38 +1316,16 @@ def _create_sql_schema(self, frame, table_name, keys=None, dtype=None):
1308
1316
1309
1317
1310
1318
# ---- SQL without SQLAlchemy ---
1311
- # Flavour specific sql strings and handler class for access to DBs without
1312
- # SQLAlchemy installed
1313
- # SQL type convertions for each DB
1319
+ # sqlite-specific sql strings and handler class
1320
+ # dictionary used for readability purposes
1314
1321
_SQL_TYPES = {
1315
- 'string' : {
1316
- 'mysql' : 'VARCHAR (63)' ,
1317
- 'sqlite' : 'TEXT' ,
1318
- },
1319
- 'floating' : {
1320
- 'mysql' : 'DOUBLE' ,
1321
- 'sqlite' : 'REAL' ,
1322
- },
1323
- 'integer' : {
1324
- 'mysql' : 'BIGINT' ,
1325
- 'sqlite' : 'INTEGER' ,
1326
- },
1327
- 'datetime' : {
1328
- 'mysql' : 'DATETIME' ,
1329
- 'sqlite' : 'TIMESTAMP' ,
1330
- },
1331
- 'date' : {
1332
- 'mysql' : 'DATE' ,
1333
- 'sqlite' : 'DATE' ,
1334
- },
1335
- 'time' : {
1336
- 'mysql' : 'TIME' ,
1337
- 'sqlite' : 'TIME' ,
1338
- },
1339
- 'boolean' : {
1340
- 'mysql' : 'BOOLEAN' ,
1341
- 'sqlite' : 'INTEGER' ,
1342
- }
1322
+ 'string' : 'TEXT' ,
1323
+ 'floating' : 'REAL' ,
1324
+ 'integer' : 'INTEGER' ,
1325
+ 'datetime' : 'TIMESTAMP' ,
1326
+ 'date' : 'DATE' ,
1327
+ 'time' : 'TIME' ,
1328
+ 'boolean' : 'INTEGER' ,
1343
1329
}
1344
1330
1345
1331
@@ -1351,22 +1337,6 @@ def _get_unicode_name(name):
1351
1337
return uname
1352
1338
1353
1339
1354
- def _get_valid_mysql_name (name ):
1355
- # Filter for unquoted identifiers
1356
- # See http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
1357
- uname = _get_unicode_name (name )
1358
- if not len (uname ):
1359
- raise ValueError ("Empty table or column name specified" )
1360
-
1361
- basere = r'[0-9,a-z,A-Z$_]'
1362
- for c in uname :
1363
- if not re .match (basere , c ):
1364
- if not (0x80 < ord (c ) < 0xFFFF ):
1365
- raise ValueError ("Invalid MySQL identifier '%s'" % uname )
1366
-
1367
- return '`' + uname + '`'
1368
-
1369
-
1370
1340
def _get_valid_sqlite_name (name ):
1371
1341
# See http://stackoverflow.com/questions/6514274/how-do-you-escape-strings\
1372
1342
# -for-sqlite-table-column-names-in-python
@@ -1385,19 +1355,6 @@ def _get_valid_sqlite_name(name):
1385
1355
return '"' + uname .replace ('"' , '""' ) + '"'
1386
1356
1387
1357
1388
- # SQL enquote and wildcard symbols
1389
- _SQL_WILDCARD = {
1390
- 'mysql' : '%s' ,
1391
- 'sqlite' : '?'
1392
- }
1393
-
1394
- # Validate and return escaped identifier
1395
- _SQL_GET_IDENTIFIER = {
1396
- 'mysql' : _get_valid_mysql_name ,
1397
- 'sqlite' : _get_valid_sqlite_name ,
1398
- }
1399
-
1400
-
1401
1358
_SAFE_NAMES_WARNING = ("The spaces in these column names will not be changed. "
1402
1359
"In pandas versions < 0.14, spaces were converted to "
1403
1360
"underscores." )
@@ -1428,9 +1385,8 @@ def _execute_create(self):
1428
1385
1429
1386
def insert_statement (self ):
1430
1387
names = list (map (text_type , self .frame .columns ))
1431
- flv = self .pd_sql .flavor
1432
- wld = _SQL_WILDCARD [flv ] # wildcard char
1433
- escape = _SQL_GET_IDENTIFIER [flv ]
1388
+ wld = '?' # wildcard char
1389
+ escape = _get_valid_sqlite_name
1434
1390
1435
1391
if self .index is not None :
1436
1392
[names .insert (0 , idx ) for idx in self .index [::- 1 ]]
@@ -1460,8 +1416,7 @@ def _create_table_setup(self):
1460
1416
if any (map (pat .search , column_names )):
1461
1417
warnings .warn (_SAFE_NAMES_WARNING , stacklevel = 6 )
1462
1418
1463
- flv = self .pd_sql .flavor
1464
- escape = _SQL_GET_IDENTIFIER [flv ]
1419
+ escape = _get_valid_sqlite_name
1465
1420
1466
1421
create_tbl_stmts = [escape (cname ) + ' ' + ctype
1467
1422
for cname , ctype , _ in column_names_and_types ]
@@ -1514,33 +1469,25 @@ def _sql_type_name(self, col):
1514
1469
if col_type not in _SQL_TYPES :
1515
1470
col_type = "string"
1516
1471
1517
- return _SQL_TYPES [col_type ][ self . pd_sql . flavor ]
1472
+ return _SQL_TYPES [col_type ]
1518
1473
1519
1474
1520
1475
class SQLiteDatabase (PandasSQL ):
1521
1476
"""
1522
1477
Version of SQLDatabase to support sqlite connections (fallback without
1523
1478
sqlalchemy). This should only be used internally.
1524
1479
1525
- For now still supports `flavor` argument to deal with 'mysql' database
1526
- for backwards compatibility, but this will be removed in future versions.
1527
-
1528
1480
Parameters
1529
1481
----------
1530
1482
con : sqlite connection object
1531
1483
1532
1484
"""
1533
1485
1534
- def __init__ (self , con , flavor , is_cursor = False ):
1486
+ def __init__ (self , con , flavor = None , is_cursor = False ):
1487
+ _validate_flavor_parameter (flavor )
1488
+
1535
1489
self .is_cursor = is_cursor
1536
1490
self .con = con
1537
- if flavor is None :
1538
- flavor = 'sqlite'
1539
- if flavor not in ['sqlite' , 'mysql' ]:
1540
- raise NotImplementedError ("flavors other than SQLite and MySQL "
1541
- "are not supported" )
1542
- else :
1543
- self .flavor = flavor
1544
1491
1545
1492
@contextmanager
1546
1493
def run_transaction (self ):
@@ -1665,24 +1612,20 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
1665
1612
1666
1613
def has_table (self , name , schema = None ):
1667
1614
# TODO(wesm): unused?
1668
- # escape = _SQL_GET_IDENTIFIER[self.flavor]
1615
+ # escape = _get_valid_sqlite_name
1669
1616
# esc_name = escape(name)
1670
1617
1671
- wld = _SQL_WILDCARD [self .flavor ]
1672
- flavor_map = {
1673
- 'sqlite' : ("SELECT name FROM sqlite_master "
1674
- "WHERE type='table' AND name=%s;" ) % wld ,
1675
- 'mysql' : "SHOW TABLES LIKE %s" % wld }
1676
- query = flavor_map .get (self .flavor )
1618
+ wld = '?'
1619
+ query = ("SELECT name FROM sqlite_master "
1620
+ "WHERE type='table' AND name=%s;" ) % wld
1677
1621
1678
1622
return len (self .execute (query , [name , ]).fetchall ()) > 0
1679
1623
1680
1624
def get_table (self , table_name , schema = None ):
1681
1625
return None # not supported in fallback mode
1682
1626
1683
1627
def drop_table (self , name , schema = None ):
1684
- escape = _SQL_GET_IDENTIFIER [self .flavor ]
1685
- drop_sql = "DROP TABLE %s" % escape (name )
1628
+ drop_sql = "DROP TABLE %s" % _get_valid_sqlite_name (name )
1686
1629
self .execute (drop_sql )
1687
1630
1688
1631
def _create_sql_schema (self , frame , table_name , keys = None , dtype = None ):
@@ -1691,7 +1634,7 @@ def _create_sql_schema(self, frame, table_name, keys=None, dtype=None):
1691
1634
return str (table .sql_schema ())
1692
1635
1693
1636
1694
- def get_schema (frame , name , flavor = 'sqlite' , keys = None , con = None , dtype = None ):
1637
+ def get_schema (frame , name , flavor = None , keys = None , con = None , dtype = None ):
1695
1638
"""
1696
1639
Get the SQL db table schema for the given frame.
1697
1640
@@ -1700,16 +1643,14 @@ def get_schema(frame, name, flavor='sqlite', keys=None, con=None, dtype=None):
1700
1643
frame : DataFrame
1701
1644
name : string
1702
1645
name of SQL table
1703
- flavor : {'sqlite', 'mysql'}, default 'sqlite'
1704
- The flavor of SQL to use. Ignored when using SQLAlchemy connectable.
1705
- 'mysql' is deprecated and will be removed in future versions, but it
1706
- will be further supported through SQLAlchemy engines.
1707
1646
keys : string or sequence, default: None
1708
1647
columns to use a primary key
1709
1648
con: an open SQL database connection object or a SQLAlchemy connectable
1710
1649
Using SQLAlchemy makes it possible to use any DB supported by that
1711
1650
library, default: None
1712
1651
If a DBAPI2 object, only sqlite3 is supported.
1652
+ flavor : 'sqlite', default None
1653
+ DEPRECATED: this parameter will be removed in a future version
1713
1654
dtype : dict of column name to SQL type, default None
1714
1655
Optional specifying the datatype for columns. The SQL type should
1715
1656
be a SQLAlchemy type, or a string for sqlite3 fallback connection.
0 commit comments