diff --git a/gcloud/bigtable/client.py b/gcloud/bigtable/client.py index 4f865909b4ab..b366ccda1ce1 100644 --- a/gcloud/bigtable/client.py +++ b/gcloud/bigtable/client.py @@ -27,6 +27,8 @@ """ +import copy + from gcloud.bigtable._generated import bigtable_cluster_service_pb2 from gcloud.bigtable._generated import bigtable_service_pb2 from gcloud.bigtable._generated import bigtable_table_service_pb2 @@ -149,6 +151,25 @@ def __init__(self, project=None, credentials=None, self._operations_stub_internal = None self._table_stub_internal = None + def copy(self): + """Make a copy of this client. + + Copies the local data stored as simple types but does not copy the + current state of any open connections with the Cloud Bigtable API. + + :rtype: :class:`.Client` + :returns: A copy of the current client. + """ + copied_creds = copy.deepcopy(self._credentials) + return self.__class__( + self.project, + copied_creds, + READ_ONLY_SCOPE in copied_creds.scopes, + self._admin, + self.user_agent, + self.timeout_seconds, + ) + @property def credentials(self): """Getter for client's credentials. diff --git a/gcloud/bigtable/test_client.py b/gcloud/bigtable/test_client.py index 3a46eb7f1321..036e7e6c58c0 100644 --- a/gcloud/bigtable/test_client.py +++ b/gcloud/bigtable/test_client.py @@ -41,7 +41,7 @@ def _constructor_test_helper(self, expected_scopes, creds, expected_creds = expected_creds or creds self.assertTrue(client._credentials is expected_creds) - self.assertEqual(client._credentials._scopes, expected_scopes) + self.assertEqual(client._credentials.scopes, expected_scopes) self.assertEqual(client.project, PROJECT) self.assertEqual(client.timeout_seconds, timeout_seconds) @@ -104,6 +104,44 @@ def mock_get_credentials(): self._constructor_test_helper(expected_scopes, None, expected_creds=creds) + def _copy_test_helper(self, read_only=False, admin=False): + credentials = _Credentials('value') + project = 'PROJECT' + timeout_seconds = 123 + user_agent = 'you-sir-age-int' + client = self._makeOne(project=project, credentials=credentials, + read_only=read_only, admin=admin, + timeout_seconds=timeout_seconds, + user_agent=user_agent) + # Put some fake stubs in place so that we can verify they + # don't get copied. + client._data_stub_internal = object() + client._cluster_stub_internal = object() + client._operations_stub_internal = object() + client._table_stub_internal = object() + + new_client = client.copy() + self.assertEqual(new_client._admin, client._admin) + self.assertEqual(new_client._credentials, client._credentials) + self.assertFalse(new_client._credentials is client._credentials) + self.assertEqual(new_client.project, client.project) + self.assertEqual(new_client.user_agent, client.user_agent) + self.assertEqual(new_client.timeout_seconds, client.timeout_seconds) + # Make sure stubs are not preserved. + self.assertEqual(new_client._data_stub_internal, None) + self.assertEqual(new_client._cluster_stub_internal, None) + self.assertEqual(new_client._operations_stub_internal, None) + self.assertEqual(new_client._table_stub_internal, None) + + def test_copy(self): + self._copy_test_helper() + + def test_copy_admin(self): + self._copy_test_helper(admin=True) + + def test_copy_read_only(self): + self._copy_test_helper(read_only=True) + def test_credentials_getter(self): credentials = _Credentials() project = 'PROJECT' @@ -439,12 +477,18 @@ def test_stop_while_stopped(self): class _Credentials(object): - _scopes = None + scopes = None + + def __init__(self, value=None): + self.value = value def create_scoped(self, scope): - self._scopes = scope + self.scopes = scope return self + def __eq__(self, other): + return self.value == other.value + class _FakeStub(object):