Skip to content

[DRAFT] chore(bigtable): add samples for sync client#17820

Draft
daniel-sanche wants to merge 6 commits into
samples_1_reorganize_samplesfrom
samples_2_add_sync_samples
Draft

[DRAFT] chore(bigtable): add samples for sync client#17820
daniel-sanche wants to merge 6 commits into
samples_1_reorganize_samplesfrom
samples_2_add_sync_samples

Conversation

@daniel-sanche

Copy link
Copy Markdown
Contributor

This PR covers sample gaps between the sync data client/generated admin client

TODO: review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +88 to +91
result_row = table.read_modify_write_row(row_key, increment_rule)

cell = result_row[0]
print(f"{cell.row_key} value: {int(cell)}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are multiple issues in this snippet:

  1. Row objects in the new data client are not subscriptable; you should access cells via .cells.
  2. Cell objects do not have a row_key attribute; the row key belongs to the Row object.
  3. Cell objects cannot be directly cast to int. Since incremented values are stored as 8-byte big-endian integers, you should decode the bytes using int.from_bytes.
Suggested change
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}")

Comment on lines +19 to +30
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"),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.

Suggested change
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"),
)

Comment on lines +73 to +91
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"
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.

Suggested change
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"
),
)
)

Comment on lines +103 to +118
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"
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The class DeleteRangeFromColumn does not exist in google.cloud.bigtable.data. To delete cells from a column, use DeleteCells instead.

Suggested change
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"
),
)

Comment on lines +324 to +331
query = ReadRowsQuery(
row_filter=row_filters.RowFilterUnion(
filters=[
row_filters.ValueRegexFilter("true"),
row_filters.ColumnQualifierRegexFilter("os_build"),
]
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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.

Suggested change
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"),
]
)
)

Comment on lines +348 to +359
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"),
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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.

Suggested change
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable cluster_path is defined here but is never used anywhere in the run_instance_operations function. Consider removing it to clean up the code.

"""

import argparse
import datetime

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The datetime module is imported here but is never used in this file. Consider removing this unused import.

# [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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
row_filter=row_filters.FamilyNameRegexFilter("stats_.*$".encode("utf-8"))
row_filter=row_filters.FamilyNameRegexFilter("stats_.*$")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant