Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
598ca88
feat: add grpc transcoding + tests
yon-mg Feb 9, 2021
a956abb
🦉 Updates from OwlBot
gcf-owl-bot[bot] Aug 25, 2021
1ca321a
chore: tweak for clarity / idiomatic usage
tseaver Aug 25, 2021
f8725d9
chore: attempt to appease Sphinx
tseaver Aug 25, 2021
79f561f
feat: add grpc transcoding + tests
yon-mg Feb 9, 2021
6a9e8c0
Merge changes.
yihjenku Sep 2, 2021
6b6dd7b
Merge changes.
yihjenku Sep 2, 2021
01df2c6
Merge branch 'transcode-takeover' of https://github.com/yihjenku/pyth…
yihjenku Sep 2, 2021
5a04dcd
Merge branch 'main' into transcode-takeover
yihjenku Sep 2, 2021
1b827a2
Merge branch 'main' into transcode-takeover
yihjenku Sep 7, 2021
51661d3
Add functions to properly handle subfields
yihjenku Sep 9, 2021
2dfbc28
Merge branch 'transcode-takeover' of https://github.com/yihjenku/pyth…
yihjenku Sep 9, 2021
12a4436
Add unit tests for get_field and delete_field.
yihjenku Sep 9, 2021
28f587d
Add function docstrings and incorporate correct native dict functions.
yihjenku Sep 14, 2021
928e3fb
Add function docstrings and incorporate correct native dict functions.
yihjenku Sep 14, 2021
6d61e4c
Merge branch 'transcode-takeover' of https://github.com/yihjenku/pyth…
yihjenku Sep 15, 2021
97c5697
Increase code coverage
yihjenku Sep 15, 2021
1450b91
Increase code coverage
yihjenku Sep 15, 2021
4c157a9
Increase code coverage
yihjenku Sep 15, 2021
c99e7bb
Reformat files
yihjenku Sep 15, 2021
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
107 changes: 106 additions & 1 deletion google/api_core/path_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

from __future__ import unicode_literals

from collections import deque
import copy
import functools
import re

Expand Down Expand Up @@ -64,7 +66,7 @@ def _expand_variable_match(positional_vars, named_vars, match):
"""Expand a matched variable with its value.

Args:
positional_vars (list): A list of positonal variables. This list will
positional_vars (list): A list of positional variables. This list will
be modified.
named_vars (dict): A dictionary of named variables.
match (re.Match): A regular expression match.
Expand Down Expand Up @@ -170,6 +172,46 @@ def _generate_pattern_for_template(tmpl):
return _VARIABLE_RE.sub(_replace_variable_with_pattern, tmpl)


def get_field(request, field):
"""Get the value of a field from a given dictionary.

Args:
request (dict): A dictionary object.
field (str): The key to the request in dot notation.

Returns:
The value of the field.
"""
parts = field.split(".")
value = request
for part in parts:
if not isinstance(value, dict):
return
value = value.get(part)
if isinstance(value, dict):
return
return value


def delete_field(request, field):
"""Delete the value of a field from a given dictionary.

Args:
request (dict): A dictionary object.
field (str): The key to the request in dot notation.
"""
parts = deque(field.split("."))
while len(parts) > 1:
if not isinstance(request, dict):
return
part = parts.popleft()
request = request.get(part)
part = parts.popleft()
if not isinstance(request, dict):
return
request.pop(part, None)


def validate(tmpl, path):
"""Validate a path against the path template.

Expand All @@ -193,3 +235,66 @@ 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

Args:
http_options (list(dict)): A list of dicts which consist of these keys,
'method' (str): The http method
'uri' (str): The path template
'body' (str): The body field name (optional)
(This is a simplified representation of the proto option `google.api.http`)

request_kwargs (dict) : A dict representing the request object

Returns:
dict: The transcoded request with these keys,
'method' (str) : The http method
'uri' (str) : The expanded uri
'body' (dict) : A dict representing the body (optional)
'query_params' (dict) : A dict mapping query parameter variables and values

Raises:
ValueError: If the request does not match the given template.
"""
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)
]
path_args = {field: get_field(request_kwargs, field) for field in path_fields}
request["uri"] = expand(uri_template, **path_args)

# Remove fields used in uri path from request
leftovers = copy.deepcopy(request_kwargs)
for path_field in path_fields:
delete_field(leftovers, path_field)

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

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

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

raise ValueError("Request obj does not match any template")
Loading