Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
🦉 Updates from OwlBot
  • Loading branch information
gcf-owl-bot[bot] committed Aug 25, 2021
commit a956abb7de3fd0c5a72eb21145e03b118a3b3718
33 changes: 18 additions & 15 deletions google/api_core/path_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def validate(tmpl, path):
pattern = _generate_pattern_for_template(tmpl) + "$"
return True if re.match(pattern, path) is not None else False


def transcode(http_options, **request_kwargs):
"""Transcodes a grpc request pattern into a proper HTTP request following the rules outlined here,
https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L44-L312
Comment thread
yihjenku marked this conversation as resolved.
Expand All @@ -220,31 +221,33 @@ def transcode(http_options, **request_kwargs):
for http_option in http_options:
Comment thread
yihjenku marked this conversation as resolved.

# Assign path
uri_template = http_option['uri']
path_fields = [match.group('name') for match in _VARIABLE_RE.finditer(uri_template)]
path_args = {field:request_kwargs.get(field, None) for field in path_fields}
leftovers = {k:v for k,v in request_kwargs.items() if k not in path_args}
answer['uri'] = expand(uri_template, **path_args)

if not validate(uri_template, answer['uri']) or not all(path_args.values()):
uri_template = http_option["uri"]
path_fields = [
match.group("name") for match in _VARIABLE_RE.finditer(uri_template)
]
path_args = {field: request_kwargs.get(field, None) for field in path_fields}
Comment thread
tseaver marked this conversation as resolved.
Outdated
leftovers = {k: v for k, v in request_kwargs.items() if k not in path_args}
answer["uri"] = expand(uri_template, **path_args)

if not validate(uri_template, answer["uri"]) or not all(path_args.values()):
continue

# Assign body and query params
body = http_option.get('body')
body = http_option.get("body")

if body:
if body == '*':
answer['body'] = leftovers
answer['query_params'] = {}
if body == "*":
answer["body"] = leftovers
answer["query_params"] = {}
else:
try:
answer['body'] = leftovers.pop(body)
answer["body"] = leftovers.pop(body)
except KeyError:
continue
answer['query_params'] = leftovers
answer["query_params"] = leftovers
else:
answer['query_params'] = leftovers
answer['method'] = http_option['method']
answer["query_params"] = leftovers
answer["method"] = http_option["method"]
return answer

raise ValueError("Request obj does not match any template")
195 changes: 123 additions & 72 deletions tests/unit/test_path_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,86 +116,137 @@ def test__replace_variable_with_pattern():


@pytest.mark.parametrize(
'http_options, request_kwargs, expected_result',
"http_options, request_kwargs, expected_result",
[
[[['get','/v1/no/template','']],
{'foo':'bar'},
['get','/v1/no/template',{},{'foo':'bar'}]],

[
[["get", "/v1/no/template", ""]],
{"foo": "bar"},
["get", "/v1/no/template", {}, {"foo": "bar"}],
],
# Single templates
[[['get','/v1/{field}','']],
{'field':'parent'},
['get','/v1/parent',{},{}]],

[[['get','/v1/{field.sub}','']],
{'field.sub':'parent', 'foo':'bar'},
['get','/v1/parent',{},{'foo':'bar'}]],

[
[["get", "/v1/{field}", ""]],
{"field": "parent"},
["get", "/v1/parent", {}, {}],
],
[
[["get", "/v1/{field.sub}", ""]],
{"field.sub": "parent", "foo": "bar"},
["get", "/v1/parent", {}, {"foo": "bar"}],
],
# Single segment wildcard
[[['get','/v1/{field=*}','']],
{'field':'parent'},
['get','/v1/parent',{},{}]],

[[['get','/v1/{field=a/*/b/*}','']],
{'field':'a/parent/b/child','foo':'bar'},
['get','/v1/a/parent/b/child',{},{'foo':'bar'}]],

[
[["get", "/v1/{field=*}", ""]],
{"field": "parent"},
["get", "/v1/parent", {}, {}],
],
[
[["get", "/v1/{field=a/*/b/*}", ""]],
{"field": "a/parent/b/child", "foo": "bar"},
["get", "/v1/a/parent/b/child", {}, {"foo": "bar"}],
],
# Double segment wildcard
[[['get','/v1/{field=**}','']],
{'field':'parent/p1'},
['get','/v1/parent/p1',{},{}]],

[[['get','/v1/{field=a/**/b/**}','']],
{'field':'a/parent/p1/b/child/c1', 'foo':'bar'},
['get','/v1/a/parent/p1/b/child/c1',{},{'foo':'bar'}]],

[
[["get", "/v1/{field=**}", ""]],
{"field": "parent/p1"},
["get", "/v1/parent/p1", {}, {}],
],
[
[["get", "/v1/{field=a/**/b/**}", ""]],
{"field": "a/parent/p1/b/child/c1", "foo": "bar"},
["get", "/v1/a/parent/p1/b/child/c1", {}, {"foo": "bar"}],
],
# Combined single and double segment wildcard
[[['get','/v1/{field=a/*/b/**}','']],
{'field':'a/parent/b/child/c1'},
['get','/v1/a/parent/b/child/c1',{},{}]],

[[['get','/v1/{field=a/**/b/*}/v2/{name}','']],
{'field':'a/parent/p1/b/child', 'name':'first', 'foo':'bar'},
['get','/v1/a/parent/p1/b/child/v2/first',{},{'foo':'bar'}]],

[
[["get", "/v1/{field=a/*/b/**}", ""]],
{"field": "a/parent/b/child/c1"},
["get", "/v1/a/parent/b/child/c1", {}, {}],
],
[
[["get", "/v1/{field=a/**/b/*}/v2/{name}", ""]],
{"field": "a/parent/p1/b/child", "name": "first", "foo": "bar"},
["get", "/v1/a/parent/p1/b/child/v2/first", {}, {"foo": "bar"}],
],
# Single field body
[[['post','/v1/no/template','data']],
{'data':{'id':1, 'info':'some info'},'foo':'bar'},
['post','/v1/no/template',{'id':1, 'info':'some info'},{'foo':'bar'}]],

[[['post','/v1/{field=a/*}/b/{name=**}','data']],
{'field':'a/parent','name':'first/last','data':{'id':1, 'info':'some info'},'foo':'bar'},
['post','/v1/a/parent/b/first/last',{'id':1, 'info':'some info'},{'foo':'bar'}]],

[
[["post", "/v1/no/template", "data"]],
{"data": {"id": 1, "info": "some info"}, "foo": "bar"},
["post", "/v1/no/template", {"id": 1, "info": "some info"}, {"foo": "bar"}],
],
[
[["post", "/v1/{field=a/*}/b/{name=**}", "data"]],
{
"field": "a/parent",
"name": "first/last",
"data": {"id": 1, "info": "some info"},
"foo": "bar",
},
[
"post",
"/v1/a/parent/b/first/last",
{"id": 1, "info": "some info"},
{"foo": "bar"},
],
],
# Wildcard body
[[['post','/v1/{field=a/*}/b/{name=**}','*']],
{'field':'a/parent','name':'first/last','data':{'id':1, 'info':'some info'},'foo':'bar'},
['post','/v1/a/parent/b/first/last',{'data':{'id':1, 'info':'some info'},'foo':'bar'},{}]],

[
[["post", "/v1/{field=a/*}/b/{name=**}", "*"]],
{
"field": "a/parent",
"name": "first/last",
"data": {"id": 1, "info": "some info"},
"foo": "bar",
},
[
"post",
"/v1/a/parent/b/first/last",
{"data": {"id": 1, "info": "some info"}, "foo": "bar"},
{},
],
],
# Additional bindings
[[['post','/v1/{field=a/*}/b/{name=**}','extra_data'], ['post','/v1/{field=a/*}/b/{name=**}','*']],
{'field':'a/parent','name':'first/last','data':{'id':1, 'info':'some info'},'foo':'bar'},
['post','/v1/a/parent/b/first/last',{'data':{'id':1, 'info':'some info'},'foo':'bar'},{}]],

[[['get','/v1/{field=a/*}/b/{name=**}',''],['get','/v1/{field=a/*}/b/first/last','']],
{'field':'a/parent','foo':'bar'},
['get','/v1/a/parent/b/first/last',{},{'foo':'bar'}]],
]
[
[
["post", "/v1/{field=a/*}/b/{name=**}", "extra_data"],
["post", "/v1/{field=a/*}/b/{name=**}", "*"],
],
{
"field": "a/parent",
"name": "first/last",
"data": {"id": 1, "info": "some info"},
"foo": "bar",
},
[
"post",
"/v1/a/parent/b/first/last",
{"data": {"id": 1, "info": "some info"}, "foo": "bar"},
{},
],
],
[
[
["get", "/v1/{field=a/*}/b/{name=**}", ""],
["get", "/v1/{field=a/*}/b/first/last", ""],
],
{"field": "a/parent", "foo": "bar"},
["get", "/v1/a/parent/b/first/last", {}, {"foo": "bar"}],
],
],
)
def test_transcode(http_options, request_kwargs, expected_result):
http_options, expected_result = helper_test_transcode(http_options, expected_result)
result = path_template.transcode(http_options, **request_kwargs)
assert result == expected_result
Comment thread
yihjenku marked this conversation as resolved.


@pytest.mark.parametrize(
'http_options, request_kwargs',
"http_options, request_kwargs",
[
[[['get','/v1/{name}','']], {'foo':'bar'}],
[[['get','/v1/{name}','']], {'name':'first/last'}],
[[['get','/v1/{name=mr/*/*}','']], {'name':'first/last'}],
[[['post','/v1/{name}','data']], {'name':'first/last'}],
]
[[["get", "/v1/{name}", ""]], {"foo": "bar"}],
[[["get", "/v1/{name}", ""]], {"name": "first/last"}],
[[["get", "/v1/{name=mr/*/*}", ""]], {"name": "first/last"}],
[[["post", "/v1/{name}", "data"]], {"name": "first/last"}],
],
)
def test_transcode_fails(http_options, request_kwargs):
http_options, _ = helper_test_transcode(http_options, range(4))
Expand All @@ -206,17 +257,17 @@ def test_transcode_fails(http_options, request_kwargs):
def helper_test_transcode(http_options_list, expected_result_list):
http_options = []
for opt_list in http_options_list:
http_option = {'method':opt_list[0], 'uri':opt_list[1]}
http_option = {"method": opt_list[0], "uri": opt_list[1]}
if opt_list[2]:
http_option['body'] = opt_list[2]
http_option["body"] = opt_list[2]
http_options.append(http_option)

expected_result = {
'method':expected_result_list[0],
'uri':expected_result_list[1],
'query_params':expected_result_list[3]
"method": expected_result_list[0],
"uri": expected_result_list[1],
"query_params": expected_result_list[3],
}
if (expected_result_list[2]):
expected_result['body'] = expected_result_list[2]
if expected_result_list[2]:
expected_result["body"] = expected_result_list[2]

return(http_options, expected_result)
return (http_options, expected_result)