From b60a88f57119be41c6378eae06dc30e7f2ad6578 Mon Sep 17 00:00:00 2001 From: vam-google Date: Tue, 13 Sep 2022 16:58:48 -0700 Subject: [PATCH 1/2] fix: Improve transcodding error message This fixes https://github.com/googleapis/python-api-core/issues/441 and https://github.com/googleapis/python-api-core/issues/440. Also, with this change we stop outputting the whole request message in transcodding erro message to prevent leaking any confidential information from a request message in a form of an error in a log message. --- google/api_core/path_template.py | 30 +++++++++++++++++++++++------- tests/unit/test_path_template.py | 3 ++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/google/api_core/path_template.py b/google/api_core/path_template.py index 2639459a..e0c2dd52 100644 --- a/google/api_core/path_template.py +++ b/google/api_core/path_template.py @@ -272,15 +272,18 @@ def transcode(http_options, message=None, **request_kwargs): ValueError: If the request does not match the given template. """ transcoded_value = message or request_kwargs + bindings = [] for http_option in http_options: request = {} # Assign path uri_template = http_option["uri"] - path_fields = [ - match.group("name") for match in _VARIABLE_RE.finditer(uri_template) + fields = [ + (m.group("name"), m.group("template")) for m in _VARIABLE_RE.finditer(uri_template) ] - path_args = {field: get_field(transcoded_value, field) for field in path_fields} + bindings.append((uri_template, fields)) + + path_args = {field: get_field(transcoded_value, field) for field, _ in fields} request["uri"] = expand(uri_template, **path_args) if not validate(uri_template, request["uri"]) or not all(path_args.values()): @@ -288,7 +291,7 @@ def transcode(http_options, message=None, **request_kwargs): # Remove fields used in uri path from request leftovers = copy.deepcopy(transcoded_value) - for path_field in path_fields: + for path_field, _ in fields: delete_field(leftovers, path_field) # Assign body and query params @@ -316,8 +319,21 @@ def transcode(http_options, message=None, **request_kwargs): request["method"] = http_option["method"] return request - raise ValueError( - "Request {} does not match any URL path template in available HttpRule's {}".format( - request_kwargs, [opt["uri"] for opt in http_options] + bindings_description = [ + "\n\tURI: \"{}\"" + "\n\tRequired request fields:\n\t\t{}".format( + uri, + "\n\t\t".join(["field: \"{}\", pattern: \"{}\"".format(n, p if p else "*") for n, p in fields]) ) + for uri, fields in bindings + ] + + raise ValueError( + "Invalid request." + "\nSome of the fields of the request message are either not initialized or " + "initialized with an invalid value." + "\nPlease make sure your request matches at least one accepted HTTP binding." + "\nTo match a binding the request message must have all the required fields " + "initialized with values matching their patterns as " + "listed below:{}".format("\n".join(bindings_description)) ) diff --git a/tests/unit/test_path_template.py b/tests/unit/test_path_template.py index 73d351c0..808b36f3 100644 --- a/tests/unit/test_path_template.py +++ b/tests/unit/test_path_template.py @@ -629,8 +629,9 @@ def test_transcode_with_additional_bindings( ) def test_transcode_fails(http_options, message, request_kwargs): http_options, _ = helper_test_transcode(http_options, range(4)) - with pytest.raises(ValueError): + with pytest.raises(ValueError) as exc_info: path_template.transcode(http_options, message, **request_kwargs) + assert str(exc_info.value).count("URI") == len(http_options) def helper_test_transcode(http_options_list, expected_result_list): From cdec49ac47a6f7446db2b1afba86cd99fc157df3 Mon Sep 17 00:00:00 2001 From: vam-google Date: Tue, 13 Sep 2022 17:04:12 -0700 Subject: [PATCH 2/2] reformat code with black --- google/api_core/path_template.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/google/api_core/path_template.py b/google/api_core/path_template.py index e0c2dd52..b8ebb2af 100644 --- a/google/api_core/path_template.py +++ b/google/api_core/path_template.py @@ -279,7 +279,8 @@ def transcode(http_options, message=None, **request_kwargs): # Assign path uri_template = http_option["uri"] fields = [ - (m.group("name"), m.group("template")) for m in _VARIABLE_RE.finditer(uri_template) + (m.group("name"), m.group("template")) + for m in _VARIABLE_RE.finditer(uri_template) ] bindings.append((uri_template, fields)) @@ -320,10 +321,15 @@ def transcode(http_options, message=None, **request_kwargs): return request bindings_description = [ - "\n\tURI: \"{}\"" + '\n\tURI: "{}"' "\n\tRequired request fields:\n\t\t{}".format( uri, - "\n\t\t".join(["field: \"{}\", pattern: \"{}\"".format(n, p if p else "*") for n, p in fields]) + "\n\t\t".join( + [ + 'field: "{}", pattern: "{}"'.format(n, p if p else "*") + for n, p in fields + ] + ), ) for uri, fields in bindings ] @@ -334,6 +340,7 @@ def transcode(http_options, message=None, **request_kwargs): "initialized with an invalid value." "\nPlease make sure your request matches at least one accepted HTTP binding." "\nTo match a binding the request message must have all the required fields " - "initialized with values matching their patterns as " - "listed below:{}".format("\n".join(bindings_description)) + "initialized with values matching their patterns as listed below:{}".format( + "\n".join(bindings_description) + ) )