Skip to content

Commit 14d1bd8

Browse files
committed
Most recent round of tweaks and experiments
1 parent defa38c commit 14d1bd8

File tree

9 files changed

+232
-21
lines changed

9 files changed

+232
-21
lines changed

google/cloud/bigquery/_helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ def _isinstance_or_raise(
10401040
raise TypeError(msg)
10411041

10421042

1043-
def _from_api_repr(obj, resource: dict):
1043+
def _from_api_repr(cls, resource: dict):
10441044
"""Factory: constructs an instance of the class (cls)
10451045
given its API representation.
10461046
@@ -1051,6 +1051,6 @@ def _from_api_repr(obj, resource: dict):
10511051
Returns:
10521052
An instance of the class initialized with data from 'resource'.
10531053
"""
1054-
config = obj
1054+
config = cls
10551055
config._properties = copy.deepcopy(resource)
10561056
return config

google/cloud/bigquery/dataset.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import google.cloud._helpers # type: ignore
2424

2525
from google.cloud.bigquery import _helpers
26+
from google.cloud.bigquery._helpers import _isinstance_or_raise, _get_sub_prop
2627
from google.cloud.bigquery.model import ModelReference
2728
from google.cloud.bigquery.routine import Routine, RoutineReference
2829
from google.cloud.bigquery.table import Table, TableReference
@@ -946,17 +947,28 @@ def external_catalog_dataset_options(self):
946947
BigQuery catalog. Contains metadata of open source database, schema
947948
or namespace represented by the current dataset."""
948949

949-
return self._properties.get("externalCatalogDatasetOptions")
950+
prop = _helpers._get_sub_prop(
951+
self._properties, ["externalCatalogDatasetOptions"]
952+
)
953+
# self._PROPERTY_TO_API_FIELD["external_catalog_dataset_options"]
954+
# )
955+
956+
if prop is not None:
957+
prop = ExternalCatalogDatasetOptions().from_api_repr(prop)
958+
print("DINOSAUR dataset.py prop: ", prop, type(prop))
959+
return prop
960+
961+
# prop = self._get_sub_prop("destinationEncryptionConfiguration")
962+
# if prop is not None:
963+
# prop = EncryptionConfiguration.from_api_repr(prop)
964+
# return prop
950965

951966
@external_catalog_dataset_options.setter
952967
def external_catalog_dataset_options(self, value):
953-
if not isinstance(value, ExternalCatalogDatasetOptions) and value is not None:
954-
raise ValueError(
955-
"external_catalog_dataset_options must be an "
956-
"ExternalCatalogDatasetOptions object or None. "
957-
f"Got {repr(value)}."
958-
)
959-
self._properties["externalCatalogDatasetOptions"] = value.to_api_repr()
968+
value = _isinstance_or_raise(value, ExternalCatalogDatasetOptions)
969+
self._properties[
970+
self._PROPERTY_TO_API_FIELD["external_catalog_dataset_options"]
971+
] = value.to_api_repr()
960972

961973
table = _get_table_reference
962974

google/cloud/bigquery/external_config.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ def to_api_repr(self) -> dict:
10661066
config = copy.deepcopy(self._properties)
10671067
return config
10681068

1069+
@classmethod
10691070
def from_api_repr(self, resource):
10701071
return _from_api_repr(self, resource)
10711072

@@ -1151,5 +1152,18 @@ def to_api_repr(self) -> dict:
11511152
config = copy.deepcopy(self._properties)
11521153
return config
11531154

1154-
def from_api_repr(self, resource):
1155-
return _from_api_repr(self, resource)
1155+
@classmethod
1156+
def from_api_repr(cls, resource: dict) -> "TODO":
1157+
"""Factory: constructs an instance of the class (cls)
1158+
given its API representation.
1159+
1160+
Args:
1161+
resource (Dict[str, Any]):
1162+
API representation of the object to be instantiated.
1163+
1164+
Returns:
1165+
An instance of the class initialized with data from 'resource'.
1166+
"""
1167+
config = cls()
1168+
config._properties = copy.deepcopy(resource)
1169+
return config

google/cloud/bigquery/table.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
import google.cloud._helpers # type: ignore
6161
from google.cloud.bigquery import _helpers
62+
from google.cloud.bigquery._helpers import _isinstance_or_raise
6263
from google.cloud.bigquery import _pandas_helpers
6364
from google.cloud.bigquery import _versions_helpers
6465
from google.cloud.bigquery import exceptions as bq_exceptions
@@ -407,6 +408,7 @@ class Table(_TableBase):
407408
"view_query": "view",
408409
"require_partition_filter": "requirePartitionFilter",
409410
"table_constraints": "tableConstraints",
411+
"external_catalog_table_options": "externalCatalogTableOptions",
410412
}
411413

412414
def __init__(self, table_ref, schema=None) -> None:
@@ -1006,17 +1008,21 @@ def external_catalog_table_options(self):
10061008
BigQuery catalog. Contains metadata of open source database, schema
10071009
or namespace represented by the current dataset."""
10081010

1009-
return self._properties.get("externalCatalogTableOptions")
1011+
prop = self._properties.get(
1012+
self._PROPERTY_TO_API_FIELD["external_catalog_table_options"]
1013+
)
1014+
if prop is not None:
1015+
prop = ExternalCatalogTableOptions.from_api_repr(prop)
1016+
return prop
10101017

10111018
@external_catalog_table_options.setter
10121019
def external_catalog_table_options(self, value):
1013-
if not isinstance(value, ExternalCatalogTableOptions) and value is not None:
1014-
raise ValueError(
1015-
"external_catalog_table_options must be an "
1016-
"ExternalCatalogTableOptions object or None. "
1017-
f"Got {repr(value)}."
1018-
)
1019-
self._properties["externalCatalogTableOptions"] = value.to_api_repr()
1020+
value = _isinstance_or_raise(
1021+
value, ExternalCatalogTableOptions, none_allowed=False
1022+
)
1023+
self._properties[
1024+
self._PROPERTY_TO_API_FIELD["external_catalog_table_options"]
1025+
] = value.to_api_repr()
10201026

10211027
@classmethod
10221028
def from_string(cls, full_table_id: str) -> "Table":

tests/unit/Untitled-2.py

Whitespace-only changes.

tests/unit/test__helpers.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
from unittest import mock
2525

2626
import google.api_core
27-
from google.cloud.bigquery._helpers import _isinstance_or_raise
27+
from google.cloud.bigquery._helpers import (
28+
_isinstance_or_raise,
29+
_from_api_repr,
30+
)
2831

2932

3033
@pytest.mark.skipif(
@@ -1696,3 +1699,21 @@ def test__invalid_isinstance_or_raise(self, value, dtype, none_allowed, expected
16961699
result = _isinstance_or_raise(value, dtype, none_allowed=none_allowed)
16971700

16981701
assert result == e
1702+
1703+
1704+
class _MockClass:
1705+
def __init__(self):
1706+
self._properties = {}
1707+
1708+
1709+
@pytest.fixture
1710+
def mock_class():
1711+
return _MockClass
1712+
1713+
1714+
class Test__from_api_repr:
1715+
def test_from_api_repr(self, mock_class):
1716+
resource = {"foo": "bar", "baz": {"qux": 1}}
1717+
config = _from_api_repr(mock_class, resource)
1718+
assert config._properties == resource
1719+
assert config._properties is not resource

tests/unit/test_dataset.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,55 @@ def test_from_string_legacy_string(self):
10141014
with self.assertRaises(ValueError):
10151015
cls.from_string("string-project:string_dataset")
10161016

1017+
API_REPR = {
1018+
"datasetReference": {"projectId": "project", "datasetId": "dataset-id"},
1019+
"labels": {},
1020+
"externalCatalogDatasetOptions": {
1021+
"defaultStorageLocationUri": "gs://test-bucket/test-path",
1022+
"parameters": {"key": "value"},
1023+
},
1024+
}
1025+
1026+
def test_external_catalog_dataset_options_setter(self):
1027+
from google.cloud.bigquery.external_config import ExternalCatalogDatasetOptions
1028+
1029+
dataset = self._make_one(self.DS_REF)
1030+
external_dataset_catalog_options = ExternalCatalogDatasetOptions(
1031+
default_storage_location_uri="gs://test-bucket/test-path",
1032+
parameters={"key": "value"},
1033+
)
1034+
1035+
# test the setter
1036+
dataset.external_catalog_dataset_options = external_dataset_catalog_options
1037+
expected = self.API_REPR
1038+
result = dataset.to_api_repr()
1039+
assert result == expected
1040+
1041+
def test_external_catalog_dataset_options_getter(self):
1042+
from google.cloud.bigquery.external_config import ExternalCatalogDatasetOptions
1043+
1044+
dataset = self._make_one(self.DS_REF)
1045+
external_dataset_catalog_options = ExternalCatalogDatasetOptions(
1046+
default_storage_location_uri="gs://test-bucket/test-path",
1047+
parameters={"key": "value"},
1048+
)
1049+
dataset.external_catalog_dataset_options = external_dataset_catalog_options
1050+
print("DINOSAUR test_dataset.py dataset: ", dataset, type(dataset))
1051+
expected = external_dataset_catalog_options
1052+
result = dataset.external_catalog_dataset_options
1053+
1054+
assert result == expected
1055+
1056+
def test_external_catalog_dataset_options_from_api_repr(self):
1057+
from google.cloud.bigquery.external_config import ExternalCatalogDatasetOptions
1058+
1059+
resource = self.API_REPR
1060+
1061+
dataset = self._make_one(self.DS_REF)
1062+
dataset = dataset.from_api_repr(resource)
1063+
result = dataset.external_catalog_dataset_options
1064+
assert result == resource["externalCatalogDatasetOptions"]
1065+
10171066
def test__build_resource_w_custom_field(self):
10181067
dataset = self._make_one(self.DS_REF)
10191068
dataset._properties["newAlphaProperty"] = "unreleased property"

tests/unit/test_external_config.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,14 @@ def test_to_api_repr(self):
955955
assert resource["defaultStorageLocationUri"] == default_storage_location_uri
956956
assert resource["parameters"] == parameters
957957

958+
def test_from_api_repr(self):
959+
instance = self._make_one()
960+
resource = {
961+
"defaultStorageLocationUri": "gs://test-bucket/test-path",
962+
"parameters": {"key": "value"},
963+
}
964+
instance.from_api_repr(resource)
965+
958966

959967
class TestExternalCatalogTableOptions:
960968
@staticmethod
@@ -1041,3 +1049,12 @@ def test_ctor_invalid_input(
10411049
)
10421050

10431051
assert "Pass" in str(e.value)
1052+
1053+
def test_from_api_repr(self):
1054+
instance = self._make_one()
1055+
resource = {
1056+
"connectionId": "connection123",
1057+
"parameters": {"key": "value"},
1058+
"storageDescriptor": "placeholder",
1059+
}
1060+
instance.from_api_repr(resource)

tests/unit/test_table.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,3 +5822,95 @@ def test_table_reference_to_bqstorage_v1_stable(table_path):
58225822
for klass in (mut.TableReference, mut.Table, mut.TableListItem):
58235823
got = klass.from_string(table_path).to_bqstorage()
58245824
assert got == expected
5825+
5826+
5827+
@pytest.fixture(scope="class")
5828+
def external_catalog_table_options():
5829+
from google.cloud.bigquery.external_config import ExternalCatalogTableOptions
5830+
5831+
return ExternalCatalogTableOptions(
5832+
connection_id="connection123",
5833+
parameters={"key": "value"},
5834+
storage_descriptor="placeholder",
5835+
)
5836+
5837+
5838+
class TestExternalCatalogTableOptions:
5839+
PROJECT = "project_id"
5840+
DS_ID = "dataset_id"
5841+
TABLE_NAME = "table_name"
5842+
5843+
@staticmethod
5844+
def _get_target_class():
5845+
from google.cloud.bigquery.table import Table
5846+
5847+
return Table
5848+
5849+
@classmethod
5850+
def _make_one(self, *args, **kw):
5851+
return self._get_target_class()(*args, **kw)
5852+
5853+
def test_external_catalog_table_options_getter(
5854+
self, external_catalog_table_options
5855+
):
5856+
from google.cloud.bigquery.external_config import ExternalCatalogTableOptions
5857+
5858+
# create objects for the test
5859+
dataset = DatasetReference(self.PROJECT, self.DS_ID)
5860+
table_ref = dataset.table(self.TABLE_NAME)
5861+
table = self._make_one(table_ref)
5862+
5863+
# Confirm that external catalog table options have not been set
5864+
assert table.external_catalog_table_options is None
5865+
5866+
# Add an ExternalCatalogTableOptions object to the table.
5867+
table._properties[
5868+
"externalCatalogTableOptions"
5869+
] = external_catalog_table_options
5870+
table_repr = table.to_api_repr()
5871+
5872+
# Extract the ecto object.
5873+
ecto_output = table_repr["externalCatalogTableOptions"]
5874+
5875+
# Confirm that external catalog table options are an
5876+
# ExternalCatalogTableOptions object
5877+
assert isinstance(ecto_output, ExternalCatalogTableOptions)
5878+
5879+
expected = {
5880+
"connectionId": "connection123",
5881+
"parameters": {"key": "value"},
5882+
"storageDescriptor": "placeholder",
5883+
}
5884+
result = ecto_output.to_api_repr()
5885+
5886+
# Confirm that the api_repr of the ecto_output matches the inputs
5887+
assert result == expected
5888+
5889+
def test_external_catalog_table_options_setter(
5890+
self, external_catalog_table_options
5891+
):
5892+
# from google.cloud.bigquery.external_config import ExternalCatalogTableOptions
5893+
5894+
# create objects for the test
5895+
dataset = DatasetReference(self.PROJECT, self.DS_ID)
5896+
table_ref = dataset.table(self.TABLE_NAME)
5897+
table = self._make_one(table_ref)
5898+
5899+
# Add an ExternalCatalogTableOptions object to the table.
5900+
table.external_catalog_table_options = external_catalog_table_options
5901+
expected = {
5902+
"tableReference": {
5903+
"projectId": "project_id",
5904+
"datasetId": "dataset_id",
5905+
"tableId": "table_name",
5906+
},
5907+
"labels": {},
5908+
"externalCatalogTableOptions": {
5909+
"connectionId": "connection123",
5910+
"parameters": {"key": "value"},
5911+
"storageDescriptor": "placeholder",
5912+
},
5913+
}
5914+
# Confirm that the api_repr of the ecto_output matches the inputs
5915+
result = table.to_api_repr()
5916+
assert result == expected

0 commit comments

Comments
 (0)