2121import functools
2222import operator
2323import typing
24- from typing import Any , Dict , Iterable , Iterator , List , Optional , Tuple , Union
24+ from typing import Any , Dict , Iterable , Iterator , List , Optional , Tuple , Union , Sequence
25+
2526import warnings
2627
2728try :
6667from google .cloud .bigquery .encryption_configuration import EncryptionConfiguration
6768from google .cloud .bigquery .enums import DefaultPandasDTypes
6869from google .cloud .bigquery .external_config import ExternalConfig
70+ from google .cloud .bigquery import schema as _schema
6971from google .cloud .bigquery .schema import _build_schema_resource
7072from google .cloud .bigquery .schema import _parse_schema_resource
7173from google .cloud .bigquery .schema import _to_schema_fields
@@ -398,7 +400,7 @@ class Table(_TableBase):
398400 "partitioning_type" : "timePartitioning" ,
399401 "range_partitioning" : "rangePartitioning" ,
400402 "time_partitioning" : "timePartitioning" ,
401- "schema" : "schema" ,
403+ "schema" : [ "schema" , "fields" ] ,
402404 "snapshot_definition" : "snapshotDefinition" ,
403405 "clone_definition" : "cloneDefinition" ,
404406 "streaming_buffer" : "streamingBuffer" ,
@@ -411,6 +413,7 @@ class Table(_TableBase):
411413 "max_staleness" : "maxStaleness" ,
412414 "resource_tags" : "resourceTags" ,
413415 "external_catalog_table_options" : "externalCatalogTableOptions" ,
416+ "foreign_type_info" : ["schema" , "foreignTypeInfo" ],
414417 }
415418
416419 def __init__ (self , table_ref , schema = None ) -> None :
@@ -451,8 +454,20 @@ def schema(self):
451454 If ``schema`` is not a sequence, or if any item in the sequence
452455 is not a :class:`~google.cloud.bigquery.schema.SchemaField`
453456 instance or a compatible mapping representation of the field.
457+
458+ .. Note::
459+ If you are referencing a schema for an external catalog table such
460+ as a Hive table, it will also be necessary to populate the foreign_type_info
461+ attribute. This is not necessary if defining the schema for a BigQuery table.
462+
463+ For details, see:
464+ https://cloud.google.com/bigquery/docs/external-tables
465+ https://cloud.google.com/bigquery/docs/datasets-intro#external_datasets
466+
454467 """
455- prop = self ._properties .get (self ._PROPERTY_TO_API_FIELD ["schema" ])
468+ prop = _helpers ._get_sub_prop (
469+ self ._properties , self ._PROPERTY_TO_API_FIELD ["schema" ]
470+ )
456471 if not prop :
457472 return []
458473 else :
@@ -463,10 +478,21 @@ def schema(self, value):
463478 api_field = self ._PROPERTY_TO_API_FIELD ["schema" ]
464479
465480 if value is None :
466- self ._properties [api_field ] = None
467- else :
481+ _helpers ._set_sub_prop (
482+ self ._properties ,
483+ api_field ,
484+ None ,
485+ )
486+ elif isinstance (value , Sequence ):
468487 value = _to_schema_fields (value )
469- self ._properties [api_field ] = {"fields" : _build_schema_resource (value )}
488+ value = _build_schema_resource (value )
489+ _helpers ._set_sub_prop (
490+ self ._properties ,
491+ api_field ,
492+ value ,
493+ )
494+ else :
495+ raise TypeError ("Schema must be a Sequence (e.g. a list) or None." )
470496
471497 @property
472498 def labels (self ):
@@ -1075,6 +1101,43 @@ def external_catalog_table_options(
10751101 self ._PROPERTY_TO_API_FIELD ["external_catalog_table_options" ]
10761102 ] = value
10771103
1104+ @property
1105+ def foreign_type_info (self ) -> Optional [_schema .ForeignTypeInfo ]:
1106+ """Optional. Specifies metadata of the foreign data type definition in
1107+ field schema (TableFieldSchema.foreign_type_definition).
1108+
1109+ Returns:
1110+ Optional[schema.ForeignTypeInfo]:
1111+ Foreign type information, or :data:`None` if not set.
1112+
1113+ .. Note::
1114+ foreign_type_info is only required if you are referencing an
1115+ external catalog such as a Hive table.
1116+ For details, see:
1117+ https://cloud.google.com/bigquery/docs/external-tables
1118+ https://cloud.google.com/bigquery/docs/datasets-intro#external_datasets
1119+ """
1120+
1121+ prop = _helpers ._get_sub_prop (
1122+ self ._properties , self ._PROPERTY_TO_API_FIELD ["foreign_type_info" ]
1123+ )
1124+ if prop is not None :
1125+ return _schema .ForeignTypeInfo .from_api_repr (prop )
1126+ return None
1127+
1128+ @foreign_type_info .setter
1129+ def foreign_type_info (self , value : Union [_schema .ForeignTypeInfo , dict , None ]):
1130+ value = _helpers ._isinstance_or_raise (
1131+ value ,
1132+ (_schema .ForeignTypeInfo , dict ),
1133+ none_allowed = True ,
1134+ )
1135+ if isinstance (value , _schema .ForeignTypeInfo ):
1136+ value = value .to_api_repr ()
1137+ _helpers ._set_sub_prop (
1138+ self ._properties , self ._PROPERTY_TO_API_FIELD ["foreign_type_info" ], value
1139+ )
1140+
10781141 @classmethod
10791142 def from_string (cls , full_table_id : str ) -> "Table" :
10801143 """Construct a table from fully-qualified table ID.
0 commit comments