Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions google/cloud/bigquery/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@
from google.cloud.bigquery.query import QueryResults


class Project(object):
"""Wrapper for resource describing a BigQuery project.

:type project_id: str
:param project_id: Opaque ID of the project

:type numeric_id: int
:param numeric_id: Numeric ID of the project

:type friendly_name: str
:param friendly_name: Display name of the project
"""
def __init__(self, project_id, numeric_id, friendly_name):
self.project_id = project_id
self.numeric_id = numeric_id
self.friendly_name = friendly_name

@classmethod
def from_api_repr(cls, resource):
"""Factory: construct an instance from a resource dict."""
return cls(
resource['id'], resource['numericId'], resource['friendlyName'])


class Client(JSONClient):
"""Client to bundle configuration needed for API requests.

Expand All @@ -48,6 +72,42 @@ class Client(JSONClient):

_connection_class = Connection

def list_projects(self, max_results=None, page_token=None):
"""List projects for the project associated with this client.

See:
https://cloud.google.com/bigquery/docs/reference/v2/projects/list

:type max_results: int
:param max_results: maximum number of projects to return, If not
passed, defaults to a value set by the API.

:type page_token: str
:param page_token: opaque marker for the next "page" of projects. If
not passed, the API will return the first page of
projects.

:rtype: tuple, (list, str)
:returns: list of :class:`gcloud.bigquery.client.Project`, plus a
"next page token" string: if the token is not None,
indicates that more projects can be retrieved with another
call (pass that value as ``page_token``).
"""
params = {}

if max_results is not None:
params['maxResults'] = max_results

if page_token is not None:
params['pageToken'] = page_token

path = '/projects'
resp = self.connection.api_request(method='GET', path=path,
query_params=params)
projects = [Project.from_api_repr(resource)
for resource in resp.get('projects', ())]
return projects, resp.get('nextPageToken')

def list_datasets(self, include_all=False, max_results=None,
page_token=None):
"""List datasets for the project associated with this client.
Expand Down
21 changes: 12 additions & 9 deletions google/cloud/resource_manager/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ class Client(BaseClient):
_connection_class = Connection

def new_project(self, project_id, name=None, labels=None):
"""Create a :class:`.Project` bound to the current client.
"""Create a project bound to the current client.

Use :meth:`Project.reload() \
<google.cloud.resource_manager.project.Project.reload>` to retrieve
project metadata after creating a :class:`.Project` instance.
project metadata after creating a
:class:`~gcloud.resource_manager.project.Project` instance.

.. note:

Expand All @@ -68,9 +69,10 @@ def new_project(self, project_id, name=None, labels=None):
:type labels: dict
:param labels: A list of labels associated with the project.

:rtype: :class:`.Project`
:returns: A new instance of a :class:`.Project` **without**
any metadata loaded.
:rtype: :class:`~gcloud.resource_manager.project.Project`
:returns: A new instance of a
:class:`~gcloud.resource_manager.project.Project`
**without** any metadata loaded.
"""
return Project(project_id=project_id,
client=self, name=name, labels=labels)
Expand All @@ -86,8 +88,9 @@ def fetch_project(self, project_id):
:type project_id: str
:param project_id: The ID for this project.

:rtype: :class:`.Project`
:returns: A :class:`.Project` with metadata fetched from the API.
:rtype: :class:`~gcloud.resource_manager.project.Project`
:returns: A :class:`~gcloud.resource_manager.project.Project` with
metadata fetched from the API.
"""
project = self.new_project(project_id)
project.reload()
Expand Down Expand Up @@ -142,7 +145,7 @@ def list_projects(self, filter_params=None, page_size=None):
:returns: A project iterator. The iterator will make multiple API
requests if you continue iterating and there are more
pages of results. Each item returned will be a.
:class:`.Project`.
:class:`~gcloud.resource_manager.project.Project`.
"""
extra_params = {}

Expand Down Expand Up @@ -175,7 +178,7 @@ def __init__(self, client, extra_params=None):
extra_params=extra_params)

def get_items_from_response(self, response):
"""Yield :class:`.Project` items from response.
"""Yield projects from response.

:type response: dict
:param response: The JSON API response for a page of projects.
Expand Down
61 changes: 61 additions & 0 deletions unit_tests/bigquery/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,67 @@ def test_ctor(self):
self.assertTrue(client.connection.credentials is creds)
self.assertTrue(client.connection.http is http)

def test_list_projects_defaults(self):
from google.cloud.bigquery.client import Project
PROJECT_1 = 'PROJECT_ONE'
PROJECT_2 = 'PROJECT_TWO'
PATH = 'projects'
TOKEN = 'TOKEN'
DATA = {
'nextPageToken': TOKEN,
'projects': [
{'kind': 'bigquery#project',
'id': PROJECT_1,
'numericId': 1,
'projectReference': {'projectId': PROJECT_1},
'friendlyName': 'One'},
{'kind': 'bigquery#project',
'id': PROJECT_2,
'numericId': 2,
'projectReference': {'projectId': PROJECT_2},
'friendlyName': 'Two'},
]
}
creds = _Credentials()
client = self._makeOne(PROJECT_1, creds)
conn = client.connection = _Connection(DATA)

projects, token = client.list_projects()

self.assertEqual(len(projects), len(DATA['projects']))
for found, expected in zip(projects, DATA['projects']):
self.assertTrue(isinstance(found, Project))
self.assertEqual(found.project_id, expected['id'])
self.assertEqual(found.numeric_id, expected['numericId'])
self.assertEqual(found.friendly_name, expected['friendlyName'])
self.assertEqual(token, TOKEN)

self.assertEqual(len(conn._requested), 1)
req = conn._requested[0]
self.assertEqual(req['method'], 'GET')
self.assertEqual(req['path'], '/%s' % PATH)

def test_list_projects_explicit_response_missing_projects_key(self):
PROJECT = 'PROJECT'
PATH = 'projects'
TOKEN = 'TOKEN'
DATA = {}
creds = _Credentials()
client = self._makeOne(PROJECT, creds)
conn = client.connection = _Connection(DATA)

projects, token = client.list_projects(max_results=3, page_token=TOKEN)

self.assertEqual(len(projects), 0)
self.assertEqual(token, None)

self.assertEqual(len(conn._requested), 1)
req = conn._requested[0]
self.assertEqual(req['method'], 'GET')
self.assertEqual(req['path'], '/%s' % PATH)
self.assertEqual(req['query_params'],
{'maxResults': 3, 'pageToken': TOKEN})

def test_list_datasets_defaults(self):
from google.cloud.bigquery.dataset import Dataset
PROJECT = 'PROJECT'
Expand Down