diff --git a/bigquery/google/cloud/bigquery/model.py b/bigquery/google/cloud/bigquery/model.py index 8b29e4008558..4049a9232467 100644 --- a/bigquery/google/cloud/bigquery/model.py +++ b/bigquery/google/cloud/bigquery/model.py @@ -268,6 +268,9 @@ def from_api_repr(cls, resource): google.cloud.bigquery.model.Model: Model parsed from ``resource``. """ this = cls(None) + # Keep a reference to the resource as a workaround to find unknown + # field values. + this._properties = resource # Convert from millis-from-epoch to timestamp well-known type. # TODO: Remove this hack once CL 238585470 hits prod. @@ -279,12 +282,9 @@ def from_api_repr(cls, resource): start_time = datetime_helpers.from_microseconds(1e3 * float(start_time)) training_run["startTime"] = datetime_helpers.to_rfc3339(start_time) - this._proto = json_format.ParseDict(resource, types.Model()) - for key in six.itervalues(cls._PROPERTY_TO_API_FIELD): - # Leave missing keys unset. This allows us to use setdefault in the - # getters where we want a default value other than None. - if key in resource: - this._properties[key] = resource[key] + this._proto = json_format.ParseDict( + resource, types.Model(), ignore_unknown_fields=True + ) return this def _build_resource(self, filter_fields): @@ -304,6 +304,7 @@ class ModelReference(object): def __init__(self): self._proto = types.ModelReference() + self._properties = {} @property def project(self): @@ -342,7 +343,12 @@ def from_api_repr(cls, resource): Model reference parsed from ``resource``. """ ref = cls() - ref._proto = json_format.ParseDict(resource, types.ModelReference()) + # Keep a reference to the resource as a workaround to find unknown + # field values. + ref._properties = resource + ref._proto = json_format.ParseDict( + resource, types.ModelReference(), ignore_unknown_fields=True + ) return ref @classmethod diff --git a/bigquery/tests/unit/model/test_model.py b/bigquery/tests/unit/model/test_model.py index 2086c333486d..b6d9756e15fe 100644 --- a/bigquery/tests/unit/model/test_model.py +++ b/bigquery/tests/unit/model/test_model.py @@ -165,6 +165,22 @@ def test_from_api_repr_w_minimal_resource(target_class): assert len(got.label_columns) == 0 +def test_from_api_repr_w_unknown_fields(target_class): + from google.cloud.bigquery import ModelReference + + resource = { + "modelReference": { + "projectId": "my-project", + "datasetId": "my_dataset", + "modelId": "my_model", + }, + "thisFieldIsNotInTheProto": "just ignore me", + } + got = target_class.from_api_repr(resource) + assert got.reference == ModelReference.from_string("my-project.my_dataset.my_model") + assert got._properties is resource + + @pytest.mark.parametrize( "resource,filter_fields,expected", [ diff --git a/bigquery/tests/unit/model/test_model_reference.py b/bigquery/tests/unit/model/test_model_reference.py index 0145c76f6ad0..ff1d1df7d499 100644 --- a/bigquery/tests/unit/model/test_model_reference.py +++ b/bigquery/tests/unit/model/test_model_reference.py @@ -37,6 +37,20 @@ def test_from_api_repr(target_class): assert got.path == "/projects/my-project/datasets/my_dataset/models/my_model" +def test_from_api_repr_w_unknown_fields(target_class): + resource = { + "projectId": "my-project", + "datasetId": "my_dataset", + "modelId": "my_model", + "thisFieldIsNotInTheProto": "just ignore me", + } + got = target_class.from_api_repr(resource) + assert got.project == "my-project" + assert got.dataset_id == "my_dataset" + assert got.model_id == "my_model" + assert got._properties is resource + + def test_to_api_repr(target_class): ref = target_class.from_string("my-project.my_dataset.my_model") got = ref.to_api_repr()