diff --git a/google/cloud/bigquery/dataset.py b/google/cloud/bigquery/dataset.py index 99c47026f..40489a38b 100644 --- a/google/cloud/bigquery/dataset.py +++ b/google/cloud/bigquery/dataset.py @@ -20,6 +20,7 @@ import copy import google.cloud._helpers + from google.cloud.bigquery import _helpers from google.cloud.bigquery.model import ModelReference from google.cloud.bigquery.routine import RoutineReference @@ -145,38 +146,60 @@ def __init__(self, role, entity_type, entity_id): "Role must be set for entity " "type %r" % (entity_type,) ) - self.role = role - self.entity_type = entity_type - self.entity_id = entity_id + self._role = role + self._entity_type = entity_type + self._entity_id = entity_id + + @property + def role(self): + """str: The role of the entry.""" + return self._role + + @property + def entity_type(self): + """str: The entity_type of the entry.""" + return self._entity_type + + @property + def entity_id(self): + """str: The entity_id of the entry.""" + return self._entity_id def __eq__(self, other): if not isinstance(other, AccessEntry): return NotImplemented - return ( - self.role == other.role - and self.entity_type == other.entity_type - and self.entity_id == other.entity_id - ) + return self._key() == other._key() def __ne__(self, other): return not self == other def __repr__(self): return "" % ( - self.role, - self.entity_type, - self.entity_id, + self._role, + self._entity_type, + self._entity_id, ) + def _key(self): + """ A tuple key that uniquely describes this field. + Used to compute this instance's hashcode and evaluate equality. + Returns: + Tuple: The contents of this :class:`~google.cloud.bigquery.dataset.AccessEntry`. + """ + return (self._role, self._entity_type, self._entity_id) + + def __hash__(self): + return hash(self._key()) + def to_api_repr(self): """Construct the API resource representation of this access entry Returns: Dict[str, object]: Access entry represented as an API resource """ - resource = {self.entity_type: self.entity_id} - if self.role is not None: - resource["role"] = self.role + resource = {self._entity_type: self._entity_id} + if self._role is not None: + resource["role"] = self._role return resource @classmethod diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py index ac13e0093..e4977a270 100644 --- a/tests/unit/test_dataset.py +++ b/tests/unit/test_dataset.py @@ -84,6 +84,20 @@ def test__eq___type_mismatch(self): self.assertNotEqual(entry, object()) self.assertEqual(entry, mock.ANY) + def test___hash__set_equality(self): + entry1 = self._make_one("OWNER", "userByEmail", "silly@example.com") + entry2 = self._make_one("OWNER", "userByEmail", "phred@example.com") + set_one = {entry1, entry2} + set_two = {entry1, entry2} + self.assertEqual(set_one, set_two) + + def test___hash__not_equals(self): + entry1 = self._make_one("OWNER", "userByEmail", "silly@example.com") + entry2 = self._make_one("OWNER", "userByEmail", "phred@example.com") + set_one = {entry1} + set_two = {entry2} + self.assertNotEqual(set_one, set_two) + def test_to_api_repr(self): entry = self._make_one("OWNER", "userByEmail", "salmon@example.com") resource = entry.to_api_repr()