google-cloud-bigtable 2.30.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/cloud/bigtable/__init__.py +25 -0
- google/cloud/bigtable/app_profile.py +377 -0
- google/cloud/bigtable/backup.py +490 -0
- google/cloud/bigtable/batcher.py +414 -0
- google/cloud/bigtable/client.py +475 -0
- google/cloud/bigtable/cluster.py +541 -0
- google/cloud/bigtable/column_family.py +362 -0
- google/cloud/bigtable/data/__init__.py +103 -0
- google/cloud/bigtable/data/_async/__init__.py +25 -0
- google/cloud/bigtable/data/_async/_mutate_rows.py +226 -0
- google/cloud/bigtable/data/_async/_read_rows.py +363 -0
- google/cloud/bigtable/data/_async/client.py +1522 -0
- google/cloud/bigtable/data/_async/mutations_batcher.py +534 -0
- google/cloud/bigtable/data/_cross_sync/__init__.py +20 -0
- google/cloud/bigtable/data/_cross_sync/_decorators.py +441 -0
- google/cloud/bigtable/data/_cross_sync/_mapping_meta.py +64 -0
- google/cloud/bigtable/data/_cross_sync/cross_sync.py +334 -0
- google/cloud/bigtable/data/_helpers.py +249 -0
- google/cloud/bigtable/data/_sync_autogen/_mutate_rows.py +182 -0
- google/cloud/bigtable/data/_sync_autogen/_read_rows.py +304 -0
- google/cloud/bigtable/data/_sync_autogen/client.py +1293 -0
- google/cloud/bigtable/data/_sync_autogen/mutations_batcher.py +449 -0
- google/cloud/bigtable/data/exceptions.py +340 -0
- google/cloud/bigtable/data/execute_query/__init__.py +43 -0
- google/cloud/bigtable/data/execute_query/_async/__init__.py +13 -0
- google/cloud/bigtable/data/execute_query/_async/execute_query_iterator.py +291 -0
- google/cloud/bigtable/data/execute_query/_byte_cursor.py +123 -0
- google/cloud/bigtable/data/execute_query/_checksum.py +43 -0
- google/cloud/bigtable/data/execute_query/_parameters_formatting.py +155 -0
- google/cloud/bigtable/data/execute_query/_query_result_parsing_utils.py +134 -0
- google/cloud/bigtable/data/execute_query/_reader.py +122 -0
- google/cloud/bigtable/data/execute_query/_sync_autogen/execute_query_iterator.py +239 -0
- google/cloud/bigtable/data/execute_query/metadata.py +399 -0
- google/cloud/bigtable/data/execute_query/values.py +123 -0
- google/cloud/bigtable/data/mutations.py +380 -0
- google/cloud/bigtable/data/read_modify_write_rules.py +112 -0
- google/cloud/bigtable/data/read_rows_query.py +536 -0
- google/cloud/bigtable/data/row.py +535 -0
- google/cloud/bigtable/data/row_filters.py +968 -0
- google/cloud/bigtable/encryption_info.py +64 -0
- google/cloud/bigtable/enums.py +223 -0
- google/cloud/bigtable/error.py +64 -0
- google/cloud/bigtable/gapic_version.py +16 -0
- google/cloud/bigtable/helpers.py +31 -0
- google/cloud/bigtable/instance.py +789 -0
- google/cloud/bigtable/policy.py +255 -0
- google/cloud/bigtable/row.py +1267 -0
- google/cloud/bigtable/row_data.py +380 -0
- google/cloud/bigtable/row_filters.py +838 -0
- google/cloud/bigtable/row_merger.py +250 -0
- google/cloud/bigtable/row_set.py +213 -0
- google/cloud/bigtable/table.py +1409 -0
- google/cloud/bigtable_admin/__init__.py +410 -0
- google/cloud/bigtable_admin/gapic_version.py +16 -0
- google/cloud/bigtable_admin/py.typed +2 -0
- google/cloud/bigtable_admin_v2/__init__.py +250 -0
- google/cloud/bigtable_admin_v2/gapic_metadata.json +962 -0
- google/cloud/bigtable_admin_v2/gapic_version.py +16 -0
- google/cloud/bigtable_admin_v2/py.typed +2 -0
- google/cloud/bigtable_admin_v2/services/__init__.py +15 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/__init__.py +22 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/async_client.py +3465 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/client.py +3944 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/pagers.py +681 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/__init__.py +40 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/base.py +751 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/grpc.py +1249 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/grpc_asyncio.py +1579 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/rest.py +6820 -0
- google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/rest_base.py +1746 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/__init__.py +22 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/async_client.py +3472 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/client.py +3949 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/pagers.py +669 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/__init__.py +40 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/base.py +708 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/grpc.py +1257 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/grpc_asyncio.py +1549 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/rest.py +6609 -0
- google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/rest_base.py +1714 -0
- google/cloud/bigtable_admin_v2/types/__init__.py +248 -0
- google/cloud/bigtable_admin_v2/types/bigtable_instance_admin.py +1364 -0
- google/cloud/bigtable_admin_v2/types/bigtable_table_admin.py +1715 -0
- google/cloud/bigtable_admin_v2/types/common.py +81 -0
- google/cloud/bigtable_admin_v2/types/instance.py +819 -0
- google/cloud/bigtable_admin_v2/types/table.py +1028 -0
- google/cloud/bigtable_admin_v2/types/types.py +776 -0
- google/cloud/bigtable_v2/__init__.py +136 -0
- google/cloud/bigtable_v2/gapic_metadata.json +193 -0
- google/cloud/bigtable_v2/gapic_version.py +16 -0
- google/cloud/bigtable_v2/py.typed +2 -0
- google/cloud/bigtable_v2/services/__init__.py +15 -0
- google/cloud/bigtable_v2/services/bigtable/__init__.py +22 -0
- google/cloud/bigtable_v2/services/bigtable/async_client.py +1741 -0
- google/cloud/bigtable_v2/services/bigtable/client.py +2194 -0
- google/cloud/bigtable_v2/services/bigtable/transports/__init__.py +38 -0
- google/cloud/bigtable_v2/services/bigtable/transports/base.py +343 -0
- google/cloud/bigtable_v2/services/bigtable/transports/grpc.py +660 -0
- google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py +762 -0
- google/cloud/bigtable_v2/services/bigtable/transports/rest.py +2489 -0
- google/cloud/bigtable_v2/services/bigtable/transports/rest_base.py +711 -0
- google/cloud/bigtable_v2/types/__init__.py +138 -0
- google/cloud/bigtable_v2/types/bigtable.py +1531 -0
- google/cloud/bigtable_v2/types/data.py +1612 -0
- google/cloud/bigtable_v2/types/feature_flags.py +119 -0
- google/cloud/bigtable_v2/types/request_stats.py +171 -0
- google/cloud/bigtable_v2/types/response_params.py +64 -0
- google/cloud/bigtable_v2/types/types.py +579 -0
- google_cloud_bigtable-2.30.0.data/scripts/fixup_bigtable_admin_v2_keywords.py +233 -0
- google_cloud_bigtable-2.30.0.data/scripts/fixup_bigtable_v2_keywords.py +186 -0
- google_cloud_bigtable-2.30.0.dist-info/LICENSE +202 -0
- google_cloud_bigtable-2.30.0.dist-info/METADATA +154 -0
- google_cloud_bigtable-2.30.0.dist-info/RECORD +115 -0
- google_cloud_bigtable-2.30.0.dist-info/WHEEL +5 -0
- google_cloud_bigtable-2.30.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
from google.cloud.bigtable.row import Cell, PartialRowData, InvalidChunk
|
|
4
|
+
|
|
5
|
+
_MISSING_COLUMN_FAMILY = "Column family {} is not among the cells stored in this row."
|
|
6
|
+
_MISSING_COLUMN = (
|
|
7
|
+
"Column {} is not among the cells stored in this row in the column family {}."
|
|
8
|
+
)
|
|
9
|
+
_MISSING_INDEX = (
|
|
10
|
+
"Index {!r} is not valid for the cells stored in this row for column {} "
|
|
11
|
+
"in the column family {}. There are {} such cells."
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _State(Enum):
|
|
16
|
+
ROW_START = "ROW_START"
|
|
17
|
+
CELL_START = "CELL_START"
|
|
18
|
+
CELL_IN_PROGRESS = "CELL_IN_PROGRESS"
|
|
19
|
+
CELL_COMPLETE = "CELL_COMPLETE"
|
|
20
|
+
ROW_COMPLETE = "ROW_COMPLETE"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _PartialRow(object):
|
|
24
|
+
__slots__ = [
|
|
25
|
+
"row_key",
|
|
26
|
+
"cells",
|
|
27
|
+
"last_family",
|
|
28
|
+
"last_family_cells",
|
|
29
|
+
"last_qualifier",
|
|
30
|
+
"last_qualifier_cells",
|
|
31
|
+
"cell",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def __init__(self, row_key):
|
|
35
|
+
self.row_key = row_key
|
|
36
|
+
self.cells = OrderedDict()
|
|
37
|
+
|
|
38
|
+
self.last_family = None
|
|
39
|
+
self.last_family_cells = OrderedDict()
|
|
40
|
+
self.last_qualifier = None
|
|
41
|
+
self.last_qualifier_cells = []
|
|
42
|
+
|
|
43
|
+
self.cell = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class _PartialCell(object):
|
|
47
|
+
__slots__ = ["family", "qualifier", "timestamp", "labels", "value", "value_index"]
|
|
48
|
+
|
|
49
|
+
def __init__(self):
|
|
50
|
+
self.family = None
|
|
51
|
+
self.qualifier = None
|
|
52
|
+
self.timestamp = None
|
|
53
|
+
self.labels = None
|
|
54
|
+
self.value = None
|
|
55
|
+
self.value_index = 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class _RowMerger(object):
|
|
59
|
+
"""
|
|
60
|
+
State machine to merge chunks from a response stream into logical rows.
|
|
61
|
+
|
|
62
|
+
The implementation is a fairly linear state machine that is implemented as
|
|
63
|
+
a method for every state in the _State enum. In general the states flow
|
|
64
|
+
from top to bottom with some repetition. Each state handler will do some
|
|
65
|
+
sanity checks, update in progress data and set the next state.
|
|
66
|
+
|
|
67
|
+
There can be multiple state transitions for each chunk, i.e. a single chunk
|
|
68
|
+
row will flow from ROW_START -> CELL_START -> CELL_COMPLETE -> ROW_COMPLETE
|
|
69
|
+
in a single iteration.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
__slots__ = ["state", "last_seen_row_key", "row"]
|
|
73
|
+
|
|
74
|
+
def __init__(self, last_seen_row=b""):
|
|
75
|
+
self.last_seen_row_key = last_seen_row
|
|
76
|
+
self.state = _State.ROW_START
|
|
77
|
+
self.row = None
|
|
78
|
+
|
|
79
|
+
def process_chunks(self, response):
|
|
80
|
+
"""
|
|
81
|
+
Process the chunks in the given response and yield logical rows.
|
|
82
|
+
This class will maintain state across multiple response protos.
|
|
83
|
+
"""
|
|
84
|
+
if response.last_scanned_row_key:
|
|
85
|
+
if self.last_seen_row_key >= response.last_scanned_row_key:
|
|
86
|
+
raise InvalidChunk("Last scanned row key is out of order")
|
|
87
|
+
self.last_seen_row_key = response.last_scanned_row_key
|
|
88
|
+
|
|
89
|
+
for chunk in response.chunks:
|
|
90
|
+
if chunk.reset_row:
|
|
91
|
+
self._handle_reset(chunk)
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
if self.state == _State.ROW_START:
|
|
95
|
+
self._handle_row_start(chunk)
|
|
96
|
+
|
|
97
|
+
if self.state == _State.CELL_START:
|
|
98
|
+
self._handle_cell_start(chunk)
|
|
99
|
+
|
|
100
|
+
if self.state == _State.CELL_IN_PROGRESS:
|
|
101
|
+
self._handle_cell_in_progress(chunk)
|
|
102
|
+
|
|
103
|
+
if self.state == _State.CELL_COMPLETE:
|
|
104
|
+
self._handle_cell_complete(chunk)
|
|
105
|
+
|
|
106
|
+
if self.state == _State.ROW_COMPLETE:
|
|
107
|
+
yield self._handle_row_complete(chunk)
|
|
108
|
+
elif chunk.commit_row:
|
|
109
|
+
raise InvalidChunk(
|
|
110
|
+
f"Chunk tried to commit row in wrong state (${self.state})"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def _handle_reset(self, chunk):
|
|
114
|
+
if self.state == _State.ROW_START:
|
|
115
|
+
raise InvalidChunk("Bare reset")
|
|
116
|
+
if chunk.row_key:
|
|
117
|
+
raise InvalidChunk("Reset chunk has a row key")
|
|
118
|
+
if chunk.HasField("family_name"):
|
|
119
|
+
raise InvalidChunk("Reset chunk has family_name")
|
|
120
|
+
if chunk.HasField("qualifier"):
|
|
121
|
+
raise InvalidChunk("Reset chunk has qualifier")
|
|
122
|
+
if chunk.timestamp_micros:
|
|
123
|
+
raise InvalidChunk("Reset chunk has a timestamp")
|
|
124
|
+
if chunk.labels:
|
|
125
|
+
raise InvalidChunk("Reset chunk has labels")
|
|
126
|
+
if chunk.value:
|
|
127
|
+
raise InvalidChunk("Reset chunk has a value")
|
|
128
|
+
|
|
129
|
+
self.state = _State.ROW_START
|
|
130
|
+
self.row = None
|
|
131
|
+
|
|
132
|
+
def _handle_row_start(self, chunk):
|
|
133
|
+
if not chunk.row_key:
|
|
134
|
+
raise InvalidChunk("New row is missing a row key")
|
|
135
|
+
if self.last_seen_row_key and self.last_seen_row_key >= chunk.row_key:
|
|
136
|
+
raise InvalidChunk("Out of order row keys")
|
|
137
|
+
|
|
138
|
+
self.row = _PartialRow(chunk.row_key)
|
|
139
|
+
self.state = _State.CELL_START
|
|
140
|
+
|
|
141
|
+
def _handle_cell_start(self, chunk):
|
|
142
|
+
# Ensure that all chunks after the first one either are missing a row
|
|
143
|
+
# key or the row is the same
|
|
144
|
+
if self.row.cells and chunk.row_key and chunk.row_key != self.row.row_key:
|
|
145
|
+
raise InvalidChunk("row key changed mid row")
|
|
146
|
+
|
|
147
|
+
if not self.row.cell:
|
|
148
|
+
self.row.cell = _PartialCell()
|
|
149
|
+
|
|
150
|
+
# Cells can inherit family/qualifier from previous cells
|
|
151
|
+
# However if the family changes, then qualifier must be specified as well
|
|
152
|
+
if chunk.HasField("family_name"):
|
|
153
|
+
self.row.cell.family = chunk.family_name.value
|
|
154
|
+
self.row.cell.qualifier = None
|
|
155
|
+
if not self.row.cell.family:
|
|
156
|
+
raise InvalidChunk("missing family for a new cell")
|
|
157
|
+
|
|
158
|
+
if chunk.HasField("qualifier"):
|
|
159
|
+
self.row.cell.qualifier = chunk.qualifier.value
|
|
160
|
+
if self.row.cell.qualifier is None:
|
|
161
|
+
raise InvalidChunk("missing qualifier for a new cell")
|
|
162
|
+
|
|
163
|
+
self.row.cell.timestamp = chunk.timestamp_micros
|
|
164
|
+
self.row.cell.labels = chunk.labels
|
|
165
|
+
|
|
166
|
+
if chunk.value_size > 0:
|
|
167
|
+
# explicitly avoid pre-allocation as it seems that bytearray
|
|
168
|
+
# concatenation performs better than slice copies.
|
|
169
|
+
self.row.cell.value = bytearray()
|
|
170
|
+
self.state = _State.CELL_IN_PROGRESS
|
|
171
|
+
else:
|
|
172
|
+
self.row.cell.value = chunk.value
|
|
173
|
+
self.state = _State.CELL_COMPLETE
|
|
174
|
+
|
|
175
|
+
def _handle_cell_in_progress(self, chunk):
|
|
176
|
+
# if this isn't the first cell chunk, make sure that everything except
|
|
177
|
+
# the value stayed constant.
|
|
178
|
+
if self.row.cell.value_index > 0:
|
|
179
|
+
if chunk.row_key:
|
|
180
|
+
raise InvalidChunk("found row key mid cell")
|
|
181
|
+
if chunk.HasField("family_name"):
|
|
182
|
+
raise InvalidChunk("In progress cell had a family name")
|
|
183
|
+
if chunk.HasField("qualifier"):
|
|
184
|
+
raise InvalidChunk("In progress cell had a qualifier")
|
|
185
|
+
if chunk.timestamp_micros:
|
|
186
|
+
raise InvalidChunk("In progress cell had a timestamp")
|
|
187
|
+
if chunk.labels:
|
|
188
|
+
raise InvalidChunk("In progress cell had labels")
|
|
189
|
+
|
|
190
|
+
self.row.cell.value += chunk.value
|
|
191
|
+
self.row.cell.value_index += len(chunk.value)
|
|
192
|
+
|
|
193
|
+
if chunk.value_size > 0:
|
|
194
|
+
self.state = _State.CELL_IN_PROGRESS
|
|
195
|
+
else:
|
|
196
|
+
self.row.cell.value = bytes(self.row.cell.value)
|
|
197
|
+
self.state = _State.CELL_COMPLETE
|
|
198
|
+
|
|
199
|
+
def _handle_cell_complete(self, chunk):
|
|
200
|
+
# since we are guaranteed that all family & qualifier cells are
|
|
201
|
+
# contiguous, we can optimize away the dict lookup by caching the last
|
|
202
|
+
# family/qualifier and simply comparing and appending
|
|
203
|
+
family_changed = False
|
|
204
|
+
if self.row.last_family != self.row.cell.family:
|
|
205
|
+
family_changed = True
|
|
206
|
+
self.row.last_family = self.row.cell.family
|
|
207
|
+
self.row.cells[
|
|
208
|
+
self.row.cell.family
|
|
209
|
+
] = self.row.last_family_cells = OrderedDict()
|
|
210
|
+
|
|
211
|
+
if family_changed or self.row.last_qualifier != self.row.cell.qualifier:
|
|
212
|
+
self.row.last_qualifier = self.row.cell.qualifier
|
|
213
|
+
self.row.last_family_cells[
|
|
214
|
+
self.row.cell.qualifier
|
|
215
|
+
] = self.row.last_qualifier_cells = []
|
|
216
|
+
|
|
217
|
+
self.row.last_qualifier_cells.append(
|
|
218
|
+
Cell(
|
|
219
|
+
self.row.cell.value,
|
|
220
|
+
self.row.cell.timestamp,
|
|
221
|
+
self.row.cell.labels,
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
self.row.cell.timestamp = 0
|
|
226
|
+
self.row.cell.value = None
|
|
227
|
+
self.row.cell.value_index = 0
|
|
228
|
+
|
|
229
|
+
if not chunk.commit_row:
|
|
230
|
+
self.state = _State.CELL_START
|
|
231
|
+
else:
|
|
232
|
+
self.state = _State.ROW_COMPLETE
|
|
233
|
+
|
|
234
|
+
def _handle_row_complete(self, chunk):
|
|
235
|
+
new_row = PartialRowData(self.row.row_key)
|
|
236
|
+
new_row._cells = self.row.cells
|
|
237
|
+
|
|
238
|
+
self.last_seen_row_key = new_row.row_key
|
|
239
|
+
self.row = None
|
|
240
|
+
self.state = _State.ROW_START
|
|
241
|
+
|
|
242
|
+
return new_row
|
|
243
|
+
|
|
244
|
+
def finalize(self):
|
|
245
|
+
"""
|
|
246
|
+
Must be called at the end of the stream to ensure there are no unmerged
|
|
247
|
+
rows.
|
|
248
|
+
"""
|
|
249
|
+
if self.row or self.state != _State.ROW_START:
|
|
250
|
+
raise ValueError("The row remains partial / is not committed.")
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Copyright 2018 Google LLC
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""User-friendly container for Google Cloud Bigtable RowSet """
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from google.cloud._helpers import _to_bytes # type: ignore
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class RowSet(object):
|
|
22
|
+
"""Convenience wrapper of google.bigtable.v2.RowSet
|
|
23
|
+
|
|
24
|
+
Useful for creating a set of row keys and row ranges, which can
|
|
25
|
+
be passed to yield_rows method of class:`.Table.yield_rows`.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self.row_keys = []
|
|
30
|
+
self.row_ranges = []
|
|
31
|
+
|
|
32
|
+
def __eq__(self, other):
|
|
33
|
+
if not isinstance(other, self.__class__):
|
|
34
|
+
return NotImplemented
|
|
35
|
+
|
|
36
|
+
if len(other.row_keys) != len(self.row_keys):
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
if len(other.row_ranges) != len(self.row_ranges):
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
if not set(other.row_keys) == set(self.row_keys):
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
if not set(other.row_ranges) == set(self.row_ranges):
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def __ne__(self, other):
|
|
51
|
+
return not self == other
|
|
52
|
+
|
|
53
|
+
def add_row_key(self, row_key):
|
|
54
|
+
"""Add row key to row_keys list.
|
|
55
|
+
|
|
56
|
+
For example:
|
|
57
|
+
|
|
58
|
+
.. literalinclude:: snippets_table.py
|
|
59
|
+
:start-after: [START bigtable_api_add_row_key]
|
|
60
|
+
:end-before: [END bigtable_api_add_row_key]
|
|
61
|
+
:dedent: 4
|
|
62
|
+
|
|
63
|
+
:type row_key: bytes
|
|
64
|
+
:param row_key: The key of a row to read
|
|
65
|
+
"""
|
|
66
|
+
self.row_keys.append(row_key)
|
|
67
|
+
|
|
68
|
+
def add_row_range(self, row_range):
|
|
69
|
+
"""Add row_range to row_ranges list.
|
|
70
|
+
|
|
71
|
+
For example:
|
|
72
|
+
|
|
73
|
+
.. literalinclude:: snippets_table.py
|
|
74
|
+
:start-after: [START bigtable_api_add_row_range]
|
|
75
|
+
:end-before: [END bigtable_api_add_row_range]
|
|
76
|
+
:dedent: 4
|
|
77
|
+
|
|
78
|
+
:type row_range: class:`RowRange`
|
|
79
|
+
:param row_range: The row range object having start and end key
|
|
80
|
+
"""
|
|
81
|
+
self.row_ranges.append(row_range)
|
|
82
|
+
|
|
83
|
+
def add_row_range_from_keys(
|
|
84
|
+
self, start_key=None, end_key=None, start_inclusive=True, end_inclusive=False
|
|
85
|
+
):
|
|
86
|
+
"""Add row range to row_ranges list from the row keys
|
|
87
|
+
|
|
88
|
+
For example:
|
|
89
|
+
|
|
90
|
+
.. literalinclude:: snippets_table.py
|
|
91
|
+
:start-after: [START bigtable_api_row_range_from_keys]
|
|
92
|
+
:end-before: [END bigtable_api_row_range_from_keys]
|
|
93
|
+
:dedent: 4
|
|
94
|
+
|
|
95
|
+
:type start_key: bytes
|
|
96
|
+
:param start_key: (Optional) Start key of the row range. If left empty,
|
|
97
|
+
will be interpreted as the empty string.
|
|
98
|
+
|
|
99
|
+
:type end_key: bytes
|
|
100
|
+
:param end_key: (Optional) End key of the row range. If left empty,
|
|
101
|
+
will be interpreted as the empty string and range will
|
|
102
|
+
be unbounded on the high end.
|
|
103
|
+
|
|
104
|
+
:type start_inclusive: bool
|
|
105
|
+
:param start_inclusive: (Optional) Whether the ``start_key`` should be
|
|
106
|
+
considered inclusive. The default is True (inclusive).
|
|
107
|
+
|
|
108
|
+
:type end_inclusive: bool
|
|
109
|
+
:param end_inclusive: (Optional) Whether the ``end_key`` should be
|
|
110
|
+
considered inclusive. The default is False (exclusive).
|
|
111
|
+
"""
|
|
112
|
+
row_range = RowRange(start_key, end_key, start_inclusive, end_inclusive)
|
|
113
|
+
self.row_ranges.append(row_range)
|
|
114
|
+
|
|
115
|
+
def add_row_range_with_prefix(self, row_key_prefix):
|
|
116
|
+
"""Add row range to row_ranges list that start with the row_key_prefix from the row keys
|
|
117
|
+
|
|
118
|
+
For example:
|
|
119
|
+
|
|
120
|
+
.. literalinclude:: snippets_table.py
|
|
121
|
+
:start-after: [START bigtable_api_add_row_range_with_prefix]
|
|
122
|
+
:end-before: [END bigtable_api_add_row_range_with_prefix]
|
|
123
|
+
|
|
124
|
+
:type row_key_prefix: str
|
|
125
|
+
:param row_key_prefix: To retrieve all rows that start with this row key prefix.
|
|
126
|
+
Prefix cannot be zero length."""
|
|
127
|
+
|
|
128
|
+
end_key = row_key_prefix[:-1] + chr(ord(row_key_prefix[-1]) + 1)
|
|
129
|
+
self.add_row_range_from_keys(
|
|
130
|
+
row_key_prefix.encode("utf-8"), end_key.encode("utf-8")
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def _update_message_request(self, message):
|
|
134
|
+
"""Add row keys and row range to given request message
|
|
135
|
+
|
|
136
|
+
:type message: class:`data_messages_v2_pb2.ReadRowsRequest`
|
|
137
|
+
:param message: The ``ReadRowsRequest`` protobuf
|
|
138
|
+
"""
|
|
139
|
+
for each in self.row_keys:
|
|
140
|
+
message.rows.row_keys._pb.append(_to_bytes(each))
|
|
141
|
+
|
|
142
|
+
for each in self.row_ranges:
|
|
143
|
+
r_kwrags = each.get_range_kwargs()
|
|
144
|
+
message.rows.row_ranges.append(r_kwrags)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class RowRange(object):
|
|
148
|
+
"""Convenience wrapper of google.bigtable.v2.RowRange
|
|
149
|
+
|
|
150
|
+
:type start_key: bytes
|
|
151
|
+
:param start_key: (Optional) Start key of the row range. If left empty,
|
|
152
|
+
will be interpreted as the empty string.
|
|
153
|
+
|
|
154
|
+
:type end_key: bytes
|
|
155
|
+
:param end_key: (Optional) End key of the row range. If left empty,
|
|
156
|
+
will be interpreted as the empty string and range will
|
|
157
|
+
be unbounded on the high end.
|
|
158
|
+
|
|
159
|
+
:type start_inclusive: bool
|
|
160
|
+
:param start_inclusive: (Optional) Whether the ``start_key`` should be
|
|
161
|
+
considered inclusive. The default is True (inclusive).
|
|
162
|
+
|
|
163
|
+
:type end_inclusive: bool
|
|
164
|
+
:param end_inclusive: (Optional) Whether the ``end_key`` should be
|
|
165
|
+
considered inclusive. The default is False (exclusive).
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def __init__(
|
|
169
|
+
self, start_key=None, end_key=None, start_inclusive=True, end_inclusive=False
|
|
170
|
+
):
|
|
171
|
+
self.start_key = start_key
|
|
172
|
+
self.start_inclusive = start_inclusive
|
|
173
|
+
self.end_key = end_key
|
|
174
|
+
self.end_inclusive = end_inclusive
|
|
175
|
+
|
|
176
|
+
def _key(self):
|
|
177
|
+
"""A tuple key that uniquely describes this field.
|
|
178
|
+
|
|
179
|
+
Used to compute this instance's hashcode and evaluate equality.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Tuple[str]: The contents of this :class:`.RowRange`.
|
|
183
|
+
"""
|
|
184
|
+
return (self.start_key, self.start_inclusive, self.end_key, self.end_inclusive)
|
|
185
|
+
|
|
186
|
+
def __hash__(self):
|
|
187
|
+
return hash(self._key())
|
|
188
|
+
|
|
189
|
+
def __eq__(self, other):
|
|
190
|
+
if not isinstance(other, self.__class__):
|
|
191
|
+
return NotImplemented
|
|
192
|
+
return self._key() == other._key()
|
|
193
|
+
|
|
194
|
+
def __ne__(self, other):
|
|
195
|
+
return not self == other
|
|
196
|
+
|
|
197
|
+
def get_range_kwargs(self):
|
|
198
|
+
"""Convert row range object to dict which can be passed to
|
|
199
|
+
google.bigtable.v2.RowRange add method.
|
|
200
|
+
"""
|
|
201
|
+
range_kwargs = {}
|
|
202
|
+
if self.start_key is not None:
|
|
203
|
+
start_key_key = "start_key_open"
|
|
204
|
+
if self.start_inclusive:
|
|
205
|
+
start_key_key = "start_key_closed"
|
|
206
|
+
range_kwargs[start_key_key] = _to_bytes(self.start_key)
|
|
207
|
+
|
|
208
|
+
if self.end_key is not None:
|
|
209
|
+
end_key_key = "end_key_open"
|
|
210
|
+
if self.end_inclusive:
|
|
211
|
+
end_key_key = "end_key_closed"
|
|
212
|
+
range_kwargs[end_key_key] = _to_bytes(self.end_key)
|
|
213
|
+
return range_kwargs
|