Skip to content
This repository was archived by the owner on Dec 4, 2024. It is now read-only.

Many updates #209

Merged
merged 6 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ jobs:
matrix:
os: [ubuntu-latest]
os-name: [Ubuntu]
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
# we do not want a large number of windows and macos builds, so
# enumerate them explicitly
include:
- os: windows-latest
os-name: Windows
python-version: 3.11
python-version: "3.13"
- os: macos-latest
os-name: MacOS
python-version: 3.11
python-version: "3.13"

name: "Test py${{ matrix.python-version }} on ${{ matrix.os-name }}"
runs-on: ${{ matrix.os }}
Expand Down
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -12,31 +12,31 @@ repos:
- id: check-added-large-files

- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
rev: v3.19.0
hooks:
- id: pyupgrade
args:
- "--py38-plus"
- "--py39-plus"

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.24.1
rev: 0.30.0
hooks:
- id: check-github-workflows
- id: check-dependabot

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.7.0
rev: 24.10.0
hooks:
- id: black-jupyter
- id: black

- repo: https://github.com/pycqa/isort
rev: 5.12.0
rev: 5.13.2
hooks:
- id: isort

- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
rev: 7.1.1
hooks:
- id: flake8
additional_dependencies: ["flake8-bugbear==23.7.10"]
14 changes: 14 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 2

build:
os: "ubuntu-22.04"
tools:
python: "3.12"

python:
install:
- requirements: "docs/requirements.txt"

sphinx:
configuration: "docs/source/conf.py"
fail_on_warning: true
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.. warning::

The code in this repository is no longer supported.


Globus Automate Client
======================

Expand Down
4 changes: 4 additions & 0 deletions changelog.d/20241204_103536_kurtmckee_updates.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
End of Life
-----------

* The Globus Automate Client is no longer supported.
7 changes: 2 additions & 5 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# -- Project information -----------------------------------------------------

project = "Globus Automate Client"
copyright = "2020-2023, University of Chicago"
copyright = "2020-2024, University of Chicago"
author = "Globus"

# The full version, including alpha/beta/rc tags
Expand Down Expand Up @@ -71,14 +71,11 @@
rst_prolog = """
.. warning::

The Globus Automate SDK and Globus Automate CLI are deprecated.
The Globus Automate SDK and Globus Automate CLI are no longer supported.

The `Globus SDK`_ and `Globus CLI`_ have integrated their functionality
and are able to interact with other Globus services, as well.

It is strongly recommended that new projects use the Globus SDK and Globus CLI,
and that existing projects begin migrating to the Globus SDK and Globus CLI.

.. _Globus SDK: https://globus-sdk-python.readthedocs.io/en/stable/
.. _Globus CLI: https://docs.globus.org/cli/

Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Globus Automate - CLI and Python SDK

.. warning::

The Globus Automate Client is deprecated in favor of the
The Globus Automate Client is no longer supported. Please migrate to the
`Globus CLI <https://docs.globus.org/cli/>`_ and the
`Globus Python SDK <https://globus-sdk-python.readthedocs.io/en/stable/>`_.

Expand Down
2 changes: 1 addition & 1 deletion docs/source/license.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
License
=======

Copyright 2020-2023 University of Chicago
Copyright 2020-2024 University of Chicago

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion docs/source/migration.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Migration to globus-sdk and globus-cli
======================================

The Globus Automate Client is deprecated.
The Globus Automate Client is no longer supported.
All functionality is now available in `globus-sdk`_ and
`globus-cli`_.

Expand Down
9 changes: 5 additions & 4 deletions globus_automate_client/action_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import uuid
from typing import Any, Dict, Iterable, List, Mapping, Optional, Type, TypeVar, Union
from collections.abc import Iterable, Mapping
from typing import Any, Optional, TypeVar, Union
from urllib.parse import quote, urlparse

from globus_sdk import BaseClient, GlobusHTTPResponse
Expand Down Expand Up @@ -76,7 +77,7 @@ def run(
manage_by: Optional[Iterable[str]] = None,
monitor_by: Optional[Iterable[str]] = None,
label: Optional[str] = None,
tags: Optional[List[str]] = None,
tags: Optional[list[str]] = None,
force_path: Optional[str] = None,
**kwargs,
) -> GlobusHTTPResponse:
Expand Down Expand Up @@ -203,7 +204,7 @@ def log(

# *reverse_order* MUST BE None to prevent reversing the sort order.
# Any other value, including False, will reverse the sort order.
params: Dict[str, Union[int, str, bool, None]] = {
params: dict[str, Union[int, str, bool, None]] = {
"reverse_order": True if reverse_order else None,
"limit": limit,
}
Expand All @@ -215,7 +216,7 @@ def log(

@classmethod
def new_client(
cls: Type[_ActionClient],
cls: type[_ActionClient],
action_url: str,
authorizer: Optional[GlobusAuthorizer],
http_timeout: int = 10,
Expand Down
5 changes: 2 additions & 3 deletions globus_automate_client/cli/actions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import functools
from typing import List

import typer

Expand Down Expand Up @@ -71,14 +70,14 @@ def action_run(
None,
help="An identifier to associate with this Action invocation request",
),
manage_by: List[str] = typer.Option(
manage_by: list[str] = typer.Option(
None,
help="A principal which may change the execution of the Action. The principal "
"is the user's or group's UUID prefixed with either 'urn:globus:groups:id:' "
"or 'urn:globus:auth:identity:' [repeatable]",
callback=principal_validator,
),
monitor_by: List[str] = typer.Option(
monitor_by: list[str] = typer.Option(
None,
help="A principal which may view the state of the Action. The principal "
"is the user's or group's UUID prefixed with either 'urn:globus:groups:id:' "
Expand Down
34 changes: 17 additions & 17 deletions globus_automate_client/cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import platform
import sys
from json import JSONDecodeError
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Set, Union, cast
from typing import Any, Callable, NamedTuple, Optional, Union, cast

import click
import typer
Expand Down Expand Up @@ -55,10 +55,10 @@ class TokenSet(NamedTuple):
# there isn't a matching dependent scope, that means we need to prompt for consent
# again. If there is a matching full-scope-string in `dependent_scopes`, then we're
# OK to use the token from looking up that base scope.
dependent_scopes: Set[str]
dependent_scopes: set[str]


TokensInTokenCache = Dict[str, Union[TokenSet, Dict[str, TokenSet]]]
TokensInTokenCache = dict[str, Union[TokenSet, dict[str, TokenSet]]]


class TokenCache:
Expand All @@ -81,7 +81,7 @@ def tokens_for_environment(self):
return self.tokens
environ_cache_key = TokenCache._environment_prefix + environ
if environ_cache_key not in self.tokens:
self.tokens[environ_cache_key]: Dict[str, TokenSet] = {}
self.tokens[environ_cache_key]: dict[str, TokenSet] = {}
return self.tokens[environ_cache_key]

def set_tokens(self, scope: str, tokens: TokenSet) -> TokenSet:
Expand Down Expand Up @@ -115,7 +115,7 @@ def get_tokens(self, scope: str) -> Optional[TokenSet]:
return self.tokens_for_environment.get(scope)

@staticmethod
def _deserialize_from_file(file_tokens: Dict[str, Any]) -> TokensInTokenCache:
def _deserialize_from_file(file_tokens: dict[str, Any]) -> TokensInTokenCache:
deserialized: TokensInTokenCache = {}
for k, v in file_tokens.items():
if k.startswith(TokenCache._environment_prefix):
Expand All @@ -142,8 +142,8 @@ def load_tokens(self):
)

@staticmethod
def _make_jsonable(tokens) -> Dict[str, Any]:
serialized: Dict[str, Any] = {}
def _make_jsonable(tokens) -> dict[str, Any]:
serialized: dict[str, Any] = {}
for k, v in tokens.items():
if isinstance(v, TokenSet):
v = v._asdict()
Expand Down Expand Up @@ -194,10 +194,10 @@ def clear_tokens(
self.modified = True

def update_from_oauth_token_response(
self, token_response: OAuthTokenResponse, original_scopes: Set[str]
) -> Dict[str, TokenSet]:
self, token_response: OAuthTokenResponse, original_scopes: set[str]
) -> dict[str, TokenSet]:
by_scopes = token_response.by_scopes
token_sets: Dict[str, TokenSet] = {}
token_sets: dict[str, TokenSet] = {}
for scope in by_scopes:
token_info = by_scopes[scope]
dependent_scopes = {s for s in original_scopes if "[" in s}
Expand Down Expand Up @@ -237,7 +237,7 @@ def safeprint(s, err: bool = False):


def _do_login_for_scopes(
native_client: NativeAppAuthClient, scopes: List[str]
native_client: NativeAppAuthClient, scopes: list[str]
) -> OAuthTokenResponse:
label = CLIENT_NAME
host = platform.node()
Expand Down Expand Up @@ -269,17 +269,17 @@ def refresh_handler(response: OAuthTokenResponse, *args, **kwargs):


def get_authorizers_for_scopes(
scopes: List[str],
scopes: list[str],
token_store: Optional[Union[pathlib.Path, str]] = None,
client_id: str = CLIENT_ID,
client_name: str = CLIENT_NAME,
no_login: bool = False,
) -> Dict[str, GlobusAuthorizer]:
) -> dict[str, GlobusAuthorizer]:
token_store = token_store or str(DEFAULT_TOKEN_FILE)
token_cache = TokenCache(token_store)
token_cache.load_tokens()
token_sets: Dict[str, TokenSet] = {}
needed_scopes: Set[str] = set()
token_sets: dict[str, TokenSet] = {}
needed_scopes: set[str] = set()
native_client = _get_globus_sdk_native_client(client_id, client_name)

for scope in scopes:
Expand All @@ -296,7 +296,7 @@ def get_authorizers_for_scopes(
)
token_sets.update(new_tokens)

authorizers: Dict[str, GlobusAuthorizer] = {}
authorizers: dict[str, GlobusAuthorizer] = {}
for scope, token_set in token_sets.items():
if token_set is not None:
authorizer: Union[RefreshTokenAuthorizer, AccessTokenAuthorizer]
Expand Down Expand Up @@ -362,7 +362,7 @@ def revoker(scope: str, token_set: TokenSet) -> bool:

def get_current_user(
no_login: bool = False, token_store: Union[pathlib.Path, str] = DEFAULT_TOKEN_FILE
) -> Optional[Dict[str, Any]]:
) -> Optional[dict[str, Any]]:
"""
When `no_login` is set, returns `None` if not logged in.
"""
Expand Down
12 changes: 6 additions & 6 deletions globus_automate_client/cli/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pathlib
import re
from errno import ENAMETOOLONG
from typing import AbstractSet, Callable, List, Optional, cast
from typing import AbstractSet, Callable, Optional, cast
from urllib.parse import urlparse

import typer
Expand Down Expand Up @@ -38,8 +38,8 @@ def url_validator_callback(url: str) -> str:


def _base_principal_validator(
principals: List[str], *, special_vals: AbstractSet[str] = frozenset()
) -> List[str]:
principals: list[str], *, special_vals: AbstractSet[str] = frozenset()
) -> list[str]:
"""
This validator ensures the principal IDs are valid UUIDs prefixed with valid
Globus ID beginnings. It will optionally determine if a provided principal
Expand Down Expand Up @@ -76,16 +76,16 @@ def _base_principal_validator(
return valid_principals


def principal_validator(principals: List[str]) -> List[str]:
def principal_validator(principals: list[str]) -> list[str]:
"""A principal ID needs to be a valid UUID."""

return _base_principal_validator(cast(List[str], principals))
return _base_principal_validator(cast(list[str], principals))


def custom_principal_validator(special_values: AbstractSet[str]) -> Callable:
"""A principal ID needs to be a valid UUID."""

def wrapper(principals: List[str]) -> List[str]:
def wrapper(principals: list[str]) -> list[str]:
return _base_principal_validator(principals, special_vals=special_values)

return wrapper
Expand Down
Loading
Loading