|
| 1 | +import datetime |
1 | 2 | import typing
|
2 | 3 | from io import StringIO
|
3 | 4 | from math import ceil
|
@@ -502,3 +503,75 @@ def test_write_dataframe_handles_npdtyes(mocker):
|
502 | 503 | assert len(spy.mock_calls[1].args[1]) == 1
|
503 | 504 | # bind parameter list should not contain numpy objects
|
504 | 505 | assert not isinstance(spy.mock_calls[1].args[1][0], np.generic)
|
| 506 | + |
| 507 | + |
| 508 | +@pandas_only |
| 509 | +def test_write_dataframe_handles_pandas_types(mocker): |
| 510 | + import pandas as pd |
| 511 | + |
| 512 | + mocker.patch("redshift_connector.Cursor.execute", return_value=None) |
| 513 | + mocker.patch("redshift_connector.Cursor.fetchone", return_value=[1]) |
| 514 | + mock_cursor: Cursor = Cursor.__new__(Cursor) |
| 515 | + mock_connection: Connection = Connection.__new__(Connection) |
| 516 | + mock_cursor._c = mock_connection |
| 517 | + |
| 518 | + mock_cursor.paramstyle = "mocked_val" |
| 519 | + |
| 520 | + for datatype, data, _type in ( |
| 521 | + ("int64", pd.Series([42]), int), |
| 522 | + ("float64", pd.Series([3.14]), float), |
| 523 | + ("object", pd.Series(["Hello, Pandas!"]), str), |
| 524 | + ("bool", pd.Series([True]), bool), |
| 525 | + ("datetime64", pd.Series([pd.Timestamp("2022-01-01")]), int), |
| 526 | + ("timedelta64", pd.Series([pd.Timedelta(days=5)]), int), |
| 527 | + ): |
| 528 | + spy = mocker.spy(mock_cursor, "execute") |
| 529 | + dataframe = pd.DataFrame(data) |
| 530 | + mock_cursor.write_dataframe(df=dataframe, table=datatype) |
| 531 | + |
| 532 | + assert spy.called |
| 533 | + assert spy.call_count == 2 # once for __is_valid_table, once for write_dataframe |
| 534 | + assert not isinstance(spy.mock_calls[1].args[1], pd.core.base.PandasObject) |
| 535 | + assert isinstance(spy.mock_calls[1].args[1], list) |
| 536 | + assert len(spy.mock_calls[1].args[1]) == 1 |
| 537 | + # bind parameter list should not contain numpy objects |
| 538 | + assert isinstance(spy.mock_calls[1].args[1][0], _type) |
| 539 | + |
| 540 | + |
| 541 | +@pandas_only |
| 542 | +@pytest.mark.parametrize( |
| 543 | + "datatype,data,_type", |
| 544 | + ( |
| 545 | + ("int", 42, int), |
| 546 | + ("float", 3.14, float), |
| 547 | + ("str", "H", str), |
| 548 | + ("bool", True, bool), |
| 549 | + ("list", [1, 2, 3], list), |
| 550 | + ("tuple", (4, 5, 6), tuple), |
| 551 | + ("set", {1, 2, 3}, set), |
| 552 | + ("datetime", datetime.datetime.now(datetime.timezone.utc), datetime.datetime), |
| 553 | + ), |
| 554 | +) |
| 555 | +def test_write_dataframe_handles_python_types(mocker, datatype, data, _type): |
| 556 | + import datetime |
| 557 | + |
| 558 | + import pandas as pd |
| 559 | + |
| 560 | + mocker.patch("redshift_connector.Cursor.execute", return_value=None) |
| 561 | + mocker.patch("redshift_connector.Cursor.fetchone", return_value=[1]) |
| 562 | + mock_cursor: Cursor = Cursor.__new__(Cursor) |
| 563 | + mock_connection: Connection = Connection.__new__(Connection) |
| 564 | + mock_cursor._c = mock_connection |
| 565 | + |
| 566 | + mock_cursor.paramstyle = "mocked_val" |
| 567 | + |
| 568 | + spy = mocker.spy(mock_cursor, "execute") |
| 569 | + dataframe = pd.DataFrame({col: [data] * 1 for col in (datatype,)}) |
| 570 | + mock_cursor.write_dataframe(df=dataframe, table=datatype) |
| 571 | + |
| 572 | + assert spy.called |
| 573 | + assert spy.call_count == 2 # once for __is_valid_table, once for write_dataframe |
| 574 | + assert not isinstance(spy.mock_calls[1].args[1], pd.core.base.PandasObject) |
| 575 | + assert isinstance(spy.mock_calls[1].args[1], list) |
| 576 | + assert len(spy.mock_calls[1].args[1]) == 1 |
| 577 | + assert isinstance((spy.mock_calls[1].args[1][0]), _type) |
0 commit comments