globus-cli 3.36.0__tar.gz → 3.38.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.36.0/src/globus_cli.egg-info → globus_cli-3.38.0}/PKG-INFO +3 -3
- {globus_cli-3.36.0 → globus_cli-3.38.0}/pyproject.toml +4 -5
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/role/__init__.py +1 -0
- globus_cli-3.38.0/src/globus_cli/commands/collection/role/delete.py +23 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/delete.py +0 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/__init__.py +4 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/_common.py +21 -0
- globus_cli-3.38.0/src/globus_cli/commands/group/set_subscription_admin_verified.py +47 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/update.py +26 -2
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/rm.py +0 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/create/transfer.py +15 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/transfer.py +2 -27
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/scopes.py +0 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/__init__.py +2 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shared_options/transfer_task_options.py +43 -0
- globus_cli-3.38.0/src/globus_cli/termio/printers/unix_printer/_formatter.py +221 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/unix_printer/unix_printer.py +7 -4
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/version.py +1 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0/src/globus_cli.egg-info}/PKG-INFO +3 -3
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli.egg-info/SOURCES.txt +3 -1
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli.egg-info/requires.txt +2 -2
- globus_cli-3.36.0/src/globus_cli/termio/printers/unix_printer/awscli_text.py +0 -127
- {globus_cli-3.36.0 → globus_cli-3.38.0}/LICENSE +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/README.rst +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/setup.cfg +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/__main__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/_click_compat.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/_warnings.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/_removal_stub.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/api.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/rename.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/bookmark/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/cli_profile_list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/create/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/create/guest.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/create/mapped.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/role/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/role/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/collection/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/local_id.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/my_shared_endpoint_list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/permission/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/role/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/search.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/set_subscription_id.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/storage_gateway/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/storage_gateway/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/create/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/create/from_json.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/create/posix.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/create/s3.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/update/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/endpoint/user_credential/update/from_json.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/cancel.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/resume.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/show_definition.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/show_logs.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/run/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/start.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/flows/validate.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/create/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/create/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/create/guest.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/create/mapped.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/set_subscription_admin_verified.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/set_subscription_id.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/update/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/update/guest.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcp/update/mapped.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/role/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/set_subscription_id.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/gcs/endpoint/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/get_identities.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/get_by_subscription.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/get_subscription_info.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/invite/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/invite/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/invite/accept.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/invite/decline.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/join.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/leave.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/add.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/approve.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/invite.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/reject.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/member/remove.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/set_policies.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/group/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/list_commands.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/login.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/logout.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/ls.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/mkdir.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/rename.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/delete_by_query.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/role/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/role/create.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/role/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/role/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/index/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/ingest.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/query.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/subject/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/subject/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/subject/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/task/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/task/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/search/task/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/session/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/session/consent.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/session/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/session/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/stat.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/cancel.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/event_list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/generate_submission_id.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/pause_info.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/task/wait.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/_common.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/create/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/delete.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/list.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/pause.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/resume.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/timer/show.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/update.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/version.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/commands/whoami.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/constants.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/endpointish/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/endpointish/endpointish.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/endpointish/entity_type.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/endpointish/errors.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/auth_requirements.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/authapi_hooks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/endpoint_types.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/flows_hooks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/generic_hooks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/search_hooks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/hooks/transfer_hooks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/messages.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/exception_handling/registry.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/globus_cli_flake8.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/_old_config.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/auth_flows.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/client_login.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/context.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/errors.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/local_server.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/manager.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/storage.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/login_manager/utils.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/command_state.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/commands.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/mutex_group.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_classes.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/delimited.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/endpoint_plus_path.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/guest_activity_notify_param.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/identity_type.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/json_strorfile.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/location.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/notify_param.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/nullable.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/task_path.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/param_types/timedelta.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shared_callbacks.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shared_options/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shared_options/endpointish.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shared_options/id_args.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/parsing/shell_completion.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/reflect.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/auth.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/gcs.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/transfer/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/transfer/activation.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/transfer/client.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/transfer/data.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/services/transfer/recursive_ls.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/_display.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/context.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/errors.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/field.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/formatters/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/formatters/auth.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/formatters/base.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/formatters/compound.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/formatters/primitive.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/base.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/custom_printer.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/json_printer.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/record_printer.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/table_printer.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/printers/unix_printer/__init__.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/termio/server_timing.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/types.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli/utils.py +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli.egg-info/dependency_links.txt +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli.egg-info/entry_points.txt +0 -0
- {globus_cli-3.36.0 → globus_cli-3.38.0}/src/globus_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: globus-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.38.0
|
|
4
4
|
Summary: Globus CLI
|
|
5
5
|
Author-email: Stephen Rosen <sirosen@globus.org>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -18,8 +18,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: globus-sdk==3.
|
|
22
|
-
Requires-Dist: click<
|
|
21
|
+
Requires-Dist: globus-sdk==3.63.0
|
|
22
|
+
Requires-Dist: click<8.4,>=8.1.4
|
|
23
23
|
Requires-Dist: jmespath==1.0.1
|
|
24
24
|
Requires-Dist: packaging>=17.0
|
|
25
25
|
Requires-Dist: typing_extensions>=4.0; python_version < "3.11"
|
|
@@ -28,8 +28,8 @@ classifiers = [
|
|
|
28
28
|
]
|
|
29
29
|
requires-python = ">=3.9"
|
|
30
30
|
dependencies = [
|
|
31
|
-
"globus-sdk==3.
|
|
32
|
-
"click>=8.1.4,<
|
|
31
|
+
"globus-sdk==3.63.0",
|
|
32
|
+
"click>=8.1.4,<8.4",
|
|
33
33
|
"jmespath==1.0.1",
|
|
34
34
|
"packaging>=17.0",
|
|
35
35
|
"typing_extensions>=4.0;python_version<'3.11'",
|
|
@@ -56,7 +56,7 @@ test = [
|
|
|
56
56
|
"pytest>=7",
|
|
57
57
|
"pytest-xdist<4",
|
|
58
58
|
"pytest-timeout<3",
|
|
59
|
-
"click-type-test==1.
|
|
59
|
+
"click-type-test==1.3.0;python_version>='3.10'",
|
|
60
60
|
"responses==0.25.8",
|
|
61
61
|
]
|
|
62
62
|
test-mindeps = [
|
|
@@ -69,7 +69,7 @@ test-mindeps = [
|
|
|
69
69
|
"typing_extensions==4.0",
|
|
70
70
|
]
|
|
71
71
|
typing = [
|
|
72
|
-
"mypy==1.
|
|
72
|
+
"mypy==1.18.2",
|
|
73
73
|
"types-jwt",
|
|
74
74
|
"types-requests",
|
|
75
75
|
"types-jmespath",
|
|
@@ -151,5 +151,4 @@ disallow_untyped_defs = false
|
|
|
151
151
|
disallow_incomplete_defs = false
|
|
152
152
|
module = [
|
|
153
153
|
"globus_cli.services.transfer.recursive_ls",
|
|
154
|
-
"globus_cli.termio.printers.unix_printer.awscli_text",
|
|
155
154
|
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from globus_cli.login_manager import LoginManager
|
|
6
|
+
from globus_cli.parsing import collection_id_arg, command
|
|
7
|
+
from globus_cli.termio import display
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@command("delete")
|
|
11
|
+
@collection_id_arg
|
|
12
|
+
@click.argument("ROLE_ID", type=click.UUID)
|
|
13
|
+
@LoginManager.requires_login("transfer")
|
|
14
|
+
def delete_command(
|
|
15
|
+
login_manager: LoginManager,
|
|
16
|
+
*,
|
|
17
|
+
collection_id: uuid.UUID,
|
|
18
|
+
role_id: uuid.UUID,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Delete a particular role on a Collection."""
|
|
21
|
+
gcs_client = login_manager.get_gcs_client(collection_id=collection_id)
|
|
22
|
+
res = gcs_client.delete_role(role_id)
|
|
23
|
+
display(res, text_mode=display.RAW, response_key="code")
|
|
@@ -19,6 +19,10 @@ from globus_cli.parsing import group
|
|
|
19
19
|
),
|
|
20
20
|
"get-by-subscription": (".get_by_subscription", "group_get_by_subscription"),
|
|
21
21
|
"update": (".update", "group_update"),
|
|
22
|
+
"set-subscription-admin-verified": (
|
|
23
|
+
".set_subscription_admin_verified",
|
|
24
|
+
"group_set_subscription_admin_verified",
|
|
25
|
+
),
|
|
22
26
|
},
|
|
23
27
|
)
|
|
24
28
|
def group_command() -> None:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import typing as t
|
|
4
|
+
import uuid
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
7
|
|
|
8
|
+
from globus_cli.constants import EXPLICIT_NULL, ExplicitNullType
|
|
7
9
|
from globus_cli.termio import Field, formatters
|
|
8
10
|
from globus_cli.types import AnyCommand
|
|
9
11
|
|
|
@@ -74,3 +76,22 @@ GROUP_FIELDS_W_SUBSCRIPTION = (
|
|
|
74
76
|
|
|
75
77
|
def group_id_arg(f: C) -> C:
|
|
76
78
|
return click.argument("GROUP_ID", type=click.UUID)(f)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class GroupSubscriptionVerifiedIdType(click.ParamType):
|
|
82
|
+
name = "TEXT"
|
|
83
|
+
|
|
84
|
+
def convert(
|
|
85
|
+
self, value: str, param: click.Parameter | None, ctx: click.Context | None
|
|
86
|
+
) -> uuid.UUID | ExplicitNullType:
|
|
87
|
+
if value.lower() == "null":
|
|
88
|
+
return EXPLICIT_NULL
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
return uuid.UUID(value)
|
|
92
|
+
except ValueError:
|
|
93
|
+
msg = (
|
|
94
|
+
f"{value} is invalid. Expected either a UUID or the special value "
|
|
95
|
+
'"null"'
|
|
96
|
+
)
|
|
97
|
+
self.fail(msg, param, ctx)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from globus_cli.constants import EXPLICIT_NULL, ExplicitNullType
|
|
8
|
+
from globus_cli.login_manager import LoginManager
|
|
9
|
+
from globus_cli.parsing import command
|
|
10
|
+
from globus_cli.termio import display
|
|
11
|
+
|
|
12
|
+
from ._common import GroupSubscriptionVerifiedIdType, group_id_arg
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@command("set-subscription-admin-verified")
|
|
16
|
+
@group_id_arg
|
|
17
|
+
@click.argument(
|
|
18
|
+
"SUBSCRIPTION_ID",
|
|
19
|
+
type=GroupSubscriptionVerifiedIdType(),
|
|
20
|
+
metavar="[SUBSCRIPTION_ID|null]",
|
|
21
|
+
)
|
|
22
|
+
@LoginManager.requires_login("groups")
|
|
23
|
+
def group_set_subscription_admin_verified(
|
|
24
|
+
login_manager: LoginManager,
|
|
25
|
+
*,
|
|
26
|
+
group_id: uuid.UUID,
|
|
27
|
+
subscription_id: uuid.UUID | ExplicitNullType,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Mark a group as a subscription-verified resource.
|
|
31
|
+
|
|
32
|
+
SUBSCRIPTION_ID is the ID of the subscription to which this group shall belong,
|
|
33
|
+
or "null" to mark the group as non-verified.
|
|
34
|
+
"""
|
|
35
|
+
groups_client = login_manager.get_groups_client()
|
|
36
|
+
|
|
37
|
+
admin_verified_id: str | None = (
|
|
38
|
+
None if subscription_id == EXPLICIT_NULL else str(subscription_id)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
response = groups_client.set_subscription_admin_verified(
|
|
42
|
+
group_id, admin_verified_id
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
display(
|
|
46
|
+
response, simple_text="Group subscription verification updated successfully"
|
|
47
|
+
)
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import typing as t
|
|
3
4
|
import uuid
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
7
|
|
|
8
|
+
from globus_cli.constants import EXPLICIT_NULL, ExplicitNullType
|
|
7
9
|
from globus_cli.login_manager import LoginManager
|
|
8
10
|
from globus_cli.parsing import command
|
|
9
11
|
from globus_cli.termio import display
|
|
10
12
|
|
|
11
|
-
from ._common import group_id_arg
|
|
13
|
+
from ._common import GroupSubscriptionVerifiedIdType, group_id_arg
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
@command("update")
|
|
@@ -18,6 +20,14 @@ from ._common import group_id_arg
|
|
|
18
20
|
@click.option(
|
|
19
21
|
"--terms-and-conditions", help="Terms and conditions for group membership"
|
|
20
22
|
)
|
|
23
|
+
@click.option(
|
|
24
|
+
"--subscription-admin-verified-id",
|
|
25
|
+
type=GroupSubscriptionVerifiedIdType(),
|
|
26
|
+
help=(
|
|
27
|
+
"The ID of the subscription to which the group belongs. Use the special value"
|
|
28
|
+
' "null" to remove subscription verification from the group.'
|
|
29
|
+
),
|
|
30
|
+
)
|
|
21
31
|
@LoginManager.requires_login("groups")
|
|
22
32
|
def group_update(
|
|
23
33
|
login_manager: LoginManager,
|
|
@@ -26,6 +36,7 @@ def group_update(
|
|
|
26
36
|
name: str | None,
|
|
27
37
|
description: str | None,
|
|
28
38
|
terms_and_conditions: str | None,
|
|
39
|
+
subscription_admin_verified_id: uuid.UUID | None | ExplicitNullType,
|
|
29
40
|
) -> None:
|
|
30
41
|
"""Update an existing group."""
|
|
31
42
|
groups_client = login_manager.get_groups_client()
|
|
@@ -36,7 +47,7 @@ def group_update(
|
|
|
36
47
|
# assemble put data using existing values for any field not given
|
|
37
48
|
# note that the API only allows modification of certain fields
|
|
38
49
|
# https://groups.api.globus.org/redoc#tag/groups/operation/update_group_v2_groups__group_id__put
|
|
39
|
-
data = {}
|
|
50
|
+
data: dict[str, t.Any] = {}
|
|
40
51
|
for attrname, argval in (
|
|
41
52
|
("name", name),
|
|
42
53
|
("description", description),
|
|
@@ -47,6 +58,19 @@ def group_update(
|
|
|
47
58
|
else:
|
|
48
59
|
data[attrname] = group[attrname]
|
|
49
60
|
|
|
61
|
+
if subscription_admin_verified_id == EXPLICIT_NULL:
|
|
62
|
+
data["subscription_admin_verified_id"] = None
|
|
63
|
+
elif (
|
|
64
|
+
subscription_admin_verified_id == group["subscription_admin_verified_id"]
|
|
65
|
+
or subscription_admin_verified_id is None
|
|
66
|
+
):
|
|
67
|
+
data["subscription_admin_verified_id"] = group["subscription_admin_verified_id"]
|
|
68
|
+
else:
|
|
69
|
+
raise click.UsageError(
|
|
70
|
+
"To set the `subscription_admin_verified_id` to a new, non-null value, use "
|
|
71
|
+
"`globus group set-subscription-admin-verified`"
|
|
72
|
+
)
|
|
73
|
+
|
|
50
74
|
response = groups_client.update_group(group_id, data)
|
|
51
75
|
|
|
52
76
|
display(response, simple_text="Group updated successfully")
|
|
@@ -16,6 +16,7 @@ from globus_cli.parsing import (
|
|
|
16
16
|
command,
|
|
17
17
|
encrypt_data_option,
|
|
18
18
|
fail_on_quota_errors_option,
|
|
19
|
+
filter_rule_options,
|
|
19
20
|
mutex_option_group,
|
|
20
21
|
preserve_timestamp_option,
|
|
21
22
|
skip_source_errors_option,
|
|
@@ -54,7 +55,14 @@ e.g. '1h30m', '500s', '10d'
|
|
|
54
55
|
"""
|
|
55
56
|
|
|
56
57
|
|
|
57
|
-
@command(
|
|
58
|
+
@command(
|
|
59
|
+
"transfer",
|
|
60
|
+
opts_to_combine={ # see 'filter_rule_options' for why this is needed
|
|
61
|
+
"include": "filter_rules",
|
|
62
|
+
"exclude": "filter_rules",
|
|
63
|
+
},
|
|
64
|
+
short_help="Create a recurring transfer timer.",
|
|
65
|
+
)
|
|
58
66
|
@click.argument(
|
|
59
67
|
"source", metavar="SOURCE_ENDPOINT_ID[:SOURCE_PATH]", type=ENDPOINT_PLUS_OPTPATH
|
|
60
68
|
)
|
|
@@ -70,6 +78,7 @@ e.g. '1h30m', '500s', '10d'
|
|
|
70
78
|
@skip_source_errors_option
|
|
71
79
|
@fail_on_quota_errors_option
|
|
72
80
|
@task_notify_option
|
|
81
|
+
@filter_rule_options
|
|
73
82
|
@click.option(
|
|
74
83
|
"--start",
|
|
75
84
|
type=click.DateTime(formats=DATETIME_FORMATS),
|
|
@@ -139,6 +148,7 @@ def transfer_command(
|
|
|
139
148
|
preserve_timestamp: bool,
|
|
140
149
|
skip_source_errors: bool,
|
|
141
150
|
fail_on_quota_errors: bool,
|
|
151
|
+
filter_rules: list[tuple[t.Literal["include", "exclude"], str]],
|
|
142
152
|
notify: dict[str, bool],
|
|
143
153
|
) -> None:
|
|
144
154
|
"""
|
|
@@ -305,6 +315,10 @@ def transfer_command(
|
|
|
305
315
|
**notify, # type: ignore[arg-type]
|
|
306
316
|
)
|
|
307
317
|
|
|
318
|
+
for rule in filter_rules:
|
|
319
|
+
method, name = rule
|
|
320
|
+
transfer_data.add_filter_rule(method=method, name=name, type="file")
|
|
321
|
+
|
|
308
322
|
if batch:
|
|
309
323
|
add_batch_to_transfer_data(
|
|
310
324
|
cmd_source_path, cmd_dest_path, None, transfer_data, batch
|
|
@@ -12,6 +12,7 @@ from globus_cli.parsing import (
|
|
|
12
12
|
command,
|
|
13
13
|
encrypt_data_option,
|
|
14
14
|
fail_on_quota_errors_option,
|
|
15
|
+
filter_rule_options,
|
|
15
16
|
mutex_option_group,
|
|
16
17
|
preserve_timestamp_option,
|
|
17
18
|
skip_source_errors_option,
|
|
@@ -136,6 +137,7 @@ fi
|
|
|
136
137
|
@encrypt_data_option(aliases=("--encrypt",))
|
|
137
138
|
@skip_source_errors_option
|
|
138
139
|
@fail_on_quota_errors_option
|
|
140
|
+
@filter_rule_options
|
|
139
141
|
@click.option(
|
|
140
142
|
"--delete",
|
|
141
143
|
is_flag=True,
|
|
@@ -170,32 +172,6 @@ fi
|
|
|
170
172
|
show_default=True,
|
|
171
173
|
help="Specify an algorithm for --external-checksum or --verify-checksum",
|
|
172
174
|
)
|
|
173
|
-
@click.option(
|
|
174
|
-
"--include",
|
|
175
|
-
multiple=True,
|
|
176
|
-
show_default=True,
|
|
177
|
-
expose_value=False, # this is combined into the filter_rules parameter
|
|
178
|
-
help=(
|
|
179
|
-
"Include files found with names that match the given pattern in "
|
|
180
|
-
'recursive transfers. Pattern may include "*", "?", or "[]" for Unix-style '
|
|
181
|
-
"globbing. This option can be given multiple times along with "
|
|
182
|
-
"--exclude to control which files are transferred, with earlier "
|
|
183
|
-
"options having priority."
|
|
184
|
-
),
|
|
185
|
-
)
|
|
186
|
-
@click.option(
|
|
187
|
-
"--exclude",
|
|
188
|
-
multiple=True,
|
|
189
|
-
show_default=True,
|
|
190
|
-
expose_value=False, # this is combined into the filter_rules parameter
|
|
191
|
-
help=(
|
|
192
|
-
"Exclude files found with names that match the given pattern in "
|
|
193
|
-
'recursive transfers. Pattern may include "*", "?", or "[]" for Unix-style '
|
|
194
|
-
"globbing. This option can be given multiple times along with "
|
|
195
|
-
"--include to control which files are transferred, with earlier "
|
|
196
|
-
"options having priority."
|
|
197
|
-
),
|
|
198
|
-
)
|
|
199
175
|
@click.option(
|
|
200
176
|
"--source-local-user",
|
|
201
177
|
help=(
|
|
@@ -392,7 +368,6 @@ def transfer_command(
|
|
|
392
368
|
deadline=deadline,
|
|
393
369
|
skip_source_errors=skip_source_errors,
|
|
394
370
|
fail_on_quota_errors=fail_on_quota_errors,
|
|
395
|
-
skip_activation_check=skip_activation_check,
|
|
396
371
|
delete_destination_extra=(delete or delete_destination_extra),
|
|
397
372
|
source_local_user=source_local_user,
|
|
398
373
|
destination_local_user=destination_local_user,
|
|
@@ -38,6 +38,7 @@ from .shared_options.id_args import (
|
|
|
38
38
|
from .shared_options.transfer_task_options import (
|
|
39
39
|
encrypt_data_option,
|
|
40
40
|
fail_on_quota_errors_option,
|
|
41
|
+
filter_rule_options,
|
|
41
42
|
preserve_timestamp_option,
|
|
42
43
|
skip_source_errors_option,
|
|
43
44
|
sync_level_option,
|
|
@@ -84,6 +85,7 @@ __all__ = [
|
|
|
84
85
|
"sync_level_option",
|
|
85
86
|
"task_notify_option",
|
|
86
87
|
"fail_on_quota_errors_option",
|
|
88
|
+
"filter_rule_options",
|
|
87
89
|
"encrypt_data_option",
|
|
88
90
|
"preserve_timestamp_option",
|
|
89
91
|
"skip_source_errors_option",
|
|
@@ -125,3 +125,46 @@ def encrypt_data_option(*, aliases: tuple[str, ...] = ()) -> t.Callable[[C], C]:
|
|
|
125
125
|
)(f)
|
|
126
126
|
|
|
127
127
|
return decorator
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def filter_rule_options(f: C) -> C:
|
|
131
|
+
"""
|
|
132
|
+
Use of this decorator must be used with
|
|
133
|
+
|
|
134
|
+
opts_to_combine={
|
|
135
|
+
"include": "filter_rules",
|
|
136
|
+
"exclude": "filter_rules",
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
in order to produce correct `filter_rules` list.
|
|
140
|
+
|
|
141
|
+
The order of `--include` and `--exclude` determines behavior, and we have to
|
|
142
|
+
modify parsing to get that ordering information.
|
|
143
|
+
"""
|
|
144
|
+
f = click.option(
|
|
145
|
+
"--include",
|
|
146
|
+
multiple=True,
|
|
147
|
+
show_default=True,
|
|
148
|
+
expose_value=False, # this is combined into the filter_rules parameter
|
|
149
|
+
help=(
|
|
150
|
+
"Include files found with names that match the given pattern in "
|
|
151
|
+
'recursive transfers. Pattern may include "*", "?", or "[]" for Unix-style '
|
|
152
|
+
"globbing. This option can be given multiple times along with "
|
|
153
|
+
"--exclude to control which files are transferred, with earlier "
|
|
154
|
+
"options having priority."
|
|
155
|
+
),
|
|
156
|
+
)(f)
|
|
157
|
+
f = click.option(
|
|
158
|
+
"--exclude",
|
|
159
|
+
multiple=True,
|
|
160
|
+
show_default=True,
|
|
161
|
+
expose_value=False, # this is combined into the filter_rules parameter
|
|
162
|
+
help=(
|
|
163
|
+
"Exclude files found with names that match the given pattern in "
|
|
164
|
+
'recursive transfers. Pattern may include "*", "?", or "[]" for Unix-style '
|
|
165
|
+
"globbing. This option can be given multiple times along with "
|
|
166
|
+
"--include to control which files are transferred, with earlier "
|
|
167
|
+
"options having priority."
|
|
168
|
+
),
|
|
169
|
+
)(f)
|
|
170
|
+
return f
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import typing as t
|
|
5
|
+
from itertools import chain
|
|
6
|
+
|
|
7
|
+
if sys.version_info >= (3, 10):
|
|
8
|
+
from typing import TypeAlias
|
|
9
|
+
else:
|
|
10
|
+
from typing_extensions import TypeAlias
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Scalar: TypeAlias = "str | int | float | bool | None"
|
|
14
|
+
NonScalar: TypeAlias = "list[Scalar | NonScalar] | dict[str, Scalar | NonScalar]"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UnixFormattingError(ValueError):
|
|
18
|
+
"""Class of errors indicating that the data could not be formatted."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def emit_any_value(item: Scalar | NonScalar) -> t.Iterator[str]:
|
|
22
|
+
"""
|
|
23
|
+
Emission of values is defined as yielding back each line of output.
|
|
24
|
+
|
|
25
|
+
Lists and dicts are handled specially. Any scalar value is just passed to Python
|
|
26
|
+
``str()``. Note that this means that null becomes "None" in our output.
|
|
27
|
+
"""
|
|
28
|
+
if isinstance(item, list):
|
|
29
|
+
yield from emit_list(item)
|
|
30
|
+
elif isinstance(item, dict):
|
|
31
|
+
yield from emit_dict(item)
|
|
32
|
+
else:
|
|
33
|
+
yield str(item)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def emit_list(
|
|
37
|
+
elements: list[Scalar | NonScalar],
|
|
38
|
+
identifier: str | None = None,
|
|
39
|
+
) -> t.Iterator[str]:
|
|
40
|
+
"""
|
|
41
|
+
Given a list, and optionally some identifier used to tag the output, emit lines of
|
|
42
|
+
output.
|
|
43
|
+
|
|
44
|
+
Supports:
|
|
45
|
+
list[dict] , list[scalar] , and list[list | scalar]
|
|
46
|
+
|
|
47
|
+
If the input mixes dicts and non-dict values, this function will raise a ValueError.
|
|
48
|
+
"""
|
|
49
|
+
# empty lists disappear in the output
|
|
50
|
+
if not elements:
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
# across these branches, mypy does not correctly narrow the type of `elements`
|
|
54
|
+
# so we need to type-ignore the argument type
|
|
55
|
+
if all(isinstance(item, dict) for item in elements):
|
|
56
|
+
yield from emit_list_of_dicts(
|
|
57
|
+
elements, # type: ignore[arg-type]
|
|
58
|
+
identifier=identifier,
|
|
59
|
+
)
|
|
60
|
+
elif any(isinstance(item, dict) for item in elements):
|
|
61
|
+
raise UnixFormattingError(
|
|
62
|
+
"Formatter cannot handle arrays which mix JSON objects "
|
|
63
|
+
"with other datatypes."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
elif any(isinstance(item, list) for item in elements):
|
|
67
|
+
yield from emit_list_containing_lists(
|
|
68
|
+
elements, # type: ignore[arg-type]
|
|
69
|
+
identifier=identifier,
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
yield from emit_scalar_list(
|
|
73
|
+
elements, # type: ignore[arg-type]
|
|
74
|
+
identifier=identifier,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def emit_scalar_list(
|
|
79
|
+
elements: list[Scalar], identifier: str | None = None
|
|
80
|
+
) -> t.Iterator[str]:
|
|
81
|
+
"""
|
|
82
|
+
Emit a list of scalars, with or without an identifier.
|
|
83
|
+
|
|
84
|
+
Given an identifier, each element is placed on a separate line of output:
|
|
85
|
+
|
|
86
|
+
>>> emit_scalar_list([1, 2], identifier="FOO")
|
|
87
|
+
FOO\t1
|
|
88
|
+
FOO\t2
|
|
89
|
+
|
|
90
|
+
Without an identifier, all elements are placed on the same line:
|
|
91
|
+
|
|
92
|
+
>>> emit_scalar_list([1, 2], identifier="FOO")
|
|
93
|
+
1\t2
|
|
94
|
+
"""
|
|
95
|
+
if identifier is not None:
|
|
96
|
+
for item in elements:
|
|
97
|
+
yield f"{identifier}\t{item}"
|
|
98
|
+
else:
|
|
99
|
+
yield "\t".join(str(item) for item in elements)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def emit_list_containing_lists(
|
|
103
|
+
elements: list[Scalar | list[Scalar | NonScalar]],
|
|
104
|
+
identifier: str | None = None,
|
|
105
|
+
) -> t.Iterator[str]:
|
|
106
|
+
"""
|
|
107
|
+
Emit a list which contains nested lists, potentially mixed with scalars.
|
|
108
|
+
First, the scalars are split off and emitted, then all of the nested lists are
|
|
109
|
+
emitted in order of appearance.
|
|
110
|
+
"""
|
|
111
|
+
scalars: list[Scalar] = []
|
|
112
|
+
nested: list[list[Scalar | NonScalar]] = []
|
|
113
|
+
for item in elements:
|
|
114
|
+
if isinstance(item, list):
|
|
115
|
+
nested.append(item)
|
|
116
|
+
else:
|
|
117
|
+
scalars.append(item)
|
|
118
|
+
|
|
119
|
+
if scalars:
|
|
120
|
+
yield from emit_scalar_list(scalars)
|
|
121
|
+
for nested_list in nested:
|
|
122
|
+
yield from emit_list(nested_list, identifier=identifier)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def emit_list_of_dicts(
|
|
126
|
+
elements: list[dict[str, Scalar | NonScalar]], identifier: str | None = None
|
|
127
|
+
) -> t.Iterator[str]:
|
|
128
|
+
keys = extract_scalar_keys(elements)
|
|
129
|
+
for item in elements:
|
|
130
|
+
yield from emit_dict(item, identifier=identifier, scalar_keys=keys)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def emit_dict(
|
|
134
|
+
item: dict[str, Scalar | NonScalar],
|
|
135
|
+
identifier: str | None = None,
|
|
136
|
+
scalar_keys: list[str] | None = None,
|
|
137
|
+
) -> t.Iterator[str]:
|
|
138
|
+
if scalar_keys is None:
|
|
139
|
+
scalar_keys = extract_scalar_keys(item)
|
|
140
|
+
scalars, non_scalars = partition_dict(item, scalar_keys)
|
|
141
|
+
|
|
142
|
+
if scalars:
|
|
143
|
+
if identifier is not None:
|
|
144
|
+
yield identifier
|
|
145
|
+
yield "\t".join(str(s) for s in scalars)
|
|
146
|
+
|
|
147
|
+
for subkey, value in non_scalars:
|
|
148
|
+
if isinstance(value, list):
|
|
149
|
+
yield from emit_list(value, identifier=subkey.upper())
|
|
150
|
+
else:
|
|
151
|
+
yield from emit_dict(value, identifier=subkey.upper())
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def partition_dict(
|
|
155
|
+
item: dict[str, Scalar | NonScalar], scalar_keys: list[str]
|
|
156
|
+
) -> tuple[list[Scalar], list[tuple[str, NonScalar]]]:
|
|
157
|
+
"""
|
|
158
|
+
Given a dict and a collection of keys for its scalar parts, split it into two lists
|
|
159
|
+
representing the scalar and non-scalar parts.
|
|
160
|
+
The non-scalar parts retain their keys.
|
|
161
|
+
|
|
162
|
+
This method assumes that the 'scalar_keys' provided are correct to the dict in
|
|
163
|
+
question.
|
|
164
|
+
"""
|
|
165
|
+
scalars: list[Scalar] = []
|
|
166
|
+
non_scalars: list[tuple[str, NonScalar]] = []
|
|
167
|
+
|
|
168
|
+
non_scalar_keys = sorted(set(item.keys()) - set(scalar_keys))
|
|
169
|
+
|
|
170
|
+
for key in scalar_keys:
|
|
171
|
+
value = item.get(key)
|
|
172
|
+
|
|
173
|
+
# we are not guaranteed that the scalar keys really map to scalars
|
|
174
|
+
# but if they don't, formatting will break, so error early
|
|
175
|
+
if isinstance(value, (list, dict)):
|
|
176
|
+
raise UnixFormattingError(
|
|
177
|
+
"Error during UNIX formatting of response data. "
|
|
178
|
+
"Lists where key-value mappings are not uniformly scalar or non-scalar "
|
|
179
|
+
"are not supported."
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
scalars.append(str(value))
|
|
183
|
+
|
|
184
|
+
for key in non_scalar_keys:
|
|
185
|
+
value = item[key]
|
|
186
|
+
|
|
187
|
+
# converse of the above: we are not "guaranteed" that the non-scalar keys
|
|
188
|
+
# do not map to scalars on a heterogeneous list[dict] structure
|
|
189
|
+
#
|
|
190
|
+
# in practice, this is not reachable because `extract_scalar_keys()` prefers
|
|
191
|
+
# to categorize data as scalar
|
|
192
|
+
if not isinstance(value, (list, dict)):
|
|
193
|
+
raise UnixFormattingError(
|
|
194
|
+
"Error during UNIX formatting of response data. "
|
|
195
|
+
"Lists where key-value mappings are not uniformly scalar or non-scalar "
|
|
196
|
+
"are not supported."
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
non_scalars.append((key, value))
|
|
200
|
+
|
|
201
|
+
return scalars, non_scalars
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def extract_scalar_keys(
|
|
205
|
+
element_or_elements: (
|
|
206
|
+
dict[str, Scalar | NonScalar] | list[dict[str, Scalar | NonScalar]]
|
|
207
|
+
),
|
|
208
|
+
) -> list[str]:
|
|
209
|
+
if isinstance(element_or_elements, dict):
|
|
210
|
+
elements: list[dict[str, Scalar | NonScalar]] = [element_or_elements]
|
|
211
|
+
else:
|
|
212
|
+
elements = element_or_elements
|
|
213
|
+
|
|
214
|
+
seen: set[str] = set()
|
|
215
|
+
for key, value in chain(*(item.items() for item in elements)):
|
|
216
|
+
if key in seen:
|
|
217
|
+
continue
|
|
218
|
+
if isinstance(value, (dict, list)):
|
|
219
|
+
continue
|
|
220
|
+
seen.add(key)
|
|
221
|
+
return sorted(seen)
|