Skip to content

Commit 3ded66e

Browse files
authored
CLN: rename internal modules. move tests. (#163)
* CLN: rename internal modules. move tests. Per GH#154 we don't need to use underscore to show submodules are private. To be 100% clear, I have added a disclaimer to the API reference as well. Also, I have split the system tests from the unit tests so that the (fast) unit tests can be more easily run separately from the (slow) system tests. I have followed the same directory structure as used in the google-cloud-bigquery library. * CLN: move _version.py back for versioneer * CLN: run tests from tests directory in conda test run
1 parent e09fc11 commit 3ded66e

File tree

15 files changed

+302
-260
lines changed

15 files changed

+302
-260
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ script:
4545
- if [[ $PYTHON == '3.6' ]] && [[ "$PANDAS" == "MASTER" ]]; then nox -s test36master ; fi
4646
- REQ="ci/requirements-${PYTHON}-${PANDAS}" ;
4747
if [ -f "$REQ.conda" ]; then
48-
pip install coverage pytest pytest-cov codecov ;
49-
pytest -v --cov=pandas_gbq --cov-report xml:/tmp/pytest-cov.xml pandas_gbq ;
48+
pip install pytest ;
49+
pytest -v tests ;
5050
fi
5151
- if [[ $COVERAGE == 'true' ]]; then nox -s cover ; fi
5252
- if [[ $LINT == 'true' ]]; then nox -s lint ; fi

docs/source/api.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
API Reference
66
*************
77

8+
.. note::
9+
10+
Only functions and classes which are members of the ``pandas_gbq`` module
11+
are considered public. Submodules and their members are considered private.
12+
813
.. autosummary::
914

1015
read_gbq

docs/source/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Changelog
55
-----------
66

77
- Tests now use `nox` to run in multiple Python environments. (:issue:`52`)
8+
- Renamed internal modules. (:issue:`154`)
89

910
0.4.1 / 2018-04-05
1011
------------------

nox.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,27 @@ def default(session):
1919
session.install('-e', '.')
2020
session.run(
2121
'pytest',
22-
os.path.join('pandas_gbq', 'tests'),
22+
os.path.join('.', 'tests', 'unit'),
23+
os.path.join('.', 'tests', 'system.py'),
2324
'--quiet',
2425
'--cov=pandas_gbq',
26+
'--cov=tests.unit',
27+
'--cov-report',
28+
'xml:/tmp/pytest-cov.xml',
29+
*session.posargs
30+
)
31+
32+
33+
@nox.session
34+
def unit(session):
35+
session.install('mock', 'pytest', 'pytest-cov')
36+
session.install('-e', '.')
37+
session.run(
38+
'pytest',
39+
os.path.join('.', 'tests', 'unit'),
40+
'--quiet',
41+
'--cov=pandas_gbq',
42+
'--cov=tests.unit',
2543
'--cov-report',
2644
'xml:/tmp/pytest-cov.xml',
2745
*session.posargs
@@ -69,7 +87,7 @@ def test36master(session):
6987
@nox.session
7088
def lint(session):
7189
session.install('flake8')
72-
session.run('flake8', 'pandas_gbq', '-v')
90+
session.run('flake8', 'pandas_gbq', 'tests', '-v')
7391

7492

7593
@nox.session

pandas_gbq/gbq.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def process_http_error(ex):
458458
def run_query(self, query, **kwargs):
459459
from google.auth.exceptions import RefreshError
460460
from concurrent.futures import TimeoutError
461-
from pandas_gbq import _query
461+
import pandas_gbq.query
462462

463463
job_config = {
464464
'query': {
@@ -484,7 +484,7 @@ def run_query(self, query, **kwargs):
484484
logger.info('Requesting query... ')
485485
query_reply = self.client.query(
486486
query,
487-
job_config=_query.query_config(
487+
job_config=pandas_gbq.query.query_config(
488488
job_config, BIGQUERY_INSTALLED_VERSION))
489489
logger.info('ok.\nQuery running...')
490490
except (RefreshError, ValueError):
@@ -552,13 +552,13 @@ def run_query(self, query, **kwargs):
552552
def load_data(
553553
self, dataframe, dataset_id, table_id, chunksize=None,
554554
schema=None):
555-
from pandas_gbq import _load
555+
from pandas_gbq import load
556556

557557
total_rows = len(dataframe)
558558
logger.info("\n\n")
559559

560560
try:
561-
for remaining_rows in _load.load_chunks(
561+
for remaining_rows in load.load_chunks(
562562
self.client, dataframe, dataset_id, table_id,
563563
chunksize=chunksize, schema=schema):
564564
logger.info("\rLoad is {0}% Complete".format(
@@ -1000,8 +1000,8 @@ def generate_bq_schema(df, default_type='STRING'):
10001000

10011001

10021002
def _generate_bq_schema(df, default_type='STRING'):
1003-
from pandas_gbq import _schema
1004-
return _schema.generate_bq_schema(df, default_type=default_type)
1003+
from pandas_gbq import schema
1004+
return schema.generate_bq_schema(df, default_type=default_type)
10051005

10061006

10071007
class _Table(GbqConnector):

pandas_gbq/_load.py renamed to pandas_gbq/load.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import six
44
from google.cloud import bigquery
55

6-
from pandas_gbq import _schema
6+
import pandas_gbq.schema
77

88

99
def encode_chunk(dataframe):
@@ -51,7 +51,7 @@ def load_chunks(
5151
job_config.source_format = 'CSV'
5252

5353
if schema is None:
54-
schema = _schema.generate_bq_schema(dataframe)
54+
schema = pandas_gbq.schema.generate_bq_schema(dataframe)
5555

5656
# Manually create the schema objects, adding NULLABLE mode
5757
# as a workaround for
File renamed without changes.
File renamed without changes.
File renamed without changes.

pandas_gbq/tests/test_gbq.py renamed to tests/system.py

Lines changed: 1 addition & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22

33
import os
4-
import re
54
import sys
65
from datetime import datetime
76
from random import randint
@@ -13,13 +12,12 @@
1312
import pytz
1413
from pandas import DataFrame, NaT, compat
1514
from pandas.compat import range, u
16-
from pandas.compat.numpy import np_datetime64_compat
1715

1816
from pandas_gbq import gbq
1917

2018
try:
2119
import mock
22-
except ImportError:
20+
except ImportError: # pragma: NO COVER
2321
from unittest import mock
2422

2523
TABLE_ID = 'new_test'
@@ -280,233 +278,7 @@ def test_get_user_account_credentials_returns_credentials(self):
280278
assert isinstance(credentials, Credentials)
281279

282280

283-
class TestGBQUnit(object):
284-
285-
@pytest.fixture(autouse=True)
286-
def mock_bigquery_client(self, monkeypatch):
287-
import google.cloud.bigquery
288-
import google.cloud.bigquery.table
289-
mock_client = mock.create_autospec(google.cloud.bigquery.Client)
290-
# Mock out SELECT 1 query results.
291-
mock_query = mock.create_autospec(google.cloud.bigquery.QueryJob)
292-
mock_query.state = 'DONE'
293-
mock_rows = mock.create_autospec(
294-
google.cloud.bigquery.table.RowIterator)
295-
mock_rows.total_rows = 1
296-
mock_rows.schema = [
297-
google.cloud.bigquery.SchemaField('_f0', 'INTEGER')]
298-
mock_rows.__iter__.return_value = [(1,)]
299-
mock_query.result.return_value = mock_rows
300-
mock_client.query.return_value = mock_query
301-
monkeypatch.setattr(
302-
gbq.GbqConnector, 'get_client', lambda _: mock_client)
303-
304-
@pytest.fixture(autouse=True)
305-
def no_auth(self, monkeypatch):
306-
import google.auth.credentials
307-
mock_credentials = mock.create_autospec(
308-
google.auth.credentials.Credentials)
309-
monkeypatch.setattr(
310-
gbq.GbqConnector,
311-
'get_application_default_credentials',
312-
lambda _: mock_credentials)
313-
monkeypatch.setattr(
314-
gbq.GbqConnector,
315-
'get_user_account_credentials',
316-
lambda _: mock_credentials)
317-
318-
def test_should_return_credentials_path_set_by_env_var(self):
319-
env = {'PANDAS_GBQ_CREDENTIALS_FILE': '/tmp/dummy.dat'}
320-
with mock.patch.dict('os.environ', env):
321-
assert gbq._get_credentials_file() == '/tmp/dummy.dat'
322-
323-
@pytest.mark.parametrize(
324-
('input', 'type_', 'expected'), [
325-
(1, 'INTEGER', int(1)),
326-
(1, 'FLOAT', float(1)),
327-
pytest.param('false', 'BOOLEAN', False, marks=pytest.mark.xfail),
328-
pytest.param(
329-
'0e9', 'TIMESTAMP',
330-
np_datetime64_compat('1970-01-01T00:00:00Z'),
331-
marks=pytest.mark.xfail),
332-
('STRING', 'STRING', 'STRING'),
333-
])
334-
def test_should_return_bigquery_correctly_typed(
335-
self, input, type_, expected):
336-
result = gbq._parse_data(
337-
dict(fields=[dict(name='x', type=type_, mode='NULLABLE')]),
338-
rows=[[input]]).iloc[0, 0]
339-
assert result == expected
340-
341-
def test_to_gbq_should_fail_if_invalid_table_name_passed(self):
342-
with pytest.raises(gbq.NotFoundException):
343-
gbq.to_gbq(DataFrame(), 'invalid_table_name', project_id="1234")
344-
345-
def test_to_gbq_with_no_project_id_given_should_fail(self):
346-
with pytest.raises(TypeError):
347-
gbq.to_gbq(DataFrame(), 'dataset.tablename')
348-
349-
def test_to_gbq_with_verbose_new_pandas_warns_deprecation(self):
350-
import pkg_resources
351-
min_bq_version = pkg_resources.parse_version('0.29.0')
352-
pandas_version = pkg_resources.parse_version('0.23.0')
353-
with pytest.warns(FutureWarning), \
354-
mock.patch(
355-
'pkg_resources.Distribution.parsed_version',
356-
new_callable=mock.PropertyMock) as mock_version:
357-
mock_version.side_effect = [min_bq_version, pandas_version]
358-
try:
359-
gbq.to_gbq(
360-
DataFrame(),
361-
'dataset.tablename',
362-
project_id='my-project',
363-
verbose=True)
364-
except gbq.TableCreationError:
365-
pass
366-
367-
def test_to_gbq_with_not_verbose_new_pandas_warns_deprecation(self):
368-
import pkg_resources
369-
min_bq_version = pkg_resources.parse_version('0.29.0')
370-
pandas_version = pkg_resources.parse_version('0.23.0')
371-
with pytest.warns(FutureWarning), \
372-
mock.patch(
373-
'pkg_resources.Distribution.parsed_version',
374-
new_callable=mock.PropertyMock) as mock_version:
375-
mock_version.side_effect = [min_bq_version, pandas_version]
376-
try:
377-
gbq.to_gbq(
378-
DataFrame(),
379-
'dataset.tablename',
380-
project_id='my-project',
381-
verbose=False)
382-
except gbq.TableCreationError:
383-
pass
384-
385-
def test_to_gbq_wo_verbose_w_new_pandas_no_warnings(self, recwarn):
386-
import pkg_resources
387-
min_bq_version = pkg_resources.parse_version('0.29.0')
388-
pandas_version = pkg_resources.parse_version('0.23.0')
389-
with mock.patch(
390-
'pkg_resources.Distribution.parsed_version',
391-
new_callable=mock.PropertyMock) as mock_version:
392-
mock_version.side_effect = [min_bq_version, pandas_version]
393-
try:
394-
gbq.to_gbq(
395-
DataFrame(), 'dataset.tablename', project_id='my-project')
396-
except gbq.TableCreationError:
397-
pass
398-
assert len(recwarn) == 0
399-
400-
def test_to_gbq_with_verbose_old_pandas_no_warnings(self, recwarn):
401-
import pkg_resources
402-
min_bq_version = pkg_resources.parse_version('0.29.0')
403-
pandas_version = pkg_resources.parse_version('0.22.0')
404-
with mock.patch(
405-
'pkg_resources.Distribution.parsed_version',
406-
new_callable=mock.PropertyMock) as mock_version:
407-
mock_version.side_effect = [min_bq_version, pandas_version]
408-
try:
409-
gbq.to_gbq(
410-
DataFrame(),
411-
'dataset.tablename',
412-
project_id='my-project',
413-
verbose=True)
414-
except gbq.TableCreationError:
415-
pass
416-
assert len(recwarn) == 0
417-
418-
def test_read_gbq_with_no_project_id_given_should_fail(self):
419-
with pytest.raises(TypeError):
420-
gbq.read_gbq('SELECT 1')
421-
422-
def test_that_parse_data_works_properly(self):
423-
424-
from google.cloud.bigquery.table import Row
425-
test_schema = {'fields': [
426-
{'mode': 'NULLABLE', 'name': 'column_x', 'type': 'STRING'}]}
427-
field_to_index = {'column_x': 0}
428-
values = ('row_value',)
429-
test_page = [Row(values, field_to_index)]
430-
431-
test_output = gbq._parse_data(test_schema, test_page)
432-
correct_output = DataFrame({'column_x': ['row_value']})
433-
tm.assert_frame_equal(test_output, correct_output)
434-
435-
def test_read_gbq_with_invalid_private_key_json_should_fail(self):
436-
with pytest.raises(gbq.InvalidPrivateKeyFormat):
437-
gbq.read_gbq('SELECT 1', project_id='x', private_key='y')
438-
439-
def test_read_gbq_with_empty_private_key_json_should_fail(self):
440-
with pytest.raises(gbq.InvalidPrivateKeyFormat):
441-
gbq.read_gbq('SELECT 1', project_id='x', private_key='{}')
442-
443-
def test_read_gbq_with_private_key_json_wrong_types_should_fail(self):
444-
with pytest.raises(gbq.InvalidPrivateKeyFormat):
445-
gbq.read_gbq(
446-
'SELECT 1', project_id='x',
447-
private_key='{ "client_email" : 1, "private_key" : True }')
448-
449-
def test_read_gbq_with_empty_private_key_file_should_fail(self):
450-
with tm.ensure_clean() as empty_file_path:
451-
with pytest.raises(gbq.InvalidPrivateKeyFormat):
452-
gbq.read_gbq('SELECT 1', project_id='x',
453-
private_key=empty_file_path)
454-
455-
def test_read_gbq_with_corrupted_private_key_json_should_fail(self):
456-
_skip_if_no_private_key_contents()
457-
458-
with pytest.raises(gbq.InvalidPrivateKeyFormat):
459-
gbq.read_gbq(
460-
'SELECT 1', project_id='x',
461-
private_key=re.sub('[a-z]', '9', _get_private_key_contents()))
462-
463-
def test_read_gbq_with_verbose_new_pandas_warns_deprecation(self):
464-
import pkg_resources
465-
min_bq_version = pkg_resources.parse_version('0.29.0')
466-
pandas_version = pkg_resources.parse_version('0.23.0')
467-
with pytest.warns(FutureWarning), \
468-
mock.patch(
469-
'pkg_resources.Distribution.parsed_version',
470-
new_callable=mock.PropertyMock) as mock_version:
471-
mock_version.side_effect = [min_bq_version, pandas_version]
472-
gbq.read_gbq('SELECT 1', project_id='my-project', verbose=True)
473-
474-
def test_read_gbq_with_not_verbose_new_pandas_warns_deprecation(self):
475-
import pkg_resources
476-
min_bq_version = pkg_resources.parse_version('0.29.0')
477-
pandas_version = pkg_resources.parse_version('0.23.0')
478-
with pytest.warns(FutureWarning), \
479-
mock.patch(
480-
'pkg_resources.Distribution.parsed_version',
481-
new_callable=mock.PropertyMock) as mock_version:
482-
mock_version.side_effect = [min_bq_version, pandas_version]
483-
gbq.read_gbq('SELECT 1', project_id='my-project', verbose=False)
484-
485-
def test_read_gbq_wo_verbose_w_new_pandas_no_warnings(self, recwarn):
486-
import pkg_resources
487-
min_bq_version = pkg_resources.parse_version('0.29.0')
488-
pandas_version = pkg_resources.parse_version('0.23.0')
489-
with mock.patch(
490-
'pkg_resources.Distribution.parsed_version',
491-
new_callable=mock.PropertyMock) as mock_version:
492-
mock_version.side_effect = [min_bq_version, pandas_version]
493-
gbq.read_gbq('SELECT 1', project_id='my-project')
494-
assert len(recwarn) == 0
495-
496-
def test_read_gbq_with_verbose_old_pandas_no_warnings(self, recwarn):
497-
import pkg_resources
498-
min_bq_version = pkg_resources.parse_version('0.29.0')
499-
pandas_version = pkg_resources.parse_version('0.22.0')
500-
with mock.patch(
501-
'pkg_resources.Distribution.parsed_version',
502-
new_callable=mock.PropertyMock) as mock_version:
503-
mock_version.side_effect = [min_bq_version, pandas_version]
504-
gbq.read_gbq('SELECT 1', project_id='my-project', verbose=True)
505-
assert len(recwarn) == 0
506-
507-
508281
def test_should_read(project, credentials):
509-
510282
query = 'SELECT "PI" AS valid_string'
511283
df = gbq.read_gbq(query, project_id=project, private_key=credentials)
512284
tm.assert_frame_equal(df, DataFrame({'valid_string': ['PI']}))

tests/unit/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)