Skip to content

Commit cf82bac

Browse files
committed
Merge pull request #1308 from dhermes/bigtable-list-tables
Implementing Bigtable list_column_families().
2 parents 0870be4 + 8b01ef1 commit cf82bac

File tree

4 files changed

+130
-3
lines changed

4 files changed

+130
-3
lines changed

gcloud/bigtable/column_family.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,24 @@ def __init__(self, column_family_id, table, gc_rule=None):
210210
self._table = table
211211
self.gc_rule = gc_rule
212212

213+
@property
214+
def name(self):
215+
"""Column family name used in requests.
216+
217+
.. note::
218+
219+
This property will not change if ``column_family_id`` does not, but
220+
the return value is not cached.
221+
222+
The table name is of the form
223+
224+
``"projects/../zones/../clusters/../tables/../columnFamilies/.."``
225+
226+
:rtype: str
227+
:returns: The column family name.
228+
"""
229+
return self._table.name + '/columnFamilies/' + self.column_family_id
230+
213231
def __eq__(self, other):
214232
if not isinstance(other, self.__class__):
215233
return False

gcloud/bigtable/table.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
bigtable_table_service_messages_pb2 as messages_pb2)
2020
from gcloud.bigtable._generated import (
2121
bigtable_service_messages_pb2 as data_messages_pb2)
22+
from gcloud.bigtable.column_family import _gc_rule_from_pb
2223
from gcloud.bigtable.column_family import ColumnFamily
2324
from gcloud.bigtable.row import Row
2425

@@ -73,17 +74,21 @@ def name(self):
7374
"""
7475
return self._cluster.name + '/tables/' + self.table_id
7576

76-
def column_family(self, column_family_id):
77+
def column_family(self, column_family_id, gc_rule=None):
7778
"""Factory to create a column family associated with this table.
7879
7980
:type column_family_id: str
8081
:param column_family_id: The ID of the column family. Must be of the
8182
form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.
8283
84+
:type gc_rule: :class:`.column_family.GarbageCollectionRule`
85+
:param gc_rule: (Optional) The garbage collection settings for this
86+
column family.
87+
8388
:rtype: :class:`.column_family.ColumnFamily`
8489
:returns: A column family owned by this table.
8590
"""
86-
return ColumnFamily(column_family_id, self)
91+
return ColumnFamily(column_family_id, self, gc_rule=gc_rule)
8792

8893
def row(self, row_key):
8994
"""Factory to create a row associated with this table.
@@ -179,6 +184,34 @@ def delete(self):
179184
# We expect a `._generated.empty_pb2.Empty`
180185
client._table_stub.DeleteTable(request_pb, client.timeout_seconds)
181186

187+
def list_column_families(self):
188+
"""List the column families owned by this table.
189+
190+
:rtype: dictionary with string as keys and
191+
:class:`.column_family.ColumnFamily` as values
192+
:returns: List of column families attached to this table.
193+
:raises: :class:`ValueError <exceptions.ValueError>` if the column
194+
family name from the response does not agree with the computed
195+
name from the column family ID.
196+
"""
197+
request_pb = messages_pb2.GetTableRequest(name=self.name)
198+
client = self._cluster._client
199+
# We expect a `._generated.bigtable_table_data_pb2.Table`
200+
table_pb = client._table_stub.GetTable(request_pb,
201+
client.timeout_seconds)
202+
203+
result = {}
204+
for column_family_id, value_pb in table_pb.column_families.items():
205+
gc_rule = _gc_rule_from_pb(value_pb.gc_rule)
206+
column_family = self.column_family(column_family_id,
207+
gc_rule=gc_rule)
208+
if column_family.name != value_pb.name:
209+
raise ValueError('Column family name %s does not agree with '
210+
'name from request: %s.' % (
211+
column_family.name, value_pb.name))
212+
result[column_family_id] = column_family
213+
return result
214+
182215
def sample_row_keys(self):
183216
"""Read a sample of row keys in the table.
184217

gcloud/bigtable/test_column_family.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,15 @@ def test_constructor(self):
355355
self.assertTrue(column_family._table is table)
356356
self.assertTrue(column_family.gc_rule is gc_rule)
357357

358+
def test_name_property(self):
359+
column_family_id = u'column-family-id'
360+
table_name = 'table_name'
361+
table = _Table(table_name)
362+
column_family = self._makeOne(column_family_id, table)
363+
364+
expected_name = table_name + '/columnFamilies/' + column_family_id
365+
self.assertEqual(column_family.name, expected_name)
366+
358367
def test___eq__(self):
359368
column_family_id = 'column_family_id'
360369
table = object()
@@ -460,3 +469,9 @@ def WhichOneof(cls, name):
460469
self.assertEqual(MockProto.names, [])
461470
self.assertRaises(ValueError, self._callFUT, MockProto)
462471
self.assertEqual(MockProto.names, ['rule'])
472+
473+
474+
class _Table(object):
475+
476+
def __init__(self, name):
477+
self.name = name

gcloud/bigtable/test_table.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ def test_column_family_factory(self):
4646
from gcloud.bigtable.column_family import ColumnFamily
4747

4848
table_id = 'table-id'
49+
gc_rule = object()
4950
table = self._makeOne(table_id, None)
5051
column_family_id = 'column_family_id'
51-
column_family = table.column_family(column_family_id)
52+
column_family = table.column_family(column_family_id, gc_rule=gc_rule)
5253

5354
self.assertTrue(isinstance(column_family, ColumnFamily))
5455
self.assertEqual(column_family.column_family_id, column_family_id)
56+
self.assertTrue(column_family.gc_rule is gc_rule)
5557
self.assertEqual(column_family._table, table)
5658

5759
def test_row_factory(self):
@@ -188,6 +190,65 @@ def test_rename(self):
188190
{},
189191
)])
190192

193+
def _list_column_families_helper(self, column_family_name=None):
194+
from gcloud.bigtable._generated import (
195+
bigtable_table_data_pb2 as data_pb2)
196+
from gcloud.bigtable._generated import (
197+
bigtable_table_service_messages_pb2 as messages_pb2)
198+
from gcloud.bigtable._testing import _FakeStub
199+
200+
project_id = 'project-id'
201+
zone = 'zone'
202+
cluster_id = 'cluster-id'
203+
table_id = 'table-id'
204+
timeout_seconds = 502
205+
cluster_name = ('projects/' + project_id + '/zones/' + zone +
206+
'/clusters/' + cluster_id)
207+
208+
client = _Client(timeout_seconds=timeout_seconds)
209+
cluster = _Cluster(cluster_name, client=client)
210+
table = self._makeOne(table_id, cluster)
211+
212+
# Create request_pb
213+
table_name = cluster_name + '/tables/' + table_id
214+
request_pb = messages_pb2.GetTableRequest(name=table_name)
215+
216+
# Create response_pb
217+
column_family_id = 'foo'
218+
if column_family_name is None:
219+
column_family_name = (table_name + '/columnFamilies/' +
220+
column_family_id)
221+
column_family = data_pb2.ColumnFamily(name=column_family_name)
222+
response_pb = data_pb2.Table(
223+
column_families={column_family_id: column_family},
224+
)
225+
226+
# Patch the stub used by the API method.
227+
client._table_stub = stub = _FakeStub(response_pb)
228+
229+
# Create expected_result.
230+
expected_result = {
231+
column_family_id: table.column_family(column_family_id),
232+
}
233+
234+
# Perform the method and check the result.
235+
result = table.list_column_families()
236+
self.assertEqual(result, expected_result)
237+
self.assertEqual(stub.method_calls, [(
238+
'GetTable',
239+
(request_pb, timeout_seconds),
240+
{},
241+
)])
242+
243+
def test_list_column_families(self):
244+
self._list_column_families_helper()
245+
246+
def test_list_column_families_failure(self):
247+
column_family_name = 'not-the-right-format'
248+
with self.assertRaises(ValueError):
249+
self._list_column_families_helper(
250+
column_family_name=column_family_name)
251+
191252
def test_delete(self):
192253
from gcloud.bigtable._generated import (
193254
bigtable_table_service_messages_pb2 as messages_pb2)

0 commit comments

Comments
 (0)