Skip to content

feat: Shimmed RowSet and RowRange for ReadRows.#1296

Open
gkevinzheng wants to merge 1 commit intomutate-rowsfrom
row-set
Open

feat: Shimmed RowSet and RowRange for ReadRows.#1296
gkevinzheng wants to merge 1 commit intomutate-rowsfrom
row-set

Conversation

@gkevinzheng
Copy link
Contributor

Changes made:

  • Refactored _MappableAttributesMixin to helpers.py for use in RowRange.
  • Used RowRange and ReadRowsQuery from the data client as backing data sources for RowRange and RowSet respectively.

@gkevinzheng gkevinzheng requested review from a team as code owners February 17, 2026 20:13
@product-auto-label product-auto-label bot added size: m Pull request size is medium. api: bigtable Issues related to the googleapis/python-bigtable API. labels Feb 17, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gkevinzheng, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces significant refactoring to align the legacy Bigtable client's RowSet and RowRange classes with the newer data client's ReadRowsQuery and RowRange implementations. By moving a common mixin to a shared helper module and having the legacy classes shim the data client's counterparts, the change promotes code reuse, simplifies future maintenance, and ensures consistency in how row keys and ranges are handled across different client versions.

Highlights

  • Refactored Mixin: The _MappableAttributesMixin class was moved from row_filters.py to a new helpers.py module to allow its reuse across different modules.
  • Shimmed RowSet: The RowSet class was updated to internally use ReadRowsQuery from the data client, delegating its core logic for managing row keys and ranges.
  • Shimmed RowRange: The RowRange class was refactored to inherit from _MappableAttributesMixin and the data client's BaseRowRange, enabling attribute remapping and leveraging the new data client's implementation.
Changelog
  • google/cloud/bigtable/data/exceptions.py
    • Corrected a trailing whitespace in a TODO comment.
  • google/cloud/bigtable/helpers.py
    • Added the _MappableAttributesMixin class, designed for remapping attribute names in classes that wrap data client objects.
  • google/cloud/bigtable/row_filters.py
    • Removed the local definition of _MappableAttributesMixin.
    • Imported _MappableAttributesMixin from google.cloud.bigtable.helpers.
  • google/cloud/bigtable/row_set.py
    • Imported BaseRowRange, ReadRowsQuery from google.cloud.bigtable.data.read_rows_query, and _MappableAttributesMixin from google.cloud.bigtable.helpers.
    • Modified the RowSet class to store an instance of ReadRowsQuery internally.
    • Updated RowSet's __eq__ method to compare the internal _read_rows_query instances.
    • Added row_keys and row_ranges properties to RowSet that delegate to the internal _read_rows_query.
    • Modified add_row_key, add_row_range, add_row_range_from_keys, and _update_message_request methods in RowSet to interact with the internal _read_rows_query object.
    • Refactored the RowRange class to inherit from _MappableAttributesMixin and BaseRowRange.
    • Defined _attribute_map in RowRange to map start_inclusive to start_is_inclusive and end_inclusive to end_is_inclusive.
    • Simplified RowRange's _key method and removed its custom __init__, __eq__, and __ne__ methods, relying on the base class and mixin.
    • Updated RowRange's get_range_kwargs to extract fields directly from its internal protobuf representation.
  • tests/unit/v2_client/test_row_set.py
    • Removed test_row_set__eq__len_row_keys_differ and test_row_set__eq__len_row_ranges_differ tests.
    • Modified test_row_range_constructor to decode start_key and end_key for assertions, reflecting changes in RowRange's internal representation.
  • tests/unit/v2_client/test_table.py
    • Updated start_key values from b"start_key" to b"begin_key" in several _create_row_request tests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

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

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 refactors RowSet and RowRange to act as shims over new data client classes, which is a solid improvement for maintainability. Moving _MappableAttributesMixin to a shared helper file is also a good refactoring. I've identified one critical bug that would cause a runtime error and another medium-severity issue related to encapsulation that could be improved.

Comment on lines +187 to +189
return {
descriptor.name: value for descriptor, value in self._pb._pb.ListFields()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

There seems to be a typo here. self._pb is the protobuf message object, which has the ListFields() method. Accessing self._pb._pb will result in an AttributeError because the protobuf message object does not have a _pb attribute.

Suggested change
return {
descriptor.name: value for descriptor, value in self._pb._pb.ListFields()
}
return {
descriptor.name: value for descriptor, value in self._pb.ListFields()
}

Comment on lines +139 to +143
for each in self._read_rows_query._row_set.row_keys:
message.rows.row_keys._pb.append(_to_bytes(each))

for each in self.row_ranges:
r_kwrags = each.get_range_kwargs()
message.rows.row_ranges.append(r_kwrags)
for each in self._read_rows_query._row_set.row_ranges:
message.rows.row_ranges.append(each)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Accessing the private attribute _row_set of _read_rows_query breaks encapsulation and makes this code brittle to future changes in the ReadRowsQuery class. It's better to use the public properties row_keys and row_ranges. While this might involve a small performance cost due to object wrapping and unwrapping for ranges, it ensures better code maintainability.

Suggested change
for each in self._read_rows_query._row_set.row_keys:
message.rows.row_keys._pb.append(_to_bytes(each))
for each in self.row_ranges:
r_kwrags = each.get_range_kwargs()
message.rows.row_ranges.append(r_kwrags)
for each in self._read_rows_query._row_set.row_ranges:
message.rows.row_ranges.append(each)
for each in self._read_rows_query.row_keys:
message.rows.row_keys._pb.append(_to_bytes(each))
for each in self._read_rows_query.row_ranges:
message.rows.row_ranges.append(each._to_pb())

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

Labels

api: bigtable Issues related to the googleapis/python-bigtable API. size: m Pull request size is medium.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant