Skip to content

Commit

Permalink
Merge branch 'globus:main' into pjhinton/sc-29242-endpoint-search-fil…
Browse files Browse the repository at this point in the history
…ter-entity-type
  • Loading branch information
pjhinton-globus authored Jan 7, 2025
2 parents d3ab91f + 805c68c commit ffdd589
Show file tree
Hide file tree
Showing 26 changed files with 514 additions and 432 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ jobs:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
tox-post-environments:
- "py3.8-mindeps"
- "py3.8-sdkmain"
- "py3.12-sdkmain"
- "py3.13-sdkmain"
cache-key-prefix: "linux"
cache-key-hash-files:
- "setup.py"

- name: "macOS"
runner: "macos-latest"
cpythons:
- "3.12"
- "3.13"
tox-environments-from-pythons: true
cache-key-prefix: "macos"
cache-key-hash-files:
Expand All @@ -43,7 +44,7 @@ jobs:
- name: "Windows"
runner: "windows-latest"
cpythons:
- "3.12"
- "3.13"
tox-environments-from-pythons: true
cache-key-prefix: "windows"
cache-key-hash-files:
Expand All @@ -52,7 +53,7 @@ jobs:
- name: "Quality"
runner: "ubuntu-latest"
cpythons:
- "3.12"
- "3.13"
tox-environments:
- "mypy"
- "reference"
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ repos:
- id: check-github-workflows
- id: check-dependabot
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.0
rev: v3.19.1
hooks:
- id: pyupgrade
args: ["--py38-plus"]
Expand Down
3 changes: 3 additions & 0 deletions changelog.d/20250106_150212_sirosen_support_313.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Enhancements

* Add official support for Python 3.13.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
requires-python = ">=3.8"
dependencies = [
Expand Down
11 changes: 7 additions & 4 deletions src/globus_cli/commands/cli_profile_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import click

from globus_cli.login_manager import is_client_login, token_storage_adapter
from globus_cli.login_manager import LoginManager, is_client_login
from globus_cli.parsing import command
from globus_cli.termio import Field, display, formatters

Expand All @@ -29,13 +29,16 @@ def _profilestr_to_datadict(s: str) -> dict[str, t.Any] | None:


def _parse_and_filter_profiles(
login_manager: LoginManager,
all: bool,
) -> tuple[list[dict[str, t.Any]], list[dict[str, t.Any]]]:
globus_env = os.getenv("GLOBUS_SDK_ENVIRONMENT", "production")

client_profiles = []
user_profiles = []
for n in token_storage_adapter().iter_namespaces(include_config_namespaces=True):
for n in login_manager.storage.adapter.iter_namespaces(
include_config_namespaces=True
):
data = _profilestr_to_datadict(n)
if not data: # skip any parse failures
continue
Expand Down Expand Up @@ -86,8 +89,8 @@ def cli_profile_list(*, all: bool) -> None:
These are the values for GLOBUS_PROFILE which have been recorded, as well as
GLOBUS_CLI_CLIENT_ID values which have been used.
"""

client_profiles, user_profiles = _parse_and_filter_profiles(all)
login_manager = LoginManager()
client_profiles, user_profiles = _parse_and_filter_profiles(login_manager, all)

if user_profiles:
fields = [
Expand Down
7 changes: 3 additions & 4 deletions src/globus_cli/commands/collection/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import click
import globus_sdk

from globus_cli.login_manager.utils import get_current_identity_id
from globus_cli.login_manager import LoginManager
from globus_cli.termio import Field, formatters
from globus_cli.types import DATA_CONTAINER_T

Expand All @@ -12,10 +12,9 @@ class LazyCurrentIdentity:
def __init__(self, value: str | None) -> None:
self._value = value

@property
def value(self) -> str:
def resolve(self, login_manager: LoginManager) -> str:
if self._value is None:
self._value = get_current_identity_id()
self._value = login_manager.get_current_identity_id()
return str(self._value)


Expand Down
7 changes: 5 additions & 2 deletions src/globus_cli/commands/collection/create/guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ def collection_create_guest(

if not user_credential_id:
user_credential_id = _select_user_credential_id(
gcs_client, mapped_collection_id, local_username, identity_id.value
gcs_client,
mapped_collection_id,
local_username,
identity_id.resolve(login_manager),
)

converted_kwargs: dict[str, t.Any] = ExplicitNullType.nullify_dict(
Expand All @@ -105,7 +108,7 @@ def collection_create_guest(
"display_name": display_name,
"enable_https": enable_https,
"force_encryption": force_encryption,
"identity_id": identity_id.value,
"identity_id": identity_id.resolve(login_manager),
"info_link": info_link,
"keywords": keywords,
"mapped_collection_id": mapped_collection_id,
Expand Down
2 changes: 1 addition & 1 deletion src/globus_cli/commands/collection/create/mapped.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def collection_create_mapped(
"domain_name": domain_name,
"enable_https": enable_https,
"force_encryption": force_encryption,
"identity_id": identity_id.value,
"identity_id": identity_id.resolve(login_manager),
"info_link": info_link,
"keywords": keywords,
"organization": organization,
Expand Down
3 changes: 1 addition & 2 deletions src/globus_cli/commands/flows/run/resume.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import globus_sdk

from globus_cli.login_manager import LoginManager
from globus_cli.login_manager.utils import get_current_identity_id
from globus_cli.parsing import command, run_id_arg
from globus_cli.termio import Field, display, formatters
from globus_cli.utils import CLIAuthRequirementsError
Expand Down Expand Up @@ -124,6 +123,6 @@ def _has_required_consent(
login_manager: LoginManager, required_scopes: list[str]
) -> bool:
auth_client = login_manager.get_auth_client()
user_identity_id = get_current_identity_id()
user_identity_id = login_manager.get_current_identity_id()
consents = auth_client.get_consents(user_identity_id).to_forest()
return consents.meets_scope_requirements(required_scopes)
20 changes: 6 additions & 14 deletions src/globus_cli/commands/logout.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import click
import globus_sdk

from globus_cli.login_manager import (
LoginManager,
delete_templated_client,
internal_native_client,
is_client_login,
remove_well_known_config,
token_storage_adapter,
)
from globus_cli.login_manager import LoginManager, is_client_login
from globus_cli.parsing import command


Expand Down Expand Up @@ -105,7 +98,7 @@ def logout_command(
# Always skip for client logins, which don't use a templated client
if delete_client and not is_client_login():
try:
delete_templated_client()
login_manager.storage.delete_templated_client()
except globus_sdk.AuthAPIError:
if not ignore_errors:
warnecho(
Expand All @@ -121,10 +114,9 @@ def logout_command(

# Attempt to revoke all tokens in storage; use the internal native client to ensure
# we have a valid Auth client
native_client = internal_native_client()
adapter = token_storage_adapter()
native_client = login_manager.storage.cli_native_client

for rs, tokendata in adapter.get_by_resource_server().items():
for rs, tokendata in login_manager.storage.adapter.get_by_resource_server().items():
for tok_key in ("access_token", "refresh_token"):
token = tokendata[tok_key]

Expand All @@ -145,9 +137,9 @@ def logout_command(
"Continuing... (--ignore-errors)",
)

adapter.remove_tokens_for_resource_server(rs)
login_manager.storage.adapter.remove_tokens_for_resource_server(rs)

remove_well_known_config("auth_user_data")
login_manager.storage.remove_well_known_config("auth_user_data")

if is_client_login():
click.echo(_CLIENT_LOGOUT_EPILOG)
Expand Down
13 changes: 3 additions & 10 deletions src/globus_cli/commands/session/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@

import globus_sdk

from globus_cli.login_manager import (
LoginManager,
get_client_login,
internal_auth_client,
is_client_login,
token_storage_adapter,
)
from globus_cli.login_manager import LoginManager, get_client_login, is_client_login
from globus_cli.parsing import command
from globus_cli.termio import Field, display, print_command_hint

Expand Down Expand Up @@ -54,7 +48,6 @@ def session_show(login_manager: LoginManager) -> None:
the time the user authenticated with that identity.
"""
auth_client = login_manager.get_auth_client()
adapter = token_storage_adapter()

# get a token to introspect, refreshing if necessary
try:
Expand All @@ -64,7 +57,7 @@ def session_show(login_manager: LoginManager) -> None:
except AttributeError: # if we have no RefreshTokenAuthorizor
pass

tokendata = adapter.get_token_data("auth.globus.org")
tokendata = login_manager.storage.adapter.get_token_data("auth.globus.org")
# if there's no token (e.g. not logged in), stub with empty data
if not tokendata:
session_info: dict[str, t.Any] = {}
Expand All @@ -73,7 +66,7 @@ def session_show(login_manager: LoginManager) -> None:
if is_client_login():
introspect_client = get_client_login()
else:
introspect_client = internal_auth_client()
introspect_client = login_manager.storage.cli_confidential_client

access_token = tokendata["access_token"]
res = introspect_client.oauth2_token_introspect(
Expand Down
8 changes: 5 additions & 3 deletions src/globus_cli/commands/timer/create/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from globus_cli.endpointish import Endpointish
from globus_cli.login_manager import LoginManager, is_client_login
from globus_cli.login_manager.utils import get_current_identity_id
from globus_cli.parsing import (
ENDPOINT_PLUS_OPTPATH,
TimedeltaType,
Expand Down Expand Up @@ -265,7 +264,9 @@ def transfer_command(
# If it's not a client login, we need to check
# that the user has the required scopes
if not is_client_login():
request_data_access = _derive_missing_scopes(auth_client, scopes_needed)
request_data_access = _derive_missing_scopes(
login_manager, auth_client, scopes_needed
)

if request_data_access:
scope_request_opts = " ".join(
Expand Down Expand Up @@ -349,11 +350,12 @@ def _derive_needed_scopes(


def _derive_missing_scopes(
login_manager: LoginManager,
auth_client: CustomAuthClient,
scopes_needed: dict[str, Scope],
) -> list[str]:
# read the identity ID stored from the login flow
user_identity_id = get_current_identity_id()
user_identity_id = login_manager.get_current_identity_id()

# get the user's Globus CLI consents
consents = auth_client.get_consents(user_identity_id).to_forest()
Expand Down
3 changes: 1 addition & 2 deletions src/globus_cli/commands/timer/resume.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import globus_sdk

from globus_cli.login_manager import LoginManager
from globus_cli.login_manager.utils import get_current_identity_id
from globus_cli.parsing import command
from globus_cli.termio import display
from globus_cli.utils import CLIAuthRequirementsError
Expand Down Expand Up @@ -117,6 +116,6 @@ def _has_required_consent(
login_manager: LoginManager, required_scopes: list[str]
) -> bool:
auth_client = login_manager.get_auth_client()
user_identity_id = get_current_identity_id()
user_identity_id = login_manager.get_current_identity_id()
consents = auth_client.get_consents(user_identity_id).to_forest()
return consents.meets_scope_requirements(required_scopes)
16 changes: 0 additions & 16 deletions src/globus_cli/login_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,13 @@
from .errors import MissingLoginError
from .manager import LoginManager
from .scopes import compute_timer_scope
from .tokenstore import (
delete_templated_client,
internal_auth_client,
internal_native_client,
read_well_known_config,
remove_well_known_config,
store_well_known_config,
token_storage_adapter,
)
from .utils import is_remote_session

__all__ = [
"MissingLoginError",
"is_remote_session",
"LoginManager",
"delete_templated_client",
"internal_auth_client",
"internal_native_client",
"token_storage_adapter",
"is_client_login",
"get_client_login",
"store_well_known_config",
"read_well_known_config",
"remove_well_known_config",
"compute_timer_scope",
]
Loading

0 comments on commit ffdd589

Please sign in to comment.