1313# limitations under the License.
1414
1515import base64
16+ import csv
1617import datetime
1718import json
1819import operator
2122import unittest
2223import uuid
2324
25+ import six
26+
2427from google .cloud import bigquery
2528from google .cloud ._helpers import UTC
2629from google .cloud .bigquery import dbapi
@@ -290,8 +293,6 @@ def test_update_table(self):
290293
291294 @staticmethod
292295 def _fetch_single_page (table ):
293- import six
294-
295296 iterator = table .fetch_data ()
296297 page = six .next (iterator .pages )
297298 return list (page )
@@ -341,7 +342,6 @@ def test_insert_data_then_dump_table(self):
341342 sorted (ROWS , key = by_age ))
342343
343344 def test_load_table_from_local_file_then_dump_table (self ):
344- import csv
345345 from google .cloud ._testing import _NamedTemporaryFile
346346
347347 ROWS = [
@@ -432,7 +432,6 @@ def test_load_table_from_local_avro_file_then_dump_table(self):
432432 sorted (ROWS , key = by_wavelength ))
433433
434434 def test_load_table_from_storage_then_dump_table (self ):
435- import csv
436435 from google .cloud ._testing import _NamedTemporaryFile
437436 from google .cloud .storage import Client as StorageClient
438437
@@ -448,11 +447,11 @@ def test_load_table_from_storage_then_dump_table(self):
448447 ]
449448 TABLE_NAME = 'test_table'
450449
451- s_client = StorageClient ()
450+ storage_client = StorageClient ()
452451
453452 # In the **very** rare case the bucket name is reserved, this
454453 # fails with a ConnectionError.
455- bucket = s_client .create_bucket (BUCKET_NAME )
454+ bucket = storage_client .create_bucket (BUCKET_NAME )
456455 self .to_delete .append (bucket )
457456
458457 blob = bucket .blob (BLOB_NAME )
@@ -501,6 +500,75 @@ def test_load_table_from_storage_then_dump_table(self):
501500 self .assertEqual (sorted (rows , key = by_age ),
502501 sorted (ROWS , key = by_age ))
503502
503+ def test_load_table_from_storage_w_autodetect_schema (self ):
504+ from google .cloud ._testing import _NamedTemporaryFile
505+ from google .cloud .storage import Client as StorageClient
506+ from google .cloud .bigquery import SchemaField
507+
508+ local_id = unique_resource_id ()
509+ bucket_name = 'bq_load_test' + local_id
510+ blob_name = 'person_ages.csv'
511+ gs_url = 'gs://{}/{}' .format (bucket_name , blob_name )
512+ rows = [
513+ ('Phred Phlyntstone' , 32 ),
514+ ('Bharney Rhubble' , 33 ),
515+ ('Wylma Phlyntstone' , 29 ),
516+ ('Bhettye Rhubble' , 27 ),
517+ ] * 100 # BigQuery internally uses the first 100 rows to detect schema
518+ table_name = 'test_table'
519+
520+ storage_client = StorageClient ()
521+
522+ # In the **very** rare case the bucket name is reserved, this
523+ # fails with a ConnectionError.
524+ bucket = storage_client .create_bucket (bucket_name )
525+ self .to_delete .append (bucket )
526+
527+ blob = bucket .blob (blob_name )
528+
529+ with _NamedTemporaryFile () as temp :
530+ with open (temp .name , 'w' ) as csv_write :
531+ writer = csv .writer (csv_write )
532+ writer .writerow (('Full Name' , 'Age' ))
533+ writer .writerows (rows )
534+
535+ with open (temp .name , 'rb' ) as csv_read :
536+ blob .upload_from_file (csv_read , content_type = 'text/csv' )
537+
538+ self .to_delete .insert (0 , blob )
539+
540+ dataset = Config .CLIENT .dataset (
541+ _make_dataset_name ('load_gcs_then_dump' ))
542+
543+ retry_403 (dataset .create )()
544+ self .to_delete .append (dataset )
545+
546+ table = dataset .table (table_name )
547+ self .to_delete .insert (0 , table )
548+
549+ job = Config .CLIENT .load_table_from_storage (
550+ 'bq_load_storage_test_' + local_id , table , gs_url )
551+ job .autodetect = True
552+
553+ job .begin ()
554+
555+ # Allow for 90 seconds of "warm up" before rows visible. See
556+ # https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataavailability
557+ # 8 tries -> 1 + 2 + 4 + 8 + 16 + 32 + 64 = 127 seconds
558+ retry = RetryInstanceState (_job_done , max_tries = 8 )
559+ retry (job .reload )()
560+
561+ table .reload ()
562+ field_name = SchemaField (
563+ u'Full_Name' , u'string' , u'NULLABLE' , None , ())
564+ field_age = SchemaField (u'Age' , u'integer' , u'NULLABLE' , None , ())
565+ self .assertEqual (table .schema , [field_name , field_age ])
566+
567+ actual_rows = self ._fetch_single_page (table )
568+ by_age = operator .itemgetter (1 )
569+ self .assertEqual (
570+ sorted (actual_rows , key = by_age ), sorted (rows , key = by_age ))
571+
504572 def test_job_cancel (self ):
505573 DATASET_NAME = _make_dataset_name ('job_cancel' )
506574 JOB_NAME = 'fetch_' + DATASET_NAME
@@ -674,7 +742,6 @@ def test_dbapi_w_standard_sql_types(self):
674742 self .assertIsNone (row )
675743
676744 def _load_table_for_dml (self , rows , dataset_name , table_name ):
677- import csv
678745 from google .cloud ._testing import _NamedTemporaryFile
679746
680747 dataset = Config .CLIENT .dataset (dataset_name )
0 commit comments