Skip to content

Commit

Permalink
New example doc format (#1008)
Browse files Browse the repository at this point in the history
* New example doc format

* Made submit-transfer doc less assumptive

* Use ref instead of relative anchor tag

* Wrap ConsentRequired in

* Dedupe copied text

* fix up missing preamble section
  • Loading branch information
derek-globus authored Jul 19, 2024
1 parent b9e65df commit ee31831
Show file tree
Hide file tree
Showing 29 changed files with 375 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

Documentation
~~~~~~~~~~~~~

- Added a new experimental "Updated Examples" section which rewrites and reorders
many examples to aid in discovery. (:pr:`NUMBER`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

Creating a Guest Collection
===========================

TODO

.. literalinclude:: user_guest_collection.py
:caption: ``user_guest_collection.py`` [:download:`download <user_guest_collection.py>`]
:language: python
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import globus_sdk
from globus_sdk.experimental.globus_app import UserApp

# Tutorial Client ID - <replace this with your own client>
NATIVE_CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
USER_APP = UserApp("my-simple-transfer", client_id=NATIVE_CLIENT_ID)

# Globus Tutorial Collection 1
# https://app.globus.org/file-manager/collections/6c54cade-bde5-45c1-bdea-f4bd71dba2cc
ENDPOINT_HOSTNAME = "https://b7a4f1.75bc.data.globus.org"
MAPPED_COLLECTION_ID = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"


def main():
gcs_client = globus_sdk.GCSClient(ENDPOINT_HOSTNAME, app=USER_APP)

# Comment out this line if the mapped collection is high assurance
attach_data_access_scope(gcs_client, MAPPED_COLLECTION_ID)

collection_request = globus_sdk.GuestCollectionDocument(
public=True,
collection_base_path="/",
display_name="example_guest_collection",
mapped_collection_id=MAPPED_COLLECTION_ID,
)

collection = gcs_client.create_collection(collection_request)
print(f"Created guest collection. Collection ID: {collection['id']}")


def attach_data_access_scope(gcs_client, collection_id):
"""Compose and attach a ``data_access`` scope for the supplied collection"""
endpoint_scopes = gcs_client.get_gcs_endpoint_scopes(gcs_client.endpoint_client_id)
collection_scopes = gcs_client.get_gcs_collection_scopes(collection_id)

manage_collections = globus_sdk.Scope(endpoint_scopes.manage_collections)
data_access = globus_sdk.Scope(collection_scopes.data_access, optional=True)

manage_collections.add_dependency(data_access)

gcs_client.add_app_scope(manage_collections)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Identifying Entity Type
=======================

TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

Endpoints and Collections
=========================

.. toctree::
:maxdepth: 1

identifying_entity_type
create_guest_collection/index
5 changes: 5 additions & 0 deletions docs/experimental/examples/flows/create.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Creating a Flow
===============

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/flows/delete.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Deleting a Flow
===============

TODO
11 changes: 11 additions & 0 deletions docs/experimental/examples/flows/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

Flows
=====

.. toctree::
:maxdepth: 1

create
list
run
delete
5 changes: 5 additions & 0 deletions docs/experimental/examples/flows/list.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Listing Flows
=============

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/flows/run.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Running a Flow
==============

TODO
22 changes: 22 additions & 0 deletions docs/experimental/examples/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Updated Examples
================

This experimental doc restructures the existing :ref:`examples` section by:

* Grouping examples by common topic
* Consolidating & updating examples into a more uniform active format
* Updating references to leverage the latest SDK constructs (notably GlobusApp)

While in ``experimental`` it should be considered a work in progress and subject to
change. Once complete, it'll be merged into the main documentation, replacing the
existing examples section.

.. toctree::
:maxdepth: 2

transferring_data/index
endpoints_and_collections/index
flows/index
projects/index
oauth2/index
5 changes: 5 additions & 0 deletions docs/experimental/examples/oauth2/authorizers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Using Authorizers
=================

TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Customizing Token Storage
=========================

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/oauth2/globus_app.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Using a Globus App
==================

TODO
12 changes: 12 additions & 0 deletions docs/experimental/examples/oauth2/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

OAuth2 at Globus
================

.. toctree::
:maxdepth: 1

globus_app
authorizers
login_flows
customizing_token_storage
three_legged_oauth
5 changes: 5 additions & 0 deletions docs/experimental/examples/oauth2/login_flows.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Running Login Flows
===================

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/oauth2/three_legged_oauth.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Performing Three-Legged OAuth in Flask
========================================

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/projects/create.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Creating a Project
==================

TODO
5 changes: 5 additions & 0 deletions docs/experimental/examples/projects/delete.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Deleting a Project
==================

TODO
10 changes: 10 additions & 0 deletions docs/experimental/examples/projects/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

Auth Projects
=============

.. toctree::
:maxdepth: 1

create
list
delete
5 changes: 5 additions & 0 deletions docs/experimental/examples/projects/list.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Listing Projects
================

TODO
11 changes: 11 additions & 0 deletions docs/experimental/examples/transferring_data/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

Transferring Data
=================

.. toctree::
:maxdepth: 1

submit_transfer/index
schedule_transfer/index
task_deadlines
recursive_ls
5 changes: 5 additions & 0 deletions docs/experimental/examples/transferring_data/recursive_ls.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Recursively Listing a Filesystem
================================

TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

Scheduling a Transfer
=====================

TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

Initiating a Transfer
=====================

Moving data within the Globus Ecosystem is performed by submitting a ``Transfer Task``
against the Globus Transfer service.

The below examples demonstrate how to do that using a globus sdk ``TransferClient``.
They are split into two categories:

#. :ref:`transferring-between-known-collections` - both source and destination
collections are known in advance and are likely be hardcoded into your script.

#. :ref:`transferring-between-unknown-collections` - either the source or
destination collection will be determined at runtime (e.g. by script argument).

We differentiate these examples because certain collections have special auth
requirements which must either be defined up front or fixed reactively if omitted.
Certain collections (mapped non-high assurance ones) require that a special scope
("data_access") to be attached to the transfer request to grant Transfer access to that
collection's data.
If both collections are known this can be done proactively with a call to
the ``add_app_data_access_scope`` method. If, however, one or more collections are
unknown, the script must reactively solve the ``ConsentRequired`` error that is raised
when the transfer is submitted.


.. _transferring-between-known-collections:

Transferring data between two known collections
-----------------------------------------------

.. note::
The script references two globus hosted "tutorial" collections. Replace these ids &
paths with your own collection ids and paths to move your own data.

.. note::
Some collections require you to attach a "data_access" scope to your transfer
request. You should evaluate whether this is necessary for both your source and
destination collections and omit the ``transfer_client.add_app_data_access_scope``
calls as needed.

A collection requires "data_access" if it is (1) a mapped collection and (2) is
not high assurance.

.. literalinclude:: submit_transfer_collections_known.py
:caption: ``submit_transfer_collections_known.py`` [:download:`download <submit_transfer_collections_known.py>`]
:language: python


.. _transferring-between-unknown-collections:

Transferring data where at least one collection is unknown
----------------------------------------------------------

In the case where your script does not know the full set of collections that it will
be interacting with, you may need to reactively solve the ``ConsentRequired`` errors
instead of proactively attaching the "data_access" scope.

This script demonstrates how to do that by:

#. Attempting to submit the transfer without any "data_access" scopes.
#. Intercepting any raised ``ConsentRequired`` errors if the request fails.
#. Attaching any scope requirements detailed in the error.
#. Retrying the transfer which implicitly puts your user through a consent flow to
resolve their auth state.

.. note::
The script references two globus hosted "tutorial" collections. Replace these ids &
paths with your own collection ids and paths to move your own data.

.. note::
Given that this script reactively fixes auth states, it can involve two user login
interactions instead of the one required by the above proactive approach.

.. literalinclude:: submit_transfer_collections_unknown.py
:caption: ``submit_transfer_collections_unknown.py`` [:download:`download <submit_transfer_collections_unknown.py>`]
:language: python
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import globus_sdk
from globus_sdk.experimental.globus_app import UserApp

# Tutorial Client ID - <replace this with your own client>
NATIVE_CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
USER_APP = UserApp("my-simple-transfer", client_id=NATIVE_CLIENT_ID)

# Globus Tutorial Collection 1
# https://app.globus.org/file-manager/collections/6c54cade-bde5-45c1-bdea-f4bd71dba2cc
SRC_COLLECTION = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"
SRC_PATH = "/share/godata/file1.txt"

# Globus Tutorial Collection 2
# https://app.globus.org/file-manager/collections/31ce9ba0-176d-45a5-add3-f37d233ba47d
DST_COLLECTION = "31ce9ba0-176d-45a5-add3-f37d233ba47d"
DST_PATH = "/~/example-transfer-script-destination.txt"


def main():
transfer_client = globus_sdk.TransferClient(app=USER_APP)

# Comment out each of these lines if the referenced collection is either
# (1) A guest collection or (2) high assurance.
transfer_client.add_app_data_access_scope(SRC_COLLECTION)
transfer_client.add_app_data_access_scope(DST_COLLECTION)

transfer_request = globus_sdk.TransferData(
source_endpoint=SRC_COLLECTION,
destination_endpoint=DST_COLLECTION,
)
transfer_request.add_item(SRC_PATH, DST_PATH)

task = transfer_client.submit_transfer(transfer_request)
print(f"Submitted transfer. Task ID: {task['task_id']}.")


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import globus_sdk
from globus_sdk.experimental.globus_app import UserApp

# Tutorial Client ID - <replace this with your own client>
NATIVE_CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
USER_APP = UserApp("my-simple-transfer", client_id=NATIVE_CLIENT_ID)

# Globus Tutorial Collection 1
# https://app.globus.org/file-manager/collections/6c54cade-bde5-45c1-bdea-f4bd71dba2cc
SRC_COLLECTION = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"
SRC_PATH = "/share/godata/file1.txt"

# Globus Tutorial Collection 2
# https://app.globus.org/file-manager/collections/31ce9ba0-176d-45a5-add3-f37d233ba47d
DST_COLLECTION = "31ce9ba0-176d-45a5-add3-f37d233ba47d"
DST_PATH = "/~/example-transfer-script-destination.txt"


def main():
transfer_client = globus_sdk.TransferClient(app=USER_APP)

transfer_request = globus_sdk.TransferData(
source_endpoint=SRC_COLLECTION,
destination_endpoint=DST_COLLECTION,
)
transfer_request.add_item(SRC_PATH, DST_PATH)

try:
task = transfer_client.submit_transfer(transfer_request)
except globus_sdk.TransferAPIError as err:
if not err.info.consent_required:
raise

print("Additional consent required.")
transfer_client.add_app_scope(err.info.consent_required.required_scopes)

task = transfer_client.submit_transfer(transfer_request)
print(f"Submitted transfer. Task ID: {task['task_id']}.")


if __name__ == "__main__":
main()
Loading

0 comments on commit ee31831

Please sign in to comment.