[DRAFT] chore(bigtable): add samples for sync client#17820
[DRAFT] chore(bigtable): add samples for sync client#17820daniel-sanche wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds new Python samples and tests for the Google Cloud Bigtable admin and data clients, while updating legacy client samples with _legacy region tags. The review feedback highlights several critical API usage issues in the new data client snippets, including incorrect attribute access on Row and Cell objects, the use of the non-existent DeleteRangeFromColumn class (which should be DeleteCells), and type mismatches where regex filters expect bytes instead of strings (or vice-versa). Additionally, the feedback suggests minor cleanups for unused imports, unused variables, and redundant fully qualified imports.
| result_row = table.read_modify_write_row(row_key, increment_rule) | ||
|
|
||
| cell = result_row[0] | ||
| print(f"{cell.row_key} value: {int(cell)}") |
There was a problem hiding this comment.
There are multiple issues in this snippet:
Rowobjects in the new data client are not subscriptable; you should access cells via.cells.Cellobjects do not have arow_keyattribute; the row key belongs to theRowobject.Cellobjects cannot be directly cast toint. Since incremented values are stored as 8-byte big-endian integers, you should decode the bytes usingint.from_bytes.
| result_row = table.read_modify_write_row(row_key, increment_rule) | |
| cell = result_row[0] | |
| print(f"{cell.row_key} value: {int(cell)}") | |
| result_row = table.read_modify_write_row(row_key, increment_rule) | |
| cell = result_row.cells[0] | |
| val = int.from_bytes(cell.value, byteorder="big", signed=True) | |
| print(f"{result_row.row_key!r} value: {val}") |
| from google.cloud.bigtable.data import ( | ||
| BigtableDataClient, | ||
| DeleteRangeFromColumn, | ||
| ) | ||
|
|
||
| client = BigtableDataClient(project=project_id) | ||
| table = client.get_table(instance_id, table_id) | ||
|
|
||
| table.mutate_row( | ||
| "phone#4c410523#20190501", | ||
| DeleteRangeFromColumn(family="cell_plan", qualifier=b"data_plan_01gb"), | ||
| ) |
There was a problem hiding this comment.
The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteRangeFromColumn, | |
| ) | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| table.mutate_row( | |
| "phone#4c410523#20190501", | |
| DeleteRangeFromColumn(family="cell_plan", qualifier=b"data_plan_01gb"), | |
| ) | |
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteCells, | |
| ) | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| table.mutate_row( | |
| "phone#4c410523#20190501", | |
| DeleteCells(family="cell_plan", qualifier=b"data_plan_01gb"), | |
| ) |
| from google.cloud.bigtable.data import ( | ||
| BigtableDataClient, | ||
| DeleteRangeFromColumn, | ||
| ReadRowsQuery, | ||
| RowMutationEntry, | ||
| ) | ||
|
|
||
| client = BigtableDataClient(project=project_id) | ||
| table = client.get_table(instance_id, table_id) | ||
|
|
||
| with table.mutations_batcher() as batcher: | ||
| for row in table.read_rows(ReadRowsQuery(limit=10)): | ||
| batcher.append( | ||
| RowMutationEntry( | ||
| row.row_key, | ||
| DeleteRangeFromColumn( | ||
| family="cell_plan", qualifier=b"data_plan_01gb" | ||
| ), | ||
| ) |
There was a problem hiding this comment.
The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteRangeFromColumn, | |
| ReadRowsQuery, | |
| RowMutationEntry, | |
| ) | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| with table.mutations_batcher() as batcher: | |
| for row in table.read_rows(ReadRowsQuery(limit=10)): | |
| batcher.append( | |
| RowMutationEntry( | |
| row.row_key, | |
| DeleteRangeFromColumn( | |
| family="cell_plan", qualifier=b"data_plan_01gb" | |
| ), | |
| ) | |
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteCells, | |
| ReadRowsQuery, | |
| RowMutationEntry, | |
| ) | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| with table.mutations_batcher() as batcher: | |
| for row in table.read_rows(ReadRowsQuery(limit=10)): | |
| batcher.append( | |
| RowMutationEntry( | |
| row.row_key, | |
| DeleteCells( | |
| family="cell_plan", qualifier=b"data_plan_01gb" | |
| ), | |
| ) | |
| ) |
| from google.cloud.bigtable.data import ( | ||
| BigtableDataClient, | ||
| DeleteRangeFromColumn, | ||
| ) | ||
| from google.cloud.bigtable.data.row_filters import LiteralValueFilter | ||
|
|
||
| client = BigtableDataClient(project=project_id) | ||
| table = client.get_table(instance_id, table_id) | ||
|
|
||
| table.check_and_mutate_row( | ||
| "phone#4c410523#20190501", | ||
| predicate=LiteralValueFilter("PQ2A.190405.003"), | ||
| true_case_mutations=DeleteRangeFromColumn( | ||
| family="cell_plan", qualifier=b"data_plan_01gb" | ||
| ), | ||
| ) |
There was a problem hiding this comment.
The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteRangeFromColumn, | |
| ) | |
| from google.cloud.bigtable.data.row_filters import LiteralValueFilter | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| table.check_and_mutate_row( | |
| "phone#4c410523#20190501", | |
| predicate=LiteralValueFilter("PQ2A.190405.003"), | |
| true_case_mutations=DeleteRangeFromColumn( | |
| family="cell_plan", qualifier=b"data_plan_01gb" | |
| ), | |
| ) | |
| from google.cloud.bigtable.data import ( | |
| BigtableDataClient, | |
| DeleteCells, | |
| ) | |
| from google.cloud.bigtable.data.row_filters import LiteralValueFilter | |
| client = BigtableDataClient(project=project_id) | |
| table = client.get_table(instance_id, table_id) | |
| table.check_and_mutate_row( | |
| "phone#4c410523#20190501", | |
| predicate=LiteralValueFilter("PQ2A.190405.003"), | |
| true_case_mutations=DeleteCells( | |
| family="cell_plan", qualifier=b"data_plan_01gb" | |
| ), | |
| ) |
| query = ReadRowsQuery( | ||
| row_filter=row_filters.RowFilterUnion( | ||
| filters=[ | ||
| row_filters.ValueRegexFilter("true"), | ||
| row_filters.ColumnQualifierRegexFilter("os_build"), | ||
| ] | ||
| ) | ||
| ) |
There was a problem hiding this comment.
In the Python Bigtable data client, both ValueRegexFilter and ColumnQualifierRegexFilter expect bytes as their patterns because cell values and column qualifiers are stored as bytes. Passing strings will cause runtime errors or matching failures.
| query = ReadRowsQuery( | |
| row_filter=row_filters.RowFilterUnion( | |
| filters=[ | |
| row_filters.ValueRegexFilter("true"), | |
| row_filters.ColumnQualifierRegexFilter("os_build"), | |
| ] | |
| ) | |
| ) | |
| query = ReadRowsQuery( | |
| row_filter=row_filters.RowFilterUnion( | |
| filters=[ | |
| row_filters.ValueRegexFilter(b"true"), | |
| row_filters.ColumnQualifierRegexFilter(b"os_build"), | |
| ] | |
| ) | |
| ) |
| query = ReadRowsQuery( | ||
| row_filter=row_filters.ConditionalRowFilter( | ||
| predicate_filter=row_filters.RowFilterChain( | ||
| filters=[ | ||
| row_filters.ColumnQualifierRegexFilter("data_plan_10gb"), | ||
| row_filters.ValueRegexFilter("true"), | ||
| ] | ||
| ), | ||
| true_filter=row_filters.ApplyLabelFilter(label="passed-filter"), | ||
| false_filter=row_filters.ApplyLabelFilter(label="filtered-out"), | ||
| ) | ||
| ) |
There was a problem hiding this comment.
In the Python Bigtable data client, both ColumnQualifierRegexFilter and ValueRegexFilter expect bytes as their patterns because column qualifiers and cell values are stored as bytes. Passing strings will cause runtime errors or matching failures.
| query = ReadRowsQuery( | |
| row_filter=row_filters.ConditionalRowFilter( | |
| predicate_filter=row_filters.RowFilterChain( | |
| filters=[ | |
| row_filters.ColumnQualifierRegexFilter("data_plan_10gb"), | |
| row_filters.ValueRegexFilter("true"), | |
| ] | |
| ), | |
| true_filter=row_filters.ApplyLabelFilter(label="passed-filter"), | |
| false_filter=row_filters.ApplyLabelFilter(label="filtered-out"), | |
| ) | |
| ) | |
| query = ReadRowsQuery( | |
| row_filter=row_filters.ConditionalRowFilter( | |
| predicate_filter=row_filters.RowFilterChain( | |
| filters=[ | |
| row_filters.ColumnQualifierRegexFilter(b"data_plan_10gb"), | |
| row_filters.ValueRegexFilter(b"true"), | |
| ] | |
| ), | |
| true_filter=row_filters.ApplyLabelFilter(label="passed-filter"), | |
| false_filter=row_filters.ApplyLabelFilter(label="filtered-out"), | |
| ) | |
| ) |
| # [END bigtable_check_instance_exists] | ||
|
|
||
| # [START bigtable_create_prod_instance] | ||
| cluster_path = client.cluster_path(project_id, instance_id, cluster_id) |
| """ | ||
|
|
||
| import argparse | ||
| import datetime |
| # [START bigtable_hw_create_filter_data_client] | ||
| # Create a filter to only retrieve the most recent version of the cell | ||
| # for each column across entire row. | ||
| row_filter = bigtable.data.row_filters.CellsColumnLimitFilter(1) |
There was a problem hiding this comment.
Since row_filters is imported directly on line 31, you can use it here instead of the fully qualified path. This also allows you to remove the dummy statement and comment on lines 37-38.
| row_filter = bigtable.data.row_filters.CellsColumnLimitFilter(1) | |
| row_filter = row_filters.CellsColumnLimitFilter(1) |
| ) | ||
|
|
||
| query = ReadRowsQuery( | ||
| row_filter=row_filters.FamilyNameRegexFilter("stats_.*$".encode("utf-8")) |
There was a problem hiding this comment.
In the Python Bigtable data client, column family names are strings, so FamilyNameRegexFilter expects a string pattern rather than bytes. Passing bytes may cause type mismatches or matching failures.
| row_filter=row_filters.FamilyNameRegexFilter("stats_.*$".encode("utf-8")) | |
| row_filter=row_filters.FamilyNameRegexFilter("stats_.*$") |
This PR covers sample gaps between the sync data client/generated admin client
TODO: review