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.
Files changed (115) hide show
  1. google/cloud/bigtable/__init__.py +25 -0
  2. google/cloud/bigtable/app_profile.py +377 -0
  3. google/cloud/bigtable/backup.py +490 -0
  4. google/cloud/bigtable/batcher.py +414 -0
  5. google/cloud/bigtable/client.py +475 -0
  6. google/cloud/bigtable/cluster.py +541 -0
  7. google/cloud/bigtable/column_family.py +362 -0
  8. google/cloud/bigtable/data/__init__.py +103 -0
  9. google/cloud/bigtable/data/_async/__init__.py +25 -0
  10. google/cloud/bigtable/data/_async/_mutate_rows.py +226 -0
  11. google/cloud/bigtable/data/_async/_read_rows.py +363 -0
  12. google/cloud/bigtable/data/_async/client.py +1522 -0
  13. google/cloud/bigtable/data/_async/mutations_batcher.py +534 -0
  14. google/cloud/bigtable/data/_cross_sync/__init__.py +20 -0
  15. google/cloud/bigtable/data/_cross_sync/_decorators.py +441 -0
  16. google/cloud/bigtable/data/_cross_sync/_mapping_meta.py +64 -0
  17. google/cloud/bigtable/data/_cross_sync/cross_sync.py +334 -0
  18. google/cloud/bigtable/data/_helpers.py +249 -0
  19. google/cloud/bigtable/data/_sync_autogen/_mutate_rows.py +182 -0
  20. google/cloud/bigtable/data/_sync_autogen/_read_rows.py +304 -0
  21. google/cloud/bigtable/data/_sync_autogen/client.py +1293 -0
  22. google/cloud/bigtable/data/_sync_autogen/mutations_batcher.py +449 -0
  23. google/cloud/bigtable/data/exceptions.py +340 -0
  24. google/cloud/bigtable/data/execute_query/__init__.py +43 -0
  25. google/cloud/bigtable/data/execute_query/_async/__init__.py +13 -0
  26. google/cloud/bigtable/data/execute_query/_async/execute_query_iterator.py +291 -0
  27. google/cloud/bigtable/data/execute_query/_byte_cursor.py +123 -0
  28. google/cloud/bigtable/data/execute_query/_checksum.py +43 -0
  29. google/cloud/bigtable/data/execute_query/_parameters_formatting.py +155 -0
  30. google/cloud/bigtable/data/execute_query/_query_result_parsing_utils.py +134 -0
  31. google/cloud/bigtable/data/execute_query/_reader.py +122 -0
  32. google/cloud/bigtable/data/execute_query/_sync_autogen/execute_query_iterator.py +239 -0
  33. google/cloud/bigtable/data/execute_query/metadata.py +399 -0
  34. google/cloud/bigtable/data/execute_query/values.py +123 -0
  35. google/cloud/bigtable/data/mutations.py +380 -0
  36. google/cloud/bigtable/data/read_modify_write_rules.py +112 -0
  37. google/cloud/bigtable/data/read_rows_query.py +536 -0
  38. google/cloud/bigtable/data/row.py +535 -0
  39. google/cloud/bigtable/data/row_filters.py +968 -0
  40. google/cloud/bigtable/encryption_info.py +64 -0
  41. google/cloud/bigtable/enums.py +223 -0
  42. google/cloud/bigtable/error.py +64 -0
  43. google/cloud/bigtable/gapic_version.py +16 -0
  44. google/cloud/bigtable/helpers.py +31 -0
  45. google/cloud/bigtable/instance.py +789 -0
  46. google/cloud/bigtable/policy.py +255 -0
  47. google/cloud/bigtable/row.py +1267 -0
  48. google/cloud/bigtable/row_data.py +380 -0
  49. google/cloud/bigtable/row_filters.py +838 -0
  50. google/cloud/bigtable/row_merger.py +250 -0
  51. google/cloud/bigtable/row_set.py +213 -0
  52. google/cloud/bigtable/table.py +1409 -0
  53. google/cloud/bigtable_admin/__init__.py +410 -0
  54. google/cloud/bigtable_admin/gapic_version.py +16 -0
  55. google/cloud/bigtable_admin/py.typed +2 -0
  56. google/cloud/bigtable_admin_v2/__init__.py +250 -0
  57. google/cloud/bigtable_admin_v2/gapic_metadata.json +962 -0
  58. google/cloud/bigtable_admin_v2/gapic_version.py +16 -0
  59. google/cloud/bigtable_admin_v2/py.typed +2 -0
  60. google/cloud/bigtable_admin_v2/services/__init__.py +15 -0
  61. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/__init__.py +22 -0
  62. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/async_client.py +3465 -0
  63. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/client.py +3944 -0
  64. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/pagers.py +681 -0
  65. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/__init__.py +40 -0
  66. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/base.py +751 -0
  67. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/grpc.py +1249 -0
  68. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/grpc_asyncio.py +1579 -0
  69. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/rest.py +6820 -0
  70. google/cloud/bigtable_admin_v2/services/bigtable_instance_admin/transports/rest_base.py +1746 -0
  71. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/__init__.py +22 -0
  72. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/async_client.py +3472 -0
  73. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/client.py +3949 -0
  74. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/pagers.py +669 -0
  75. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/__init__.py +40 -0
  76. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/base.py +708 -0
  77. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/grpc.py +1257 -0
  78. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/grpc_asyncio.py +1549 -0
  79. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/rest.py +6609 -0
  80. google/cloud/bigtable_admin_v2/services/bigtable_table_admin/transports/rest_base.py +1714 -0
  81. google/cloud/bigtable_admin_v2/types/__init__.py +248 -0
  82. google/cloud/bigtable_admin_v2/types/bigtable_instance_admin.py +1364 -0
  83. google/cloud/bigtable_admin_v2/types/bigtable_table_admin.py +1715 -0
  84. google/cloud/bigtable_admin_v2/types/common.py +81 -0
  85. google/cloud/bigtable_admin_v2/types/instance.py +819 -0
  86. google/cloud/bigtable_admin_v2/types/table.py +1028 -0
  87. google/cloud/bigtable_admin_v2/types/types.py +776 -0
  88. google/cloud/bigtable_v2/__init__.py +136 -0
  89. google/cloud/bigtable_v2/gapic_metadata.json +193 -0
  90. google/cloud/bigtable_v2/gapic_version.py +16 -0
  91. google/cloud/bigtable_v2/py.typed +2 -0
  92. google/cloud/bigtable_v2/services/__init__.py +15 -0
  93. google/cloud/bigtable_v2/services/bigtable/__init__.py +22 -0
  94. google/cloud/bigtable_v2/services/bigtable/async_client.py +1741 -0
  95. google/cloud/bigtable_v2/services/bigtable/client.py +2194 -0
  96. google/cloud/bigtable_v2/services/bigtable/transports/__init__.py +38 -0
  97. google/cloud/bigtable_v2/services/bigtable/transports/base.py +343 -0
  98. google/cloud/bigtable_v2/services/bigtable/transports/grpc.py +660 -0
  99. google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py +762 -0
  100. google/cloud/bigtable_v2/services/bigtable/transports/rest.py +2489 -0
  101. google/cloud/bigtable_v2/services/bigtable/transports/rest_base.py +711 -0
  102. google/cloud/bigtable_v2/types/__init__.py +138 -0
  103. google/cloud/bigtable_v2/types/bigtable.py +1531 -0
  104. google/cloud/bigtable_v2/types/data.py +1612 -0
  105. google/cloud/bigtable_v2/types/feature_flags.py +119 -0
  106. google/cloud/bigtable_v2/types/request_stats.py +171 -0
  107. google/cloud/bigtable_v2/types/response_params.py +64 -0
  108. google/cloud/bigtable_v2/types/types.py +579 -0
  109. google_cloud_bigtable-2.30.0.data/scripts/fixup_bigtable_admin_v2_keywords.py +233 -0
  110. google_cloud_bigtable-2.30.0.data/scripts/fixup_bigtable_v2_keywords.py +186 -0
  111. google_cloud_bigtable-2.30.0.dist-info/LICENSE +202 -0
  112. google_cloud_bigtable-2.30.0.dist-info/METADATA +154 -0
  113. google_cloud_bigtable-2.30.0.dist-info/RECORD +115 -0
  114. google_cloud_bigtable-2.30.0.dist-info/WHEEL +5 -0
  115. 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