9
9
- `TestSQLiteFallbackApi`: test the public API with a sqlite DBAPI connection
10
10
- Tests for the different SQL flavors (flavor specific type conversions)
11
11
- Tests for the sqlalchemy mode: `_TestSQLAlchemy` is the base class with
12
- common methods, the different tested flavors (sqlite3, MySQL, PostgreSQL)
12
+ common methods, `_TestSQLAlchemyConn` tests the API with a SQLAlchemy
13
+ Connection object. The different tested flavors (sqlite3, MySQL, PostgreSQL)
13
14
derive from the base class
14
15
- Tests for the fallback mode (`TestSQLiteFallback` and `TestMySQLLegacy`)
15
16
@@ -854,6 +855,31 @@ def test_sqlalchemy_type_mapping(self):
854
855
self .assertTrue (isinstance (table .table .c ['time' ].type , sqltypes .DateTime ))
855
856
856
857
858
+ class _EngineToConnMixin (object ):
859
+ """
860
+ A mixin that causes setup_connect to create a conn rather than an engine.
861
+ """
862
+
863
+ def setUp (self ):
864
+ super (_EngineToConnMixin , self ).setUp ()
865
+ engine = self .conn
866
+ conn = engine .connect ()
867
+ self .__tx = conn .begin ()
868
+ self .pandasSQL = sql .SQLDatabase (conn )
869
+ self .__engine = engine
870
+ self .conn = conn
871
+
872
+ def tearDown (self ):
873
+ self .__tx .rollback ()
874
+ self .conn .close ()
875
+ self .conn = self .__engine
876
+ self .pandasSQL = sql .SQLDatabase (self .__engine )
877
+
878
+
879
+ class TestSQLApiConn (_EngineToConnMixin , TestSQLApi ):
880
+ pass
881
+
882
+
857
883
class TestSQLiteFallbackApi (_TestSQLApi ):
858
884
"""
859
885
Test the public sqlite connection fallback API
@@ -990,9 +1016,6 @@ def setup_connect(self):
990
1016
except sqlalchemy .exc .OperationalError :
991
1017
raise nose .SkipTest ("Can't connect to {0} server" .format (self .flavor ))
992
1018
993
- def tearDown (self ):
994
- raise NotImplementedError ()
995
-
996
1019
def test_aread_sql (self ):
997
1020
self ._read_sql_iris ()
998
1021
@@ -1347,8 +1370,12 @@ def test_double_precision(self):
1347
1370
self .assertTrue (isinstance (col_dict ['i64' ].type , sqltypes .BigInteger ))
1348
1371
1349
1372
1373
+ class _TestSQLAlchemyConn (_EngineToConnMixin , _TestSQLAlchemy ):
1374
+ def test_transactions (self ):
1375
+ raise nose .SkipTest ("Nested transactions rollbacks don't work with Pandas" )
1376
+
1350
1377
1351
- class TestSQLiteAlchemy ( _TestSQLAlchemy ):
1378
+ class _TestSQLiteAlchemy ( object ):
1352
1379
"""
1353
1380
Test the sqlalchemy backend against an in-memory sqlite database.
1354
1381
@@ -1365,8 +1392,8 @@ def setup_driver(cls):
1365
1392
cls .driver = None
1366
1393
1367
1394
def tearDown (self ):
1395
+ super (_TestSQLiteAlchemy , self ).tearDown ()
1368
1396
# in memory so tables should not be removed explicitly
1369
- pass
1370
1397
1371
1398
def test_default_type_conversion (self ):
1372
1399
df = sql .read_sql_table ("types_test_data" , self .conn )
@@ -1404,7 +1431,7 @@ def test_bigint_warning(self):
1404
1431
self .assertEqual (len (w ), 0 , "Warning triggered for other table" )
1405
1432
1406
1433
1407
- class TestMySQLAlchemy ( _TestSQLAlchemy ):
1434
+ class _TestMySQLAlchemy ( object ):
1408
1435
"""
1409
1436
Test the sqlalchemy backend against an MySQL database.
1410
1437
@@ -1425,6 +1452,7 @@ def setup_driver(cls):
1425
1452
raise nose .SkipTest ('pymysql not installed' )
1426
1453
1427
1454
def tearDown (self ):
1455
+ super (_TestMySQLAlchemy , self ).tearDown ()
1428
1456
c = self .conn .execute ('SHOW TABLES' )
1429
1457
for table in c .fetchall ():
1430
1458
self .conn .execute ('DROP TABLE %s' % table [0 ])
@@ -1478,7 +1506,7 @@ def test_read_procedure(self):
1478
1506
tm .assert_frame_equal (df , res2 )
1479
1507
1480
1508
1481
- class TestPostgreSQLAlchemy ( _TestSQLAlchemy ):
1509
+ class _TestPostgreSQLAlchemy ( object ):
1482
1510
"""
1483
1511
Test the sqlalchemy backend against an PostgreSQL database.
1484
1512
@@ -1499,6 +1527,7 @@ def setup_driver(cls):
1499
1527
raise nose .SkipTest ('psycopg2 not installed' )
1500
1528
1501
1529
def tearDown (self ):
1530
+ super (_TestPostgreSQLAlchemy , self ).tearDown ()
1502
1531
c = self .conn .execute (
1503
1532
"SELECT table_name FROM information_schema.tables"
1504
1533
" WHERE table_schema = 'public'" )
@@ -1550,15 +1579,18 @@ def test_schema_support(self):
1550
1579
1551
1580
## specifying schema in user-provided meta
1552
1581
1553
- engine2 = self .connect ()
1554
- meta = sqlalchemy .MetaData (engine2 , schema = 'other' )
1555
- pdsql = sql .SQLDatabase (engine2 , meta = meta )
1556
- pdsql .to_sql (df , 'test_schema_other2' , index = False )
1557
- pdsql .to_sql (df , 'test_schema_other2' , index = False , if_exists = 'replace' )
1558
- pdsql .to_sql (df , 'test_schema_other2' , index = False , if_exists = 'append' )
1559
- res1 = sql .read_sql_table ('test_schema_other2' , self .conn , schema = 'other' )
1560
- res2 = pdsql .read_table ('test_schema_other2' )
1561
- tm .assert_frame_equal (res1 , res2 )
1582
+ # The schema won't be applied on another Connection
1583
+ # because of transactional schemas
1584
+ if isinstance (self .conn , sqlalchemy .engine .Engine ):
1585
+ engine2 = self .connect ()
1586
+ meta = sqlalchemy .MetaData (engine2 , schema = 'other' )
1587
+ pdsql = sql .SQLDatabase (engine2 , meta = meta )
1588
+ pdsql .to_sql (df , 'test_schema_other2' , index = False )
1589
+ pdsql .to_sql (df , 'test_schema_other2' , index = False , if_exists = 'replace' )
1590
+ pdsql .to_sql (df , 'test_schema_other2' , index = False , if_exists = 'append' )
1591
+ res1 = sql .read_sql_table ('test_schema_other2' , self .conn , schema = 'other' )
1592
+ res2 = pdsql .read_table ('test_schema_other2' )
1593
+ tm .assert_frame_equal (res1 , res2 )
1562
1594
1563
1595
def test_datetime_with_time_zone (self ):
1564
1596
# Test to see if we read the date column with timezones that
@@ -1574,6 +1606,31 @@ def test_datetime_with_time_zone(self):
1574
1606
# "2000-06-01 00:00:00-07:00" should convert to "2000-06-01 07:00:00"
1575
1607
self .assertEqual (df .DateColWithTz [1 ], Timestamp ('2000-06-01 07:00:00' ))
1576
1608
1609
+
1610
+ class TestMySQLAlchemy (_TestMySQLAlchemy , _TestSQLAlchemy ):
1611
+ pass
1612
+
1613
+
1614
+ class TestMySQLAlchemyConn (_TestMySQLAlchemy , _TestSQLAlchemyConn ):
1615
+ pass
1616
+
1617
+
1618
+ class TestPostgreSQLAlchemy (_TestPostgreSQLAlchemy , _TestSQLAlchemy ):
1619
+ pass
1620
+
1621
+
1622
+ class TestPostgreSQLAlchemyConn (_TestPostgreSQLAlchemy , _TestSQLAlchemyConn ):
1623
+ pass
1624
+
1625
+
1626
+ class TestSQLiteAlchemy (_TestSQLiteAlchemy , _TestSQLAlchemy ):
1627
+ pass
1628
+
1629
+
1630
+ class TestSQLiteAlchemyConn (_TestSQLiteAlchemy , _TestSQLAlchemyConn ):
1631
+ pass
1632
+
1633
+
1577
1634
#------------------------------------------------------------------------------
1578
1635
#--- Test Sqlite / MySQL fallback
1579
1636
0 commit comments