@@ -41,6 +41,24 @@ class DatabaseError(IOError):
4141_SQLALCHEMY_INSTALLED = None
4242
4343
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+
4462def _is_sqlalchemy_connectable (con ):
4563 global _SQLALCHEMY_INSTALLED
4664 if _SQLALCHEMY_INSTALLED is None :
@@ -517,7 +535,7 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None,
517535 chunksize = chunksize )
518536
519537
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' ,
521539 index = True , index_label = None , chunksize = None , dtype = None ):
522540 """
523541 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',
532550 Using SQLAlchemy makes it possible to use any DB supported by that
533551 library.
534552 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
539555 schema : string, default None
540556 Name of SQL schema in database to write to (if database flavor
541557 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',
573589 chunksize = chunksize , dtype = dtype )
574590
575591
576- def has_table (table_name , con , flavor = 'sqlite' , schema = None ):
592+ def has_table (table_name , con , flavor = None , schema = None ):
577593 """
578594 Check if DataBase has named table.
579595
@@ -585,10 +601,8 @@ def has_table(table_name, con, flavor='sqlite', schema=None):
585601 Using SQLAlchemy makes it possible to use any DB supported by that
586602 library.
587603 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
592606 schema : string, default None
593607 Name of SQL schema in database to write to (if database flavor supports
594608 this). If None, use default schema (default).
@@ -603,12 +617,6 @@ def has_table(table_name, con, flavor='sqlite', schema=None):
603617table_exists = has_table
604618
605619
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-
612620def _engine_builder (con ):
613621 """
614622 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,
632640 Convenience function to return the correct PandasSQL subclass based on the
633641 provided parameters
634642 """
643+ _validate_flavor_parameter (flavor )
644+
635645 # When support for DBAPI connections is removed,
636646 # is_cursor should not be necessary.
637647 con = _engine_builder (con )
638648 if _is_sqlalchemy_connectable (con ):
639649 return SQLDatabase (con , schema = schema , meta = meta )
640650 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 )
644652
645653
646654class SQLTable (PandasObject ):
@@ -1035,11 +1043,11 @@ class PandasSQL(PandasObject):
10351043
10361044 def read_sql (self , * args , ** kwargs ):
10371045 raise ValueError ("PandasSQL must be created with an SQLAlchemy "
1038- "connectable or connection+sql flavor " )
1046+ "connectable or sqlite connection " )
10391047
10401048 def to_sql (self , * args , ** kwargs ):
10411049 raise ValueError ("PandasSQL must be created with an SQLAlchemy "
1042- "connectable or connection+sql flavor " )
1050+ "connectable or sqlite connection " )
10431051
10441052
10451053class SQLDatabase (PandasSQL ):
@@ -1308,38 +1316,16 @@ def _create_sql_schema(self, frame, table_name, keys=None, dtype=None):
13081316
13091317
13101318# ---- 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
13141321_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' ,
13431329}
13441330
13451331
@@ -1351,22 +1337,6 @@ def _get_unicode_name(name):
13511337 return uname
13521338
13531339
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-
13701340def _get_valid_sqlite_name (name ):
13711341 # See http://stackoverflow.com/questions/6514274/how-do-you-escape-strings\
13721342 # -for-sqlite-table-column-names-in-python
@@ -1385,19 +1355,6 @@ def _get_valid_sqlite_name(name):
13851355 return '"' + uname .replace ('"' , '""' ) + '"'
13861356
13871357
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-
14011358_SAFE_NAMES_WARNING = ("The spaces in these column names will not be changed. "
14021359 "In pandas versions < 0.14, spaces were converted to "
14031360 "underscores." )
@@ -1428,9 +1385,8 @@ def _execute_create(self):
14281385
14291386 def insert_statement (self ):
14301387 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
14341390
14351391 if self .index is not None :
14361392 [names .insert (0 , idx ) for idx in self .index [::- 1 ]]
@@ -1460,8 +1416,7 @@ def _create_table_setup(self):
14601416 if any (map (pat .search , column_names )):
14611417 warnings .warn (_SAFE_NAMES_WARNING , stacklevel = 6 )
14621418
1463- flv = self .pd_sql .flavor
1464- escape = _SQL_GET_IDENTIFIER [flv ]
1419+ escape = _get_valid_sqlite_name
14651420
14661421 create_tbl_stmts = [escape (cname ) + ' ' + ctype
14671422 for cname , ctype , _ in column_names_and_types ]
@@ -1514,33 +1469,25 @@ def _sql_type_name(self, col):
15141469 if col_type not in _SQL_TYPES :
15151470 col_type = "string"
15161471
1517- return _SQL_TYPES [col_type ][ self . pd_sql . flavor ]
1472+ return _SQL_TYPES [col_type ]
15181473
15191474
15201475class SQLiteDatabase (PandasSQL ):
15211476 """
15221477 Version of SQLDatabase to support sqlite connections (fallback without
15231478 sqlalchemy). This should only be used internally.
15241479
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-
15281480 Parameters
15291481 ----------
15301482 con : sqlite connection object
15311483
15321484 """
15331485
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+
15351489 self .is_cursor = is_cursor
15361490 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
15441491
15451492 @contextmanager
15461493 def run_transaction (self ):
@@ -1665,24 +1612,20 @@ def to_sql(self, frame, name, if_exists='fail', index=True,
16651612
16661613 def has_table (self , name , schema = None ):
16671614 # TODO(wesm): unused?
1668- # escape = _SQL_GET_IDENTIFIER[self.flavor]
1615+ # escape = _get_valid_sqlite_name
16691616 # esc_name = escape(name)
16701617
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
16771621
16781622 return len (self .execute (query , [name , ]).fetchall ()) > 0
16791623
16801624 def get_table (self , table_name , schema = None ):
16811625 return None # not supported in fallback mode
16821626
16831627 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 )
16861629 self .execute (drop_sql )
16871630
16881631 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):
16911634 return str (table .sql_schema ())
16921635
16931636
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 ):
16951638 """
16961639 Get the SQL db table schema for the given frame.
16971640
@@ -1700,16 +1643,14 @@ def get_schema(frame, name, flavor='sqlite', keys=None, con=None, dtype=None):
17001643 frame : DataFrame
17011644 name : string
17021645 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.
17071646 keys : string or sequence, default: None
17081647 columns to use a primary key
17091648 con: an open SQL database connection object or a SQLAlchemy connectable
17101649 Using SQLAlchemy makes it possible to use any DB supported by that
17111650 library, default: None
17121651 If a DBAPI2 object, only sqlite3 is supported.
1652+ flavor : 'sqlite', default None
1653+ DEPRECATED: this parameter will be removed in a future version
17131654 dtype : dict of column name to SQL type, default None
17141655 Optional specifying the datatype for columns. The SQL type should
17151656 be a SQLAlchemy type, or a string for sqlite3 fallback connection.
0 commit comments