|
15 | 15 | import unittest
|
16 | 16 |
|
17 | 17 | import mock
|
| 18 | +import six |
| 19 | +try: |
| 20 | + import pandas |
| 21 | +except ImportError: # pragma: NO COVER |
| 22 | + pandas = None |
18 | 23 |
|
19 | 24 | from google.cloud.bigquery.dataset import DatasetReference
|
20 | 25 |
|
@@ -773,3 +778,143 @@ def test_row(self):
|
773 | 778 | row.z
|
774 | 779 | with self.assertRaises(KeyError):
|
775 | 780 | row['z']
|
| 781 | + |
| 782 | + |
| 783 | +class TestRowIterator(unittest.TestCase): |
| 784 | + |
| 785 | + def test_constructor(self): |
| 786 | + from google.cloud.bigquery.table import RowIterator |
| 787 | + from google.cloud.bigquery._helpers import _item_to_row |
| 788 | + from google.cloud.bigquery._helpers import _rows_page_start |
| 789 | + |
| 790 | + client = mock.sentinel.client |
| 791 | + api_request = mock.sentinel.api_request |
| 792 | + path = '/foo' |
| 793 | + iterator = RowIterator(client, api_request, path) |
| 794 | + |
| 795 | + self.assertFalse(iterator._started) |
| 796 | + self.assertIs(iterator.client, client) |
| 797 | + self.assertEqual(iterator.path, path) |
| 798 | + self.assertIs(iterator._item_to_value, _item_to_row) |
| 799 | + self.assertEqual(iterator._items_key, 'rows') |
| 800 | + self.assertIsNone(iterator.max_results) |
| 801 | + self.assertEqual(iterator.extra_params, {}) |
| 802 | + self.assertEqual(iterator._page_start, _rows_page_start) |
| 803 | + # Changing attributes. |
| 804 | + self.assertEqual(iterator.page_number, 0) |
| 805 | + self.assertIsNone(iterator.next_page_token) |
| 806 | + self.assertEqual(iterator.num_results, 0) |
| 807 | + |
| 808 | + def test_iterate(self): |
| 809 | + from google.cloud.bigquery.table import RowIterator |
| 810 | + from google.cloud.bigquery.table import SchemaField |
| 811 | + from google.cloud.bigquery._helpers import _field_to_index_mapping |
| 812 | + |
| 813 | + schema = [ |
| 814 | + SchemaField('name', 'STRING', mode='REQUIRED'), |
| 815 | + SchemaField('age', 'INTEGER', mode='REQUIRED') |
| 816 | + ] |
| 817 | + rows = [ |
| 818 | + {'f': [{'v': 'Phred Phlyntstone'}, {'v': '32'}]}, |
| 819 | + {'f': [{'v': 'Bharney Rhubble'}, {'v': '33'}]}, |
| 820 | + ] |
| 821 | + path = '/foo' |
| 822 | + api_request = mock.Mock(return_value={'rows': rows}) |
| 823 | + row_iterator = RowIterator( |
| 824 | + mock.sentinel.client, api_request, path=path) |
| 825 | + row_iterator._schema = schema |
| 826 | + row_iterator._field_to_index = _field_to_index_mapping(schema) |
| 827 | + self.assertEqual(row_iterator.num_results, 0) |
| 828 | + |
| 829 | + rows_iter = iter(row_iterator) |
| 830 | + |
| 831 | + val1 = six.next(rows_iter) |
| 832 | + print(val1) |
| 833 | + self.assertEqual(val1.name, 'Phred Phlyntstone') |
| 834 | + self.assertEqual(row_iterator.num_results, 1) |
| 835 | + |
| 836 | + val2 = six.next(rows_iter) |
| 837 | + self.assertEqual(val2.name, 'Bharney Rhubble') |
| 838 | + self.assertEqual(row_iterator.num_results, 2) |
| 839 | + |
| 840 | + with self.assertRaises(StopIteration): |
| 841 | + six.next(rows_iter) |
| 842 | + |
| 843 | + api_request.assert_called_once_with( |
| 844 | + method='GET', path=path, query_params={}) |
| 845 | + |
| 846 | + @unittest.skipIf(pandas is None, 'Requires `pandas`') |
| 847 | + def test_to_dataframe(self): |
| 848 | + from google.cloud.bigquery.table import RowIterator |
| 849 | + from google.cloud.bigquery.table import SchemaField |
| 850 | + from google.cloud.bigquery._helpers import _field_to_index_mapping |
| 851 | + |
| 852 | + schema = [ |
| 853 | + SchemaField('name', 'STRING', mode='REQUIRED'), |
| 854 | + SchemaField('age', 'INTEGER', mode='REQUIRED') |
| 855 | + ] |
| 856 | + rows = [ |
| 857 | + {'f': [{'v': 'Phred Phlyntstone'}, {'v': '32'}]}, |
| 858 | + {'f': [{'v': 'Bharney Rhubble'}, {'v': '33'}]}, |
| 859 | + {'f': [{'v': 'Wylma Phlyntstone'}, {'v': '29'}]}, |
| 860 | + {'f': [{'v': 'Bhettye Rhubble'}, {'v': '27'}]}, |
| 861 | + ] |
| 862 | + path = '/foo' |
| 863 | + api_request = mock.Mock(return_value={'rows': rows}) |
| 864 | + row_iterator = RowIterator( |
| 865 | + mock.sentinel.client, api_request, path=path) |
| 866 | + row_iterator._schema = schema |
| 867 | + row_iterator._field_to_index = _field_to_index_mapping(schema) |
| 868 | + |
| 869 | + df = row_iterator.to_dataframe() |
| 870 | + |
| 871 | + self.assertIsInstance(df, pandas.DataFrame) |
| 872 | + self.assertEqual(len(df), 4) # verify the number of rows |
| 873 | + self.assertEqual(list(df), ['name', 'age']) # verify the column names |
| 874 | + |
| 875 | + @unittest.skipIf(pandas is None, 'Requires `pandas`') |
| 876 | + def test_to_dataframe_w_empty_results(self): |
| 877 | + from google.cloud.bigquery.table import RowIterator |
| 878 | + from google.cloud.bigquery.table import SchemaField |
| 879 | + from google.cloud.bigquery._helpers import _field_to_index_mapping |
| 880 | + |
| 881 | + schema = [ |
| 882 | + SchemaField('name', 'STRING', mode='REQUIRED'), |
| 883 | + SchemaField('age', 'INTEGER', mode='REQUIRED') |
| 884 | + ] |
| 885 | + path = '/foo' |
| 886 | + api_request = mock.Mock(return_value={'rows': []}) |
| 887 | + row_iterator = RowIterator( |
| 888 | + mock.sentinel.client, api_request, path=path) |
| 889 | + row_iterator._schema = schema |
| 890 | + row_iterator._field_to_index = _field_to_index_mapping(schema) |
| 891 | + |
| 892 | + df = row_iterator.to_dataframe() |
| 893 | + |
| 894 | + self.assertIsInstance(df, pandas.DataFrame) |
| 895 | + self.assertEqual(len(df), 0) # verify the number of rows |
| 896 | + self.assertEqual(list(df), ['name', 'age']) # verify the column names |
| 897 | + |
| 898 | + @mock.patch('google.cloud.bigquery.table.pandas', new=None) |
| 899 | + def test_to_dataframe_error_if_pandas_is_none(self): |
| 900 | + from google.cloud.bigquery.table import RowIterator |
| 901 | + from google.cloud.bigquery.table import SchemaField |
| 902 | + from google.cloud.bigquery._helpers import _field_to_index_mapping |
| 903 | + |
| 904 | + schema = [ |
| 905 | + SchemaField('name', 'STRING', mode='REQUIRED'), |
| 906 | + SchemaField('age', 'INTEGER', mode='REQUIRED') |
| 907 | + ] |
| 908 | + rows = [ |
| 909 | + {'f': [{'v': 'Phred Phlyntstone'}, {'v': '32'}]}, |
| 910 | + {'f': [{'v': 'Bharney Rhubble'}, {'v': '33'}]}, |
| 911 | + ] |
| 912 | + path = '/foo' |
| 913 | + api_request = mock.Mock(return_value={'rows': rows}) |
| 914 | + row_iterator = RowIterator( |
| 915 | + mock.sentinel.client, api_request, path=path) |
| 916 | + row_iterator._schema = schema |
| 917 | + row_iterator._field_to_index = _field_to_index_mapping(schema) |
| 918 | + |
| 919 | + with self.assertRaises(ValueError): |
| 920 | + row_iterator.to_dataframe() |
0 commit comments