-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BQ Tables: ctor, scalar property definitions #1021
Changes from 5 commits
f1ae00e
a545ff0
85e5ad7
019d3e4
0f93943
a8a46d0
ca4a1be
10eaddd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Copyright 2015 Google Inc. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""BigQuery utility functions.""" | ||
|
||
|
||
import datetime | ||
import sys | ||
|
||
import pytz | ||
|
||
_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.utc) | ||
|
||
|
||
def _millis(when): | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
"""Convert a zone-aware datetime to integer milliseconds. | ||
|
||
:type when: ``datetime.datetime`` | ||
:param when: the datetime to convert | ||
|
||
:rtype: integer | ||
:returns: milliseconds since epoch for ``when`` | ||
""" | ||
return int(_total_seconds(when - _EPOCH) * 1000) | ||
|
||
|
||
def _datetime_from_prop(value): | ||
"""Convert non-none timestamp to datetime, assuming UTC. | ||
|
||
:rtype: ``datetime.datetime``, or ``NoneType`` | ||
""" | ||
if value is not None: | ||
# back-end returns timestamps as milliseconds since the epoch | ||
value = datetime.datetime.utcfromtimestamp(value / 1000.0) | ||
return value.replace(tzinfo=pytz.utc) | ||
|
||
|
||
def _prop_from_datetime(value): | ||
"""Convert non-none datetime to timestamp, assuming UTC. | ||
|
||
:type value: ``datetime.datetime``, or None | ||
:param value: the timestamp | ||
|
||
:rtype: integer, or ``NoneType`` | ||
:returns: the timestamp, in milliseconds, or None | ||
""" | ||
if value is not None: | ||
if value.tzinfo is None: | ||
# Assume UTC | ||
value = value.replace(tzinfo=pytz.utc) | ||
# back-end wants timestamps as milliseconds since the epoch | ||
return _millis(value) | ||
|
||
|
||
if sys.version_info[:2] < (2, 7): | ||
def _total_seconds(offset): # pragma: NO COVER | ||
"""Backport of timedelta.total_seconds() from python 2.7+.""" | ||
seconds = offset.days * 24 * 60 * 60 + offset.seconds | ||
microseconds = seconds * 10**6 + offset.microseconds | ||
return microseconds / (10**6 * 1.0) | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
else: | ||
def _total_seconds(offset): | ||
return offset.total_seconds() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
# Copyright 2015 Google Inc. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Define API Datasets.""" | ||
|
||
import datetime | ||
|
||
import six | ||
|
||
from gcloud.bigquery._helpers import _datetime_from_prop | ||
from gcloud.bigquery._helpers import _prop_from_datetime | ||
|
||
|
||
class Table(object): | ||
"""Tables represent a set of rows whose values correspond to a schema. | ||
|
||
See: | ||
https://cloud.google.com/bigquery/docs/reference/v2/tables | ||
|
||
:type name: string | ||
:param name: the name of the table | ||
|
||
:type dataset: :class:`gcloud.bigquery.dataset.Dataset` | ||
:param dataset: The dataset which contains the table. | ||
""" | ||
|
||
def __init__(self, name, dataset): | ||
self.name = name | ||
self._dataset = dataset | ||
self._properties = {} | ||
|
||
@property | ||
def path(self): | ||
"""URL path for the table's APIs. | ||
|
||
:rtype: string | ||
:returns: the path based on project and dataste name. | ||
""" | ||
return '%s/tables/%s' % (self._dataset.path, self.name) | ||
|
||
@property | ||
def created(self): | ||
"""Datetime at which the table was created. | ||
|
||
:rtype: ``datetime.datetime``, or ``NoneType`` | ||
:returns: the creation time (None until set from the server). | ||
""" | ||
return _datetime_from_prop(self._properties.get('creationTime')) | ||
|
||
@property | ||
def etag(self): | ||
"""ETag for the table resource. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: the ETag (None until set from the server). | ||
""" | ||
return self._properties.get('etag') | ||
|
||
@property | ||
def modified(self): | ||
"""Datetime at which the table was last modified. | ||
|
||
:rtype: ``datetime.datetime``, or ``NoneType`` | ||
:returns: the modification time (None until set from the server). | ||
""" | ||
return _datetime_from_prop(self._properties.get('lastModifiedTime')) | ||
|
||
@property | ||
def num_bytes(self): | ||
"""The size of the table in bytes. | ||
|
||
:rtype: integer, or ``NoneType`` | ||
:returns: the byte count (None until set from the server). | ||
""" | ||
return self._properties.get('numBytes') | ||
|
||
@property | ||
def num_rows(self): | ||
"""The number of rows in the table. | ||
|
||
:rtype: integer, or ``NoneType`` | ||
:returns: the row count (None until set from the server). | ||
""" | ||
return self._properties.get('numRows') | ||
|
||
@property | ||
def self_link(self): | ||
"""URL for the table resource. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: the URL (None until set from the server). | ||
""" | ||
return self._properties.get('selfLink') | ||
|
||
@property | ||
def table_id(self): | ||
"""ID for the table resource. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: the ID (None until set from the server). | ||
""" | ||
return self._properties.get('id') | ||
|
||
@property | ||
def table_type(self): | ||
"""The type of the table. | ||
|
||
Possible values are "TABLE" or "VIEW". | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: the URL (None until set from the server). | ||
""" | ||
return self._properties.get('type') | ||
|
||
@property | ||
def description(self): | ||
"""Description of the table. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: The description as set by the user, or None (the default). | ||
""" | ||
return self._properties.get('description') | ||
|
||
@description.setter | ||
def description(self, value): | ||
"""Update description of the table. | ||
|
||
:type value: string, or ``NoneType`` | ||
:param value: new description | ||
|
||
:raises: ValueError for invalid value types. | ||
""" | ||
if not isinstance(value, six.string_types) and value is not None: | ||
raise ValueError("Pass a string, or None") | ||
self._properties['description'] = value | ||
|
||
@property | ||
def expires(self): | ||
"""Datetime at which the table will be removed. | ||
|
||
:rtype: ``datetime.datetime``, or ``NoneType`` | ||
:returns: the expiration time, or None | ||
""" | ||
return _datetime_from_prop(self._properties.get('expirationTime')) | ||
|
||
@expires.setter | ||
def expires(self, value): | ||
"""Update atetime at which the table will be removed. | ||
|
||
:type value: ``datetime.datetime``, or ``NoneType`` | ||
:param value: the new expiration time, or None | ||
""" | ||
if not isinstance(value, datetime.datetime) and value is not None: | ||
raise ValueError("Pass a datetime, or None") | ||
self._properties['expirationTime'] = _prop_from_datetime(value) | ||
|
||
@property | ||
def friendly_name(self): | ||
"""Title of the table. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: The name as set by the user, or None (the default). | ||
""" | ||
return self._properties.get('friendlyName') | ||
|
||
@friendly_name.setter | ||
def friendly_name(self, value): | ||
"""Update title of the table. | ||
|
||
:type value: string, or ``NoneType`` | ||
:param value: new title | ||
|
||
:raises: ValueError for invalid value types. | ||
""" | ||
if not isinstance(value, six.string_types) and value is not None: | ||
raise ValueError("Pass a string, or None") | ||
self._properties['friendlyName'] = value | ||
|
||
@property | ||
def location(self): | ||
"""Location in which the table is hosted. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: The location as set by the user, or None (the default). | ||
""" | ||
return self._properties.get('location') | ||
|
||
@location.setter | ||
def location(self, value): | ||
"""Update location in which the table is hosted. | ||
|
||
:type value: string, or ``NoneType`` | ||
:param value: new location | ||
|
||
:raises: ValueError for invalid value types. | ||
""" | ||
if not isinstance(value, six.string_types) and value is not None: | ||
raise ValueError("Pass a string, or None") | ||
self._properties['location'] = value | ||
|
||
@property | ||
def view_query(self): | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
"""SQL query definiing the table as a view. | ||
|
||
:rtype: string, or ``NoneType`` | ||
:returns: The query as set by the user, or None (the default). | ||
""" | ||
view = self._properties.get('view') | ||
if view is not None: | ||
return view.get('query') | ||
|
||
@view_query.setter | ||
def view_query(self, value): | ||
"""Update SQL query definiing the table as a view. | ||
|
||
:type value: string | ||
:param value: new location | ||
|
||
:raises: ValueError for invalid value types. | ||
""" | ||
if not isinstance(value, six.string_types): | ||
raise ValueError("Pass a string, or None") | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
self._properties['view'] = {'query': value} | ||
|
||
@view_query.deleter | ||
def view_query(self): | ||
"""Delete SQL query definiing the table as a view.""" | ||
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong. |
||
self._properties.pop('view', None) |
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
Sorry, something went wrong.