Skip to content

Commit 3e70975

Browse files
test: upload DATE column with various dtypes (#420)
* test: upload DATE column with various dtypes * add dbdate tests * test with db-dtypes only with newer pandas * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * sort by row number Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent e34b704 commit 3e70975

File tree

5 files changed

+120
-19
lines changed

5 files changed

+120
-19
lines changed

CONTRIBUTING.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ In order to add a feature:
2222
documentation.
2323

2424
- The feature must work fully on the following CPython versions:
25-
3.7, 3.8 and 3.9 on both UNIX and Windows.
25+
3.7, 3.8, 3.9 and 3.10 on both UNIX and Windows.
2626

2727
- The feature must not add unnecessary dependencies (where
2828
"unnecessary" is of course subjective, but new dependencies should
@@ -72,7 +72,7 @@ We use `nox <https://nox.readthedocs.io/en/latest/>`__ to instrument our tests.
7272

7373
- To run a single unit test::
7474

75-
$ nox -s unit-3.9 -- -k <name of test>
75+
$ nox -s unit-3.10 -- -k <name of test>
7676

7777

7878
.. note::
@@ -143,12 +143,12 @@ Running System Tests
143143
$ nox -s system
144144

145145
# Run a single system test
146-
$ nox -s system-3.9 -- -k <name of test>
146+
$ nox -s system-3.10 -- -k <name of test>
147147

148148

149149
.. note::
150150

151-
System tests are only configured to run under Python 3.7, 3.8 and 3.9.
151+
System tests are only configured to run under Python 3.7, 3.8, 3.9 and 3.10.
152152
For expediency, we do not run them in older versions of Python 3.
153153

154154
This alone will not run the tests. You'll need to change some local
@@ -224,10 +224,12 @@ We support:
224224
- `Python 3.7`_
225225
- `Python 3.8`_
226226
- `Python 3.9`_
227+
- `Python 3.10`_
227228

228229
.. _Python 3.7: https://docs.python.org/3.7/
229230
.. _Python 3.8: https://docs.python.org/3.8/
230231
.. _Python 3.9: https://docs.python.org/3.9/
232+
.. _Python 3.10: https://docs.python.org/3.10/
231233

232234

233235
Supported versions can be found in our ``noxfile.py`` `config`_.

noxfile.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
BLACK_PATHS = ["docs", "pandas_gbq", "tests", "noxfile.py", "setup.py"]
2929

3030
DEFAULT_PYTHON_VERSION = "3.8"
31-
SYSTEM_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9"]
32-
UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9"]
31+
SYSTEM_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10"]
32+
UNIT_TEST_PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10"]
3333

3434
CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute()
3535

@@ -146,7 +146,11 @@ def system(session):
146146
# Install all test dependencies, then install this package into the
147147
# virtualenv's dist-packages.
148148
session.install("mock", "pytest", "google-cloud-testutils", "-c", constraints_path)
149-
session.install("-e", ".[tqdm]", "-c", constraints_path)
149+
if session.python == "3.9":
150+
extras = "[tqdm,db-dtypes]"
151+
else:
152+
extras = "[tqdm]"
153+
session.install("-e", f".{extras}", "-c", constraints_path)
150154

151155
# Run py.test against the system tests.
152156
if system_test_exists:

owlbot.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@
2929
# ----------------------------------------------------------------------------
3030

3131
extras = ["tqdm"]
32+
extras_by_python = {
33+
"3.9": ["tqdm", "db-dtypes"],
34+
}
3235
templated_files = common.py_library(
33-
unit_test_python_versions=["3.7", "3.8", "3.9"],
34-
system_test_python_versions=["3.7", "3.8", "3.9"],
36+
unit_test_python_versions=["3.7", "3.8", "3.9", "3.10"],
37+
system_test_python_versions=["3.7", "3.8", "3.9", "3.10"],
3538
cov_level=86,
3639
unit_test_extras=extras,
3740
system_test_extras=extras,
41+
system_test_extras_by_python=extras_by_python,
3842
intersphinx_dependencies={
3943
"pandas": "https://pandas.pydata.org/pandas-docs/stable/",
4044
"pydata-google-auth": "https://pydata-google-auth.readthedocs.io/en/latest/",

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
# https://github.com/pydata/pandas-gbq/issues/343
3434
"google-cloud-bigquery[bqstorage,pandas]>=1.11.1,<3.0.0dev,!=2.4.*",
3535
]
36-
extras = {"tqdm": "tqdm>=4.23.0"}
36+
extras = {
37+
"tqdm": "tqdm>=4.23.0",
38+
"db-dtypes": "db-dtypes >=0.3.0,<2.0.0",
39+
}
3740

3841
# Setup boilerplate below this line.
3942

tests/system/test_to_gbq.py

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,20 @@
99
import pandas.testing
1010
import pytest
1111

12+
try:
13+
import db_dtypes
14+
except ImportError:
15+
db_dtypes = None
16+
1217

1318
pytest.importorskip("google.cloud.bigquery", minversion="1.24.0")
1419

1520

21+
@pytest.fixture(params=["default", "load_parquet", "load_csv"])
22+
def api_method(request):
23+
return request.param
24+
25+
1626
@pytest.fixture
1727
def method_under_test(credentials, project_id):
1828
import pandas_gbq
@@ -23,7 +33,7 @@ def method_under_test(credentials, project_id):
2333

2434

2535
@pytest.mark.parametrize(
26-
["input_series"],
36+
["input_series", "skip_csv"],
2737
[
2838
# Ensure that 64-bit floating point numbers are unchanged.
2939
# See: https://github.com/pydata/pandas-gbq/issues/326
@@ -41,17 +51,13 @@ def method_under_test(credentials, project_id):
4151
],
4252
name="test_col",
4353
),
54+
False,
4455
),
4556
(
4657
pandas.Series(
4758
[
4859
"abc",
4960
"defg",
50-
# Ensure that empty strings are written as empty string,
51-
# not NULL. See:
52-
# https://github.com/googleapis/python-bigquery-pandas/issues/366
53-
"",
54-
None,
5561
# Ensure that unicode characters are encoded. See:
5662
# https://github.com/googleapis/python-bigquery-pandas/issues/106
5763
"信用卡",
@@ -60,23 +66,105 @@ def method_under_test(credentials, project_id):
6066
],
6167
name="test_col",
6268
),
69+
False,
70+
),
71+
(
72+
pandas.Series(
73+
[
74+
"abc",
75+
"defg",
76+
# Ensure that empty strings are written as empty string,
77+
# not NULL. See:
78+
# https://github.com/googleapis/python-bigquery-pandas/issues/366
79+
"",
80+
None,
81+
],
82+
name="empty_strings",
83+
),
84+
True,
6385
),
6486
],
6587
)
6688
def test_series_round_trip(
67-
method_under_test, random_dataset_id, bigquery_client, input_series
89+
method_under_test,
90+
random_dataset_id,
91+
bigquery_client,
92+
input_series,
93+
api_method,
94+
skip_csv,
6895
):
96+
if api_method == "load_csv" and skip_csv:
97+
pytest.skip("Loading with CSV not supported.")
6998
table_id = f"{random_dataset_id}.round_trip_{random.randrange(1_000_000)}"
7099
input_series = input_series.sort_values().reset_index(drop=True)
71100
df = pandas.DataFrame(
72101
# Some errors only occur in multi-column dataframes. See:
73102
# https://github.com/googleapis/python-bigquery-pandas/issues/366
74103
{"test_col": input_series, "test_col2": input_series}
75104
)
76-
method_under_test(df, table_id)
105+
method_under_test(df, table_id, api_method=api_method)
77106

78107
round_trip = bigquery_client.list_rows(table_id).to_dataframe()
79108
round_trip_series = round_trip["test_col"].sort_values().reset_index(drop=True)
80109
pandas.testing.assert_series_equal(
81-
round_trip_series, input_series, check_exact=True,
110+
round_trip_series, input_series, check_exact=True, check_names=False,
111+
)
112+
113+
114+
DATAFRAME_ROUND_TRIPS = [
115+
# Ensure that a DATE column can be written with datetime64[ns] dtype
116+
# data. See:
117+
# https://github.com/googleapis/python-bigquery-pandas/issues/362
118+
(
119+
pandas.DataFrame(
120+
{
121+
"date_col": pandas.Series(
122+
["2021-04-17", "1999-12-31", "2038-01-19"], dtype="datetime64[ns]",
123+
),
124+
}
125+
),
126+
[{"name": "date_col", "type": "DATE"}],
127+
True,
128+
),
129+
]
130+
if db_dtypes is not None:
131+
DATAFRAME_ROUND_TRIPS.append(
132+
(
133+
pandas.DataFrame(
134+
{
135+
"date_col": pandas.Series(
136+
["2021-04-17", "1999-12-31", "2038-01-19"], dtype="dbdate",
137+
),
138+
}
139+
),
140+
[{"name": "date_col", "type": "DATE"}],
141+
False,
142+
)
143+
)
144+
145+
146+
@pytest.mark.parametrize(
147+
["input_df", "table_schema", "skip_csv"], DATAFRAME_ROUND_TRIPS
148+
)
149+
def test_dataframe_round_trip_with_table_schema(
150+
method_under_test,
151+
random_dataset_id,
152+
bigquery_client,
153+
input_df,
154+
table_schema,
155+
api_method,
156+
skip_csv,
157+
):
158+
if api_method == "load_csv" and skip_csv:
159+
pytest.skip("Loading with CSV not supported.")
160+
table_id = f"{random_dataset_id}.round_trip_w_schema_{random.randrange(1_000_000)}"
161+
input_df["row_num"] = input_df.index
162+
input_df.sort_values("row_num", inplace=True)
163+
method_under_test(
164+
input_df, table_id, table_schema=table_schema, api_method=api_method
165+
)
166+
round_trip = bigquery_client.list_rows(table_id).to_dataframe(
167+
dtypes=dict(zip(input_df.columns, input_df.dtypes))
82168
)
169+
round_trip.sort_values("row_num", inplace=True)
170+
pandas.testing.assert_frame_equal(input_df, round_trip)

0 commit comments

Comments
 (0)