Skip to content

Commit

Permalink
Adding base client class in core.
Browse files Browse the repository at this point in the history
This is pre-work in #952, but came up in #933 as well.
  • Loading branch information
dhermes committed Jun 26, 2015
1 parent 7dece69 commit 3068473
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 108 deletions.
104 changes: 104 additions & 0 deletions gcloud/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 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.

"""gcloud client base class for interacting with API."""


from gcloud.credentials import get_for_service_account_json
from gcloud.credentials import get_for_service_account_p12


class Client(object):
"""Client to bundle configuration needed for API requests.
:type credentials: :class:`oauth2client.client.OAuth2Credentials` or
:class:`NoneType`
:param credentials: The OAuth2 Credentials to use for the connection
owned by this client. If not passed (and if no ``http``
object is passed), falls back to the default inferred
from the environment.
:type http: :class:`httplib2.Http` or class that defines ``request()``.
:param http: An optional HTTP object to make requests. If not passed, an
``http`` object is created that is bound to the
``credentials`` for the current object.
"""

def __init__(self, credentials=None, http=None):
self.credentials = credentials
self.http = http

@classmethod
def from_service_account_json(cls, json_credentials_path, *args, **kwargs):
"""Factory to retrieve JSON credentials while creating client.
:type json_credentials_path: string
:param json_credentials_path: The path to a private key file (this file
was given to you when you created the
service account). This file must contain
a JSON object with a private key and
other credentials information (downloaded
from the Google APIs console).
:type args: tuple
:param args: Remaining positional arguments to pass to constructor.
:type kwargs: dictionary
:param kwargs: Remaining keyword arguments to pass to constructor.
:rtype: :class:`gcloud.pubsub.client.Client`
:returns: The client created with the retrieved JSON credentials.
:raises: class:`TypeError` if there is a conflict with the kwargs
and the credentials created by the factory.
"""
if 'credentials' in kwargs:
raise TypeError('credentials must not be in keyword arguments')
credentials = get_for_service_account_json(json_credentials_path)
kwargs['credentials'] = credentials
return cls(*args, **kwargs)

@classmethod
def from_service_account_p12(cls, client_email, private_key_path,
*args, **kwargs):
"""Factory to retrieve P12 credentials while creating client.
.. note::
Unless you have an explicit reason to use a PKCS12 key for your
service account, we recommend using a JSON key.
:type client_email: string
:param client_email: The e-mail attached to the service account.
:type private_key_path: string
:param private_key_path: The path to a private key file (this file was
given to you when you created the service
account). This file must be in P12 format.
:type args: tuple
:param args: Remaining positional arguments to pass to constructor.
:type kwargs: dictionary
:param kwargs: Remaining keyword arguments to pass to constructor.
:rtype: :class:`gcloud.client.Client`
:returns: The client created with the retrieved P12 credentials.
:raises: class:`TypeError` if there is a conflict with the kwargs
and the credentials created by the factory.
"""
if 'credentials' in kwargs:
raise TypeError('credentials must not be in keyword arguments')
credentials = get_for_service_account_p12(client_email,
private_key_path)
kwargs['credentials'] = credentials
return cls(*args, **kwargs)
20 changes: 16 additions & 4 deletions gcloud/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,12 @@ def from_service_account_json(cls, json_credentials_path, *args, **kwargs):
:rtype: :class:`gcloud.connection.Connection`
:returns: The connection created with the retrieved JSON credentials.
:raises: class:`TypeError` if there is a conflict with the kwargs
and the credentials created by the factory.
"""
credentials = get_for_service_account_json(json_credentials_path)
if 'credentials' in kwargs:
raise TypeError('credentials must not be in keyword arguments')
credentials = get_for_service_account_json(json_credentials_path)
kwargs['credentials'] = credentials
return cls(*args, **kwargs)

Expand Down Expand Up @@ -167,25 +169,35 @@ def from_service_account_p12(cls, client_email, private_key_path,
:rtype: :class:`gcloud.connection.Connection`
:returns: The connection created with the retrieved P12 credentials.
:raises: class:`TypeError` if there is a conflict with the kwargs
and the credentials created by the factory.
"""
credentials = get_for_service_account_p12(client_email,
private_key_path)
if 'credentials' in kwargs:
raise TypeError('credentials must not be in keyword arguments')
credentials = get_for_service_account_p12(client_email,
private_key_path)
kwargs['credentials'] = credentials
return cls(*args, **kwargs)

@classmethod
def from_environment(cls, *args, **kwargs):
"""Factory to retrieve implicit credentials while creating connection.
:type args: tuple
:param args: Remaining positional arguments to pass to constructor.
:type kwargs: dictionary
:param kwargs: Remaining keyword arguments to pass to constructor.
:rtype: :class:`gcloud.connection.Connection`
:returns: The connection created with the retrieved implicit
credentials.
:raises: class:`TypeError` if there is a conflict with the kwargs
and the credentials created by the factory.
"""
credentials = get_credentials()
if 'credentials' in kwargs:
raise TypeError('credentials must not be in keyword arguments')
credentials = get_credentials()
kwargs['credentials'] = credentials
return cls(*args, **kwargs)

Expand Down
57 changes: 2 additions & 55 deletions gcloud/pubsub/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@


from gcloud._helpers import _get_production_project
from gcloud.client import Client as BaseClient
from gcloud.credentials import get_credentials
from gcloud.credentials import get_for_service_account_json
from gcloud.credentials import get_for_service_account_p12
from gcloud.pubsub.connection import Connection
from gcloud.pubsub.subscription import Subscription
from gcloud.pubsub.topic import Topic


class Client(object):
class Client(BaseClient):
"""Client to bundle configuration needed for API requests.
:type project: string
Expand Down Expand Up @@ -59,58 +58,6 @@ def __init__(self, project=None, credentials=None, http=None):
credentials = get_credentials()
self.connection = Connection(credentials=credentials, http=http)

@classmethod
def from_service_account_json(cls, json_credentials_path, project=None):
"""Factory to retrieve JSON credentials while creating client.
:type json_credentials_path: string
:param json_credentials_path: The path to a private key file (this file
was given to you when you created the
service account). This file must contain
a JSON object with a private key and
other credentials information (downloaded
from the Google APIs console).
:type project: string
:param project: the project which the client acts on behalf of. Will be
passed when creating a topic. If not passed, falls
back to the default inferred from the environment.
:rtype: :class:`gcloud.pubsub.client.Client`
:returns: The client created with the retrieved JSON credentials.
"""
credentials = get_for_service_account_json(json_credentials_path)
return cls(project=project, credentials=credentials)

@classmethod
def from_service_account_p12(cls, client_email, private_key_path,
project=None):
"""Factory to retrieve P12 credentials while creating client.
.. note::
Unless you have an explicit reason to use a PKCS12 key for your
service account, we recommend using a JSON key.
:type client_email: string
:param client_email: The e-mail attached to the service account.
:type private_key_path: string
:param private_key_path: The path to a private key file (this file was
given to you when you created the service
account). This file must be in P12 format.
:type project: string
:param project: the project which the client acts on behalf of. Will be
passed when creating a topic. If not passed, falls
back to the default inferred from the environment.
:rtype: :class:`gcloud.pubsub.client.Client`
:returns: The client created with the retrieved P12 credentials.
"""
credentials = get_for_service_account_p12(client_email,
private_key_path)
return cls(project=project, credentials=credentials)

def list_topics(self, page_size=None, page_token=None):
"""List topics for the project associated with this client.
Expand Down
49 changes: 0 additions & 49 deletions gcloud/pubsub/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,55 +82,6 @@ def test_ctor_explicit(self):
self.assertTrue(client_obj.connection._credentials is CREDS)
self.assertEqual(CREDS._scopes, SCOPE)

def test_from_service_account_json(self):
from gcloud._testing import _Monkey
from gcloud.pubsub import client
from gcloud.pubsub.connection import Connection

PROJECT = 'PROJECT'
KLASS = self._getTargetClass()
CREDS = _Credentials()
_CALLED = []

def mock_creds(arg1):
_CALLED.append((arg1,))
return CREDS

BOGUS_ARG = object()
with _Monkey(client, get_for_service_account_json=mock_creds):
client_obj = KLASS.from_service_account_json(
BOGUS_ARG, project=PROJECT)

self.assertEqual(client_obj.project, PROJECT)
self.assertTrue(isinstance(client_obj.connection, Connection))
self.assertTrue(client_obj.connection._credentials is CREDS)
self.assertEqual(_CALLED, [(BOGUS_ARG,)])

def test_from_service_account_p12(self):
from gcloud._testing import _Monkey
from gcloud.pubsub import client
from gcloud.pubsub.connection import Connection

PROJECT = 'PROJECT'
KLASS = self._getTargetClass()
CREDS = _Credentials()
_CALLED = []

def mock_creds(arg1, arg2):
_CALLED.append((arg1, arg2))
return CREDS

BOGUS_ARG1 = object()
BOGUS_ARG2 = object()
with _Monkey(client, get_for_service_account_p12=mock_creds):
client_obj = KLASS.from_service_account_p12(
BOGUS_ARG1, BOGUS_ARG2, project=PROJECT)

self.assertEqual(client_obj.project, PROJECT)
self.assertTrue(isinstance(client_obj.connection, Connection))
self.assertTrue(client_obj.connection._credentials is CREDS)
self.assertEqual(_CALLED, [(BOGUS_ARG1, BOGUS_ARG2)])

def test_list_topics_no_paging(self):
from gcloud.pubsub.topic import Topic
PROJECT = 'PROJECT'
Expand Down
83 changes: 83 additions & 0 deletions gcloud/test_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 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.

import unittest2


class TestClient(unittest2.TestCase):

def _getTargetClass(self):
from gcloud.client import Client
return Client

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor_explict(self):
CREDENTIALS = object()
HTTP = object()
CLIENT_OBJ = self._makeOne(credentials=CREDENTIALS, http=HTTP)
self.assertTrue(CLIENT_OBJ.credentials is CREDENTIALS)
self.assertTrue(CLIENT_OBJ.http is HTTP)

def test_from_service_account_json(self):
from gcloud._testing import _Monkey
from gcloud import client

KLASS = self._getTargetClass()
CREDENTIALS = object()
_CALLED = []

def mock_creds(arg1):
_CALLED.append((arg1,))
return CREDENTIALS

BOGUS_ARG = object()
with _Monkey(client, get_for_service_account_json=mock_creds):
CLIENT_OBJ = KLASS.from_service_account_json(BOGUS_ARG)

self.assertTrue(CLIENT_OBJ.credentials is CREDENTIALS)
self.assertEqual(_CALLED, [(BOGUS_ARG,)])

def test_from_service_account_json_fail(self):
KLASS = self._getTargetClass()
CREDENTIALS = object()
self.assertRaises(TypeError, KLASS.from_service_account_json, None,
credentials=CREDENTIALS)

def test_from_service_account_p12(self):
from gcloud._testing import _Monkey
from gcloud import client

KLASS = self._getTargetClass()
CREDENTIALS = object()
_CALLED = []

def mock_creds(arg1, arg2):
_CALLED.append((arg1, arg2))
return CREDENTIALS

BOGUS_ARG1 = object()
BOGUS_ARG2 = object()
with _Monkey(client, get_for_service_account_p12=mock_creds):
CLIENT_OBJ = KLASS.from_service_account_p12(BOGUS_ARG1, BOGUS_ARG2)

self.assertTrue(CLIENT_OBJ.credentials is CREDENTIALS)
self.assertEqual(_CALLED, [(BOGUS_ARG1, BOGUS_ARG2)])

def test_from_service_account_p12_fail(self):
KLASS = self._getTargetClass()
CREDENTIALS = object()
self.assertRaises(TypeError, KLASS.from_service_account_p12, None,
None, credentials=CREDENTIALS)

0 comments on commit 3068473

Please sign in to comment.