From 127f4f10b7ec5ebf8361a6770951f4e84f646033 Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 10:34:58 -0700 Subject: [PATCH 1/6] CLN: Warn that default dialect is changing to "standard" Towards issue #195 --- pandas_gbq/gbq.py | 11 ++- tests/system/test_gbq.py | 160 +++++++++++++++++++++++---------------- tests/unit/test_gbq.py | 34 ++++++--- 3 files changed, 130 insertions(+), 75 deletions(-) diff --git a/pandas_gbq/gbq.py b/pandas_gbq/gbq.py index df20e76b..afc01bb6 100644 --- a/pandas_gbq/gbq.py +++ b/pandas_gbq/gbq.py @@ -471,7 +471,7 @@ def _parse_data(schema, rows): def read_gbq(query, project_id=None, index_col=None, col_order=None, reauth=False, private_key=None, auth_local_webserver=False, - dialect='legacy', location=None, configuration=None, + dialect=None, location=None, configuration=None, verbose=None): r"""Load data from Google BigQuery using google-cloud-python @@ -515,6 +515,8 @@ def read_gbq(query, project_id=None, index_col=None, col_order=None, .. versionadded:: 0.2.0 dialect : str, default 'legacy' + Note: The default value is changing to 'standard' in a future verion. + SQL syntax dialect to use. Value can be one of: ``'legacy'`` @@ -552,6 +554,13 @@ def read_gbq(query, project_id=None, index_col=None, col_order=None, df: DataFrame DataFrame representing results of query. """ + if dialect is None: + dialect = 'legacy' + warnings.warn( + 'The default value for dialect is changing to "standard" in a ' + 'future version. Pass in dialect="legacy" to disable this ' + 'warning.', + FutureWarning, stacklevel=1) _test_google_api_imports() diff --git a/tests/system/test_gbq.py b/tests/system/test_gbq.py index 39b2f4ee..2fd6b3de 100644 --- a/tests/system/test_gbq.py +++ b/tests/system/test_gbq.py @@ -127,7 +127,8 @@ def test_should_be_able_to_get_results_from_query(self, gbq_connector): def test_should_read(project, credentials): query = 'SELECT "PI" AS valid_string' - df = gbq.read_gbq(query, project_id=project, private_key=credentials) + df = gbq.read_gbq( + query, project_id=project, private_key=credentials, dialect='legacy') tm.assert_frame_equal(df, DataFrame({'valid_string': ['PI']})) @@ -145,19 +146,22 @@ def setup(self, project, credentials): def test_should_properly_handle_valid_strings(self, project_id): query = 'SELECT "PI" AS valid_string' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'valid_string': ['PI']})) def test_should_properly_handle_empty_strings(self, project_id): query = 'SELECT "" AS empty_string' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'empty_string': [""]})) def test_should_properly_handle_null_strings(self, project_id): query = 'SELECT STRING(NULL) AS null_string' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'null_string': [None]})) def test_should_properly_handle_valid_integers(self, project_id): @@ -178,7 +182,8 @@ def test_should_properly_handle_nullable_integers(self, project_id): def test_should_properly_handle_valid_longs(self, project_id): query = 'SELECT 1 << 62 AS valid_long' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'valid_long': [1 << 62]})) @@ -187,21 +192,24 @@ def test_should_properly_handle_nullable_longs(self, project_id): (SELECT 1 << 62 AS nullable_long), (SELECT NULL AS nullable_long)''' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'nullable_long': [1 << 62, None]}).astype(object)) def test_should_properly_handle_null_integers(self, project_id): query = 'SELECT INTEGER(NULL) AS null_integer' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'null_integer': [None]})) def test_should_properly_handle_valid_floats(self, project_id): from math import pi query = 'SELECT PI() AS valid_float' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame( {'valid_float': [pi]})) @@ -211,7 +219,8 @@ def test_should_properly_handle_nullable_floats(self, project_id): (SELECT PI() AS nullable_float), (SELECT NULL AS nullable_float)''' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'nullable_float': [pi, None]})) @@ -219,7 +228,8 @@ def test_should_properly_handle_valid_doubles(self, project_id): from math import pi query = 'SELECT PI() * POW(10, 307) AS valid_double' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame( {'valid_double': [pi * 10 ** 307]})) @@ -229,27 +239,31 @@ def test_should_properly_handle_nullable_doubles(self, project_id): (SELECT PI() * POW(10, 307) AS nullable_double), (SELECT NULL AS nullable_double)''' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'nullable_double': [pi * 10 ** 307, None]})) def test_should_properly_handle_null_floats(self, project_id): query = 'SELECT FLOAT(NULL) AS null_float' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'null_float': [np.nan]})) def test_should_properly_handle_timestamp_unix_epoch(self, project_id): query = 'SELECT TIMESTAMP("1970-01-01 00:00:00") AS unix_epoch' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame( {'unix_epoch': [np.datetime64('1970-01-01T00:00:00.000000Z')]})) def test_should_properly_handle_arbitrary_timestamp(self, project_id): query = 'SELECT TIMESTAMP("2004-09-15 05:00:00") AS valid_timestamp' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({ 'valid_timestamp': [np.datetime64('2004-09-15T05:00:00.000000Z')] })) @@ -257,25 +271,29 @@ def test_should_properly_handle_arbitrary_timestamp(self, project_id): def test_should_properly_handle_null_timestamp(self, project_id): query = 'SELECT TIMESTAMP(NULL) AS null_timestamp' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'null_timestamp': [NaT]})) def test_should_properly_handle_true_boolean(self, project_id): query = 'SELECT BOOLEAN(TRUE) AS true_boolean' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'true_boolean': [True]})) def test_should_properly_handle_false_boolean(self, project_id): query = 'SELECT BOOLEAN(FALSE) AS false_boolean' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'false_boolean': [False]})) def test_should_properly_handle_null_boolean(self, project_id): query = 'SELECT BOOLEAN(NULL) AS null_boolean' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'null_boolean': [None]})) def test_should_properly_handle_nullable_booleans(self, project_id): @@ -283,7 +301,8 @@ def test_should_properly_handle_nullable_booleans(self, project_id): (SELECT BOOLEAN(TRUE) AS nullable_boolean), (SELECT NULL AS nullable_boolean)''' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'nullable_boolean': [True, None]}).astype(object)) @@ -300,14 +319,16 @@ def test_unicode_string_conversion_and_normalization(self, project_id): query = 'SELECT "{0}" AS unicode_string'.format(unicode_string) df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, correct_test_datatype) def test_index_column(self, project_id): query = "SELECT 'a' AS string_1, 'b' AS string_2" result_frame = gbq.read_gbq(query, project_id=project_id, index_col="string_1", - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') correct_frame = DataFrame( {'string_1': ['a'], 'string_2': ['b']}).set_index("string_1") assert result_frame.index.name == correct_frame.index.name @@ -317,7 +338,8 @@ def test_column_order(self, project_id): col_order = ['string_3', 'string_1', 'string_2'] result_frame = gbq.read_gbq(query, project_id=project_id, col_order=col_order, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') correct_frame = DataFrame({'string_1': ['a'], 'string_2': [ 'b'], 'string_3': ['c']})[col_order] tm.assert_frame_equal(result_frame, correct_frame) @@ -330,14 +352,16 @@ def test_read_gbq_raises_invalid_column_order(self, project_id): with pytest.raises(gbq.InvalidColumnOrder): gbq.read_gbq(query, project_id=project_id, col_order=col_order, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') def test_column_order_plus_index(self, project_id): query = "SELECT 'a' AS string_1, 'b' AS string_2, 'c' AS string_3" col_order = ['string_3', 'string_2'] result_frame = gbq.read_gbq(query, project_id=project_id, index_col='string_1', col_order=col_order, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') correct_frame = DataFrame( {'string_1': ['a'], 'string_2': ['b'], 'string_3': ['c']}) correct_frame.set_index('string_1', inplace=True) @@ -352,13 +376,15 @@ def test_read_gbq_raises_invalid_index_column(self, project_id): with pytest.raises(gbq.InvalidIndexColumn): gbq.read_gbq(query, project_id=project_id, index_col='string_bbb', col_order=col_order, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') def test_malformed_query(self, project_id): with pytest.raises(gbq.GenericGBQException): gbq.read_gbq("SELCET * FORM [publicdata:samples.shakespeare]", project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') def test_bad_project_id(self): with pytest.raises(gbq.GenericGBQException): @@ -370,7 +396,8 @@ def test_bad_table_name(self, project_id): with pytest.raises(gbq.GenericGBQException): gbq.read_gbq("SELECT * FROM [publicdata:samples.nope]", project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') def test_download_dataset_larger_than_200k_rows(self, project_id): test_size = 200005 @@ -380,7 +407,8 @@ def test_download_dataset_larger_than_200k_rows(self, project_id): "GROUP EACH BY id ORDER BY id ASC LIMIT {0}" .format(test_size), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert len(df.drop_duplicates()) == test_size def test_zero_rows(self, project_id): @@ -390,7 +418,8 @@ def test_zero_rows(self, project_id): "FROM [publicdata:samples.wikipedia] " "WHERE timestamp=-9999999", project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') page_array = np.zeros( (0,), dtype=[('title', object), ('id', np.dtype(int)), ('is_bot', np.dtype(bool)), ('ts', 'M8[ns]')]) @@ -420,10 +449,11 @@ def test_standard_sql(self, project_id): "`publicdata.samples.wikipedia` LIMIT 10" # Test that a standard sql statement fails when using - # the legacy SQL dialect (default value) + # the legacy SQL dialect. with pytest.raises(gbq.GenericGBQException): gbq.read_gbq(standard_sql, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') # Test that a standard sql statement succeeds when # setting dialect='standard' @@ -432,21 +462,6 @@ def test_standard_sql(self, project_id): private_key=self.credentials) assert len(df.drop_duplicates()) == 10 - def test_invalid_option_for_sql_dialect(self, project_id): - sql_statement = "SELECT DISTINCT id FROM " \ - "`publicdata.samples.wikipedia` LIMIT 10" - - # Test that an invalid option for `dialect` raises ValueError - with pytest.raises(ValueError): - gbq.read_gbq(sql_statement, project_id=project_id, - dialect='invalid', - private_key=self.credentials) - - # Test that a correct option for dialect succeeds - # to make sure ValueError was due to invalid dialect - gbq.read_gbq(sql_statement, project_id=project_id, - dialect='standard', private_key=self.credentials) - def test_query_with_parameters(self, project_id): sql_statement = "SELECT @param1 + @param2 AS valid_result" config = { @@ -479,13 +494,15 @@ def test_query_with_parameters(self, project_id): # when parameters are not supplied via configuration with pytest.raises(ValueError): gbq.read_gbq(sql_statement, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') # Test that the query is successful because we have supplied # the correct query parameters via the 'config' option df = gbq.read_gbq(sql_statement, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'valid_result': [3]})) def test_query_inside_configuration(self, project_id): @@ -502,11 +519,13 @@ def test_query_inside_configuration(self, project_id): with pytest.raises(ValueError): gbq.read_gbq(query_no_use, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') df = gbq.read_gbq(None, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'valid_string': ['PI']})) def test_configuration_without_query(self, project_id): @@ -530,7 +549,8 @@ def test_configuration_without_query(self, project_id): with pytest.raises(ValueError): gbq.read_gbq(sql_statement, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') def test_configuration_raises_value_error_with_multiple_config( self, project_id): @@ -549,7 +569,8 @@ def test_configuration_raises_value_error_with_multiple_config( with pytest.raises(ValueError): gbq.read_gbq(sql_statement, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') def test_timeout_configuration(self, project_id): sql_statement = 'SELECT 1' @@ -562,7 +583,8 @@ def test_timeout_configuration(self, project_id): with pytest.raises(gbq.QueryTimeout): gbq.read_gbq(sql_statement, project_id=project_id, private_key=self.credentials, - configuration=config) + configuration=config, + dialect='legacy') def test_query_response_bytes(self): assert self.gbq_connector.sizeof_fmt(999) == "999.0 B" @@ -689,7 +711,8 @@ def test_upload_data(self, project_id): result = gbq.read_gbq("SELECT COUNT(*) AS num_rows FROM {0}" .format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert result['num_rows'][0] == test_size def test_upload_data_if_table_exists_fail(self, project_id): @@ -725,7 +748,8 @@ def test_upload_data_if_table_exists_append(self, project_id): result = gbq.read_gbq("SELECT COUNT(*) AS num_rows FROM {0}" .format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert result['num_rows'][0] == test_size * 2 # Try inserting with a different schema, confirm failure @@ -754,7 +778,8 @@ def test_upload_subset_columns_if_table_exists_append(self, project_id): result = gbq.read_gbq("SELECT COUNT(*) AS num_rows FROM {0}" .format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert result['num_rows'][0] == test_size * 2 def test_upload_data_if_table_exists_replace(self, project_id): @@ -775,7 +800,8 @@ def test_upload_data_if_table_exists_replace(self, project_id): result = gbq.read_gbq("SELECT COUNT(*) AS num_rows FROM {0}" .format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert result['num_rows'][0] == 5 def test_upload_data_if_table_exists_raises_value_error(self, project_id): @@ -818,7 +844,8 @@ def test_upload_chinese_unicode_data(self, project_id): result_df = gbq.read_gbq( "SELECT * FROM {0}".format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert len(result_df) == test_size @@ -851,7 +878,8 @@ def test_upload_other_unicode_data(self, project_id): result_df = gbq.read_gbq("SELECT * FROM {0}".format( self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert len(result_df) == test_size @@ -879,10 +907,11 @@ def test_upload_mixed_float_and_int(self, project_id): project_id=project_id, private_key=self.credentials) - result_df = gbq.read_gbq("SELECT * FROM {0}".format( - self.destination_table + test_id), + result_df = gbq.read_gbq( + 'SELECT * FROM {0}'.format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert len(result_df) == test_size @@ -1173,10 +1202,11 @@ def test_upload_data_with_timestamp(self, project_id): project_id=project_id, private_key=self.credentials) - result_df = gbq.read_gbq("SELECT * FROM {0}".format( - self.destination_table + test_id), + result_df = gbq.read_gbq( + 'SELECT * FROM {0}'.format(self.destination_table + test_id), project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') assert len(result_df) == test_size diff --git a/tests/unit/test_gbq.py b/tests/unit/test_gbq.py index d3560450..f308d9f4 100644 --- a/tests/unit/test_gbq.py +++ b/tests/unit/test_gbq.py @@ -190,12 +190,12 @@ def test_read_gbq_with_no_project_id_given_should_fail(monkeypatch): auth, 'get_application_default_credentials', mock_none_credentials) with pytest.raises(ValueError) as exception: - gbq.read_gbq('SELECT 1') + gbq.read_gbq('SELECT 1', dialect='standard') assert 'Could not determine project ID' in str(exception) def test_read_gbq_with_inferred_project_id(monkeypatch): - df = gbq.read_gbq('SELECT 1') + df = gbq.read_gbq('SELECT 1', dialect='standard') assert df is not None @@ -214,32 +214,35 @@ def test_that_parse_data_works_properly(): def test_read_gbq_with_invalid_private_key_json_should_fail(): with pytest.raises(pandas_gbq.exceptions.InvalidPrivateKeyFormat): - gbq.read_gbq('SELECT 1', project_id='x', private_key='y') + gbq.read_gbq( + 'SELECT 1', dialect='standard', project_id='x', private_key='y') def test_read_gbq_with_empty_private_key_json_should_fail(): with pytest.raises(pandas_gbq.exceptions.InvalidPrivateKeyFormat): - gbq.read_gbq('SELECT 1', project_id='x', private_key='{}') + gbq.read_gbq( + 'SELECT 1', dialect='standard', project_id='x', private_key='{}') def test_read_gbq_with_private_key_json_wrong_types_should_fail(): with pytest.raises(pandas_gbq.exceptions.InvalidPrivateKeyFormat): gbq.read_gbq( - 'SELECT 1', project_id='x', + 'SELECT 1', dialect='standard', project_id='x', private_key='{ "client_email" : 1, "private_key" : True }') def test_read_gbq_with_empty_private_key_file_should_fail(): with tm.ensure_clean() as empty_file_path: with pytest.raises(pandas_gbq.exceptions.InvalidPrivateKeyFormat): - gbq.read_gbq('SELECT 1', project_id='x', + gbq.read_gbq('SELECT 1', dialect='standard', project_id='x', private_key=empty_file_path) def test_read_gbq_with_corrupted_private_key_json_should_fail(): with pytest.raises(pandas_gbq.exceptions.InvalidPrivateKeyFormat): gbq.read_gbq( - 'SELECT 1', project_id='x', private_key='99999999999999999') + 'SELECT 1', dialect='standard', project_id='x', + private_key='99999999999999999') def test_read_gbq_with_verbose_new_pandas_warns_deprecation(min_bq_version): @@ -272,7 +275,7 @@ def test_read_gbq_wo_verbose_w_new_pandas_no_warnings(recwarn, min_bq_version): 'pkg_resources.Distribution.parsed_version', new_callable=mock.PropertyMock) as mock_version: mock_version.side_effect = [min_bq_version, pandas_version] - gbq.read_gbq('SELECT 1', project_id='my-project') + gbq.read_gbq('SELECT 1', project_id='my-project', dialect='standard') assert len(recwarn) == 0 @@ -283,10 +286,23 @@ def test_read_gbq_with_verbose_old_pandas_no_warnings(recwarn, min_bq_version): 'pkg_resources.Distribution.parsed_version', new_callable=mock.PropertyMock) as mock_version: mock_version.side_effect = [min_bq_version, pandas_version] - gbq.read_gbq('SELECT 1', project_id='my-project', verbose=True) + gbq.read_gbq( + 'SELECT 1', project_id='my-project', dialect='standard', + verbose=True) assert len(recwarn) == 0 +def test_read_gbq_with_invalid_dialect(): + with pytest.raises(ValueError) as excinfo: + gbq.read_gbq('SELECT 1', dialect='invalid') + assert 'is not valid for dialect' in str(excinfo.value) + + +def test_read_gbq_without_dialect_warns_future_change(): + with pytest.warns(FutureWarning): + gbq.read_gbq('SELECT 1') + + def test_generate_bq_schema_deprecated(): # 11121 Deprecation of generate_bq_schema with pytest.warns(FutureWarning): From f8d62cbd907e57af1cc0ff09316a82514fb4419f Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 11:04:23 -0700 Subject: [PATCH 2/6] Increment stacklevel so line where read_gbq is called is highlighted. --- .travis.yml | 6 +++--- pandas_gbq/gbq.py | 4 ++-- tests/system/test_gbq.py | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbd76951..8ea7181a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,10 @@ sudo: false language: python env: - - PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' PYENV_VERSION=2.7.14 + - PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' PYENV_VERSION=2.7.15 - PYTHON=3.5 PANDAS=0.18.1 COVERAGE='true' LINT='false' PYENV_VERSION=3.5.4 - - PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' PYENV_VERSION=3.6.1 - - PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' PYENV_VERSION=3.6.1 + - PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' PYENV_VERSION=3.6.4 + - PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' PYENV_VERSION=3.6.4 before_install: - echo "before_install" diff --git a/pandas_gbq/gbq.py b/pandas_gbq/gbq.py index afc01bb6..e7642ccd 100644 --- a/pandas_gbq/gbq.py +++ b/pandas_gbq/gbq.py @@ -560,7 +560,7 @@ def read_gbq(query, project_id=None, index_col=None, col_order=None, 'The default value for dialect is changing to "standard" in a ' 'future version. Pass in dialect="legacy" to disable this ' 'warning.', - FutureWarning, stacklevel=1) + FutureWarning, stacklevel=2) _test_google_api_imports() @@ -568,7 +568,7 @@ def read_gbq(query, project_id=None, index_col=None, col_order=None, warnings.warn( "verbose is deprecated and will be removed in " "a future version. Set logging level in order to vary " - "verbosity", FutureWarning, stacklevel=1) + "verbosity", FutureWarning, stacklevel=2) if dialect not in ('legacy', 'standard'): raise ValueError("'{0}' is not valid for dialect".format(dialect)) diff --git a/tests/system/test_gbq.py b/tests/system/test_gbq.py index 2fd6b3de..bb91befb 100644 --- a/tests/system/test_gbq.py +++ b/tests/system/test_gbq.py @@ -167,7 +167,8 @@ def test_should_properly_handle_null_strings(self, project_id): def test_should_properly_handle_valid_integers(self, project_id): query = 'SELECT INTEGER(3) AS valid_integer' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal(df, DataFrame({'valid_integer': [3]})) def test_should_properly_handle_nullable_integers(self, project_id): @@ -175,7 +176,8 @@ def test_should_properly_handle_nullable_integers(self, project_id): (SELECT 1 AS nullable_integer), (SELECT NULL AS nullable_integer)''' df = gbq.read_gbq(query, project_id=project_id, - private_key=self.credentials) + private_key=self.credentials, + dialect='legacy') tm.assert_frame_equal( df, DataFrame({'nullable_integer': [1, None]}).astype(object)) From e782f4e6d404b6341aedc62ea3326a3450b40731 Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 11:08:16 -0700 Subject: [PATCH 3/6] Update pyenv --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8ea7181a..3625ed68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,8 @@ before_install: install: # work around https://github.com/travis-ci/travis-ci/issues/8363 # https://github.com/pre-commit/pre-commit/commit/e3ab8902692e896da9ded42bd4d76ea4e1de359d + - git clone git://github.com/pyenv/pyenv-update.git ~/.pyenv/plugins/pyenv-update + - pyenv update - pyenv install -s $PYENV_VERSION - pyenv global system $PYENV_VERSION # Upgrade setuptools and pip to work around From 2bc4d318c4a3bc3390841f6c6094c1b4149fe819 Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 11:16:35 -0700 Subject: [PATCH 4/6] Try Python 2.7.15 via Travis build instead of pyenv --- .travis.yml | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3625ed68..7e2915d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,26 @@ -sudo: false - language: python +matrix: + include: + - os: linux + python: 2.7 + env: PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' TRAVIS_PYTHON_VERSION=2.7.15 + - os: linux + python: 3.5 + env: PYTHON=3.5 PANDAS=0.18.1 COVERAGE='true' LINT='false' TRAVIS_PYTHON_VERSION=3.5.4 + - os: linux + python: 3.6 + env: PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' TRAVIS_PYTHON_VERSION=3.6.4 + - os: linux + python: 3.6 + env: PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' TRAVIS_PYTHON_VERSION=3.6.4 env: - - PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' PYENV_VERSION=2.7.15 - - PYTHON=3.5 PANDAS=0.18.1 COVERAGE='true' LINT='false' PYENV_VERSION=3.5.4 - - PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' PYENV_VERSION=3.6.4 - - PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' PYENV_VERSION=3.6.4 before_install: - echo "before_install" - source ci/travis_process_gbq_encryption.sh install: - # work around https://github.com/travis-ci/travis-ci/issues/8363 - # https://github.com/pre-commit/pre-commit/commit/e3ab8902692e896da9ded42bd4d76ea4e1de359d - - git clone git://github.com/pyenv/pyenv-update.git ~/.pyenv/plugins/pyenv-update - - pyenv update - - pyenv install -s $PYENV_VERSION - - pyenv global system $PYENV_VERSION # Upgrade setuptools and pip to work around # https://github.com/pypa/setuptools/issues/885 - pip install --upgrade setuptools From af1dc10e25e882131fd6f33a3496b16c6c59f1cc Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 11:27:20 -0700 Subject: [PATCH 5/6] Add to changelog --- docs/source/changelog.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 6600e52c..47a43f9f 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,11 +1,14 @@ Changelog ========= -.. _changelog-0.5.1: +.. _changelog-0.6.0: -0.5.1 / (Unreleased) +0.6.0 / 2018-08-15 -------------------- +- Warn when ``dialect`` is not passed in to ``read_gbq``. The default dialect + will be changing from 'legacy' to 'standard' in a future version. + (:issue:`195`) - Use general float with 15 decimal digit precision when writing to local CSV buffer in ``to_gbq``. This prevents numerical overflow in certain edge cases. (:issue:`192`) From ec35d9edb1219c235f6c286ca679ee050ce19a26 Mon Sep 17 00:00:00 2001 From: Tim Swast Date: Wed, 15 Aug 2018 11:28:30 -0700 Subject: [PATCH 6/6] Remove unused TRAVIS_PYTHON_VERSION env var. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7e2915d9..b1ab8f9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,16 @@ matrix: include: - os: linux python: 2.7 - env: PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' TRAVIS_PYTHON_VERSION=2.7.15 + env: PYTHON=2.7 PANDAS=0.19.2 COVERAGE='false' LINT='true' - os: linux python: 3.5 - env: PYTHON=3.5 PANDAS=0.18.1 COVERAGE='true' LINT='false' TRAVIS_PYTHON_VERSION=3.5.4 + env: PYTHON=3.5 PANDAS=0.18.1 COVERAGE='true' LINT='false' - os: linux python: 3.6 - env: PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' TRAVIS_PYTHON_VERSION=3.6.4 + env: PYTHON=3.6 PANDAS=0.20.1 COVERAGE='false' LINT='false' - os: linux python: 3.6 - env: PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' TRAVIS_PYTHON_VERSION=3.6.4 + env: PYTHON=3.6 PANDAS=MASTER COVERAGE='false' LINT='true' env: before_install: