def add_item(self, source_path, destination_path, recursive=False, **params): """ Add a file or directory to be transfered. If the item is a symlink to a file or directory, the file or directory at the target of the symlink will be transfered. Appends a transfer_item document to the DATA key of the transfer document. """ source_path = safe_stringify(source_path) destination_path = safe_stringify(destination_path) item_data = { "DATA_TYPE": "transfer_item", "source_path": source_path, "destination_path": destination_path, "recursive": recursive, } item_data.update(params) logger.debug( 'TransferData[{}, {}].add_item: "{}"->"{}"'.format( self["source_endpoint"], self["destination_endpoint"], source_path, destination_path, ) ) self["DATA"].append(item_data)
def _convert_listarg(val): if isinstance(val, collections.Iterable) and not isinstance( val, six.string_types ): return ",".join(safe_stringify(x) for x in val) else: return safe_stringify(val)
def delete_subject(self, index_id, subject, **params): """ ``DELETE /v1/index/<index_id>/subject`` **Examples** Delete all data for subject ``http://example.com/abc`` from index ``index_id``, even data which is not visible to the current user: >>> sc = globus_sdk.SearchClient(...) >>> subject_data = sc.get_subject(index_id, 'http://example.com/abc') **External Documentation** See `Delete Subject \ <https://docs.globus.org/api/search/subject_ops/#delete_by_subject>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params(params, subject=subject) self.logger.info( "SearchClient.delete_subject({}, {}, ...)".format(index_id, subject) ) path = self.qjoin_path("v1/index", index_id, "subject") return self.delete(path, params=params)
def delete_by_query(self, index_id, data): """ ``POST /v1/index/<index_id>/delete_by_query`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> query_data = { >>> "q": "user query", >>> "filters": [ >>> { >>> "type": "range", >>> "field_name": "path.to.date", >>> "values": [ >>> {"from": "*", >>> "to": "2014-11-07"} >>> ] >>> } >>> ] >>> } >>> sc.delete_by_query(index_id, query_data) **External Documentation** See `Delete By Query \ <https://docs.globus.org/api/search/subject_ops/#delete_by_query>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.delete_by_query({}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "delete_by_query") return self.post(path, data)
def get_subject(self, index_id, subject, **params): """ ``GET /v1/index/<index_id>/subject`` **Examples** Fetch the data for subject ``http://example.com/abc`` from index ``index_id``: >>> sc = globus_sdk.SearchClient(...) >>> subject_data = sc.get_subject(index_id, 'http://example.com/abc') **External Documentation** See `Get Subject \ <https://docs.globus.org/api/search/subject_ops/#get_by_subject>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params(params, subject=subject) self.logger.info( "SearchClient.get_subject({}, {}, ...)".format(index_id, subject) ) path = self.qjoin_path("v1/index", index_id, "subject") return self.get(path, params=params)
def update_entry(self, index_id, data): """ ``PUT /v1/index/<index_id>/entry`` **Examples** Update an entry with a subject of ``https://example.com/foo/bar`` and a null entry_id: >>> sc = globus_sdk.SearchClient(...) >>> sc.update_entry(index_id, { >>> "subject": "https://example.com/foo/bar", >>> "visible_to": ["public"], >>> "content": { >>> "foo/bar": "some val" >>> } >>> }) **External Documentation** See `Update Entry \ <https://docs.globus.org/api/search/entry_ops/#update_single_entry>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.update_entry({}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "entry") return self.put(path, data)
def delete_entry(self, index_id, subject, entry_id=None, **params): """ ``DELETE /v1/index/<index_id>/entry`` **Examples** Delete an entry with a subject of ``https://example.com/foo/bar`` and a null entry_id: >>> sc = globus_sdk.SearchClient(...) >>> sc.delete_entry(index_id, "https://example.com/foo/bar") Delete an entry with a subject of ``https://example.com/foo/bar`` and an entry_id of "foo/bar": >>> sc = globus_sdk.SearchClient(...) >>> sc.delete_entry(index_id, "https://example.com/foo/bar", >>> entry_id="foo/bar") **External Documentation** See `Delete Entry \ <https://docs.globus.org/api/search/entry_ops/#delete_single_entry>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params(params, subject=subject, entry_id=entry_id) self.logger.info( "SearchClient.delete_entry({}, {}, {}, ...)".format( index_id, subject, entry_id ) ) path = self.qjoin_path("v1/index", index_id, "entry") return self.delete(path, params=params)
def update_namespace(self, namespace_id, **kwargs): """ ``PATCH /namespace/<id>`` ** Parameters ** ``namespace_id`` (*string*) The id for the namespace to update ``display_name`` (*string*) The updated display name of the namespace ``description`` (*string*) description of the new namespace ``creators`` (*string*) The Principal URN for a Globus Group who's members are permitted to add to this namespace ``admins`` (*string*) The Principal URN for a Globus Group who's members are permitted to perform administrative functions on this namespace ``provider-type`` (*string*) The type of the provider used for minting external identifiers ``provider-config`` (*dict*) Configuration for the provider used for minting external identfiers in JSON format """ kwargs = _json_parse_args(kwargs, _namespace_json_props) kwargs, body = _split_dict(kwargs, _namespace_properties) self.logger.info( "IdentifierClient.update_namespace({}, ...)".format(namespace_id)) path = self.qjoin_path("namespace", safe_stringify(namespace_id)) return self.put(path, body, params=kwargs)
def test_safe_stringify(value): """ safe_stringifies strings, bytes, explicit unicode, an int, an object and confirms safe_stringify returns utf-8 encoding for all inputs """ safe_value = safe_stringify(value) assert safe_value == u"1" assert type(safe_value) == six.text_type
def ingest(self, index_id, data): """ ``POST /v1/index/<index_id>/ingest`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> ingest_data = { >>> "ingest_type": "GMetaEntry", >>> "ingest_data": { >>> "subject": "https://example.com/foo/bar", >>> "visible_to": ["public"], >>> "content": { >>> "foo/bar": "some val" >>> } >>> } >>> } >>> sc.ingest(index_id, ingest_data) or with multiple entries at once via a GMetaList: >>> sc = globus_sdk.SearchClient(...) >>> ingest_data = { >>> "ingest_type": "GMetaList", >>> "ingest_data": { >>> "gmeta": [ >>> { >>> "subject": "https://example.com/foo/bar", >>> "visible_to": ["public"], >>> "content": { >>> "foo/bar": "some val" >>> } >>> }, >>> { >>> "subject": "https://example.com/foo/bar", >>> "id": "otherentry", >>> "visible_to": ["public"], >>> "content": { >>> "foo/bar": "some otherval" >>> } >>> } >>> ] >>> } >>> } >>> sc.ingest(index_id, ingest_data) **External Documentation** See `Ingest \ <https://docs.globus.org/api/search/ingest/>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.ingest({}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "ingest") return self.post(path, data)
def get_identifier(self, identifier_id, **params): """ ``GET /id/<identifier_id> ** Parameters ** ``identifier_id`` The identification url for the identifier """ path = self.qjoin_path('id', safe_stringify(identifier_id)) self.logger.info('IdentifierClient.get_identifier({})'.format( identifier_id)) return self.get(path, params=params)
def delete_namespace(self, namespace_id, **params): """ ``DELETE /namespace/<namespace_id> ** Parameters ** ``namespace_id`` (*string*) The id for the namespace to remove """ path = self.qjoin_path("namespace", safe_stringify(namespace_id)) self.logger.info( "IdentifierClient.delete_namespace({})".format(namespace_id)) return self.delete(path, params=params)
def add_item(self, path, **params): """ Add a file or directory or symlink to be deleted. If any of the paths are directories, ``recursive`` must be set True on the top level ``DeleteData``. Symlinks will never be followed, only deleted. Appends a delete_item document to the DATA key of the delete document. """ path = safe_stringify(path) item_data = {"DATA_TYPE": "delete_item", "path": path} item_data.update(params) logger.debug('DeleteData[{}].add_item: "{}"'.format(self["endpoint"], path)) self["DATA"].append(item_data)
def get_task(self, task_id, **params): """ ``GET /v1/task/<task_id>`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> task = sc.get_task(task_id) >>> assert task['index_id'] == known_index_id >>> print(task["task_id"] + " | " + task['state']) """ task_id = safe_stringify(task_id) self.logger.info(f"SearchClient.get_task({task_id})") path = self.qjoin_path("v1/task", task_id) return self.get(path, params=params)
def add_item(self, path, **params): """ Add a file or directory or symlink to be deleted. If any of the paths are directories, ``recursive`` must be set True on the top level ``DeleteData``. Symlinks will never be followed, only deleted. Appends a delete_item document to the DATA key of the delete document. """ path = safe_stringify(path) item_data = {"DATA_TYPE": "delete_item", "path": path} item_data.update(params) logger.debug('DeleteData[{}].add_item: "{}"'.format( self["endpoint"], path)) self["DATA"].append(item_data)
def get_task_list(self, index_id, **params): """ ``GET /v1/task_list/<index_id>`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> task_list = sc.get_task_list(index_id) >>> for task in task_list['tasks']: >>> print(task["task_id"] + " | " + task['state']) """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.get_task_list({})".format(index_id)) path = self.qjoin_path("v1/task_list", index_id) return self.get(path, params=params)
def get_query_template_list(self, index_id): """ ``GET /v1/index/<index_id>/query_template`` **External Documentation** See `Get Query Template List \ <https://docs.globus.org/api/search/query_templates/#get_query_template_list>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info(f"SearchClient.get_query_template_list({index_id})") path = self.qjoin_path("v1/index", index_id, "query_template") return self.get(path)
def add_item(self, source_path, destination_path, recursive=False): """ Add a file or directory to be transfered. If the item is a symlink to a file or directory, the file or directory at the target of the symlink will be transfered. Appends a transfer_item document to the DATA key of the transfer document. """ source_path = safe_stringify(source_path) destination_path = safe_stringify(destination_path) item_data = { "DATA_TYPE": "transfer_item", "source_path": source_path, "destination_path": destination_path, "recursive": recursive, } logger.debug('TransferData[{}, {}].add_item: "{}"->"{}"'.format( self["source_endpoint"], self["destination_endpoint"], source_path, destination_path, )) self["DATA"].append(item_data)
def add_symlink_item(self, source_path, destination_path): """ Add a symlink to be transfered as a symlink rather than as the target of the symlink. Appends a transfer_symlink_item document to the DATA key of the transfer document. """ source_path = safe_stringify(source_path) destination_path = safe_stringify(destination_path) item_data = { "DATA_TYPE": "transfer_symlink_item", "source_path": source_path, "destination_path": destination_path, } logger.debug( 'TransferData[{}, {}].add_symlink_item: "{}"->"{}"'.format( self["source_endpoint"], self["destination_endpoint"], source_path, destination_path, ) ) self["DATA"].append(item_data)
def get_task(self, task_id, **params): """ ``GET /v1/task/<task_id>`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> task = sc.get_task(task_id) >>> assert task['index_id'] == known_index_id >>> print(task["task_id"] + " | " + task['state']) """ task_id = safe_stringify(task_id) self.logger.info("SearchClient.get_task({})".format(task_id)) path = self.qjoin_path("v1/task", task_id) return self.get(path, params=params)
def get_query_template_list(self, index_id): """ ``GET /v1/index/<index_id>/query_template`` **External Documentation** See `Get Query Template List \ <https://docs.globus.org/api/search/query_templates/#get_query_template_list>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.get_query_template_list({})".format(index_id)) path = self.qjoin_path("v1/index", index_id, "query_template") return self.get(path)
def test_safe_stringify(self): """ safe_stringifies strings, bytes, explicit unicode, an int, an object and confirms safe_stringify returns utf-8 encoding for all inputs """ class testObject(object): def __str__(self): return "1" inputs = ["1", str(1), b"1", u"1", 1, testObject()] # confirm each input outputs unicode for value in inputs: safe_value = safe_stringify(value) self.assertEqual(safe_value, u"1") self.assertEqual(type(safe_value), six.text_type)
def get_query_template(self, index_id, template_name): """ ``GET /v1/index/<index_id>/query_template/<template_name>`` **External Documentation** See `Get Query Template \ <https://docs.globus.org/api/search/query_templates/#get_query_template>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info( "SearchClient.get_query_template({}, {})".format(index_id, template_name) ) path = self.qjoin_path("v1/index", index_id, "query_template", template_name) return self.get(path)
def endpoint_autoactivate(self, endpoint_id, **params): r""" ``POST /endpoint/<endpoint_id>/autoactivate`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` The following example will try to "auto" activate the endpoint using a credential available from another endpoint or sign in by the user with the same identity provider, but only if the endpoint is not already activated or going to expire within an hour (3600 seconds). If that fails, direct the user to the globus website to perform activation: **Examples** >>> tc = globus_sdk.TransferClient() >>> r = tc.endpoint_autoactivate(ep_id, if_expires_in=3600) >>> while (r["code"] == "AutoActivateFailed"): >>> print("Endpoint requires manual activation, please open " >>> "the following URL in a browser to activate the " >>> "endpoint:") >>> print("https://www.globus.org/app/endpoints/%s/activate" >>> % ep_id) >>> # For python 2.X, use raw_input() instead >>> input("Press ENTER after activating the endpoint:") >>> r = tc.endpoint_autoactivate(ep_id, if_expires_in=3600) This is the recommended flow for most thick client applications, because many endpoints require activation via OAuth MyProxy, which must be done in a browser anyway. Web based clients can link directly to the URL. **External Documentation** See `Autoactivate endpoint \ <https://docs.globus.org/api/transfer/endpoint_activation/#autoactivate_endpoint>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.endpoint_autoactivate({})".format(endpoint_id)) path = self.qjoin_path("endpoint", endpoint_id, "autoactivate") return self.post(path, params=params)
def post_search(self, index_id, data): """ ``POST /v1/index/<index_id>/search`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> query_data = { >>> "@datatype": "GSearchRequest", >>> "q": "user query", >>> "filters": [ >>> { >>> "type": "range", >>> "field_name": "path.to.date", >>> "values": [ >>> {"from": "*", >>> "to": "2014-11-07"} >>> ] >>> } >>> ], >>> "facets": [ >>> {"name": "Publication Date", >>> "field_name": "path.to.date", >>> "type": "date_histogram", >>> "date_interval": "year"} >>> ], >>> "sort": [ >>> {"field_name": "path.to.date", >>> "order": "asc"} >>> ] >>> } >>> search_result = sc.post_search(index_id, query_data) **External Documentation** See `POST Search Query \ <https://docs.globus.org/api/search/search/#complex_post_query>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info(f"SearchClient.post_search({index_id}, ...)") path = self.qjoin_path("v1/index", index_id, "search") return self.post(path, data)
def post_search(self, index_id, data): """ ``POST /v1/index/<index_id>/search`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> query_data = { >>> "@datatype": "GSearchRequest", >>> "q": "user query", >>> "filters": [ >>> { >>> "type": "range", >>> "field_name": "path.to.date", >>> "values": [ >>> {"from": "*", >>> "to": "2014-11-07"} >>> ] >>> } >>> ], >>> "facets": [ >>> {"name": "Publication Date", >>> "field_name": "path.to.date", >>> "type": "date_histogram", >>> "date_interval": "year"} >>> ], >>> "sort": [ >>> {"field_name": "path.to.date", >>> "order": "asc"} >>> ] >>> } >>> search_result = sc.post_search(index_id, query_data) **External Documentation** See `POST Search Query \ <https://docs.globus.org/api/search/search/#complex_post_query>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.post_search({}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "search") return self.post(path, data)
def endpoint_deactivate(self, endpoint_id, **params): """ ``POST /endpoint/<endpoint_id>/deactivate`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Deactive endpoint \ <https://docs.globus.org/api/transfer/endpoint_activation/#deactivate_endpoint>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.endpoint_deactivate({})".format(endpoint_id)) path = self.qjoin_path("endpoint", endpoint_id, "deactivate") return self.post(path, params=params)
def create_entry(self, index_id, data): """ ``POST /v1/index/<index_id>/entry`` **Examples** Create an entry with a subject of ``https://example.com/foo/bar`` and a null entry_id: >>> sc = globus_sdk.SearchClient(...) >>> sc.create_entry(index_id, { >>> "subject": "https://example.com/foo/bar", >>> "visible_to": ["public"], >>> "content": { >>> "foo/bar": "some val" >>> } >>> }) Create an entry with a subject of ``https://example.com/foo/bar`` and an entry_id of ``foo/bar``: >>> sc = globus_sdk.SearchClient(...) >>> sc.create_entry(index_id, { >>> "subject": "https://example.com/foo/bar", >>> "visible_to": ["public"], >>> "id": "foo/bar", >>> "content": { >>> "foo/bar": "some val" >>> } >>> }) **External Documentation** See `Create Entry \ <https://docs.globus.org/api/search/entry_ops/#create_single_entry>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info( "SearchClient.create_entry({0}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "entry") return self.post(path, data)
def delete_endpoint_role(self, endpoint_id, role_id): """ ``DELETE /endpoint/<endpoint_id>/role/<role_id>`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Delete endpoint role by id \ <https://docs.globus.org/api/transfer/endpoint_roles/#delete_endpoint_role_by_id>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info("TransferClient.delete_endpoint_role({}, {})".format( endpoint_id, role_id)) path = self.qjoin_path('endpoint', endpoint_id, 'role', role_id) return self.delete(path)
def add_endpoint_server(self, endpoint_id, server_data): """ ``POST /endpoint/<endpoint_id>/server`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Add endpoint server \ <https://docs.globus.org/api/transfer/endpoint/#add_endpoint_server>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.add_endpoint_server({}, ...)".format(endpoint_id)) path = self.qjoin_path("endpoint", endpoint_id, "server") return self.post(path, server_data)
def add_endpoint_role(self, endpoint_id, role_data): """ ``POST /endpoint/<endpoint_id>/role`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Create endpoint role \ <https://docs.globus.org/api/transfer/endpoint_roles/#create_endpoint_role>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.add_endpoint_role({}, ...)".format(endpoint_id)) path = self.qjoin_path('endpoint', endpoint_id, 'role') return self.post(path, role_data)
def endpoint_get_activation_requirements(self, endpoint_id, **params): """ ``GET /endpoint/<endpoint_id>/activation_requirements`` :rtype: :class:`ActivationRequirementsResponse <globus_sdk.transfer.response.ActivationRequirementsResponse>` **External Documentation** See `Get activation requirements \ <https://docs.globus.org/api/transfer/endpoint_activation/#get_activation_requirements>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) path = self.qjoin_path("endpoint", endpoint_id, "activation_requirements") return self.get(path, params=params, response_class=ActivationRequirementsResponse)
def recursive_operation_ls(self, endpoint_id, depth=3, filter_after_first=True, **params): """ Makes recursive calls to ``GET /operation/endpoint/<endpoint_id>/ls`` Does not preserve access to top level operation_ls fields, but adds a "path" field for every item that represents the full path to that item. :rtype: iterable of :class:`GlobusResponse <globus_sdk.response.GlobusResponse>` **Parameters** ``endpoint_id`` (*string*) The endpoint being recursively ls'ed. If no "path" is given in params, the start path is determined by this endpoint. ``depth`` (*int*) The maximum file depth the recursive ls will go to. ``filter_after_first`` (*bool*) If False, any "filter" in params will only be applied to the first, top level ls, all results beyond that will be unfiltered. ``params`` Parameters that will be passed through as query params. **Examples** >>> tc = globus_sdk.TransferClient(...) >>> for entry in tc.recursive_operation_ls(ep_id, path="/~/project1/"): >>> print(entry["path"], entry["type"]) **External Documentation** See `List Directory Contents \ <https://docs.globus.org/api/transfer/file_operations/#list_directory_contents>`_ in the REST documentation for details, but note that top level data fields are no longer available and an additional per item "path" field is added. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.recursive_operation_ls({}, {}, {})".format( endpoint_id, depth, params)) return RecursiveLsResponse(self, endpoint_id, depth, filter_after_first, params)
def add_endpoint_acl_rule(self, endpoint_id, rule_data): """ ``POST /endpoint/<endpoint_id>/access`` **Parameters** ``endpoint_id`` (*string*) ID of endpoint to which to add the acl ``rule_data`` (*dict*) A python dict representation of an ``access`` document :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **Examples** >>> tc = globus_sdk.TransferClient() >>> rule_data = { >>> "DATA_TYPE": "access", >>> "principal_type": "identity", >>> "principal": identity_id, >>> "path": "/dataset1/", >>> "permissions": "rw", >>> } >>> result = tc.add_endpoint_acl_rule(endpoint_id, rule_data) >>> rule_id = result["access_id"] **External Documentation** See `Create access rule \ <https://docs.globus.org/api/transfer/acl/#rest_access_create>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.add_endpoint_acl_rule({}, ...)".format( endpoint_id)) path = self.qjoin_path('endpoint', endpoint_id, 'access') return self.post(path, rule_data)
def endpoint_role_list(self, endpoint_id, **params): """ ``GET /endpoint/<endpoint_id>/role_list`` :rtype: :class:`IterableTransferResponse <globus_sdk.transfer.response.IterableTransferResponse>` **External Documentation** See `Get list of endpoint roles \ <https://docs.globus.org/api/transfer/endpoint_roles/#get_list_of_endpoint_roles>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.endpoint_role_list({}, ...)".format(endpoint_id)) path = self.qjoin_path('endpoint', endpoint_id, 'role_list') return self.get(path, params=params, response_class=IterableTransferResponse)
def delete_endpoint_server(self, endpoint_id, server_id): """ ``DELETE /endpoint/<endpoint_id>/server/<server_id>`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Delete endpoint server by id \ <https://docs.globus.org/api/transfer/endpoint/#delete_endpoint_server_by_id>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.delete_endpoint_server({}, {})".format( endpoint_id, server_id)) path = self.qjoin_path("endpoint", endpoint_id, "server", str(server_id)) return self.delete(path)
def get_endpoint_server(self, endpoint_id, server_id, **params): """ ``GET /endpoint/<endpoint_id>/server/<server_id>`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **External Documentation** See `Get endpoint server list \ <https://docs.globus.org/api/transfer/endpoint/#get_endpoint_server_list>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.get_endpoint_server({}, {}, ...)".format( endpoint_id, server_id)) path = self.qjoin_path("endpoint", endpoint_id, "server", str(server_id)) return self.get(path, params=params)
def recursive_operation_ls( self, endpoint_id, depth=3, filter_after_first=True, **params ): """ Makes recursive calls to ``GET /operation/endpoint/<endpoint_id>/ls`` Does not preserve access to top level operation_ls fields, but adds a "path" field for every item that represents the full path to that item. :rtype: iterable of :class:`GlobusResponse <globus_sdk.response.GlobusResponse>` **Parameters** ``endpoint_id`` (*string*) The endpoint being recursively ls'ed. If no "path" is given in params, the start path is determined by this endpoint. ``depth`` (*int*) The maximum file depth the recursive ls will go to. ``filter_after_first`` (*bool*) If False, any "filter" in params will only be applied to the first, top level ls, all results beyond that will be unfiltered. ``params`` Parameters that will be passed through as query params. **Examples** >>> tc = globus_sdk.TransferClient(...) >>> for entry in tc.recursive_operation_ls(ep_id, path="/~/project1/"): >>> print(entry["path"], entry["type"]) **External Documentation** See `List Directory Contents \ <https://docs.globus.org/api/transfer/file_operations/#list_directory_contents>`_ in the REST documentation for details, but note that top level data fields are no longer available and an additional per item "path" field is added. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.recursive_operation_ls({}, {}, {})".format( endpoint_id, depth, params ) ) return RecursiveLsResponse(self, endpoint_id, depth, filter_after_first, params)
def search( self, index_id, q, offset=0, limit=10, query_template=None, advanced=False, **params ): """ ``GET /v1/index/<index_id>/search`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> result = sc.search(index_id, 'query string') >>> advanced_result = sc.search(index_id, 'author: "Ada Lovelace"', >>> advanced=True) **External Documentation** See `GET Search Query \ <https://docs.globus.org/api/search/search/#simple_get_query>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params( params, q=q, offset=offset, limit=limit, query_template=query_template, advanced=advanced, ) self.logger.info("SearchClient.search({}, ...)".format(index_id)) path = self.qjoin_path("v1/index", index_id, "search") return self.get(path, params=params)
def search( self, index_id, q, offset=0, limit=10, query_template=None, advanced=False, **params, ): """ ``GET /v1/index/<index_id>/search`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> result = sc.search(index_id, 'query string') >>> advanced_result = sc.search(index_id, 'author: "Ada Lovelace"', >>> advanced=True) **External Documentation** See `GET Search Query \ <https://docs.globus.org/api/search/search/#simple_get_query>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params( params, q=q, offset=offset, limit=limit, query_template=query_template, advanced=advanced, ) self.logger.info(f"SearchClient.search({index_id}, ...)") path = self.qjoin_path("v1/index", index_id, "search") return self.get(path, params=params)
def setUp(self): """ Creates a list for tracking cleanup of assets created during testing Sets up a test endpoint """ super(BaseClientTests, self).setUp() # list of dicts, each containing a function and a list of args # to pass to that function s.t. calling f(*args) cleans an asset self.asset_cleanup = [] # set up test endpoint # name randomized to prevent collision data = {"display_name": "Base Test Endpoint-" + str(getrandbits(128))} r = self.bc.post("endpoint", data) self.test_ep_id = safe_stringify(r["id"]) # track asset for cleanup path = self.bc.qjoin_path("endpoint", self.test_ep_id) self.asset_cleanup.append({ "function": self.bc.delete, "args": [path], "name": "test_ep" }) # for ease of removal
def __init__(self, transfer_client, endpoint, label=None, recursive=False, **kwargs): endpoint = safe_stringify(endpoint) logger.info("Creating a new DeleteData object") self["DATA_TYPE"] = "delete" self["submission_id"] = transfer_client.get_submission_id()["value"] logger.info("DeleteData.submission_id = {}".format( self["submission_id"])) self["endpoint"] = endpoint logger.info("DeleteData.endpoint = {}".format(endpoint)) self["recursive"] = recursive logger.info("DeleteData.recursive = {}".format(recursive)) if label is not None: self["label"] = label logger.debug("DeleteData.label = {}".format(label)) self["DATA"] = [] self.update(kwargs)
def endpoint_activate(self, endpoint_id, requirements_data, **params): """ ``POST /endpoint/<endpoint_id>/activate`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` Consider using autoactivate and web activation instead, described in the example for :meth:`~globus_sdk.TransferClient.endpoint_autoactivate`. **External Documentation** See `Activate endpoint \ <https://docs.globus.org/api/transfer/endpoint_activation/#activate_endpoint>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.endpoint_activate({})".format(endpoint_id)) path = self.qjoin_path("endpoint", endpoint_id, "activate") return self.post(path, json_body=requirements_data, params=params)
def __init__( self, transfer_client, endpoint, label=None, submission_id=None, recursive=False, deadline=None, **kwargs ): endpoint = safe_stringify(endpoint) logger.info("Creating a new DeleteData object") self["DATA_TYPE"] = "delete" self["submission_id"] = ( submission_id or transfer_client.get_submission_id()["value"] ) logger.info("DeleteData.submission_id = {}".format(self["submission_id"])) self["endpoint"] = endpoint logger.info("DeleteData.endpoint = {}".format(endpoint)) self["recursive"] = recursive logger.info("DeleteData.recursive = {}".format(recursive)) if label is not None: self["label"] = label logger.debug("DeleteData.label = {}".format(label)) if deadline is not None: self["deadline"] = str(deadline) logger.debug("DeleteData.deadline = {}".format(deadline)) self["DATA"] = [] self.update(kwargs) for option, value in kwargs.items(): logger.info( "DeleteData.{} = {} (option passed in via kwargs)".format(option, value) )
def test_post(self): """ Makes a test endpoint, verifies results Sends nonsense post, confirms 404 Sends post without data, confirms 400 Sends post to non-post resource, confirms 405 """ # post to create a new endpoint, name randomized to prevent collision post_data = {"display_name": "Post Test-" + str(getrandbits(128))} post_res = self.bc.post("endpoint", post_data) # validate results self.assertIn("id", post_res) self.assertEqual(post_res["DATA_TYPE"], "endpoint_create_result") self.assertEqual(post_res["code"], "Created") self.assertEqual(post_res["message"], "Endpoint created successfully") # track asset for cleanup path = self.bc.qjoin_path("endpoint", safe_stringify(post_res["id"])) self.asset_cleanup.append({"function": self.bc.delete, "args": [path]}) # send nonsense post with self.assertRaises(GlobusAPIError) as apiErr: self.bc.post("nonsense_path") self.assertEqual(apiErr.exception.http_status, 404) self.assertEqual(apiErr.exception.code, "ClientError.NotFound") # send post without data with self.assertRaises(GlobusAPIError) as apiErr: self.bc.post("endpoint") self.assertEqual(apiErr.exception.http_status, 400) self.assertEqual(apiErr.exception.code, "BadRequest") # send post to endpoint with id (get/delete resource) with self.assertRaises(GlobusAPIError) as apiErr: path = self.bc.qjoin_path("endpoint", self.test_ep_id) self.bc.post(path) self.assertEqual(apiErr.exception.http_status, 405) self.assertEqual(apiErr.exception.code, "ClientError.BadMethod")
def delete_endpoint(self, endpoint_id): """ ``DELETE /endpoint/<endpoint_id>`` :rtype: :class:`TransferResponse <globus_sdk.transfer.response.TransferResponse>` **Examples** >>> tc = globus_sdk.TransferClient() >>> delete_result = tc.delete_endpoint(endpoint_id) **External Documentation** See `Delete endpoint by id \ <https://docs.globus.org/api/transfer/endpoint/#delete_endpoint_by_id>`_ in the REST documentation for details. """ endpoint_id = safe_stringify(endpoint_id) self.logger.info( "TransferClient.delete_endpoint({})".format(endpoint_id)) path = self.qjoin_path("endpoint", endpoint_id) return self.delete(path)
def get_index(self, index_id, **params): """ ``GET /v1/index/<index_id>`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> index = sc.get_index(index_id) >>> assert index['index_id'] == index_id >>> print(index["display_name"], >>> "(" + index_id + "):", >>> index["description"]) **External Documentation** See `Get Index Metadata \ <https://docs.globus.org/api/search/index_meta/>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info(f"SearchClient.get_index({index_id})") path = self.qjoin_path("v1/index", index_id) return self.get(path, params=params)
def get_entry(self, index_id, subject, entry_id=None, **params): """ ``GET /v1/index/<index_id>/entry`` **Examples** Lookup the entry with a subject of ``https://example.com/foo/bar`` and a null entry_id: >>> sc = globus_sdk.SearchClient(...) >>> entry_data = sc.get_entry(index_id, 'http://example.com/foo/bar') Lookup the entry with a subject of ``https://example.com/foo/bar`` and an entry_id of ``foo/bar``: >>> sc = globus_sdk.SearchClient(...) >>> entry_data = sc.get_entry(index_id, 'http://example.com/foo/bar', >>> entry_id='foo/bar') **External Documentation** See `Get Entry \ <https://docs.globus.org/api/search/entry_ops/#get_single_entry>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) merge_params(params, subject=subject, entry_id=entry_id) self.logger.info( "SearchClient.get_entry({}, {}, {}, ...)".format( index_id, subject, entry_id ) ) path = self.qjoin_path("v1/index", index_id, "entry") return self.get(path, params=params)
def get_index(self, index_id, **params): """ ``GET /v1/index/<index_id>`` **Examples** >>> sc = globus_sdk.SearchClient(...) >>> index = sc.get_index(index_id) >>> assert index['index_id'] == index_id >>> print(index["display_name"], >>> "(" + index_id + "):", >>> index["description"]) **External Documentation** See `Get Index Metadata \ <https://docs.globus.org/api/search/index_meta/>`_ in the API documentation for details. """ index_id = safe_stringify(index_id) self.logger.info("SearchClient.get_index({})".format(index_id)) path = self.qjoin_path("v1/index", index_id) return self.get(path, params=params)
def _convert_listarg(val): if isinstance(val, collections.Iterable) and not isinstance( val, six.string_types): return ",".join(safe_stringify(x) for x in val) else: return safe_stringify(val)
def __init__(self, name, value, multiline=False): self.multiline = multiline self.name = safe_stringify(name) self.raw_value = safe_stringify(value) self.value = self._format_value(self.raw_value)
def __init__( self, transfer_client, source_endpoint, destination_endpoint, label=None, submission_id=None, sync_level=None, verify_checksum=False, preserve_timestamp=False, encrypt_data=False, deadline=None, recursive_symlinks="ignore", **kwargs ): source_endpoint = safe_stringify(source_endpoint) destination_endpoint = safe_stringify(destination_endpoint) logger.info("Creating a new TransferData object") self["DATA_TYPE"] = "transfer" self["submission_id"] = ( submission_id or transfer_client.get_submission_id()["value"] ) logger.info("TransferData.submission_id = {}".format(self["submission_id"])) self["source_endpoint"] = source_endpoint logger.info("TransferData.source_endpoint = {}".format(source_endpoint)) self["destination_endpoint"] = destination_endpoint logger.info( "TransferData.destination_endpoint = {}".format(destination_endpoint) ) self["verify_checksum"] = verify_checksum logger.info("TransferData.verify_checksum = {}".format(verify_checksum)) self["preserve_timestamp"] = preserve_timestamp logger.info("TransferData.preserve_timestamp = {}".format(preserve_timestamp)) self["encrypt_data"] = encrypt_data logger.info("TransferData.encrypt_data = {}".format(encrypt_data)) self["recursive_symlinks"] = recursive_symlinks logger.info("TransferData.recursive_symlinks = {}".format(recursive_symlinks)) if label is not None: self["label"] = label logger.debug("TransferData.label = {}".format(label)) if deadline is not None: self["deadline"] = str(deadline) logger.debug("TransferData.deadline = {}".format(deadline)) # map the sync_level (if it's a nice string) to one of the known int # values # you can get away with specifying an invalid sync level -- the API # will just reject you with an error. This is kind of important: if # more levels are added in the future this method doesn't become # garbage overnight if sync_level is not None: sync_dict = {"exists": 0, "size": 1, "mtime": 2, "checksum": 3} self["sync_level"] = sync_dict.get(sync_level, sync_level) logger.info( "TransferData.sync_level = {} ({})".format( self["sync_level"], sync_level ) ) self["DATA"] = [] self.update(kwargs) for option, value in kwargs.items(): logger.info( "TransferData.{} = {} (option passed in via kwargs)".format( option, value ) )
def __init__(self, transfer_client, source_endpoint, destination_endpoint, label=None, submission_id=None, sync_level=None, verify_checksum=False, preserve_timestamp=False, encrypt_data=False, deadline=None, recursive_symlinks="ignore", **kwargs): source_endpoint = safe_stringify(source_endpoint) destination_endpoint = safe_stringify(destination_endpoint) logger.info("Creating a new TransferData object") self["DATA_TYPE"] = "transfer" self["submission_id"] = submission_id or \ transfer_client.get_submission_id()["value"] logger.info("TransferData.submission_id = {}".format( self["submission_id"])) self["source_endpoint"] = source_endpoint logger.info( "TransferData.source_endpoint = {}".format(source_endpoint)) self["destination_endpoint"] = destination_endpoint logger.info("TransferData.destination_endpoint = {}".format( destination_endpoint)) self["verify_checksum"] = verify_checksum logger.info( "TransferData.verify_checksum = {}".format(verify_checksum)) self["preserve_timestamp"] = preserve_timestamp logger.info( "TransferData.preserve_timestamp = {}".format(preserve_timestamp)) self["encrypt_data"] = encrypt_data logger.info("TransferData.encrypt_data = {}".format(encrypt_data)) self["recursive_symlinks"] = recursive_symlinks logger.info( "TransferData.recursive_symlinks = {}".format(recursive_symlinks)) if label is not None: self["label"] = label logger.debug("TransferData.label = {}".format(label)) if deadline is not None: self["deadline"] = str(deadline) logger.debug("TransferData.deadline = {}".format(deadline)) # map the sync_level (if it's a nice string) to one of the known int # values # you can get away with specifying an invalid sync level -- the API # will just reject you with an error. This is kind of important: if # more levels are added in the future this method doesn't become # garbage overnight if sync_level is not None: sync_dict = {"exists": 0, "size": 1, "mtime": 2, "checksum": 3} self['sync_level'] = sync_dict.get(sync_level, sync_level) logger.info("TransferData.sync_level = {} ({})".format( self['sync_level'], sync_level)) self["DATA"] = [] self.update(kwargs) for option, value in kwargs.items(): logger.info( "TransferData.{} = {} (option passed in via kwargs)".format( option, value))