Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 347e555

Browse files
committedSep 18, 2017
BQ: client.extract_table starts extract job
Add system tests for extract_table.
1 parent 40a3c54 commit 347e555

File tree

8 files changed

+472
-96
lines changed

8 files changed

+472
-96
lines changed
 

‎bigquery/google/cloud/bigquery/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from google.cloud.bigquery.client import Client
3333
from google.cloud.bigquery.dataset import AccessEntry
3434
from google.cloud.bigquery.dataset import Dataset
35+
from google.cloud.bigquery.job import ExtractJobConfig
3536
from google.cloud.bigquery.schema import SchemaField
3637
from google.cloud.bigquery.table import Table
3738

@@ -41,6 +42,7 @@
4142
'ArrayQueryParameter',
4243
'Client',
4344
'Dataset',
45+
'ExtractJobConfig',
4446
'ScalarQueryParameter',
4547
'SchemaField',
4648
'StructQueryParameter',

‎bigquery/google/cloud/bigquery/_helpers.py

+76
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,82 @@ def _time_to_json(value):
299299
_SCALAR_VALUE_TO_JSON_PARAM['TIMESTAMP'] = _timestamp_to_json_parameter
300300

301301

302+
class _ApiResourceProperty(object):
303+
"""Base property implementation.
304+
305+
Values will be stored on a `_properties` helper attribute of the
306+
property's job instance.
307+
308+
:type name: str
309+
:param name: name of the property
310+
311+
:type resource_name: str
312+
:param resource_name: name of the property in the resource dictionary
313+
"""
314+
315+
def __init__(self, name, resource_name):
316+
self.name = name
317+
self.resource_name = resource_name
318+
319+
def __get__(self, instance, owner):
320+
"""Descriptor protocol: accessor"""
321+
if instance is None:
322+
return self
323+
return instance._properties.get(self.resource_name)
324+
325+
def _validate(self, value):
326+
"""Subclasses override to impose validation policy."""
327+
pass
328+
329+
def __set__(self, instance, value):
330+
"""Descriptor protocol: mutator"""
331+
self._validate(value)
332+
instance._properties[self.resource_name] = value
333+
334+
def __delete__(self, instance):
335+
"""Descriptor protocol: deleter"""
336+
del instance._properties[self.resource_name]
337+
338+
339+
class _TypedApiResourceProperty(_ApiResourceProperty):
340+
"""Property implementation: validates based on value type.
341+
342+
:type name: str
343+
:param name: name of the property
344+
345+
:type resource_name: str
346+
:param resource_name: name of the property in the resource dictionary
347+
348+
:type property_type: type or sequence of types
349+
:param property_type: type to be validated
350+
"""
351+
def __init__(self, name, resource_name, property_type):
352+
super(_TypedApiResourceProperty, self).__init__(
353+
name, resource_name)
354+
self.property_type = property_type
355+
356+
def _validate(self, value):
357+
"""Ensure that 'value' is of the appropriate type.
358+
359+
:raises: ValueError on a type mismatch.
360+
"""
361+
if value is None:
362+
return
363+
if not isinstance(value, self.property_type):
364+
raise ValueError('Required type: %s' % (self.property_type,))
365+
366+
367+
class _EnumApiResourceProperty(_ApiResourceProperty):
368+
"""Pseudo-enumeration class.
369+
370+
:type name: str
371+
:param name: name of the property.
372+
373+
:type resource_name: str
374+
:param resource_name: name of the property in the resource dictionary
375+
"""
376+
377+
302378
class _ConfigurationProperty(object):
303379
"""Base property implementation.
304380

‎bigquery/google/cloud/bigquery/client.py

+23-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
"""Client for interacting with the Google BigQuery API."""
1616

17+
import uuid
18+
1719
from google.api.core import page_iterator
1820
from google.cloud.client import ClientWithProject
1921
from google.cloud.bigquery._http import Connection
@@ -360,27 +362,39 @@ def copy_table(self, job_id, destination, *sources):
360362
"""
361363
return CopyJob(job_id, destination, sources, client=self)
362364

363-
def extract_table_to_storage(self, job_id, source, *destination_uris):
365+
def extract_table(
366+
self, source, *destination_uris, job_config=None, job_id=None):
364367
"""Construct a job for extracting a table into Cloud Storage files.
365368
366369
See
367370
https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs#configuration.extract
368371
369-
:type job_id: str
370-
:param job_id: Name of the job.
371-
372-
:type source: :class:`google.cloud.bigquery.table.Table`
372+
:type source: :class:`google.cloud.bigquery.table.TableReference`
373373
:param source: table to be extracted.
374374
375375
:type destination_uris: sequence of string
376-
:param destination_uris: URIs of CloudStorage file(s) into which
377-
table data is to be extracted; in format
378-
``gs://<bucket_name>/<object_name_or_glob>``.
376+
:param destination_uris:
377+
URIs of Cloud Storage file(s) into which table data is to be
378+
extracted; in format ``gs://<bucket_name>/<object_name_or_glob>``.
379+
380+
:type job_config: :class:`google.cloud.bigquery.job.ExtractJobConfig`
381+
:param job_config:
382+
(Optional) Extra configuration options for the extract job.
383+
384+
:type job_id: str
385+
:param job_id: (Optional) The ID of the job.
379386
380387
:rtype: :class:`google.cloud.bigquery.job.ExtractJob`
381388
:returns: a new ``ExtractJob`` instance
382389
"""
383-
return ExtractJob(job_id, source, destination_uris, client=self)
390+
if job_id is None:
391+
job_id = str(uuid.uuid4())
392+
393+
job = ExtractJob(
394+
job_id, source, list(destination_uris), client=self,
395+
job_config=job_config)
396+
job.begin()
397+
return job
384398

385399
def run_async_query(self, job_id, query,
386400
udf_resources=(), query_parameters=()):
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.