Skip to content

Commit ae36d52

Browse files
committed
Merge pull request #1450 from dhermes/fix-1402
Dropping _has_field.
2 parents 62ba7c5 + cac4730 commit ae36d52

9 files changed

Lines changed: 82 additions & 147 deletions

File tree

gcloud/_helpers.py

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -388,49 +388,6 @@ def _datetime_to_pb_timestamp(when):
388388
return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)
389389

390390

391-
def _has_field(message_pb, property_name):
392-
"""Determine if a field is set on a protobuf.
393-
394-
:type message_pb: :class:`google.protobuf.message.Message`
395-
:param message_pb: The message to check for ``property_name``.
396-
397-
:type property_name: str
398-
:param property_name: The property value to check against.
399-
400-
:rtype: bool
401-
:returns: Flag indicating if ``property_name`` is set on ``message_pb``.
402-
"""
403-
# NOTE: As of proto3, HasField() only works for message fields, not for
404-
# singular (non-message) fields. First try to use HasField and
405-
# if it fails (with a ValueError) we manually consult the fields.
406-
try:
407-
return message_pb.HasField(property_name)
408-
except ValueError:
409-
all_fields = set([field.name for field in message_pb._fields])
410-
return property_name in all_fields
411-
412-
413-
def _get_pb_property_value(message_pb, property_name):
414-
"""Return a message field value.
415-
416-
:type message_pb: :class:`google.protobuf.message.Message`
417-
:param message_pb: The message to check for ``property_name``.
418-
419-
:type property_name: str
420-
:param property_name: The property value to check against.
421-
422-
:rtype: object
423-
:returns: The value of ``property_name`` set on ``message_pb``.
424-
:raises: :class:`ValueError <exceptions.ValueError>` if the result returned
425-
from the ``message_pb`` does not contain the ``property_name``
426-
value.
427-
"""
428-
if _has_field(message_pb, property_name):
429-
return getattr(message_pb, property_name)
430-
else:
431-
raise ValueError('Message does not contain %s.' % (property_name,))
432-
433-
434391
try:
435392
from pytz import UTC # pylint: disable=unused-import,wrong-import-position
436393
except ImportError:

gcloud/bigtable/cluster.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from google.longrunning import operations_pb2
2121

2222
from gcloud._helpers import _pb_timestamp_to_datetime
23-
from gcloud._helpers import _get_pb_property_value
2423
from gcloud.bigtable._generated import bigtable_cluster_data_pb2 as data_pb2
2524
from gcloud.bigtable._generated import (
2625
bigtable_cluster_service_messages_pb2 as messages_pb2)
@@ -240,8 +239,12 @@ def table(self, table_id):
240239
return Table(table_id, self)
241240

242241
def _update_from_pb(self, cluster_pb):
243-
self.display_name = _get_pb_property_value(cluster_pb, 'display_name')
244-
self.serve_nodes = _get_pb_property_value(cluster_pb, 'serve_nodes')
242+
if not cluster_pb.display_name: # Simple field (string)
243+
raise ValueError('Cluster protobuf does not contain display_name')
244+
if not cluster_pb.serve_nodes: # Simple field (int32)
245+
raise ValueError('Cluster protobuf does not contain serve_nodes')
246+
self.display_name = cluster_pb.display_name
247+
self.serve_nodes = cluster_pb.serve_nodes
245248

246249
@classmethod
247250
def from_pb(cls, cluster_pb, client):

gcloud/bigtable/test_cluster.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,53 @@ def test_table_factory(self):
207207
self.assertEqual(table.table_id, table_id)
208208
self.assertEqual(table._cluster, cluster)
209209

210+
def test__update_from_pb_success(self):
211+
from gcloud.bigtable._generated import (
212+
bigtable_cluster_data_pb2 as data_pb2)
213+
from gcloud.bigtable.cluster import _DEFAULT_SERVE_NODES
214+
215+
display_name = 'display_name'
216+
serve_nodes = 8
217+
cluster_pb = data_pb2.Cluster(
218+
display_name=display_name,
219+
serve_nodes=serve_nodes,
220+
)
221+
222+
cluster = self._makeOne(None, None, None)
223+
self.assertEqual(cluster.display_name, None)
224+
self.assertEqual(cluster.serve_nodes, _DEFAULT_SERVE_NODES)
225+
cluster._update_from_pb(cluster_pb)
226+
self.assertEqual(cluster.display_name, display_name)
227+
self.assertEqual(cluster.serve_nodes, serve_nodes)
228+
229+
def test__update_from_pb_no_display_name(self):
230+
from gcloud.bigtable._generated import (
231+
bigtable_cluster_data_pb2 as data_pb2)
232+
from gcloud.bigtable.cluster import _DEFAULT_SERVE_NODES
233+
234+
cluster_pb = data_pb2.Cluster(serve_nodes=331)
235+
cluster = self._makeOne(None, None, None)
236+
self.assertEqual(cluster.display_name, None)
237+
self.assertEqual(cluster.serve_nodes, _DEFAULT_SERVE_NODES)
238+
with self.assertRaises(ValueError):
239+
cluster._update_from_pb(cluster_pb)
240+
self.assertEqual(cluster.display_name, None)
241+
self.assertEqual(cluster.serve_nodes, _DEFAULT_SERVE_NODES)
242+
243+
def test__update_from_pb_no_serve_nodes(self):
244+
from gcloud.bigtable._generated import (
245+
bigtable_cluster_data_pb2 as data_pb2)
246+
from gcloud.bigtable.cluster import _DEFAULT_SERVE_NODES
247+
248+
cluster_pb = data_pb2.Cluster(display_name='name')
249+
cluster = self._makeOne(None, None, None)
250+
self.assertEqual(cluster.display_name, None)
251+
self.assertEqual(cluster.serve_nodes, _DEFAULT_SERVE_NODES)
252+
with self.assertRaises(ValueError):
253+
cluster._update_from_pb(cluster_pb)
254+
self.assertEqual(cluster.display_name, None)
255+
self.assertEqual(cluster.serve_nodes, _DEFAULT_SERVE_NODES)
256+
210257
def test_from_pb_success(self):
211258
from gcloud.bigtable._generated import (
212259
bigtable_cluster_data_pb2 as data_pb2)

gcloud/datastore/connection.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import os
1818

19-
from gcloud._helpers import _has_field
2019
from gcloud import connection
2120
from gcloud.environment_vars import GCD_HOST
2221
from gcloud.exceptions import make_exception
@@ -402,7 +401,7 @@ def _prepare_key_for_request(key_pb): # pragma: NO COVER copied from helpers
402401
:returns: A key which will be added to a request. It will be the
403402
original if nothing needs to be changed.
404403
"""
405-
if _has_field(key_pb.partition_id, 'dataset_id'):
404+
if key_pb.partition_id.dataset_id: # Simple field (string)
406405
new_key_pb = _entity_pb2.Key()
407406
new_key_pb.CopyFrom(key_pb)
408407
new_key_pb.partition_id.ClearField('dataset_id')

gcloud/datastore/helpers.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import six
2424

2525
from gcloud._helpers import _datetime_from_microseconds
26-
from gcloud._helpers import _has_field
2726
from gcloud._helpers import _microseconds_from_datetime
2827
from gcloud.datastore._generated import entity_pb2 as _entity_pb2
2928
from gcloud.datastore.entity import Entity
@@ -110,7 +109,7 @@ def _get_meaning(value_pb, is_list=False):
110109
if all_meanings:
111110
raise ValueError('Different meanings set on values '
112111
'within a list_value')
113-
elif _has_field(value_pb, 'meaning'):
112+
elif value_pb.meaning: # Simple field (int32)
114113
meaning = value_pb.meaning
115114

116115
return meaning
@@ -160,7 +159,7 @@ def entity_from_protobuf(pb):
160159
:returns: The entity derived from the protobuf.
161160
"""
162161
key = None
163-
if _has_field(pb, 'key'):
162+
if pb.HasField('key'): # Message field (Key)
164163
key = key_from_protobuf(pb.key)
165164

166165
entity_props = {}
@@ -260,18 +259,18 @@ def key_from_protobuf(pb):
260259
path_args = []
261260
for element in pb.path_element:
262261
path_args.append(element.kind)
263-
if _has_field(element, 'id'):
262+
if element.id: # Simple field (int64)
264263
path_args.append(element.id)
265264
# This is safe: we expect proto objects returned will only have
266265
# one of `name` or `id` set.
267-
if _has_field(element, 'name'):
266+
if element.name: # Simple field (string)
268267
path_args.append(element.name)
269268

270269
project = None
271-
if _has_field(pb.partition_id, 'dataset_id'):
270+
if pb.partition_id.dataset_id: # Simple field (string)
272271
project = pb.partition_id.dataset_id
273272
namespace = None
274-
if _has_field(pb.partition_id, 'namespace'):
273+
if pb.partition_id.namespace: # Simple field (string)
275274
namespace = pb.partition_id.namespace
276275

277276
return Key(*path_args, namespace=namespace, project=project)
@@ -351,29 +350,30 @@ def _get_value_from_value_pb(value_pb):
351350
:returns: The value provided by the Protobuf.
352351
"""
353352
result = None
354-
if _has_field(value_pb, 'timestamp_microseconds_value'):
353+
# Simple field (int64)
354+
if value_pb.HasField('timestamp_microseconds_value'):
355355
microseconds = value_pb.timestamp_microseconds_value
356356
result = _datetime_from_microseconds(microseconds)
357357

358-
elif _has_field(value_pb, 'key_value'):
358+
elif value_pb.HasField('key_value'): # Message field (Key)
359359
result = key_from_protobuf(value_pb.key_value)
360360

361-
elif _has_field(value_pb, 'boolean_value'):
361+
elif value_pb.HasField('boolean_value'): # Simple field (bool)
362362
result = value_pb.boolean_value
363363

364-
elif _has_field(value_pb, 'double_value'):
364+
elif value_pb.HasField('double_value'): # Simple field (double)
365365
result = value_pb.double_value
366366

367-
elif _has_field(value_pb, 'integer_value'):
367+
elif value_pb.HasField('integer_value'): # Simple field (int64)
368368
result = value_pb.integer_value
369369

370-
elif _has_field(value_pb, 'string_value'):
370+
elif value_pb.HasField('string_value'): # Simple field (string)
371371
result = value_pb.string_value
372372

373-
elif _has_field(value_pb, 'blob_value'):
373+
elif value_pb.HasField('blob_value'): # Simple field (bytes)
374374
result = value_pb.blob_value
375375

376-
elif _has_field(value_pb, 'entity_value'):
376+
elif value_pb.HasField('entity_value'): # Message field (Entity)
377377
result = entity_from_protobuf(value_pb.entity_value)
378378

379379
elif value_pb.list_value:
@@ -429,7 +429,7 @@ def _prepare_key_for_request(key_pb):
429429
:returns: A key which will be added to a request. It will be the
430430
original if nothing needs to be changed.
431431
"""
432-
if _has_field(key_pb.partition_id, 'dataset_id'):
432+
if key_pb.partition_id.dataset_id: # Simple field (string)
433433
# We remove the dataset_id from the protobuf. This is because
434434
# the backend fails a request if the key contains un-prefixed
435435
# project. The backend fails because requests to

gcloud/datastore/test_connection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,8 @@ def request(self, **kw):
900900

901901

902902
def _compare_key_pb_after_request(test, key_before, key_after):
903-
from gcloud._helpers import _has_field
904-
test.assertFalse(_has_field(key_after.partition_id, 'dataset_id'))
903+
# Unset values are False-y.
904+
test.assertEqual(key_after.partition_id.dataset_id, '')
905905
test.assertEqual(key_before.partition_id.namespace,
906906
key_after.partition_id.namespace)
907907
test.assertEqual(len(key_before.path_element),

gcloud/datastore/test_helpers.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ def _callFUT(self, entity):
198198
return entity_to_protobuf(entity)
199199

200200
def _compareEntityProto(self, entity_pb1, entity_pb2):
201-
from gcloud._helpers import _has_field
202201
from gcloud.datastore.helpers import _property_tuples
203202

204203
self.assertEqual(entity_pb1.key, entity_pb2.key)
@@ -209,7 +208,7 @@ def _compareEntityProto(self, entity_pb1, entity_pb2):
209208
name1, val1 = pair1
210209
name2, val2 = pair2
211210
self.assertEqual(name1, name2)
212-
if _has_field(val1, 'entity_value'):
211+
if val1.HasField('entity_value'): # Message field (Entity)
213212
self.assertEqual(val1.meaning, val2.meaning)
214213
self._compareEntityProto(val1.entity_value,
215214
val2.entity_value)
@@ -768,8 +767,6 @@ def test_prefixed(self):
768767
self.assertEqual(PREFIXED, result)
769768

770769
def test_unprefixed_bogus_key_miss(self):
771-
from gcloud._helpers import _has_field
772-
773770
UNPREFIXED = 'PROJECT'
774771
PREFIX = 's~'
775772
CONNECTION = _Connection(PREFIX, from_missing=False)
@@ -785,14 +782,13 @@ def test_unprefixed_bogus_key_miss(self):
785782
self.assertEqual(len(path_element), 1)
786783
self.assertEqual(path_element[0].kind, '__MissingLookupKind')
787784
self.assertEqual(path_element[0].id, 1)
788-
self.assertFalse(_has_field(path_element[0], 'name'))
785+
# Unset values are False-y.
786+
self.assertEqual(path_element[0].name, '')
789787

790788
PREFIXED = PREFIX + UNPREFIXED
791789
self.assertEqual(result, PREFIXED)
792790

793791
def test_unprefixed_bogus_key_hit(self):
794-
from gcloud._helpers import _has_field
795-
796792
UNPREFIXED = 'PROJECT'
797793
PREFIX = 'e~'
798794
CONNECTION = _Connection(PREFIX, from_missing=True)
@@ -807,7 +803,8 @@ def test_unprefixed_bogus_key_hit(self):
807803
self.assertEqual(len(path_element), 1)
808804
self.assertEqual(path_element[0].kind, '__MissingLookupKind')
809805
self.assertEqual(path_element[0].id, 1)
810-
self.assertFalse(_has_field(path_element[0], 'name'))
806+
# Unset values are False-y.
807+
self.assertEqual(path_element[0].name, '')
811808

812809
PREFIXED = PREFIX + UNPREFIXED
813810
self.assertEqual(result, PREFIXED)

gcloud/datastore/test_key.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ def test_completed_key_on_complete(self):
333333
self.assertRaises(ValueError, key.completed_key, 5678)
334334

335335
def test_to_protobuf_defaults(self):
336-
from gcloud._helpers import _has_field
337336
from gcloud.datastore._generated import entity_pb2
338337

339338
_KIND = 'KIND'
@@ -343,16 +342,16 @@ def test_to_protobuf_defaults(self):
343342

344343
# Check partition ID.
345344
self.assertEqual(pb.partition_id.dataset_id, self._DEFAULT_PROJECT)
345+
# Unset values are False-y.
346346
self.assertEqual(pb.partition_id.namespace, '')
347-
self.assertFalse(_has_field(pb.partition_id, 'namespace'))
348347

349348
# Check the element PB matches the partial key and kind.
350349
elem, = list(pb.path_element)
351350
self.assertEqual(elem.kind, _KIND)
351+
# Unset values are False-y.
352352
self.assertEqual(elem.name, '')
353-
self.assertFalse(_has_field(elem, 'name'))
353+
# Unset values are False-y.
354354
self.assertEqual(elem.id, 0)
355-
self.assertFalse(_has_field(elem, 'id'))
356355

357356
def test_to_protobuf_w_explicit_project(self):
358357
_PROJECT = 'PROJECT-ALT'
@@ -383,14 +382,13 @@ def test_to_protobuf_w_explicit_path(self):
383382
self.assertEqual(elems[1].id, _ID)
384383

385384
def test_to_protobuf_w_no_kind(self):
386-
from gcloud._helpers import _has_field
387-
388385
key = self._makeOne('KIND', project=self._DEFAULT_PROJECT)
389386
# Force the 'kind' to be unset. Maybe `to_protobuf` should fail
390387
# on this? The backend certainly will.
391388
key._path[-1].pop('kind')
392389
pb = key.to_protobuf()
393-
self.assertFalse(_has_field(pb.path_element[0], 'kind'))
390+
# Unset values are False-y.
391+
self.assertEqual(pb.path_element[0].kind, '')
394392

395393
def test_is_partial_no_name_or_id(self):
396394
key = self._makeOne('KIND', project=self._DEFAULT_PROJECT)

0 commit comments

Comments
 (0)