Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.8k
Pull in / reconcile all PRs for #314#347
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
d52d81f8477e85037a732c586a7cb721f42c9fa1f32c3725d36966e879e0b0575338999d7fc2f40c03c51fdacb448677eec3fcb2eaa7afbb5f1667a72f3e5af77e593b8ea274262b41325b7b5c13b28c23eaf39dFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -4,35 +4,23 @@ | ||
| """ | ||
| class _MetadataMixin(object): | ||
| """Abstract mixin for cloud storage classes with associated metadata. | ||
| class _PropertyMixin(object): | ||
| """Abstract mixin for cloud storage classes with associated propertties. | ||
| Non-abstract subclasses should implement: | ||
| - CUSTOM_METADATA_FIELDS | ||
| - CUSTOM_PROPERTY_ACCESSORS | ||
| - connection | ||
| - path | ||
| """ | ||
| CUSTOM_METADATA_FIELDS = None | ||
| CUSTOM_PROPERTY_ACCESSORS = None | ||
| """Mapping of field name -> accessor for fields w/ custom accessors. | ||
| Expected to be set by subclasses. Fields in this mapping will cause | ||
| `get_metadata()` to raise a KeyError with a message to use the relevant | ||
| accessor methods. | ||
| :meth:`_get_property()` to raise a KeyError with a message to use the | ||
| relevant accessor methods. | ||
| """ | ||
| def __init__(self, name=None, metadata=None): | ||
| """_MetadataMixin constructor. | ||
| :type name: string | ||
| :param name: The name of the object. | ||
| :type metadata: dict | ||
| :param metadata: All the other data provided by Cloud Storage. | ||
| """ | ||
| self.name = name | ||
| self.metadata = metadata | ||
| @property | ||
| def connection(self): | ||
| """Abstract getter for the connection to use.""" | ||
| @@ -43,90 +31,91 @@ def path(self): | ||
| """Abstract getter for the object path.""" | ||
| raise NotImplementedError | ||
| def has_metadata(self, field=None): | ||
| """Check if metadata is available. | ||
| def __init__(self, name=None, properties=None): | ||
| """_PropertyMixin constructor. | ||
| :type field: string | ||
| :param field: (optional) the particular field to check for. | ||
| :type name: string | ||
| :param name: The name of the object. | ||
| :rtype: bool | ||
| :returns: Whether metadata is available locally. | ||
| :type properties: dict | ||
| :param properties: All the other data provided by Cloud Storage. | ||
| """ | ||
| if not self.metadata: | ||
| return False | ||
| elif field and field not in self.metadata: | ||
| return False | ||
| else: | ||
| return True | ||
| self.name = name | ||
| self._properties = {} | ||
| if properties is not None: | ||
| self._properties.update(properties) | ||
| def reload_metadata(self): | ||
| """Reload metadata from Cloud Storage. | ||
| @property | ||
| def properties(self): | ||
| """Ensure properties are loaded, and return a copy. | ||
| :rtype: dict | ||
| """ | ||
| if not self._properties: | ||
| self._reload_properties() | ||
| return self._properties.copy() | ||
| :rtype: :class:`_MetadataMixin` | ||
| def _reload_properties(self): | ||
| """Reload properties from Cloud Storage. | ||
| :rtype: :class:`_PropertyMixin` | ||
| :returns: The object you just reloaded data for. | ||
| """ | ||
| # Pass only '?projection=noAcl' here because 'acl' and related | ||
| # are handled via 'get_acl()' etc. | ||
This comment was marked as spam.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page.
This comment was marked as spam.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page.
This comment was marked as spam.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page.
This comment was marked as spam.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page. | ||
| query_params = {'projection': 'noAcl'} | ||
| self.metadata = self.connection.api_request( | ||
| self._properties = self.connection.api_request( | ||
| method='GET', path=self.path, query_params=query_params) | ||
| return self | ||
| def get_metadata(self, field=None, default=None): | ||
| """Get all metadata or a specific field. | ||
| def _patch_properties(self, properties): | ||
| """Update particular fields of this object's properties. | ||
| This method will only update the fields provided and will not | ||
| touch the other fields. | ||
| It will also reload the properties locally based on the server's | ||
| response. | ||
| :type properties: dict | ||
| :param properties: The dictionary of values to update. | ||
| :rtype: :class:`_PropertyMixin` | ||
| :returns: The current object. | ||
| """ | ||
| # Pass '?projection=full' here because 'PATCH' documented not | ||
| # to work properly w/ 'noAcl'. | ||
| self._properties = self.connection.api_request( | ||
| method='PATCH', path=self.path, data=properties, | ||
| query_params={'projection': 'full'}) | ||
| return self | ||
| def _get_property(self, field, default=None): | ||
| """Return the value of a field from the server-side representation. | ||
| If you request a field that isn't available, and that field can | ||
| be retrieved by refreshing data from Cloud Storage, this method | ||
| will reload the data using :func:`_MetadataMixin.reload_metadata`. | ||
| will reload the data using :func:`_PropertyMixin._reload_properties`. | ||
| :type field: string | ||
| :param field: (optional) A particular field to retrieve from metadata. | ||
| :param field: A particular field to retrieve from properties. | ||
| :type default: anything | ||
| :param default: The value to return if the field provided wasn't found. | ||
| :rtype: dict or anything | ||
| :returns: All metadata or the value of the specific field. | ||
| :raises: :class:`KeyError` if the field is in CUSTOM_METADATA_FIELDS. | ||
| :rtype: anything | ||
| :returns: value of the specific field, or the default if not found. | ||
| """ | ||
| # We ignore 'acl' and related fields because they are meant to be | ||
| # handled via 'get_acl()' and related methods. | ||
| custom = self.CUSTOM_METADATA_FIELDS.get(field) | ||
| # Raise for fields which have custom accessors. | ||
| custom = self.CUSTOM_PROPERTY_ACCESSORS.get(field) | ||
| if custom is not None: | ||
| message = 'Use %s or related methods instead.' % custom | ||
| message = "Use '%s' or related methods instead." % custom | ||
| raise KeyError((field, message)) | ||
| if not self.has_metadata(field=field): | ||
| self.reload_metadata() | ||
| if field: | ||
| return self.metadata.get(field, default) | ||
| else: | ||
| return self.metadata | ||
| def patch_metadata(self, metadata): | ||
| """Update particular fields of this object's metadata. | ||
| This method will only update the fields provided and will not | ||
| touch the other fields. | ||
| It will also reload the metadata locally based on the server's | ||
| response. | ||
| :type metadata: dict | ||
| :param metadata: The dictionary of values to update. | ||
| :rtype: :class:`_MetadataMixin` | ||
| :returns: The current object. | ||
| """ | ||
| self.metadata = self.connection.api_request( | ||
| method='PATCH', path=self.path, data=metadata, | ||
| query_params={'projection': 'full'}) | ||
| return self | ||
| return self.properties.get(field, default) | ||
| def get_acl(self): | ||
| """Get ACL metadata as an object. | ||
| """Get ACL as an object. | ||
| :returns: An ACL object for the current object. | ||
| """ | ||
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.