Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions google/cloud/bigquery/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def _record_from_json(value, field):
for subfield, cell in zip(field.fields, value['f']):
converter = _CELLDATA_FROM_JSON[subfield.field_type]
if field.mode == 'REPEATED':
value = [converter(item, field) for item in cell['v']]
value = [converter(item, subfield) for item in cell['v']]
else:
value = converter(cell['v'], field)
value = converter(cell['v'], subfield)
record[subfield.name] = value
return record

Expand Down
258 changes: 258 additions & 0 deletions unit_tests/bigquery/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,255 @@
import unittest


class Test_not_null(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _not_null
return _not_null(value, field)

def test_w_none_nullable(self):
self.assertFalse(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
self.assertTrue(self._callFUT(None, _Field('REQUIRED')))

def test_w_value(self):
self.assertTrue(self._callFUT(object(), object()))


class Test_int_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _int_from_json
return _int_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
with self.assertRaises(TypeError):
self._callFUT(None, _Field('REQUIRED'))

def test_w_string_value(self):
coerced = self._callFUT('42', object())
self.assertEqual(coerced, 42)

def test_w_float_value(self):
coerced = self._callFUT(42, object())
self.assertEqual(coerced, 42)


class Test_float_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _float_from_json
return _float_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
with self.assertRaises(TypeError):
self._callFUT(None, _Field('REQUIRED'))

def test_w_string_value(self):
coerced = self._callFUT('3.1415', object())
self.assertEqual(coerced, 3.1415)

def test_w_float_value(self):
coerced = self._callFUT(3.1415, object())
self.assertEqual(coerced, 3.1415)


class Test_bool_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _bool_from_json
return _bool_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
with self.assertRaises(AttributeError):
self._callFUT(None, _Field('REQUIRED'))

def test_w_value_t(self):
coerced = self._callFUT('T', object())
self.assertTrue(coerced)

def test_w_value_true(self):
coerced = self._callFUT('True', object())
self.assertTrue(coerced)

def test_w_value_1(self):
coerced = self._callFUT('1', object())
self.assertTrue(coerced)

def test_w_value_other(self):
coerced = self._callFUT('f', object())
self.assertFalse(coerced)


class Test_datetime_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _datetime_from_json
return _datetime_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
with self.assertRaises(TypeError):
self._callFUT(None, _Field('REQUIRED'))

def test_w_string_value(self):
import datetime
from google.cloud._helpers import _EPOCH
coerced = self._callFUT('1.234567', object())
self.assertEqual(
coerced,
_EPOCH + datetime.timedelta(seconds=1, microseconds=234567))

def test_w_float_value(self):
import datetime
from google.cloud._helpers import _EPOCH
coerced = self._callFUT(1.234567, object())
self.assertEqual(
coerced,
_EPOCH + datetime.timedelta(seconds=1, microseconds=234567))


class Test_record_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _record_from_json
return _record_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
with self.assertRaises(TypeError):
self._callFUT(None, _Field('REQUIRED'))

def test_w_nullable_subfield_none(self):
subfield = _Field('NULLABLE', 'age', 'INTEGER')
field = _Field('REQUIRED', fields=[subfield])
value = {'f': [{'v': None}]}
coerced = self._callFUT(value, field)
self.assertEqual(coerced, {'age': None})

def test_w_scalar_subfield(self):
subfield = _Field('REQUIRED', 'age', 'INTEGER')
field = _Field('REQUIRED', fields=[subfield])
value = {'f': [{'v': 42}]}
coerced = self._callFUT(value, field)
self.assertEqual(coerced, {'age': 42})

def test_w_repeated_subfield(self):
subfield = _Field('REPEATED', 'color', 'STRING')
field = _Field('REQUIRED', fields=[subfield])
value = {'f': [{'v': ['red', 'yellow', 'blue']}]}
coerced = self._callFUT(value, field)
self.assertEqual(coerced, {'color': ['red', 'yellow', 'blue']})

def test_w_record_subfield(self):
full_name = _Field('REQUIRED', 'full_name', 'STRING')
area_code = _Field('REQUIRED', 'area_code', 'STRING')
local_number = _Field('REQUIRED', 'local_number', 'STRING')
rank = _Field('REQUIRED', 'rank', 'INTEGER')
phone = _Field('NULLABLE', 'phone', 'RECORD',
fields=[area_code, local_number, rank])
person = _Field('REQUIRED', 'person', 'RECORD',
fields=[full_name, phone])
value = {
'f': [
{'v': 'Phred Phlyntstone'},
{'v': {'f': [{'v': '800'}, {'v': '555-1212'}, {'v': 1}]}},
],
}
expected = {
'full_name': 'Phred Phlyntstone',
'phone': {
'area_code': '800',
'local_number': '555-1212',
'rank': 1,
}
}
coerced = self._callFUT(value, person)
self.assertEqual(coerced, expected)


class Test_string_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _string_from_json
return _string_from_json(value, field)

def test_w_none_nullable(self):
self.assertIsNone(self._callFUT(None, _Field('NULLABLE')))

def test_w_none_required(self):
self.assertIsNone(self._callFUT(None, _Field('RECORD')))

def test_w_string_value(self):
coerced = self._callFUT('Wonderful!', object())
self.assertEqual(coerced, 'Wonderful!')


class Test_rows_from_json(unittest.TestCase):

def _callFUT(self, value, field):
from google.cloud.bigquery._helpers import _rows_from_json
return _rows_from_json(value, field)

def test_w_record_subfield(self):
full_name = _Field('REQUIRED', 'full_name', 'STRING')
area_code = _Field('REQUIRED', 'area_code', 'STRING')
local_number = _Field('REQUIRED', 'local_number', 'STRING')
rank = _Field('REQUIRED', 'rank', 'INTEGER')
phone = _Field('NULLABLE', 'phone', 'RECORD',
fields=[area_code, local_number, rank])
color = _Field('REPEATED', 'color', 'STRING')
schema = [full_name, phone, color]
rows = [
{'f': [
{'v': 'Phred Phlyntstone'},
{'v': {'f': [{'v': '800'}, {'v': '555-1212'}, {'v': 1}]}},
{'v': ['orange', 'black']},
]},
{'f': [
{'v': 'Bharney Rhubble'},
{'v': {'f': [{'v': '877'}, {'v': '768-5309'}, {'v': 2}]}},
{'v': ['brown']},
]},
{'f': [
{'v': 'Wylma Phlyntstone'},
{'v': None},
{'v': []},
]},
]
phred_phone = {
'area_code': '800',
'local_number': '555-1212',
'rank': 1,
}
bharney_phone = {
'area_code': '877',
'local_number': '768-5309',
'rank': 2,
}
expected = [
('Phred Phlyntstone', phred_phone, ['orange', 'black']),
('Bharney Rhubble', bharney_phone, ['brown']),
('Wylma Phlyntstone', None, []),
]
coerced = self._callFUT(rows, schema)
self.assertEqual(coerced, expected)


class Test_ConfigurationProperty(unittest.TestCase):

def _getTargetClass(self):
Expand Down Expand Up @@ -114,3 +363,12 @@ def __init__(self):
del wrapper.attr
self.assertEqual(wrapper.attr, None)
self.assertEqual(wrapper._configuration._attr, None)


class _Field(object):

def __init__(self, mode, name='unknown', field_type='UNKNOWN', fields=()):
self.mode = mode
self.name = name
self.field_type = field_type
self.fields = fields