Skip to content
This repository was archived by the owner on Sep 12, 2025. It is now read-only.

Commit 04867c6

Browse files
film42yirutangpartheaLinchin
authored
Fix: Add response object to any append rows requests exception (#838)
* Fix: Add response object to any append rows requests exception Should an AppendRowsRequest fail, you need to inspect the response to see what went wrong. Currently this lib only raises an exception with the code and message, throwing the actual response away. This patch adds the response to any exception raise. This is fine because the base grpc error has a response kwarg that this lib wasn't using. Now you can catch the error and call `e.response.row_errors` to see the underlying row errors. Fixes: #836 * fix system test * lint --------- Co-authored-by: Yiru Tang <yiru@google.com> Co-authored-by: Anthonios Partheniou <partheniou@google.com> Co-authored-by: Lingqing Gan <lingqing.gan@gmail.com>
1 parent 1560654 commit 04867c6

File tree

3 files changed

+41
-13
lines changed

3 files changed

+41
-13
lines changed

google/cloud/bigquery_storage_v1/writer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def _on_response(self, response: gapic_types.AppendRowsResponse):
285285
future: AppendRowsFuture = self._futures_queue.get_nowait()
286286
if response.error.code:
287287
exc = exceptions.from_grpc_status(
288-
response.error.code, response.error.message
288+
response.error.code, response.error.message, response=response
289289
)
290290
future.set_exception(exc)
291291
else:

google/cloud/bigquery_storage_v1beta2/writer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def _on_response(self, response: gapic_types.AppendRowsResponse):
269269
future: AppendRowsFuture = self._futures_queue.get_nowait()
270270
if response.error.code:
271271
exc = exceptions.from_grpc_status(
272-
response.error.code, response.error.message
272+
response.error.code, response.error.message, response=response
273273
)
274274
future.set_exception(exc)
275275
else:

tests/system/test_writer.py

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def table(project_id, dataset, bq_client):
3131
schema = [
3232
bigquery.SchemaField("first_name", "STRING", mode="NULLABLE"),
3333
bigquery.SchemaField("last_name", "STRING", mode="NULLABLE"),
34-
bigquery.SchemaField("age", "INTEGER", mode="NULLABLE"),
34+
bigquery.SchemaField("age", "INTEGER", mode="REQUIRED"),
3535
]
3636

3737
unique_suffix = str(uuid.uuid4()).replace("-", "_")
@@ -52,15 +52,8 @@ def bqstorage_write_client(credentials):
5252
return bigquery_storage_v1.BigQueryWriteClient(credentials=credentials)
5353

5454

55-
def test_append_rows_with_invalid_stream_name_fails_fast(bqstorage_write_client):
56-
bad_request = gapic_types.AppendRowsRequest()
57-
bad_request.write_stream = "this-is-an-invalid-stream-resource-path"
58-
59-
with pytest.raises(exceptions.GoogleAPICallError):
60-
bqstorage_write_client.append_rows(bad_request)
61-
62-
63-
def test_append_rows_with_proto3(bqstorage_write_client, table):
55+
@pytest.fixture(scope="function")
56+
def append_rows_stream(bqstorage_write_client, table):
6457
person_pb = person_pb2.PersonProto()
6558

6659
stream_name = f"projects/{table.project}/datasets/{table.dataset_id}/tables/{table.table_id}/_default"
@@ -81,11 +74,22 @@ def test_append_rows_with_proto3(bqstorage_write_client, table):
8174
bqstorage_write_client,
8275
request_template,
8376
)
77+
return append_rows_stream
78+
79+
80+
def test_append_rows_with_invalid_stream_name_fails_fast(bqstorage_write_client):
81+
bad_request = gapic_types.AppendRowsRequest()
82+
bad_request.write_stream = "this-is-an-invalid-stream-resource-path"
83+
84+
with pytest.raises(exceptions.GoogleAPICallError):
85+
bqstorage_write_client.append_rows(bad_request)
8486

87+
88+
def test_append_rows_with_proto3(append_rows_stream):
8589
request = gapic_types.AppendRowsRequest()
8690
proto_data = gapic_types.AppendRowsRequest.ProtoData()
8791
proto_rows = gapic_types.ProtoRows()
88-
row = person_pb
92+
row = person_pb2.PersonProto()
8993
row.first_name = "fn"
9094
row.last_name = "ln"
9195
row.age = 20
@@ -96,3 +100,27 @@ def test_append_rows_with_proto3(bqstorage_write_client, table):
96100

97101
assert response_future.result()
98102
# The request should success
103+
104+
105+
def test_append_rows_with_proto3_got_response_on_failure(append_rows_stream):
106+
"""When the request fails and there is a response, verify that the response
107+
is included in the exception. For more details, see
108+
https://github.com/googleapis/python-bigquery-storage/issues/836
109+
"""
110+
111+
# Make an invalid request by leaving the required field row.age blank.
112+
request = gapic_types.AppendRowsRequest()
113+
proto_data = gapic_types.AppendRowsRequest.ProtoData()
114+
proto_rows = gapic_types.ProtoRows()
115+
row = person_pb2.PersonProto()
116+
row.first_name = "fn"
117+
row.last_name = "ln"
118+
proto_rows.serialized_rows.append(row.SerializeToString())
119+
proto_data.rows = proto_rows
120+
request.proto_rows = proto_data
121+
response_future = append_rows_stream.send(request)
122+
123+
with pytest.raises(exceptions.GoogleAPICallError) as excinfo:
124+
response_future.result()
125+
126+
assert isinstance(excinfo.value.response, gapic_types.AppendRowsResponse)

0 commit comments

Comments
 (0)