globus-cli 3.27.0__tar.gz → 3.28.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {globus-cli-3.27.0/src/globus_cli.egg-info → globus_cli-3.28.0}/PKG-INFO +2 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/pyproject.toml +1 -1
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/__init__.py +1 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/_common.py +46 -7
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/create.py +2 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/resume.py +4 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/update.py +9 -2
- globus_cli-3.28.0/src/globus_cli/commands/flows/validate.py +106 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/create/transfer.py +2 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/resume.py +4 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/exception_handling/hooks.py +109 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/manager.py +10 -4
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/commands.py +4 -0
- globus_cli-3.28.0/src/globus_cli/services/auth.py +83 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/printer.py +8 -1
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/version.py +1 -1
- {globus-cli-3.27.0 → globus_cli-3.28.0/src/globus_cli.egg-info}/PKG-INFO +2 -2
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli.egg-info/SOURCES.txt +1 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli.egg-info/requires.txt +1 -1
- globus-cli-3.27.0/src/globus_cli/services/auth.py +0 -163
- {globus-cli-3.27.0 → globus_cli-3.28.0}/LICENSE +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/README.rst +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/setup.cfg +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/setup.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/__main__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/_warnings.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/api.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/rename.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/bookmark/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/cli_profile_list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/create/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/create/guest.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/create/mapped.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/collection/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/activate.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/deactivate.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/is_activated.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/local_id.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/my_shared_endpoint_list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/permission/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/role/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/search.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/add.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/server/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/set_subscription_id.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/storage_gateway/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/storage_gateway/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/create/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/create/from_json.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/create/posix.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/create/s3.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/update/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/endpoint/user_credential/update/from_json.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/cancel.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/show_definition.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/show_logs.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/run/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/flows/start.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/create/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/create/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/create/guest.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/create/mapped.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/set_subscription_id.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/update/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/update/guest.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcp/update/mapped.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/role/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/set_subscription_id.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/gcs/endpoint/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/get_identities.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/get_by_subscription.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/get_subscription_info.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/invite/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/invite/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/invite/accept.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/invite/decline.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/join.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/leave.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/add.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/approve.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/invite.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/reject.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/member/remove.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/set_policies.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/group/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/list_commands.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/login.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/logout.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/ls.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/mkdir.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/rename.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/rm.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/delete_by_query.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/role/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/role/create.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/role/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/role/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/index/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/ingest.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/query.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/subject/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/subject/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/subject/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/task/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/task/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/search/task/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/session/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/session/consent.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/session/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/session/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/stat.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/cancel.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/event_list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/generate_submission_id.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/pause_info.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/task/wait.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/_common.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/create/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/delete.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/list.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/pause.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/timer/show.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/transfer.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/update.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/version.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/commands/whoami.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/constants.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/endpointish/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/endpointish/endpointish.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/endpointish/entity_type.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/endpointish/errors.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/exception_handling/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/exception_handling/registry.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/globus_cli_flake8.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/_old_config.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/auth_flows.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/client_login.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/context.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/errors.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/local_server.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/scopes.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/tokenstore.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/login_manager/utils.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/command_state.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/mutex_group.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_classes.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/delimited.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/endpoint_plus_path.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/identity_type.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/json_strorfile.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/location.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/notify_param.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/nullable.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/task_path.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/param_types/timedelta.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shared_callbacks.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shared_options/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shared_options/endpointish.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shared_options/id_args.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shared_options/transfer_task_options.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/parsing/shell_completion.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/reflect.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/gcs.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/activation.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/client.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/data.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/delegate_proxy.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/services/transfer/recursive_ls.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/awscli_text.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/context.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/errors.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/field.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/formatters/__init__.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/formatters/auth.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/formatters/base.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/formatters/compound.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/formatters/primitive.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/termio/server_timing.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/types.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli/utils.py +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli.egg-info/dependency_links.txt +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli.egg-info/entry_points.txt +0 -0
- {globus-cli-3.27.0 → globus_cli-3.28.0}/src/globus_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: globus-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.28.0
|
|
4
4
|
Summary: Globus CLI
|
|
5
5
|
Author-email: Stephen Rosen <sirosen@globus.org>
|
|
6
6
|
Project-URL: homepage, https://github.com/globus/globus-cli
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: globus-sdk==3.
|
|
21
|
+
Requires-Dist: globus-sdk==3.41.0
|
|
22
22
|
Requires-Dist: click<9,>=8.1.4
|
|
23
23
|
Requires-Dist: jmespath==1.0.1
|
|
24
24
|
Requires-Dist: packaging>=17.0
|
|
@@ -6,6 +6,7 @@ from globus_cli.parsing import group
|
|
|
6
6
|
lazy_subcommands={
|
|
7
7
|
"create": (".create", "create_command"),
|
|
8
8
|
"update": (".update", "update_command"),
|
|
9
|
+
"validate": (".validate", "validate_command"),
|
|
9
10
|
"delete": (".delete", "delete_command"),
|
|
10
11
|
"list": (".list", "list_command"),
|
|
11
12
|
"show": (".show", "show_command"),
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
1
6
|
import click
|
|
2
7
|
|
|
3
8
|
from globus_cli.parsing import JSONStringOrFile
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
"--input-schema",
|
|
7
|
-
"input_schema",
|
|
8
|
-
type=JSONStringOrFile(),
|
|
9
|
-
help="""
|
|
10
|
+
_input_schema_helptext = """
|
|
10
11
|
The JSON input schema that governs the parameters
|
|
11
12
|
used to start the flow.
|
|
12
13
|
|
|
@@ -21,11 +22,22 @@ input_schema_option = click.option(
|
|
|
21
22
|
|
|
22
23
|
\b
|
|
23
24
|
--input-schema schema.json
|
|
25
|
+
"""
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
""
|
|
27
|
+
input_schema_option = click.option(
|
|
28
|
+
"--input-schema",
|
|
29
|
+
"input_schema",
|
|
30
|
+
type=JSONStringOrFile(),
|
|
31
|
+
help=_input_schema_helptext,
|
|
27
32
|
)
|
|
28
33
|
|
|
34
|
+
input_schema_option_with_default = click.option(
|
|
35
|
+
"--input-schema",
|
|
36
|
+
"input_schema",
|
|
37
|
+
type=JSONStringOrFile(),
|
|
38
|
+
help=_input_schema_helptext
|
|
39
|
+
+ "\n If unspecified, the default is an empty JSON object ('{}').",
|
|
40
|
+
)
|
|
29
41
|
|
|
30
42
|
subtitle_option = click.option(
|
|
31
43
|
"--subtitle",
|
|
@@ -102,3 +114,30 @@ keywords_option = click.option(
|
|
|
102
114
|
to create a list of keywords.
|
|
103
115
|
""",
|
|
104
116
|
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class SubscriptionIdType(click.ParamType):
|
|
120
|
+
name = "SUBSCRIPTION_ID"
|
|
121
|
+
|
|
122
|
+
def convert(
|
|
123
|
+
self, value: str, param: click.Parameter | None, ctx: click.Context | None
|
|
124
|
+
) -> uuid.UUID | t.Literal["DEFAULT"]:
|
|
125
|
+
if value.upper() == "DEFAULT":
|
|
126
|
+
return "DEFAULT"
|
|
127
|
+
try:
|
|
128
|
+
return uuid.UUID(value)
|
|
129
|
+
except ValueError:
|
|
130
|
+
self.fail(f"{value} must be either a UUID or 'DEFAULT'", param, ctx)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
subscription_id_option = click.option(
|
|
134
|
+
"--subscription-id",
|
|
135
|
+
"subscription_id",
|
|
136
|
+
type=SubscriptionIdType(),
|
|
137
|
+
multiple=False,
|
|
138
|
+
help="""
|
|
139
|
+
A subscription ID to assign to the flow.
|
|
140
|
+
|
|
141
|
+
The value may be a UUID or the word "DEFAULT".
|
|
142
|
+
""",
|
|
143
|
+
)
|
|
@@ -7,7 +7,7 @@ import click
|
|
|
7
7
|
from globus_cli.commands.flows._common import (
|
|
8
8
|
administrators_option,
|
|
9
9
|
description_option,
|
|
10
|
-
|
|
10
|
+
input_schema_option_with_default,
|
|
11
11
|
keywords_option,
|
|
12
12
|
starters_option,
|
|
13
13
|
subtitle_option,
|
|
@@ -31,7 +31,7 @@ ROLE_TYPES = ("flow_viewer", "flow_starter", "flow_administrator", "flow_owner")
|
|
|
31
31
|
type=JSONStringOrFile(),
|
|
32
32
|
metavar="DEFINITION",
|
|
33
33
|
)
|
|
34
|
-
@
|
|
34
|
+
@input_schema_option_with_default
|
|
35
35
|
@subtitle_option
|
|
36
36
|
@description_option
|
|
37
37
|
@administrators_option
|
|
@@ -129,5 +129,7 @@ def _has_required_consent(
|
|
|
129
129
|
) -> bool:
|
|
130
130
|
auth_client = login_manager.get_auth_client()
|
|
131
131
|
user_identity_id = get_current_identity_id()
|
|
132
|
-
consents = auth_client.get_consents(user_identity_id)
|
|
133
|
-
|
|
132
|
+
consents = auth_client.get_consents(user_identity_id).to_forest()
|
|
133
|
+
# FIXME: this type ignore is temporary because `meets_scope_requirements()`
|
|
134
|
+
# has too tight of a type
|
|
135
|
+
return consents.meets_scope_requirements(required_scopes) # type: ignore[arg-type]
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import typing as t
|
|
3
4
|
import uuid
|
|
4
5
|
|
|
5
6
|
import click
|
|
7
|
+
from globus_sdk.utils import MISSING
|
|
6
8
|
|
|
7
9
|
from globus_cli.commands.flows._common import (
|
|
8
10
|
description_option,
|
|
9
|
-
|
|
11
|
+
input_schema_option_with_default,
|
|
12
|
+
subscription_id_option,
|
|
10
13
|
subtitle_option,
|
|
11
14
|
)
|
|
12
15
|
from globus_cli.login_manager import LoginManager
|
|
@@ -60,7 +63,7 @@ ROLE_TYPES = ("flow_viewer", "flow_starter", "flow_administrator", "flow_owner")
|
|
|
60
63
|
)
|
|
61
64
|
@subtitle_option
|
|
62
65
|
@description_option
|
|
63
|
-
@
|
|
66
|
+
@input_schema_option_with_default
|
|
64
67
|
@click.option(
|
|
65
68
|
"--administrators",
|
|
66
69
|
type=CommaDelimitedList(),
|
|
@@ -104,6 +107,7 @@ ROLE_TYPES = ("flow_viewer", "flow_starter", "flow_administrator", "flow_owner")
|
|
|
104
107
|
Passing an empty string will clear any existing keywords.
|
|
105
108
|
""",
|
|
106
109
|
)
|
|
110
|
+
@subscription_id_option
|
|
107
111
|
@LoginManager.requires_login("flows")
|
|
108
112
|
def update_command(
|
|
109
113
|
login_manager: LoginManager,
|
|
@@ -119,6 +123,7 @@ def update_command(
|
|
|
119
123
|
starters: list[str] | None,
|
|
120
124
|
viewers: list[str] | None,
|
|
121
125
|
keywords: list[str] | None,
|
|
126
|
+
subscription_id: uuid.UUID | t.Literal["DEFAULT"] | None,
|
|
122
127
|
) -> None:
|
|
123
128
|
"""
|
|
124
129
|
Update a flow.
|
|
@@ -154,6 +159,7 @@ def update_command(
|
|
|
154
159
|
flow_starters=starters,
|
|
155
160
|
flow_viewers=viewers,
|
|
156
161
|
keywords=keywords,
|
|
162
|
+
subscription_id=subscription_id or MISSING,
|
|
157
163
|
)
|
|
158
164
|
|
|
159
165
|
# Configure formatters for principals
|
|
@@ -170,6 +176,7 @@ def update_command(
|
|
|
170
176
|
Field("Description", "description"),
|
|
171
177
|
Field("Keywords", "keywords", formatter=formatters.ArrayFormatter()),
|
|
172
178
|
Field("Owner", "flow_owner", formatter=principal_formatter),
|
|
179
|
+
Field("Subscription ID", "subscription_id"),
|
|
173
180
|
Field("Created At", "created_at", formatter=formatters.Date),
|
|
174
181
|
Field("Updated At", "updated_at", formatter=formatters.Date),
|
|
175
182
|
Field(
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import globus_sdk
|
|
5
|
+
|
|
6
|
+
from globus_cli.commands.flows._common import input_schema_option
|
|
7
|
+
from globus_cli.login_manager import LoginManager
|
|
8
|
+
from globus_cli.parsing import JSONStringOrFile, ParsedJSONData, command
|
|
9
|
+
from globus_cli.termio import Field, display
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@command("validate", short_help="Validate a flow definition")
|
|
13
|
+
@click.argument(
|
|
14
|
+
"definition",
|
|
15
|
+
type=JSONStringOrFile(),
|
|
16
|
+
metavar="DEFINITION",
|
|
17
|
+
)
|
|
18
|
+
@input_schema_option
|
|
19
|
+
@LoginManager.requires_login("flows")
|
|
20
|
+
def validate_command(
|
|
21
|
+
login_manager: LoginManager,
|
|
22
|
+
*,
|
|
23
|
+
definition: ParsedJSONData,
|
|
24
|
+
input_schema: ParsedJSONData | None,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Validate a flow definition (BETA).
|
|
28
|
+
|
|
29
|
+
DEFINITION is the JSON document that defines the flow's instructions.
|
|
30
|
+
The definition document may be specified inline, or it may be
|
|
31
|
+
a path to a JSON file.
|
|
32
|
+
|
|
33
|
+
Example: Inline JSON:
|
|
34
|
+
|
|
35
|
+
\b
|
|
36
|
+
globus flows validate \\
|
|
37
|
+
'{{"StartAt": "a", "States": {{"a": {{"Type": "Pass", "End": true}}}}}}'
|
|
38
|
+
|
|
39
|
+
Example: Path to JSON file:
|
|
40
|
+
|
|
41
|
+
\b
|
|
42
|
+
globus flows validate definition.json
|
|
43
|
+
"""
|
|
44
|
+
payload = {}
|
|
45
|
+
|
|
46
|
+
# Ensure that the definition is a JSON object
|
|
47
|
+
if not isinstance(definition.data, dict):
|
|
48
|
+
raise click.UsageError("Flow definition must be a JSON object")
|
|
49
|
+
payload["definition"] = definition.data
|
|
50
|
+
|
|
51
|
+
# Ensure the input schema, if provided, is a JSON object
|
|
52
|
+
if input_schema is not None:
|
|
53
|
+
if not isinstance(input_schema.data, dict):
|
|
54
|
+
raise click.UsageError("--input-schema must be a JSON object")
|
|
55
|
+
payload["input_schema"] = input_schema.data
|
|
56
|
+
|
|
57
|
+
# Configure client
|
|
58
|
+
flows_client = login_manager.get_flows_client()
|
|
59
|
+
|
|
60
|
+
res = flows_client.validate_flow(**payload)
|
|
61
|
+
|
|
62
|
+
display(
|
|
63
|
+
res,
|
|
64
|
+
text_mode=_validate_flow_output_handler,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _validate_flow_output_handler(result: globus_sdk.GlobusHTTPResponse) -> None:
|
|
69
|
+
# Discovered scopes output
|
|
70
|
+
analysis_response = result.get("analysis")
|
|
71
|
+
# Beta API: Defend against the case where 'analysis' is no longer returned
|
|
72
|
+
if analysis_response is not None:
|
|
73
|
+
_validate_flow_analysis_output_handler(analysis_response)
|
|
74
|
+
click.echo()
|
|
75
|
+
|
|
76
|
+
scopes_response = result.get("scopes")
|
|
77
|
+
# Beta API: Defend against the case where 'scopes' is no longer returned
|
|
78
|
+
if scopes_response is not None:
|
|
79
|
+
_validate_flow_scope_output_handler(scopes_response)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _validate_flow_scope_output_handler(scopes_response: dict[str, str]) -> None:
|
|
83
|
+
# Always include User and Flow scopes
|
|
84
|
+
scopes_fields = [Field("RunAs", "RunAs"), Field("Scope", "scope")]
|
|
85
|
+
scope_entries = [
|
|
86
|
+
{"RunAs": k, "scope": scope}
|
|
87
|
+
for k, scopes in scopes_response.items()
|
|
88
|
+
for scope in scopes
|
|
89
|
+
]
|
|
90
|
+
click.echo("Discovered Scopes")
|
|
91
|
+
click.echo("=================")
|
|
92
|
+
if scope_entries:
|
|
93
|
+
display.render_table(
|
|
94
|
+
scope_entries,
|
|
95
|
+
fields=scopes_fields,
|
|
96
|
+
)
|
|
97
|
+
else:
|
|
98
|
+
click.echo("No scopes discovered")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _validate_flow_analysis_output_handler(analysis_response: dict[str, str]) -> None:
|
|
102
|
+
# Always include the analysis output
|
|
103
|
+
click.echo("Analysis")
|
|
104
|
+
click.echo("========")
|
|
105
|
+
if count := analysis_response.get("number_of_possibilities"):
|
|
106
|
+
click.echo(f"Possible State Traversals: {count}")
|
|
@@ -315,13 +315,13 @@ def _derive_missing_scopes(
|
|
|
315
315
|
user_identity_id = get_current_identity_id()
|
|
316
316
|
|
|
317
317
|
# get the user's Globus CLI consents
|
|
318
|
-
consents = auth_client.get_consents(user_identity_id)
|
|
318
|
+
consents = auth_client.get_consents(user_identity_id).to_forest()
|
|
319
319
|
|
|
320
320
|
# check the 'needs_data_access' scope names against the 3rd-order dependencies
|
|
321
321
|
# of the Timer scope and record the names of the ones which we need to request
|
|
322
322
|
will_request_data_access: list[str] = []
|
|
323
323
|
for name, scope_object in scopes_needed.items():
|
|
324
|
-
if not consents.
|
|
324
|
+
if not consents.meets_scope_requirements([str(scope_object)]):
|
|
325
325
|
will_request_data_access.append(name)
|
|
326
326
|
|
|
327
327
|
# return these ultimately filtered requirements
|
|
@@ -122,5 +122,7 @@ def _has_required_consent(
|
|
|
122
122
|
) -> bool:
|
|
123
123
|
auth_client = login_manager.get_auth_client()
|
|
124
124
|
user_identity_id = get_current_identity_id()
|
|
125
|
-
consents = auth_client.get_consents(user_identity_id)
|
|
126
|
-
|
|
125
|
+
consents = auth_client.get_consents(user_identity_id).to_forest()
|
|
126
|
+
# FIXME: this type ignore is temporary because `meets_scope_requirements()`
|
|
127
|
+
# has too tight of a type
|
|
128
|
+
return consents.meets_scope_requirements(required_scopes) # type: ignore[arg-type]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import textwrap
|
|
4
5
|
import typing as t
|
|
5
6
|
|
|
6
7
|
import click
|
|
@@ -20,6 +21,38 @@ def _pretty_json(data: dict, compact: bool = False) -> str:
|
|
|
20
21
|
return json.dumps(data, indent=2, separators=(",", ": "), sort_keys=True)
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
_JSONPATH_SPECIAL_CHARS = "[]'\"\\."
|
|
25
|
+
_JSONPATH_ESCAPE_MAP = str.maketrans(
|
|
26
|
+
{
|
|
27
|
+
"'": "\\'",
|
|
28
|
+
"\\": "\\\\",
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _jsonpath_from_pydantic_loc(loc: list[str | int]) -> str:
|
|
34
|
+
"""
|
|
35
|
+
Given a 'loc' from pydantic error data, convert it into a JSON Path expression.
|
|
36
|
+
|
|
37
|
+
Takes the following steps:
|
|
38
|
+
- turns integers into integer indices
|
|
39
|
+
- turns most strings into dotted access
|
|
40
|
+
- turns strings containing special characters into single-quoted bracket access
|
|
41
|
+
with ' and \\ escaped
|
|
42
|
+
"""
|
|
43
|
+
path = "$"
|
|
44
|
+
for part in loc:
|
|
45
|
+
if isinstance(part, int):
|
|
46
|
+
path += f"[{part}]"
|
|
47
|
+
else:
|
|
48
|
+
if any(c in part for c in _JSONPATH_SPECIAL_CHARS):
|
|
49
|
+
part = f"'{part.translate(_JSONPATH_ESCAPE_MAP)}'"
|
|
50
|
+
path += f"[{part}]"
|
|
51
|
+
else:
|
|
52
|
+
path += f".{part}"
|
|
53
|
+
return path
|
|
54
|
+
|
|
55
|
+
|
|
23
56
|
_DEFAULT_SESSION_REAUTH_MESSAGE = (
|
|
24
57
|
"The resource you are trying to access requires you to re-authenticate."
|
|
25
58
|
)
|
|
@@ -271,6 +304,82 @@ def searchapi_hook(exception: globus_sdk.SearchAPIError) -> None:
|
|
|
271
304
|
write_error_info("Search API Error", fields)
|
|
272
305
|
|
|
273
306
|
|
|
307
|
+
@sdk_error_handler(
|
|
308
|
+
error_class="FlowsAPIError",
|
|
309
|
+
condition=lambda err: err.code == "UNPROCESSABLE_ENTITY",
|
|
310
|
+
)
|
|
311
|
+
def flows_validation_error_hook(exception: globus_sdk.FlowsAPIError) -> None:
|
|
312
|
+
message_string: str = exception.raw_json["error"]["message"] # type: ignore[index]
|
|
313
|
+
details: str | list[dict[str, t.Any]] = exception.raw_json["error"]["detail"] # type: ignore[index] # noqa: E501
|
|
314
|
+
message_fields = [PrintableErrorField("message", message_string)]
|
|
315
|
+
|
|
316
|
+
# conditionally do this work if there are multiple details
|
|
317
|
+
if isinstance(details, list) and len(details) > 1:
|
|
318
|
+
num_errors = len(details)
|
|
319
|
+
# try to extract 'loc' and 'msg' from the details, but only
|
|
320
|
+
# update 'message_fields' if the data are present
|
|
321
|
+
try:
|
|
322
|
+
messages = [
|
|
323
|
+
f"{_jsonpath_from_pydantic_loc(data['loc'])}: {data['msg']}"
|
|
324
|
+
for data in details
|
|
325
|
+
]
|
|
326
|
+
except KeyError:
|
|
327
|
+
pass
|
|
328
|
+
else:
|
|
329
|
+
message_fields = [
|
|
330
|
+
PrintableErrorField(
|
|
331
|
+
"message", f"{num_errors} validation errors", multiline=True
|
|
332
|
+
),
|
|
333
|
+
PrintableErrorField(
|
|
334
|
+
"errors",
|
|
335
|
+
"\n".join(messages),
|
|
336
|
+
multiline=True,
|
|
337
|
+
),
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
write_error_info(
|
|
341
|
+
"Flows API Error",
|
|
342
|
+
[
|
|
343
|
+
PrintableErrorField("HTTP status", exception.http_status),
|
|
344
|
+
PrintableErrorField("code", exception.code),
|
|
345
|
+
*message_fields,
|
|
346
|
+
],
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@sdk_error_handler(error_class="FlowsAPIError")
|
|
351
|
+
def flows_error_hook(exception: globus_sdk.FlowsAPIError) -> None:
|
|
352
|
+
details: list[dict[str, t.Any]] | str = exception.raw_json["error"]["detail"] # type: ignore[index] # noqa: E501
|
|
353
|
+
detail_fields: list[PrintableErrorField] = []
|
|
354
|
+
|
|
355
|
+
# if the detail is a string, return that as a single field
|
|
356
|
+
if isinstance(details, str):
|
|
357
|
+
if len(details) > 120:
|
|
358
|
+
details = textwrap.fill(details, width=80)
|
|
359
|
+
detail_fields = [PrintableErrorField("detail", details, multiline=True)]
|
|
360
|
+
# if it's a list of objects, wrap them into a multiline detail field
|
|
361
|
+
else:
|
|
362
|
+
detail_fields = [
|
|
363
|
+
PrintableErrorField(
|
|
364
|
+
"detail",
|
|
365
|
+
"\n".join(_pretty_json(detail, compact=True) for detail in details),
|
|
366
|
+
multiline=True,
|
|
367
|
+
)
|
|
368
|
+
]
|
|
369
|
+
|
|
370
|
+
write_error_info(
|
|
371
|
+
"Flows API Error",
|
|
372
|
+
[
|
|
373
|
+
PrintableErrorField("HTTP status", exception.http_status),
|
|
374
|
+
PrintableErrorField("code", exception.code),
|
|
375
|
+
PrintableErrorField(
|
|
376
|
+
"message", exception.raw_json["error"]["message"] # type: ignore[index]
|
|
377
|
+
),
|
|
378
|
+
*detail_fields,
|
|
379
|
+
],
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
|
|
274
383
|
@sdk_error_handler(
|
|
275
384
|
error_class="AuthAPIError",
|
|
276
385
|
condition=lambda err: err.message == "invalid_grant",
|
|
@@ -7,6 +7,7 @@ import uuid
|
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
9
|
import globus_sdk
|
|
10
|
+
from globus_sdk.experimental.consents import ConsentForest
|
|
10
11
|
from globus_sdk.experimental.scope_parser import Scope
|
|
11
12
|
from globus_sdk.scopes import (
|
|
12
13
|
AuthScopes,
|
|
@@ -37,7 +38,7 @@ from .tokenstore import (
|
|
|
37
38
|
from .utils import get_current_identity_id, is_remote_session
|
|
38
39
|
|
|
39
40
|
if t.TYPE_CHECKING:
|
|
40
|
-
from ..services.auth import
|
|
41
|
+
from ..services.auth import CustomAuthClient
|
|
41
42
|
from ..services.gcs import CustomGCSClient
|
|
42
43
|
from ..services.transfer import CustomTransferClient
|
|
43
44
|
|
|
@@ -178,14 +179,19 @@ class LoginManager:
|
|
|
178
179
|
else:
|
|
179
180
|
# If there are dependent scopes all required scope paths are present in the
|
|
180
181
|
# user's cached consent forest.
|
|
181
|
-
|
|
182
|
+
#
|
|
183
|
+
# FIXME: this type ignore is temporary because `meets_scope_requirements()`
|
|
184
|
+
# has too tight of a type
|
|
185
|
+
return self._cached_consent_forest.meets_scope_requirements(
|
|
186
|
+
required_scopes # type: ignore[arg-type]
|
|
187
|
+
)
|
|
182
188
|
|
|
183
189
|
@property
|
|
184
190
|
@functools.lru_cache(maxsize=1) # noqa: B019
|
|
185
|
-
def _cached_consent_forest(self) ->
|
|
191
|
+
def _cached_consent_forest(self) -> ConsentForest:
|
|
186
192
|
identity_id = get_current_identity_id()
|
|
187
193
|
|
|
188
|
-
return self.get_auth_client().get_consents(identity_id)
|
|
194
|
+
return self.get_auth_client().get_consents(identity_id).to_forest()
|
|
189
195
|
|
|
190
196
|
def run_login_flow(
|
|
191
197
|
self,
|
|
@@ -212,6 +212,10 @@ class TopLevelGroup(GlobusCommandGroup):
|
|
|
212
212
|
def invoke(self, ctx: click.Context) -> t.Any:
|
|
213
213
|
try:
|
|
214
214
|
return super().invoke(ctx)
|
|
215
|
+
# explicitly re-raise any IOError (e.g. broken pipe) in order to engage
|
|
216
|
+
# click's existing handling of broken pipes
|
|
217
|
+
except OSError:
|
|
218
|
+
raise
|
|
215
219
|
except Exception:
|
|
216
220
|
# mypy thinks that exc_info could be (None, None, None), but... nope. False.
|
|
217
221
|
custom_except_hook(sys.exc_info()) # type: ignore[arg-type]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
import globus_sdk
|
|
7
|
+
import globus_sdk.scopes
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _is_uuid(s: str) -> bool:
|
|
11
|
+
try:
|
|
12
|
+
uuid.UUID(s)
|
|
13
|
+
return True
|
|
14
|
+
except ValueError:
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GetIdentitiesKwargs(t.TypedDict, total=False):
|
|
19
|
+
provision: bool
|
|
20
|
+
usernames: str
|
|
21
|
+
ids: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CustomAuthClient(globus_sdk.AuthClient):
|
|
25
|
+
def _lookup_identity_field(
|
|
26
|
+
self,
|
|
27
|
+
id_name: str | None = None,
|
|
28
|
+
id_id: str | None = None,
|
|
29
|
+
field: t.Literal["id", "username"] = "id",
|
|
30
|
+
provision: bool = False,
|
|
31
|
+
) -> str | None:
|
|
32
|
+
assert (id_name or id_id) and not (id_name and id_id)
|
|
33
|
+
|
|
34
|
+
kw: GetIdentitiesKwargs = dict(provision=provision)
|
|
35
|
+
if id_name:
|
|
36
|
+
kw["usernames"] = id_name
|
|
37
|
+
elif id_id:
|
|
38
|
+
kw["ids"] = id_id
|
|
39
|
+
else:
|
|
40
|
+
raise NotImplementedError("must provide id or name")
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
value = self.get_identities(**kw)["identities"][0][field]
|
|
44
|
+
# capture any failure to lookup this data, including:
|
|
45
|
+
# - identity doesn't exist (`identities=[]`)
|
|
46
|
+
# - field is missing
|
|
47
|
+
except LookupError:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
if not isinstance(value, str):
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
return value
|
|
54
|
+
|
|
55
|
+
# this method has been added in the latest SDK versions but is not
|
|
56
|
+
# present in the last release
|
|
57
|
+
# this is therefore temporary until an SDK release ships with the change
|
|
58
|
+
# so that CLI testing against SDK main can succeed
|
|
59
|
+
if not hasattr(globus_sdk.AuthClient, "userinfo"):
|
|
60
|
+
userinfo = globus_sdk.AuthClient.oauth2_userinfo
|
|
61
|
+
|
|
62
|
+
@t.overload
|
|
63
|
+
def maybe_lookup_identity_id(
|
|
64
|
+
self, identity_name: str, provision: t.Literal[True]
|
|
65
|
+
) -> str: ...
|
|
66
|
+
|
|
67
|
+
@t.overload
|
|
68
|
+
def maybe_lookup_identity_id(
|
|
69
|
+
self, identity_name: str, provision: bool = False
|
|
70
|
+
) -> str | None: ...
|
|
71
|
+
|
|
72
|
+
def maybe_lookup_identity_id(
|
|
73
|
+
self, identity_name: str, provision: bool = False
|
|
74
|
+
) -> str | None:
|
|
75
|
+
if _is_uuid(identity_name):
|
|
76
|
+
return identity_name
|
|
77
|
+
else:
|
|
78
|
+
return self._lookup_identity_field(
|
|
79
|
+
id_name=identity_name, provision=provision
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def lookup_identity_name(self, identity_id: str) -> str | None:
|
|
83
|
+
return self._lookup_identity_field(id_id=identity_id, field="username")
|
|
@@ -170,7 +170,6 @@ class Renderer:
|
|
|
170
170
|
TABLE = TextMode.text_table
|
|
171
171
|
SILENT = TextMode.silent
|
|
172
172
|
JSON = TextMode.json
|
|
173
|
-
TABLE = TextMode.text_table
|
|
174
173
|
RECORD = TextMode.text_record
|
|
175
174
|
RECORD_LIST = TextMode.text_record_list
|
|
176
175
|
RAW = TextMode.text_raw
|
|
@@ -200,6 +199,14 @@ class Renderer:
|
|
|
200
199
|
sort_json_keys=sort_json_keys,
|
|
201
200
|
)
|
|
202
201
|
|
|
202
|
+
def render_table(
|
|
203
|
+
self,
|
|
204
|
+
iterable: t.Iterable[t.Any],
|
|
205
|
+
fields: list[Field],
|
|
206
|
+
print_headers: bool = True,
|
|
207
|
+
) -> None:
|
|
208
|
+
print_table(iterable, fields, print_headers)
|
|
209
|
+
|
|
203
210
|
|
|
204
211
|
display = Renderer()
|
|
205
212
|
|
|
@@ -7,7 +7,7 @@ if t.TYPE_CHECKING:
|
|
|
7
7
|
|
|
8
8
|
# single source of truth for package version,
|
|
9
9
|
# see https://packaging.python.org/en/latest/single_source_version/
|
|
10
|
-
__version__ = "3.
|
|
10
|
+
__version__ = "3.28.0"
|
|
11
11
|
|
|
12
12
|
# app name to send as part of SDK requests
|
|
13
13
|
app_name = f"Globus CLI v{__version__}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: globus-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.28.0
|
|
4
4
|
Summary: Globus CLI
|
|
5
5
|
Author-email: Stephen Rosen <sirosen@globus.org>
|
|
6
6
|
Project-URL: homepage, https://github.com/globus/globus-cli
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: globus-sdk==3.
|
|
21
|
+
Requires-Dist: globus-sdk==3.41.0
|
|
22
22
|
Requires-Dist: click<9,>=8.1.4
|
|
23
23
|
Requires-Dist: jmespath==1.0.1
|
|
24
24
|
Requires-Dist: packaging>=17.0
|
|
@@ -105,6 +105,7 @@ src/globus_cli/commands/flows/list.py
|
|
|
105
105
|
src/globus_cli/commands/flows/show.py
|
|
106
106
|
src/globus_cli/commands/flows/start.py
|
|
107
107
|
src/globus_cli/commands/flows/update.py
|
|
108
|
+
src/globus_cli/commands/flows/validate.py
|
|
108
109
|
src/globus_cli/commands/flows/run/__init__.py
|
|
109
110
|
src/globus_cli/commands/flows/run/cancel.py
|
|
110
111
|
src/globus_cli/commands/flows/run/delete.py
|