3232from google .cloud .bigquery ._helpers import QueryParametersProperty
3333from google .cloud .bigquery ._helpers import ScalarQueryParameter
3434from google .cloud .bigquery ._helpers import StructQueryParameter
35+ from google .cloud .bigquery ._helpers import UDFResource
3536from google .cloud .bigquery ._helpers import UDFResourcesProperty
3637from google .cloud .bigquery ._helpers import _EnumProperty
38+ from google .cloud .bigquery ._helpers import _query_param_from_api_repr
3739from google .cloud .bigquery ._helpers import _TypedProperty
3840
3941_DONE_STATE = 'DONE'
6163}
6264
6365
66+ def _bool_or_none (value ):
67+ """Helper: deserialize boolean value from JSON string."""
68+ if isinstance (value , bool ):
69+ return value
70+ if value is not None :
71+ return value .lower () in ['t' , 'true' , '1' ]
72+
73+
74+ def _int_or_none (value ):
75+ """Helper: deserialize int value from JSON string."""
76+ if isinstance (value , int ):
77+ return value
78+ if value is not None :
79+ return int (value )
80+
81+
6482def _error_result_to_exception (error_result ):
6583 """Maps BigQuery error reasons to an exception.
6684
@@ -311,6 +329,10 @@ def _scrub_local_properties(self, cleaned):
311329 """Helper: handle subclass properties in cleaned."""
312330 pass
313331
332+ def _copy_configuration_properties (self , configuration ):
333+ """Helper: assign subclass configuration properties in cleaned."""
334+ raise NotImplementedError ("Abstract" )
335+
314336 def _set_properties (self , api_response ):
315337 """Update properties from resource in body of ``api_response``
316338
@@ -330,6 +352,8 @@ def _set_properties(self, api_response):
330352
331353 self ._properties .clear ()
332354 self ._properties .update (cleaned )
355+ configuration = cleaned ['configuration' ][self ._JOB_TYPE ]
356+ self ._copy_configuration_properties (configuration )
333357
334358 # For Future interface
335359 self ._set_future_result ()
@@ -731,7 +755,7 @@ def _populate_config_resource(self, configuration):
731755 if self .quote_character is not None :
732756 configuration ['quote' ] = self .quote_character
733757 if self .skip_leading_rows is not None :
734- configuration ['skipLeadingRows' ] = self .skip_leading_rows
758+ configuration ['skipLeadingRows' ] = str ( self .skip_leading_rows )
735759 if self .source_format is not None :
736760 configuration ['sourceFormat' ] = self .source_format
737761 if self .write_disposition is not None :
@@ -769,6 +793,28 @@ def _scrub_local_properties(self, cleaned):
769793 schema = cleaned .pop ('schema' , {'fields' : ()})
770794 self .schema = _parse_schema_resource (schema )
771795
796+ def _copy_configuration_properties (self , configuration ):
797+ """Helper: assign subclass configuration properties in cleaned."""
798+ self .allow_jagged_rows = _bool_or_none (
799+ configuration .get ('allowJaggedRows' ))
800+ self .allow_quoted_newlines = _bool_or_none (
801+ configuration .get ('allowQuotedNewlines' ))
802+ self .autodetect = _bool_or_none (
803+ configuration .get ('autodetect' ))
804+ self .create_disposition = configuration .get ('createDisposition' )
805+ self .encoding = configuration .get ('encoding' )
806+ self .field_delimiter = configuration .get ('fieldDelimiter' )
807+ self .ignore_unknown_values = _bool_or_none (
808+ configuration .get ('ignoreUnknownValues' ))
809+ self .max_bad_records = _int_or_none (
810+ configuration .get ('maxBadRecords' ))
811+ self .null_marker = configuration .get ('nullMarker' )
812+ self .quote_character = configuration .get ('quote' )
813+ self .skip_leading_rows = _int_or_none (
814+ configuration .get ('skipLeadingRows' ))
815+ self .source_format = configuration .get ('sourceFormat' )
816+ self .write_disposition = configuration .get ('writeDisposition' )
817+
772818 @classmethod
773819 def from_api_repr (cls , resource , client ):
774820 """Factory: construct a job given its API representation
@@ -879,6 +925,11 @@ def _build_resource(self):
879925
880926 return resource
881927
928+ def _copy_configuration_properties (self , configuration ):
929+ """Helper: assign subclass configuration properties in cleaned."""
930+ self .create_disposition = configuration .get ('createDisposition' )
931+ self .write_disposition = configuration .get ('writeDisposition' )
932+
882933 @classmethod
883934 def from_api_repr (cls , resource , client ):
884935 """Factory: construct a job given its API representation
@@ -1012,6 +1063,14 @@ def _build_resource(self):
10121063
10131064 return resource
10141065
1066+ def _copy_configuration_properties (self , configuration ):
1067+ """Helper: assign subclass configuration properties in cleaned."""
1068+ self .compression = configuration .get ('compression' )
1069+ self .destination_format = configuration .get ('destinationFormat' )
1070+ self .field_delimiter = configuration .get ('fieldDelimiter' )
1071+ self .print_header = _bool_or_none (
1072+ configuration .get ('printHeader' ))
1073+
10151074 @classmethod
10161075 def from_api_repr (cls , resource , client ):
10171076 """Factory: construct a job given its API representation
@@ -1207,7 +1266,8 @@ def _populate_config_resource(self, configuration):
12071266 if self .maximum_billing_tier is not None :
12081267 configuration ['maximumBillingTier' ] = self .maximum_billing_tier
12091268 if self .maximum_bytes_billed is not None :
1210- configuration ['maximumBytesBilled' ] = self .maximum_bytes_billed
1269+ configuration ['maximumBytesBilled' ] = str (
1270+ self .maximum_bytes_billed )
12111271 if len (self ._udf_resources ) > 0 :
12121272 configuration [self ._UDF_KEY ] = [
12131273 {udf_resource .udf_type : udf_resource .value }
@@ -1257,6 +1317,25 @@ def _scrub_local_properties(self, cleaned):
12571317 configuration = cleaned ['configuration' ]['query' ]
12581318
12591319 self .query = configuration ['query' ]
1320+
1321+ def _copy_configuration_properties (self , configuration ):
1322+ """Helper: assign subclass configuration properties in cleaned."""
1323+ self .allow_large_results = _bool_or_none (
1324+ configuration .get ('allowLargeResults' ))
1325+ self .flatten_results = _bool_or_none (
1326+ configuration .get ('flattenResults' ))
1327+ self .use_query_cache = _bool_or_none (
1328+ configuration .get ('useQueryCache' ))
1329+ self .use_legacy_sql = _bool_or_none (
1330+ configuration .get ('useLegacySql' ))
1331+
1332+ self .create_disposition = configuration .get ('createDisposition' )
1333+ self .priority = configuration .get ('priority' )
1334+ self .write_disposition = configuration .get ('writeDisposition' )
1335+ self .maximum_billing_tier = configuration .get ('maximumBillingTier' )
1336+ self .maximum_bytes_billed = _int_or_none (
1337+ configuration .get ('maximumBytesBilled' ))
1338+
12601339 dest_remote = configuration .get ('destinationTable' )
12611340
12621341 if dest_remote is None :
@@ -1265,9 +1344,30 @@ def _scrub_local_properties(self, cleaned):
12651344 else :
12661345 dest_local = self ._destination_table_resource ()
12671346 if dest_remote != dest_local :
1268- dataset = self ._client .dataset (dest_remote ['datasetId' ])
1347+ project = dest_remote ['projectId' ]
1348+ dataset = self ._client .dataset (
1349+ dest_remote ['datasetId' ], project = project )
12691350 self .destination = dataset .table (dest_remote ['tableId' ])
12701351
1352+ def_ds = configuration .get ('defaultDataset' )
1353+ if def_ds is None :
1354+ if self .default_dataset is not None :
1355+ del self .default_dataset
1356+ else :
1357+ project = def_ds ['projectId' ]
1358+ self .default_dataset = self ._client .dataset (def_ds ['datasetId' ])
1359+
1360+ udf_resources = []
1361+ for udf_mapping in configuration .get (self ._UDF_KEY , ()):
1362+ key_val , = udf_mapping .items ()
1363+ udf_resources .append (UDFResource (key_val [0 ], key_val [1 ]))
1364+ self ._udf_resources = udf_resources
1365+
1366+ self ._query_parameters = [
1367+ _query_param_from_api_repr (mapping )
1368+ for mapping in configuration .get (self ._QUERY_PARAMETERS_KEY , ())
1369+ ]
1370+
12711371 @classmethod
12721372 def from_api_repr (cls , resource , client ):
12731373 """Factory: construct a job given its API representation
0 commit comments