Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions google/cloud/bigtable/data/_async/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,33 @@ async def mutate_row(
exception_factory=_retry_exception_factory,
)

@CrossSync.convert
def _get_mutate_rows_operation(
self,
mutation_entries: list[RowMutationEntry],
*,
operation_timeout: float | TABLE_DEFAULT,
attempt_timeout: float | None | TABLE_DEFAULT,
retryable_errors: Sequence[type[Exception]] | TABLE_DEFAULT,
) -> CrossSync._MutateRowsOperation:
"""
Gets the bulk mutate rows operation object for the given mutation entries.
"""
operation_timeout, attempt_timeout = _get_timeouts(
operation_timeout, attempt_timeout, self
)
retryable_excs = _get_retryable_errors(retryable_errors, self)

operation = CrossSync._MutateRowsOperation(
self.client._gapic_client,
self,
mutation_entries,
operation_timeout,
attempt_timeout,
retryable_exceptions=retryable_excs,
)
return operation
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a big fan of polluting this file like this.

I mentioned in another comment that we should be able to get the information we need by parsing the exception group, which means we wouldn't need to do this

But even if we ignore that thread, I'd say it could be cleaner to just copy these three lines building the operation directly in the shim, instead of adding this helper. That way we're polluting the shim codebase, instead of the data client

What do you think?


@CrossSync.convert
async def bulk_mutate_rows(
self,
Expand Down Expand Up @@ -1597,18 +1624,11 @@ async def bulk_mutate_rows(
Contains details about any failed entries in .exceptions
ValueError: if invalid arguments are provided
"""
operation_timeout, attempt_timeout = _get_timeouts(
operation_timeout, attempt_timeout, self
)
retryable_excs = _get_retryable_errors(retryable_errors, self)

operation = CrossSync._MutateRowsOperation(
self.client._gapic_client,
self,
operation = self._get_mutate_rows_operation(
mutation_entries,
operation_timeout,
attempt_timeout,
retryable_exceptions=retryable_excs,
operation_timeout=operation_timeout,
attempt_timeout=attempt_timeout,
retryable_errors=retryable_errors,
)
await operation.start()

Expand Down
37 changes: 27 additions & 10 deletions google/cloud/bigtable/data/_sync_autogen/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,29 @@ def mutate_row(
exception_factory=_retry_exception_factory,
)

def _get_mutate_rows_operation(
self,
mutation_entries: list[RowMutationEntry],
*,
operation_timeout: float | TABLE_DEFAULT,
attempt_timeout: float | None | TABLE_DEFAULT,
retryable_errors: Sequence[type[Exception]] | TABLE_DEFAULT,
) -> CrossSync._Sync_Impl._MutateRowsOperation:
"""Gets the bulk mutate rows operation object for the given mutation entries."""
(operation_timeout, attempt_timeout) = _get_timeouts(
operation_timeout, attempt_timeout, self
)
retryable_excs = _get_retryable_errors(retryable_errors, self)
operation = CrossSync._Sync_Impl._MutateRowsOperation(
self.client._gapic_client,
self,
mutation_entries,
operation_timeout,
attempt_timeout,
retryable_exceptions=retryable_excs,
)
return operation

def bulk_mutate_rows(
self,
mutation_entries: list[RowMutationEntry],
Expand Down Expand Up @@ -1337,17 +1360,11 @@ def bulk_mutate_rows(
MutationsExceptionGroup: if one or more mutations fails
Contains details about any failed entries in .exceptions
ValueError: if invalid arguments are provided"""
(operation_timeout, attempt_timeout) = _get_timeouts(
operation_timeout, attempt_timeout, self
)
retryable_excs = _get_retryable_errors(retryable_errors, self)
operation = CrossSync._Sync_Impl._MutateRowsOperation(
self.client._gapic_client,
self,
operation = self._get_mutate_rows_operation(
mutation_entries,
operation_timeout,
attempt_timeout,
retryable_exceptions=retryable_excs,
operation_timeout=operation_timeout,
attempt_timeout=attempt_timeout,
retryable_errors=retryable_errors,
)
operation.start()

Expand Down
17 changes: 11 additions & 6 deletions google/cloud/bigtable/row.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,16 @@ def _set_cell(self, column_family_id, column, value, timestamp=None, state=None)
integer (8 bytes).

:type timestamp: :class:`datetime.datetime`
:param timestamp: (Optional) The timestamp of the operation.
:param timestamp: (Optional) The timestamp of the operation. If a
timestamp is not provided, the current system time
will be used.

:type state: bool
:param state: (Optional) The state that is passed along to
:meth:`_get_mutations`.
"""
if timestamp is None:
# Use current Bigtable server time.
timestamp_micros = mutations._SERVER_SIDE_TIMESTAMP
if timestamp is None or timestamp == mutations._SERVER_SIDE_TIMESTAMP:
timestamp_micros = timestamp
Comment on lines +164 to +165
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The logic for handling the timestamp argument is a bit condensed and could be made more explicit for better readability and maintainability. Expanding the if condition to handle the None and _SERVER_SIDE_TIMESTAMP cases separately would make the intent clearer.

Suggested change
if timestamp is None or timestamp == mutations._SERVER_SIDE_TIMESTAMP:
timestamp_micros = timestamp
if timestamp is None:
# Let SetCell handle client-side timestamp generation by passing None.
timestamp_micros = None
elif timestamp == mutations._SERVER_SIDE_TIMESTAMP:
# Use server-side timestamp.
timestamp_micros = mutations._SERVER_SIDE_TIMESTAMP

Copy link
Contributor

Choose a reason for hiding this comment

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

I kind of agree with this, it's easier to skim. But I also think the current code is totally fine

Copy link
Contributor

Choose a reason for hiding this comment

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

Another way to improve readability would just be to add a comment:

if timestamp is None or timestamp == mutations._SERVER_SIDE_TIMESTAMP:
    # preserve special-case values (client-side or server-side timestamp)
    timestamp_micros = timestamp

else:
timestamp_micros = _microseconds_from_datetime(timestamp)
# Truncate to millisecond granularity.
Expand Down Expand Up @@ -351,7 +352,9 @@ def set_cell(self, column_family_id, column, value, timestamp=None):
integer (8 bytes).

:type timestamp: :class:`datetime.datetime`
:param timestamp: (Optional) The timestamp of the operation.
:param timestamp: (Optional) The timestamp of the operation. If a
timestamp is not provided, the current system time
will be used.
"""
self._set_cell(column_family_id, column, value, timestamp=timestamp, state=None)

Expand Down Expand Up @@ -651,7 +654,9 @@ def set_cell(self, column_family_id, column, value, timestamp=None, state=True):
integer (8 bytes).

:type timestamp: :class:`datetime.datetime`
:param timestamp: (Optional) The timestamp of the operation.
:param timestamp: (Optional) The timestamp of the operation. If a
timestamp is not provided, the current system time
will be used.

:type state: bool
:param state: (Optional) The state that the mutation should be
Expand Down
Loading
Loading