Uh oh!
There was an error while loading. Please reload this page.
This repository was archived by the owner on Mar 31, 2026. It is now read-only.
- Notifications
You must be signed in to change notification settings - Fork 173
feat: add if*generation*Match support, pt1#123
Merged
frankyn
merged 21 commits into
googleapis:master
from
MaxxleLLC:metageneration_match_pt1May 15, 2020
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
3fa6245
feat: add ifMetageneration*Match support, pt1
4cbad43
fix unit tests, add test for helper
b905487
fix unit tests
ddecf53
add generation match args into more methods
74961fa
feat: add if*generation*Match support, pt2
7e08361
Lint fix.
6f9f910
delete "more than one set "checks
ff26d2f
del excess import
551df43
Merge branch 'metageneration_match_pt1' into metageneration_match_pt2
1f4d9c1
delete "more than one set" checks
0a34086
Merge branch 'master' into metageneration_match_pt1
frankyn e1b67b5
Merge branch 'master' into metageneration_match_pt1
bd5b54f
rename the helper; add error raising in case of wront parameters type
ea37318
Merge branch 'metageneration_match_pt2' into metageneration_match_pt1
9d19e15
Merge branch 'metageneration_match_pt1' of https://github.com/q-logic…
d8f790a
Merge branch 'master' into metageneration_match_pt1
frankyn bbebfc1
add more system tests
e9748bb
system tests fixes
3e83091
cleanup system test
0dbd9a9
fix comments
dc0bb4f
delete excess checks
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -30,6 +30,18 @@ | ||
| _DEFAULT_STORAGE_HOST = u"https://storage.googleapis.com" | ||
| # generation match parameters in camel and snake cases | ||
| _GENERATION_MATCH_PARAMETERS = ( | ||
| ("if_generation_match", "ifGenerationMatch"), | ||
| ("if_generation_not_match", "ifGenerationNotMatch"), | ||
| ("if_metageneration_match", "ifMetagenerationMatch"), | ||
| ("if_metageneration_not_match", "ifMetagenerationNotMatch"), | ||
| ("if_source_generation_match", "ifSourceGenerationMatch"), | ||
| ("if_source_generation_not_match", "ifSourceGenerationNotMatch"), | ||
| ("if_source_metageneration_match", "ifSourceMetagenerationMatch"), | ||
| ("if_source_metageneration_not_match", "ifSourceMetagenerationNotMatch"), | ||
| ) | ||
| def _get_storage_host(): | ||
| return os.environ.get(STORAGE_EMULATOR_ENV_VAR, _DEFAULT_STORAGE_HOST) | ||
| @@ -121,27 +133,64 @@ def _query_params(self): | ||
| params["userProject"] = self.user_project | ||
| return params | ||
| def reload(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| def reload( | ||
| self, | ||
| client=None, | ||
| timeout=_DEFAULT_TIMEOUT, | ||
| if_generation_match=None, | ||
| if_generation_not_match=None, | ||
| if_metageneration_match=None, | ||
| if_metageneration_not_match=None, | ||
| ): | ||
| """Reload properties from Cloud Storage. | ||
| If :attr:`user_project` is set, bills the API request to that project. | ||
| :type client: :class:`~google.cloud.storage.client.Client` or | ||
| ``NoneType`` | ||
| :param client: the client to use. If not passed, falls back to the | ||
| :param client: the client to use. If not passed, falls back to the | ||
| ``client`` stored on the current object. | ||
| :type timeout: float or tuple | ||
| :param timeout: (Optional) The amount of time, in seconds, to wait | ||
| for the server response. | ||
| Can also be passed as a tuple (connect_timeout, read_timeout). | ||
| See :meth:`requests.Session.request` documentation for details. | ||
| :type if_generation_match: long | ||
| :param if_generation_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation matches the given value. | ||
| Setting to 0 makes the operation succeed only if there | ||
| are no live versions of the blob. | ||
| :type if_generation_not_match: long | ||
| :param if_generation_not_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation does not match the given | ||
| value. If no live blob exists, the precondition fails. | ||
| Setting to 0 makes the operation succeed only if there | ||
| is a live version of the blob. | ||
| :type if_metageneration_match: long | ||
| :param if_metageneration_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration matches the given value. | ||
| :type if_metageneration_not_match: long | ||
| :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration does not match the given value. | ||
| """ | ||
| client = self._require_client(client) | ||
| query_params = self._query_params | ||
| # Pass only '?projection=noAcl' here because 'acl' and related | ||
| # are handled via custom endpoints. | ||
| query_params["projection"] = "noAcl" | ||
| _add_generation_match_parameters( | ||
| query_params, | ||
| if_generation_match=if_generation_match, | ||
| if_generation_not_match=if_generation_not_match, | ||
| if_metageneration_match=if_metageneration_match, | ||
| if_metageneration_not_match=if_metageneration_not_match, | ||
| ) | ||
| api_response = client._connection.api_request( | ||
| method="GET", | ||
| path=self.path, | ||
| @@ -180,7 +229,15 @@ def _set_properties(self, value): | ||
| # If the values are reset, the changes must as well. | ||
| self._changes = set() | ||
| def patch(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| def patch( | ||
| self, | ||
| client=None, | ||
| timeout=_DEFAULT_TIMEOUT, | ||
| if_generation_match=None, | ||
| if_generation_not_match=None, | ||
| if_metageneration_match=None, | ||
| if_metageneration_not_match=None, | ||
| ): | ||
| """Sends all changed properties in a PATCH request. | ||
| Updates the ``_properties`` with the response from the backend. | ||
| @@ -189,20 +246,49 @@ def patch(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| :type client: :class:`~google.cloud.storage.client.Client` or | ||
| ``NoneType`` | ||
| :param client: the client to use. If not passed, falls back to the | ||
| :param client: the client to use. If not passed, falls back to the | ||
| ``client`` stored on the current object. | ||
| :type timeout: float or tuple | ||
| :param timeout: (Optional) The amount of time, in seconds, to wait | ||
| for the server response. | ||
| Can also be passed as a tuple (connect_timeout, read_timeout). | ||
| See :meth:`requests.Session.request` documentation for details. | ||
| :type if_generation_match: long | ||
| :param if_generation_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation matches the given value. | ||
| Setting to 0 makes the operation succeed only if there | ||
| are no live versions of the blob. | ||
| :type if_generation_not_match: long | ||
| :param if_generation_not_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation does not match the given | ||
| value. If no live blob exists, the precondition fails. | ||
| Setting to 0 makes the operation succeed only if there | ||
| is a live version of the blob. | ||
| :type if_metageneration_match: long | ||
| :param if_metageneration_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration matches the given value. | ||
| :type if_metageneration_not_match: long | ||
| :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration does not match the given value. | ||
| """ | ||
| client = self._require_client(client) | ||
| query_params = self._query_params | ||
| # Pass '?projection=full' here because 'PATCH' documented not | ||
| # to work properly w/ 'noAcl'. | ||
| query_params["projection"] = "full" | ||
| _add_generation_match_parameters( | ||
| query_params, | ||
| if_generation_match=if_generation_match, | ||
| if_generation_not_match=if_generation_not_match, | ||
| if_metageneration_match=if_metageneration_match, | ||
| if_metageneration_not_match=if_metageneration_not_match, | ||
| ) | ||
| update_properties = {key: self._properties[key] for key in self._changes} | ||
| # Make the API call. | ||
| @@ -216,7 +302,15 @@ def patch(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| ) | ||
| self._set_properties(api_response) | ||
| def update(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| def update( | ||
| self, | ||
| client=None, | ||
| timeout=_DEFAULT_TIMEOUT, | ||
| if_generation_match=None, | ||
| if_generation_not_match=None, | ||
| if_metageneration_match=None, | ||
| if_metageneration_not_match=None, | ||
| ): | ||
| """Sends all properties in a PUT request. | ||
| Updates the ``_properties`` with the response from the backend. | ||
| @@ -225,18 +319,46 @@ def update(self, client=None, timeout=_DEFAULT_TIMEOUT): | ||
| :type client: :class:`~google.cloud.storage.client.Client` or | ||
| ``NoneType`` | ||
| :param client: the client to use. If not passed, falls back to the | ||
| :param client: the client to use. If not passed, falls back to the | ||
| ``client`` stored on the current object. | ||
| :type timeout: float or tuple | ||
| :param timeout: (Optional) The amount of time, in seconds, to wait | ||
| for the server response. | ||
| Can also be passed as a tuple (connect_timeout, read_timeout). | ||
| See :meth:`requests.Session.request` documentation for details. | ||
| :type if_generation_match: long | ||
| :param if_generation_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation matches the given value. | ||
| Setting to 0 makes the operation succeed only if there | ||
| are no live versions of the blob. | ||
| :type if_generation_not_match: long | ||
| :param if_generation_not_match: (Optional) Make the operation conditional on whether | ||
| the blob's current generation does not match the given | ||
| value. If no live blob exists, the precondition fails. | ||
| Setting to 0 makes the operation succeed only if there | ||
| is a live version of the blob. | ||
| :type if_metageneration_match: long | ||
| :param if_metageneration_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration matches the given value. | ||
| :type if_metageneration_not_match: long | ||
| :param if_metageneration_not_match: (Optional) Make the operation conditional on whether the | ||
| blob's current metageneration does not match the given value. | ||
| """ | ||
| client = self._require_client(client) | ||
| query_params = self._query_params | ||
| query_params["projection"] = "full" | ||
| _add_generation_match_parameters( | ||
| query_params, | ||
| if_metageneration_match=if_metageneration_match, | ||
| if_metageneration_not_match=if_metageneration_not_match, | ||
| ) | ||
| api_response = client._connection.api_request( | ||
| method="PUT", | ||
| path=self.path, | ||
| @@ -312,3 +434,52 @@ def _convert_to_timestamp(value): | ||
| utc_naive = value.replace(tzinfo=None) - value.utcoffset() | ||
| mtime = (utc_naive - datetime(1970, 1, 1)).total_seconds() | ||
| return mtime | ||
| def _add_generation_match_parameters(parameters, **match_parameters): | ||
| """Add generation match parameters into the given parameters list. | ||
| :type parameters: list or dict | ||
| :param parameters: Parameters list or dict. | ||
| :type match_parameters: dict | ||
| :param match_parameters: if*generation*match parameters to add. | ||
| :raises: :exc:`ValueError` if ``parameters`` is not a ``list()`` | ||
| or a ``dict()``. | ||
| """ | ||
| for snakecase_name, camelcase_name in _GENERATION_MATCH_PARAMETERS: | ||
| value = match_parameters.get(snakecase_name) | ||
| if value is not None: | ||
| if isinstance(parameters, list): | ||
| parameters.append((camelcase_name, value)) | ||
| elif isinstance(parameters, dict): | ||
| parameters[camelcase_name] = value | ||
| else: | ||
| raise ValueError( | ||
| "`parameters` argument should be a dict() or a list()." | ||
| ) | ||
| def _raise_if_more_than_one_set(**kwargs): | ||
| """Raise ``ValueError`` exception if more than one parameter was set. | ||
| :type error: :exc:`ValueError` | ||
| :param error: Description of which fields were set | ||
| :raises: :class:`~ValueError` containing the fields that were set | ||
| """ | ||
| if sum(arg is not None for arg in kwargs.values()) > 1: | ||
| escaped_keys = ["'%s'" % name for name in kwargs.keys()] | ||
| keys_but_last = ", ".join(escaped_keys[:-1]) | ||
| last_key = escaped_keys[-1] | ||
| msg = "Pass at most one of {keys_but_last} and {last_key}".format( | ||
| keys_but_last=keys_but_last, last_key=last_key | ||
| ) | ||
| raise ValueError(msg) | ||
IlyaFaer marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.