Repository: googleapis/python-bigquery

Issue:
`AccessEntry` incorrectly parsed from API Representation
Thanks for stopping by to let us know something could be better!

**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response.

Please run down the following list and make sure you've tried the usual "quick fixes":

  - Search the issues already opened: https://github.com/googleapis/python-bigquery/issues
  - Search StackOverflow: https://stackoverflow.com/questions/tagged/google-cloud-platform+python

If you are still having issues, please be sure to include as much information as possible:

#### Environment details

  - OS type and version: Debian GNU/Linux 11 (bullseye)
  - Python version: Python 3.10.13
  - pip version: pip 23.2.1
  - `google-cloud-bigquery` version: 3.11.4

#### Steps to reproduce

  1. Create an `AccessEntry` through `AccessEntry.from_api_repr` without a role in the payload.
    a. This is how the BigQuery API returns `view` type `AccessEntry`s.
  2. Create the same `AccessEntry` through `AccessEntry.__init__` with the equivalent resource.
  3. Compare the 2 for equality and get `False`

#### Code example

```python
from google.cloud.bigquery.dataset import AccessEntry

resource = {
    'view': {
        'projectId': 'my-project',
        'datasetId': 'my_dataset',
        'tableId': 'my_table',
    }
}

api_repr_entry = AccessEntry.from_api_repr(resource)
expected_entry = AccessEntry(
    entity_type='view',
    entity_id=resource['view'],
)

print(api_repr_entry == expected_entry) # False

>>> print(api_repr_entry._properties) # {'view': {'projectId': 'my-project', 'datasetId': 'my_dataset', 'tableId': 'my_table'}}
>>> print(expected_entry._properties) # {'view': {'projectId': 'my-project', 'datasetId': 'my_dataset', 'tableId': 'my_table'}, 'role': None}
```

The entry created through `AccessEntry.__init__` has `'role': None` in its `AccessEntry#_properties` while the one from `AccessEntry.from_api_repr` does not causing the equality to fail. This is due to the `_properties` being overwritten with the API resource which doesn't include the `role` key when it's `null`.

Making sure to follow these steps will guarantee the quickest resolution possible.

Thanks!



Discussion:

Resolving patch:
diff --git a/google/cloud/bigquery/dataset.py b/google/cloud/bigquery/dataset.py
--- a/google/cloud/bigquery/dataset.py
+++ b/google/cloud/bigquery/dataset.py
@@ -501,9 +501,7 @@ def from_api_repr(cls, resource: dict) -> "AccessEntry":
         if len(entry) != 0:
             raise ValueError("Entry has unexpected keys remaining.", entry)
 
-        config = cls(role, entity_type, entity_id)
-        config._properties = copy.deepcopy(resource)
-        return config
+        return cls(role, entity_type, entity_id)
 
 
 class Dataset(object):


Test patch:
diff --git a/tests/unit/test_dataset.py b/tests/unit/test_dataset.py
--- a/tests/unit/test_dataset.py
+++ b/tests/unit/test_dataset.py
@@ -152,6 +152,22 @@ def test_from_api_repr_w_unknown_entity_type(self):
         exp_resource = entry.to_api_repr()
         self.assertEqual(resource, exp_resource)
 
+    def test_from_api_repr_wo_role(self):
+        resource = {
+            "view": {
+                "projectId": "my-project",
+                "datasetId": "my_dataset",
+                "tableId": "my_table",
+            }
+        }
+        entry = self._get_target_class().from_api_repr(resource)
+        exp_entry = self._make_one(
+            role=None,
+            entity_type="view",
+            entity_id=resource["view"],
+        )
+        self.assertEqual(entry, exp_entry)
+
     def test_to_api_repr_w_extra_properties(self):
         resource = {
             "role": "READER",