2222
2323import base64
2424import copy
25- from typing import FrozenSet ,Iterable ,Optional
25+ from typing import FrozenSet ,Iterable ,Optional , Union
2626
2727from google .cloud .bigquery ._helpers import _to_bytes
2828from google .cloud .bigquery ._helpers import _bytes_to_json
2929from google .cloud .bigquery ._helpers import _int_or_none
3030from google .cloud .bigquery ._helpers import _str_or_none
31- from google .cloud .bigquery .format_options import ParquetOptions
31+ from google .cloud .bigquery .format_options import AvroOptions , ParquetOptions
3232from google .cloud .bigquery .schema import SchemaField
3333
3434
@@ -548,7 +548,13 @@ def from_api_repr(cls, resource: dict) -> "GoogleSheetsOptions":
548548return config
549549
550550
551- _OPTION_CLASSES = (BigtableOptions ,CSVOptions ,GoogleSheetsOptions ,ParquetOptions )
551+ _OPTION_CLASSES = (
552+ AvroOptions ,
553+ BigtableOptions ,
554+ CSVOptions ,
555+ GoogleSheetsOptions ,
556+ ParquetOptions ,
557+ )
552558
553559
554560class HivePartitioningOptions (object ):
@@ -646,11 +652,6 @@ class ExternalConfig(object):
646652
647653def __init__ (self ,source_format ):
648654self ._properties = {"sourceFormat" :source_format }
649- self ._options = None
650- for optcls in _OPTION_CLASSES :
651- if source_format == optcls ._SOURCE_FORMAT :
652- self ._options = optcls ()
653- break
654655
655656@property
656657def source_format (self ):
@@ -663,9 +664,17 @@ def source_format(self):
663664return self ._properties ["sourceFormat" ]
664665
665666@property
666- def options (self ):
667- """Optional[Dict[str, Any]]: Source-specific options."""
668- return self ._options
667+ def options (self )-> Optional [Union [_OPTION_CLASSES ]]:
668+ """Source-specific options."""
669+ for optcls in _OPTION_CLASSES :
670+ if self .source_format == optcls ._SOURCE_FORMAT :
671+ options = optcls ()
672+ self ._properties .setdefault (optcls ._RESOURCE_NAME , {})
673+ options ._properties = self ._properties [optcls ._RESOURCE_NAME ]
674+ return options
675+
676+ # No matching source format found.
677+ return None
669678
670679@property
671680def autodetect (self ):
@@ -815,23 +824,120 @@ def schema(self, value):
815824self ._properties ["schema" ]= prop
816825
817826@property
818- def parquet_options (self ):
819- """Optional[google.cloud.bigquery.format_options.ParquetOptions]: Additional
820- properties to set if ``sourceFormat`` is set to PARQUET.
827+ def avro_options (self )-> Optional [AvroOptions ]:
828+ """Additional properties to set if ``sourceFormat`` is set to AVRO.
829+
830+ See:
831+ https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#ExternalDataConfiguration.FIELDS.avro_options
832+ """
833+ if self .source_format == ExternalSourceFormat .AVRO :
834+ self ._properties .setdefault (AvroOptions ._RESOURCE_NAME , {})
835+ resource = self ._properties .get (AvroOptions ._RESOURCE_NAME )
836+ if resource is None :
837+ return None
838+ options = AvroOptions ()
839+ options ._properties = resource
840+ return options
841+
842+ @avro_options .setter
843+ def avro_options (self ,value ):
844+ if self .source_format != ExternalSourceFormat .AVRO :
845+ msg = f"Cannot set Avro options, source format is{ self .source_format } "
846+ raise TypeError (msg )
847+ self ._properties [AvroOptions ._RESOURCE_NAME ]= value ._properties
848+
849+ @property
850+ def bigtable_options (self )-> Optional [BigtableOptions ]:
851+ """Additional properties to set if ``sourceFormat`` is set to BIGTABLE.
852+
853+ See:
854+ https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#ExternalDataConfiguration.FIELDS.bigtable_options
855+ """
856+ if self .source_format == ExternalSourceFormat .BIGTABLE :
857+ self ._properties .setdefault (BigtableOptions ._RESOURCE_NAME , {})
858+ resource = self ._properties .get (BigtableOptions ._RESOURCE_NAME )
859+ if resource is None :
860+ return None
861+ options = BigtableOptions ()
862+ options ._properties = resource
863+ return options
864+
865+ @bigtable_options .setter
866+ def bigtable_options (self ,value ):
867+ if self .source_format != ExternalSourceFormat .BIGTABLE :
868+ msg = f"Cannot set Bigtable options, source format is{ self .source_format } "
869+ raise TypeError (msg )
870+ self ._properties [BigtableOptions ._RESOURCE_NAME ]= value ._properties
871+
872+ @property
873+ def csv_options (self )-> Optional [CSVOptions ]:
874+ """Additional properties to set if ``sourceFormat`` is set to CSV.
875+
876+ See:
877+ https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#ExternalDataConfiguration.FIELDS.csv_options
878+ """
879+ if self .source_format == ExternalSourceFormat .CSV :
880+ self ._properties .setdefault (CSVOptions ._RESOURCE_NAME , {})
881+ resource = self ._properties .get (CSVOptions ._RESOURCE_NAME )
882+ if resource is None :
883+ return None
884+ options = CSVOptions ()
885+ options ._properties = resource
886+ return options
887+
888+ @csv_options .setter
889+ def csv_options (self ,value ):
890+ if self .source_format != ExternalSourceFormat .CSV :
891+ msg = f"Cannot set CSV options, source format is{ self .source_format } "
892+ raise TypeError (msg )
893+ self ._properties [CSVOptions ._RESOURCE_NAME ]= value ._properties
894+
895+ @property
896+ def google_sheets_options (self )-> Optional [GoogleSheetsOptions ]:
897+ """Additional properties to set if ``sourceFormat`` is set to
898+ GOOGLE_SHEETS.
899+
900+ See:
901+ https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#ExternalDataConfiguration.FIELDS.google_sheets_options
902+ """
903+ if self .source_format == ExternalSourceFormat .GOOGLE_SHEETS :
904+ self ._properties .setdefault (GoogleSheetsOptions ._RESOURCE_NAME , {})
905+ resource = self ._properties .get (GoogleSheetsOptions ._RESOURCE_NAME )
906+ if resource is None :
907+ return None
908+ options = GoogleSheetsOptions ()
909+ options ._properties = resource
910+ return options
911+
912+ @google_sheets_options .setter
913+ def google_sheets_options (self ,value ):
914+ if self .source_format != ExternalSourceFormat .GOOGLE_SHEETS :
915+ msg = f"Cannot set Google Sheets options, source format is{ self .source_format } "
916+ raise TypeError (msg )
917+ self ._properties [GoogleSheetsOptions ._RESOURCE_NAME ]= value ._properties
918+
919+ @property
920+ def parquet_options (self )-> Optional [ParquetOptions ]:
921+ """Additional properties to set if ``sourceFormat`` is set to PARQUET.
821922
822923 See:
823924 https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#ExternalDataConfiguration.FIELDS.parquet_options
824925 """
825- if self .source_format != ExternalSourceFormat .PARQUET :
926+ if self .source_format == ExternalSourceFormat .PARQUET :
927+ self ._properties .setdefault (ParquetOptions ._RESOURCE_NAME , {})
928+ resource = self ._properties .get (ParquetOptions ._RESOURCE_NAME )
929+ if resource is None :
826930return None
827- return self ._options
931+ options = ParquetOptions ()
932+ options ._properties = resource
933+ return options
828934
829935@parquet_options .setter
830936def parquet_options (self ,value ):
831937if self .source_format != ExternalSourceFormat .PARQUET :
832938msg = f"Cannot set Parquet options, source format is{ self .source_format } "
833939raise TypeError (msg )
834- self ._options = value
940+ self ._properties [ ParquetOptions . _RESOURCE_NAME ] = value . _properties
835941
836942def to_api_repr (self )-> dict :
837943"""Build an API representation of this object.
@@ -841,10 +947,6 @@ def to_api_repr(self) -> dict:
841947 A dictionary in the format used by the BigQuery API.
842948 """
843949config = copy .deepcopy (self ._properties )
844- if self .options is not None :
845- r = self .options .to_api_repr ()
846- if r != {}:
847- config [self .options ._RESOURCE_NAME ]= r
848950return config
849951
850952@classmethod
@@ -862,10 +964,5 @@ def from_api_repr(cls, resource: dict) -> "ExternalConfig":
862964 ExternalConfig: Configuration parsed from ``resource``.
863965 """
864966config = cls (resource ["sourceFormat" ])
865- for optcls in _OPTION_CLASSES :
866- opts = resource .get (optcls ._RESOURCE_NAME )
867- if opts is not None :
868- config ._options = optcls .from_api_repr (opts )
869- break
870967config ._properties = copy .deepcopy (resource )
871968return config