Skip to content

Commit b0a7fb1

Browse files
committed
Adds fixtures, tests, corrections to classes and tests
1 parent d71d904 commit b0a7fb1

File tree

7 files changed

+181
-79
lines changed

7 files changed

+181
-79
lines changed

google/cloud/bigquery/dataset.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +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
26+
from google.cloud.bigquery._helpers import _isinstance_or_raise
2727
from google.cloud.bigquery.model import ModelReference
2828
from google.cloud.bigquery.routine import Routine, RoutineReference
2929
from google.cloud.bigquery.table import Table, TableReference
@@ -955,15 +955,15 @@ def external_catalog_dataset_options(self):
955955
prop = ExternalCatalogDatasetOptions().from_api_repr(prop)
956956
return prop
957957

958-
959958
@external_catalog_dataset_options.setter
960959
def external_catalog_dataset_options(self, value):
961-
value = _isinstance_or_raise(value, ExternalCatalogDatasetOptions)
960+
value = _isinstance_or_raise(
961+
value, ExternalCatalogDatasetOptions, none_allowed=True
962+
)
962963
self._properties[
963964
self._PROPERTY_TO_API_FIELD["external_catalog_dataset_options"]
964965
] = value.to_api_repr()
965966

966-
967967
table = _get_table_reference
968968
model = _get_model_reference
969969
routine = _get_routine_reference

google/cloud/bigquery/external_config.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030
_int_or_none,
3131
_str_or_none,
3232
_isinstance_or_raise,
33-
_from_api_repr,
33+
_get_sub_prop,
3434
)
3535
from google.cloud.bigquery.format_options import AvroOptions, ParquetOptions
36-
from google.cloud.bigquery.schema import SchemaField
36+
from google.cloud.bigquery.schema import SchemaField, StorageDescriptor
3737

3838

3939
class ExternalSourceFormat(object):
@@ -1067,7 +1067,7 @@ def to_api_repr(self) -> dict:
10671067
return config
10681068

10691069
@classmethod
1070-
def from_api_repr(cls, resource: dict) -> "TODO":
1070+
def from_api_repr(cls, resource: dict) -> ExternalCatalogDatasetOptions:
10711071
"""Factory: constructs an instance of the class (cls)
10721072
given its API representation.
10731073
@@ -1082,6 +1082,7 @@ def from_api_repr(cls, resource: dict) -> "TODO":
10821082
config._properties = copy.deepcopy(resource)
10831083
return config
10841084

1085+
10851086
class ExternalCatalogTableOptions:
10861087
"""Metadata about open source compatible table. The fields contained in these
10871088
options correspond to hive metastore's table level properties.
@@ -1104,7 +1105,7 @@ def __init__(
11041105
connection_id: Optional[str] = None,
11051106
parameters: Union[Dict[str, Any], None] = None,
11061107
storage_descriptor: Optional[
1107-
str
1108+
StorageDescriptor
11081109
] = None, # TODO implement StorageDescriptor, then correct this type hint
11091110
):
11101111
self._properties = {} # type: Dict[str, Any]
@@ -1146,12 +1147,19 @@ def storage_descriptor(self) -> Any:
11461147
"""Optional. A storage descriptor containing information about the
11471148
physical storage of this table."""
11481149

1149-
return self._properties.get("storageDescriptor")
1150+
prop = _get_sub_prop(self._properties, ["storageDescriptor"])
1151+
1152+
if prop is not None:
1153+
prop = StorageDescriptor().from_api_repr(prop)
1154+
return prop
11501155

11511156
@storage_descriptor.setter
1152-
def storage_descriptor(self, value: Optional[str]):
1153-
value = _isinstance_or_raise(value, str, none_allowed=True)
1154-
self._properties["storageDescriptor"] = value
1157+
def storage_descriptor(self, value):
1158+
value = _isinstance_or_raise(value, StorageDescriptor, none_allowed=True)
1159+
if value is not None:
1160+
self._properties["storageDescriptor"] = value.to_api_repr()
1161+
else:
1162+
self._properties["storageDescriptor"] = value
11551163

11561164
def to_api_repr(self) -> dict:
11571165
"""Build an API representation of this object.
@@ -1164,7 +1172,7 @@ def to_api_repr(self) -> dict:
11641172
return config
11651173

11661174
@classmethod
1167-
def from_api_repr(cls, resource: dict) -> "TODO":
1175+
def from_api_repr(cls, resource: dict) -> ExternalCatalogTableOptions:
11681176
"""Factory: constructs an instance of the class (cls)
11691177
given its API representation.
11701178

google/cloud/bigquery/schema.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from google.cloud.bigquery._helpers import (
2626
_isinstance_or_raise,
2727
_from_api_repr,
28+
_get_sub_prop,
2829
)
2930
from google.cloud.bigquery.enums import StandardSqlTypeNames
3031

@@ -715,7 +716,7 @@ def __init__(
715716
input_format: Optional[str] = None,
716717
location_uri: Optional[str] = None,
717718
output_format: Optional[str] = None,
718-
serde_info: Optional[Any] = None,
719+
serde_info: Optional[SerDeInfo] = None,
719720
):
720721
self._properties = {}
721722
self.input_format = input_format
@@ -766,14 +767,20 @@ def output_format(self, value: Optional[str]):
766767
def serde_info(self) -> Any:
767768
"""Optional. Serializer and deserializer information."""
768769

769-
return self._properties.get("serdeInfo")
770+
prop = _get_sub_prop(self._properties, ["serDeInfo"])
771+
print(f"DINOSAUR in SD: {prop}\n\n{self._properties}")
772+
if prop is not None:
773+
prop = SerDeInfo().from_api_repr(prop)
774+
775+
return prop
770776

771777
@serde_info.setter
772-
def serde_info(self, value: Optional[Any]):
773-
value = _isinstance_or_raise(
774-
value, str, none_allowed=True
775-
) # TODO fix, when serde class is done
776-
self._properties["serdeInfo"] = value
778+
def serde_info(self, value):
779+
value = _isinstance_or_raise(value, SerDeInfo, none_allowed=True)
780+
if value is not None:
781+
self._properties["serDeInfo"] = value.to_api_repr()
782+
else:
783+
self._properties["serDeInfo"] = value
777784

778785
def to_api_repr(self) -> dict:
779786
"""Build an API representation of this object.
@@ -784,8 +791,21 @@ def to_api_repr(self) -> dict:
784791
"""
785792
return copy.deepcopy(self._properties)
786793

787-
def from_api_repr(self, resource):
788-
return _from_api_repr(self, resource)
794+
@classmethod
795+
def from_api_repr(cls, resource: dict) -> StorageDescriptor:
796+
"""Factory: constructs an instance of the class (cls)
797+
given its API representation.
798+
799+
Args:
800+
resource (Dict[str, Any]):
801+
API representation of the object to be instantiated.
802+
803+
Returns:
804+
An instance of the class initialized with data from 'resource'.
805+
"""
806+
config = cls()
807+
config._properties = copy.deepcopy(resource)
808+
return config
789809

790810

791811
class SerDeInfo:
@@ -825,7 +845,7 @@ def serialization_library(self) -> Any:
825845

826846
@serialization_library.setter
827847
def serialization_library(self, value: str):
828-
value = _isinstance_or_raise(value, str)
848+
value = _isinstance_or_raise(value, str, none_allowed=False)
829849
self._properties["serializationLibrary"] = value
830850

831851
@property
@@ -860,5 +880,18 @@ def to_api_repr(self) -> dict:
860880
"""
861881
return copy.deepcopy(self._properties)
862882

863-
def from_api_repr(self, resource):
864-
return _from_api_repr(self, resource)
883+
@classmethod
884+
def from_api_repr(cls, resource: dict) -> SerDeInfo:
885+
"""Factory: constructs an instance of the class (cls)
886+
given its API representation.
887+
888+
Args:
889+
resource (Dict[str, Any]):
890+
API representation of the object to be instantiated.
891+
892+
Returns:
893+
An instance of the class initialized with data from 'resource'.
894+
"""
895+
config = cls()
896+
config._properties = copy.deepcopy(resource)
897+
return config

tests/unit/test_dataset.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,12 +1048,10 @@ def test_external_catalog_dataset_options_getter(self):
10481048
dataset.external_catalog_dataset_options = ecdo_obj
10491049
expected = ecdo_obj._properties
10501050
result = dataset.external_catalog_dataset_options._properties
1051-
1051+
10521052
assert result == expected
10531053

10541054
def test_external_catalog_dataset_options_from_api_repr(self):
1055-
from google.cloud.bigquery.external_config import ExternalCatalogDatasetOptions
1056-
10571055
resource = self.API_REPR
10581056
klass = self._get_target_class()
10591057
dataset = klass.from_api_repr(resource)

tests/unit/test_external_config.py

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414

1515
import base64
1616
import copy
17-
from typing import Any, Dict
17+
from typing import Any, Dict, Optional
1818
import unittest
1919

2020
from google.cloud.bigquery import external_config
2121
from google.cloud.bigquery.external_config import (
2222
ExternalCatalogDatasetOptions,
23-
ExternalCatalogTableOptions
23+
ExternalCatalogTableOptions,
2424
)
2525
from google.cloud.bigquery import schema
26+
from google.cloud.bigquery.schema import StorageDescriptor, SerDeInfo
2627

2728
import pytest
2829

@@ -909,7 +910,6 @@ def _get_target_class():
909910
def _make_one(self, *args, **kw):
910911
return self._get_target_class()(*args, **kw)
911912

912-
913913
@pytest.mark.parametrize(
914914
"default_storage_location_uri,parameters",
915915
[
@@ -971,6 +971,23 @@ def test_from_api_repr(self):
971971
assert result._properties == resource
972972

973973

974+
@pytest.fixture
975+
def _make_storage_descriptor():
976+
serdeinfo = SerDeInfo(
977+
serialization_library="testpath.to.LazySimpleSerDe",
978+
name="serde_lib_name",
979+
parameters={"key": "value"},
980+
)
981+
982+
obj = StorageDescriptor(
983+
input_format="testpath.to.OrcInputFormat",
984+
location_uri="gs://test/path/",
985+
output_format="testpath.to.OrcOutputFormat",
986+
serde_info=serdeinfo,
987+
)
988+
return obj
989+
990+
974991
class TestExternalCatalogTableOptions:
975992
@staticmethod
976993
def _get_target_class():
@@ -982,38 +999,52 @@ def _make_one(self, *args, **kw):
982999
@pytest.mark.parametrize(
9831000
"connection_id,parameters,storage_descriptor",
9841001
[
985-
("connection123", {"key": "value"}, "placeholder"), # set all params
1002+
(
1003+
"connection123",
1004+
{"key": "value"},
1005+
"_make_storage_descriptor",
1006+
), # set all params
9861007
("connection123", None, None), # set only one parameter at a time
9871008
(None, {"key": "value"}, None),
988-
(None, None, "placeholder"),
1009+
(None, None, "_make_storage_descriptor"),
9891010
(None, None, None), # use default parameters
9901011
],
9911012
)
992-
def test_ctor_initialization(self, connection_id, parameters, storage_descriptor):
1013+
def test_ctor_initialization(
1014+
self, connection_id, parameters, storage_descriptor, request
1015+
):
1016+
if storage_descriptor == "_make_storage_descriptor":
1017+
storage_descriptor = request.getfixturevalue(storage_descriptor)
1018+
9931019
instance = self._make_one(
9941020
connection_id=connection_id,
9951021
parameters=parameters,
9961022
storage_descriptor=storage_descriptor,
9971023
)
998-
assert instance._properties == {
999-
"connectionId": connection_id,
1000-
"parameters": parameters,
1001-
"storageDescriptor": storage_descriptor,
1002-
}
1024+
1025+
assert instance._properties["connectionId"] == connection_id
1026+
assert instance._properties["parameters"] == parameters
1027+
if storage_descriptor is not None:
1028+
assert (
1029+
instance._properties["storageDescriptor"]
1030+
== storage_descriptor.to_api_repr()
1031+
)
1032+
else:
1033+
assert instance._properties["storageDescriptor"] == storage_descriptor
10031034

10041035
@pytest.mark.parametrize(
10051036
"connection_id, parameters, storage_descriptor",
10061037
[
10071038
pytest.param(
10081039
123,
10091040
{"test_key": "test_value"},
1010-
"test placeholder",
1041+
"_make_storage_descriptor",
10111042
id="connection_id-invalid-type",
10121043
),
10131044
pytest.param(
10141045
"connection123",
10151046
123,
1016-
"test placeholder",
1047+
"_make_storage_descriptor",
10171048
id="parameters-invalid-type",
10181049
),
10191050
pytest.param(
@@ -1028,8 +1059,11 @@ def test_ctor_invalid_input(
10281059
self,
10291060
connection_id: str,
10301061
parameters: Dict[str, Any],
1031-
storage_descriptor: str,
1062+
storage_descriptor: Optional[StorageDescriptor],
1063+
request,
10321064
):
1065+
if storage_descriptor == "_make_storage_descriptor":
1066+
storage_descriptor = request.getfixturevalue(storage_descriptor)
10331067
with pytest.raises(TypeError) as e:
10341068
external_config.ExternalCatalogTableOptions(
10351069
connection_id=connection_id,
@@ -1039,32 +1073,36 @@ def test_ctor_invalid_input(
10391073

10401074
assert "Pass " in str(e.value)
10411075

1042-
def test_to_api_repr(self):
1076+
def test_to_api_repr(self, _make_storage_descriptor):
10431077
instance = self._make_one()
1078+
10441079
instance._properties = {
10451080
"connectionId": "connection123",
10461081
"parameters": {"key": "value"},
1047-
"storageDescriptor": "placeholder",
1082+
"storageDescriptor": _make_storage_descriptor.to_api_repr(),
10481083
}
10491084

10501085
resource = instance.to_api_repr()
1051-
1052-
assert resource == {
1086+
expected = {
10531087
"connectionId": "connection123",
10541088
"parameters": {"key": "value"},
1055-
"storageDescriptor": "placeholder",
1089+
"storageDescriptor": _make_storage_descriptor.to_api_repr(),
10561090
}
1091+
assert resource == expected
10571092

1058-
1059-
def test_from_api_repr(self):
1093+
def test_from_api_repr(self, _make_storage_descriptor):
10601094
instance = self._make_one()
1095+
storage_descriptor = _make_storage_descriptor
10611096
resource = {
10621097
"connectionId": "connection123",
10631098
"parameters": {"key": "value"},
1064-
"storageDescriptor": "placeholder",
1099+
"storageDescriptor": storage_descriptor,
10651100
}
10661101
result = instance.from_api_repr(resource)
1067-
10681102
assert isinstance(result, ExternalCatalogTableOptions)
1069-
assert result._properties == resource
1070-
1103+
assert result._properties["connectionId"] == "connection123"
1104+
assert result._properties["parameters"] == {"key": "value"}
1105+
assert (
1106+
result._properties["storageDescriptor"].to_api_repr()
1107+
== storage_descriptor.to_api_repr()
1108+
)

0 commit comments

Comments
 (0)