-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add final set of protobuf helpers to api_core #4259
Add final set of protobuf helpers to api_core #4259
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is surprisingly complex
|
||
def _resolve_subkeys(key, separator='.'): | ||
"""Given a key which may actually be a nested key, return the top level | ||
key and any nested subkeys as separate values. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
if separator in key: | ||
index = key.index(separator) | ||
subkey = key[index + 1:] | ||
key = key[:index] |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
default is generally recommended, as protobuf messages almost | ||
always have default values for unset values and it is not always | ||
possible to tell the difference between a falsy value and an | ||
unset one. If no default is set then raises :class:`KeyError` will |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
# Attempt to get the value from the two types of objects we know about. | ||
# If we get something else, complain. | ||
if isinstance(msg_or_dict, Message): | ||
answer = getattr(msg_or_dict, key, default) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
raise KeyError(key) | ||
|
||
# If a subkey exists, call this method recursively against the answer. | ||
if subkey and answer is not default: |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
type(msg_or_dict))) | ||
|
||
# We may be setting a nested key. Resolve this. | ||
key, subkey = _resolve_subkeys(key) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
# If a subkey exists, then get that object and call this method | ||
# recursively against it using the subkey. | ||
if subkey is not None: | ||
if isinstance(msg_or_dict, collections.MutableMapping): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
|
||
|
||
def setdefault(msg_or_dict, key, value): | ||
"""Set the key on a protobuf Message or dictioanary to a given value if the |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
current value is falsy. | ||
|
||
Because protobuf Messages do not distinguish between unset values and | ||
falsy ones particularly well, this method treats any falsy value |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
# Clear the existing repeated protobuf message of any elements | ||
# currently inside it. | ||
while getattr(msg, key): | ||
getattr(msg, key).pop() |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
if isinstance(item, collections.Mapping): | ||
getattr(msg, key).add(**item) | ||
else: | ||
getattr(msg, key).extend([item]) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
elif isinstance(value, Message): | ||
# Assign the protobuf message values to the protobuf message. | ||
for item_key, item_value in value.ListFields(): | ||
set(getattr(msg, key), item_key.name, item_value) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
def _set_field_on_message(msg, key, value): | ||
"""Set helper for protobuf Messages.""" | ||
# Attempt to set the value on the types of objects we know how to deal | ||
# with. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
getattr(msg, key).add(**item) | ||
else: | ||
getattr(msg, key).extend([item]) | ||
elif isinstance(value, collections.Mapping): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Closes #3842
Note: this is directly ported from gax, barring minor changes, this code has already been reviewed.