X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/c69d271455a0550cda8e56ab6a4685fe3d7d91ea..95e5ccacf6c1193b313fa90a6d39baafa2ba67d8:/sdk/python/arvados/collection.py diff --git a/sdk/python/arvados/collection.py b/sdk/python/arvados/collection.py index 8fb90c9443..e38a6bd475 100644 --- a/sdk/python/arvados/collection.py +++ b/sdk/python/arvados/collection.py @@ -13,6 +13,8 @@ import os import re import errno import hashlib +import datetime +import ciso8601 import time import threading @@ -1269,6 +1271,18 @@ class Collection(RichCollectionBase): def root_collection(self): return self + def get_properties(self): + if self._api_response and self._api_response["properties"]: + return self._api_response["properties"] + else: + return {} + + def get_trash_at(self): + if self._api_response and self._api_response["trash_at"]: + return ciso8601.parse_datetime(self._api_response["trash_at"]) + else: + return None + def stream_name(self): return "." @@ -1436,17 +1450,34 @@ class Collection(RichCollectionBase): @must_be_writable @synchronized @retry_method - def save(self, merge=True, num_retries=None): + def save(self, + properties=None, + storage_classes=None, + trash_at=None, + merge=True, + num_retries=None): """Save collection to an existing collection record. Commit pending buffer blocks to Keep, merge with remote record (if - merge=True, the default), and update the collection record. Returns + merge=True, the default), and update the collection record. Returns the current manifest text. Will raise AssertionError if not associated with a collection record on the API server. If you want to save a manifest to Keep only, see `save_new()`. + :properties: + Additional properties of collection. This value will replace any existing + properties of collection. + + :storage_classes: + Specify desirable storage classes to be used when writing data to Keep. + + :trash_at: + A collection is *expiring* when it has a *trash_at* time in the future. + An expiring collection can be accessed as normal, + but is scheduled to be trashed automatically at the *trash_at* time. + :merge: Update and merge remote changes before saving. Otherwise, any remote changes will be ignored and overwritten. @@ -1455,6 +1486,24 @@ class Collection(RichCollectionBase): Retry count on API calls (if None, use the collection default) """ + if properties and type(properties) is not dict: + raise errors.ArgumentError("properties must be dictionary type.") + + if storage_classes and type(storage_classes) is not list: + raise errors.ArgumentError("storage_classes must be list type.") + + if trash_at and type(trash_at) is not datetime.datetime: + raise errors.ArgumentError("trash_at must be datetime type.") + + body={} + if properties: + body["properties"] = properties + if storage_classes: + body["storage_classes_desired"] = storage_classes + if trash_at: + t = trash_at.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + body["trash_at"] = t + if not self.committed(): if not self._has_collection_uuid(): raise AssertionError("Collection manifest_locator is not a collection uuid. Use save_new() for new collections.") @@ -1465,14 +1514,20 @@ class Collection(RichCollectionBase): self.update() text = self.manifest_text(strip=False) + body['manifest_text'] = text + self._remember_api_response(self._my_api().collections().update( uuid=self._manifest_locator, - body={'manifest_text': text} - ).execute( - num_retries=num_retries)) + body=body + ).execute(num_retries=num_retries)) self._manifest_text = self._api_response["manifest_text"] self._portable_data_hash = self._api_response["portable_data_hash"] self.set_committed(True) + elif body: + self._remember_api_response(self._my_api().collections().update( + uuid=self._manifest_locator, + body=body + ).execute(num_retries=num_retries)) return self._manifest_text @@ -1483,6 +1538,9 @@ class Collection(RichCollectionBase): def save_new(self, name=None, create_collection_record=True, owner_uuid=None, + properties=None, + storage_classes=None, + trash_at=None, ensure_unique_name=False, num_retries=None): """Save collection to a new collection record. @@ -1490,7 +1548,7 @@ class Collection(RichCollectionBase): Commit pending buffer blocks to Keep and, when create_collection_record is True (default), create a new collection record. After creating a new collection record, this Collection object will be associated with - the new record used by `save()`. Returns the current manifest text. + the new record used by `save()`. Returns the current manifest text. :name: The collection name. @@ -1503,6 +1561,18 @@ class Collection(RichCollectionBase): the user, or project uuid that will own this collection. If None, defaults to the current user. + :properties: + Additional properties of collection. This value will replace any existing + properties of collection. + + :storage_classes: + Specify desirable storage classes to be used when writing data to Keep. + + :trash_at: + A collection is *expiring* when it has a *trash_at* time in the future. + An expiring collection can be accessed as normal, + but is scheduled to be trashed automatically at the *trash_at* time. + :ensure_unique_name: If True, ask the API server to rename the collection if it conflicts with a collection with the same name and owner. If @@ -1512,6 +1582,15 @@ class Collection(RichCollectionBase): Retry count on API calls (if None, use the collection default) """ + if properties and type(properties) is not dict: + raise errors.ArgumentError("properties must be dictionary type.") + + if storage_classes and type(storage_classes) is not list: + raise errors.ArgumentError("storage_classes must be list type.") + + if trash_at and type(trash_at) is not datetime.datetime: + raise errors.ArgumentError("trash_at must be datetime type.") + self._my_block_manager().commit_all() text = self.manifest_text(strip=False) @@ -1525,6 +1604,13 @@ class Collection(RichCollectionBase): "replication_desired": self.replication_desired} if owner_uuid: body["owner_uuid"] = owner_uuid + if properties: + body["properties"] = properties + if storage_classes: + body["storage_classes_desired"] = storage_classes + if trash_at: + t = trash_at.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + body["trash_at"] = t self._remember_api_response(self._my_api().collections().create(ensure_unique_name=ensure_unique_name, body=body).execute(num_retries=num_retries)) text = self._api_response["manifest_text"]