Skip to content

Commit

Permalink
Merge pull request #103 from globus/release/0.13.0rc2
Browse files Browse the repository at this point in the history
Release/0.13.0rc2
  • Loading branch information
kurtmckee authored Oct 6, 2023
2 parents 4b9b299 + 835aed2 commit 0bf58a9
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 57 deletions.
17 changes: 11 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
id: "setup-python"
uses: "actions/setup-python@v4"
with:
python-version: "3.11"
python-version: "3.12"
cache: "pip"
cache-dependency-path: |
.github/workflows/ci.yaml
Expand Down Expand Up @@ -107,34 +107,39 @@ jobs:
os:
- name: "Linux"
value: "ubuntu-latest"
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
tox-extras: [""]

include:
# Test Windows.
- os:
name: "Windows"
value: "windows-latest"
python-version: "3.11"
python-version: "3.12"
tox-extras: ""

# Test Mac.
- os:
name: "Mac"
value: "macos-latest"
python-version: "3.11"
python-version: "3.12"
tox-extras: ""

# Test minimum dependencies.
- os:
name: "Linux"
value: "ubuntu-latest"
python-version: "3.7"
python-version: "3.8"
tox-extras: "-minimum_flask"
- os:
name: "Linux"
value: "ubuntu-latest"
python-version: "3.11"
python-version: "3.12"
tox-extras: "-minimum_flask"

steps:
Expand Down
11 changes: 9 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ repos:
hooks:
- id: alphabetize-codeowners

- repo: https://github.com/psf/black
rev: 23.7.0
# Enforce Python 3.8+ idioms.
- repo: https://github.com/asottile/pyupgrade
rev: v3.14.0
hooks:
- id: pyupgrade
args: [--py38-plus]

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

Expand Down
13 changes: 13 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2

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

sphinx:
configuration: "docs/source/conf.py"

python:
install:
- requirements: "docs/requirements.txt"
21 changes: 21 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ Unreleased changes are documented in files in the `changelog.d`_ directory.

.. scriv-insert-here
.. _changelog-0.13.0rc2:

0.13.0rc2 — 2023-10-06
======================

Python support
--------------

- Support Python 3.12.
- Drop support for Python 3.7.

Development
-----------

- Remove unused dependencies.

Dependencies
------------

- Raise the minimum Flask version to 2.3.0, which dropped support for Python 3.7.

.. _changelog-0.13.0rc1:

0.13.0rc1 — 2023-07-24
Expand Down
3 changes: 2 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
sphinx_material
sphinx==7.2.1
sphinx_material==0.0.35
28 changes: 15 additions & 13 deletions globus_action_provider_tools/authentication.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import logging
from time import time
from typing import FrozenSet, Iterable, List, Optional, Union, cast
Expand Down Expand Up @@ -26,7 +28,7 @@ def identity_principal(id_: str) -> str:
return f"urn:globus:auth:identity:{id_}"


class AuthState(object):
class AuthState:
# Cache for introspection operations, max lifetime: 30 seconds
introspect_cache: TTLCache = TTLCache(maxsize=100, ttl=30)

Expand All @@ -42,7 +44,7 @@ def __init__(
auth_client: ConfidentialAppAuthClient,
bearer_token: str,
expected_scopes: Iterable[str],
expected_audience: Optional[str] = None,
expected_audience: str | None = None,
) -> None:
self.auth_client = auth_client
self.bearer_token = bearer_token
Expand All @@ -56,10 +58,10 @@ def __init__(
self.expected_audience = auth_client.client_id
else:
self.expected_audience = expected_audience
self.errors: List[Exception] = []
self._groups_client: Optional[GroupsClient] = None
self.errors: list[Exception] = []
self._groups_client: GroupsClient | None = None

def introspect_token(self) -> Optional[GlobusHTTPResponse]:
def introspect_token(self) -> GlobusHTTPResponse | None:
# There are cases where a null or empty string bearer token are present as a
# placeholder
if self.bearer_token is None:
Expand Down Expand Up @@ -103,26 +105,26 @@ def introspect_token(self) -> Optional[GlobusHTTPResponse]:
return resp

@property
def effective_identity(self) -> Optional[str]:
def effective_identity(self) -> str | None:
tkn_details = self.introspect_token()
if tkn_details is None:
return None
effective = identity_principal(tkn_details["sub"])
return effective

@property
def identities(self) -> FrozenSet[str]:
def identities(self) -> frozenset[str]:
tkn_details = self.introspect_token()
if tkn_details is None:
return frozenset()
return frozenset(map(identity_principal, tkn_details["identity_set"]))

@property
def principals(self) -> FrozenSet[str]:
def principals(self) -> frozenset[str]:
return self.identities.union(self.groups)

@property # type: ignore
def groups(self) -> FrozenSet[str]:
def groups(self) -> frozenset[str]:
try:
groups_client = self._get_groups_client()
except (GlobusAPIError, KeyError, ValueError) as err:
Expand Down Expand Up @@ -163,7 +165,7 @@ def groups(self) -> FrozenSet[str]:
return groups_set

@property
def dependent_tokens_cache_id(self) -> Optional[str]:
def dependent_tokens_cache_id(self) -> str | None:
tkn_details = self.introspect_token()
if tkn_details is None:
return None
Expand Down Expand Up @@ -200,7 +202,7 @@ def get_authorizer_for_scope(
scope: str,
bypass_dependent_token_cache=False,
required_authorizer_expiration_time: int = 60,
) -> Optional[Union[RefreshTokenAuthorizer, AccessTokenAuthorizer]]:
) -> RefreshTokenAuthorizer | AccessTokenAuthorizer | None:
"""Retrieve a Globus SDK authorizer for use in accessing a further Globus Auth registered
service / "resource server". This authorizer can be passed to any Globus SDK
Client class for use in accessing the Client's service.
Expand Down Expand Up @@ -353,7 +355,7 @@ def __init__(
client_id: str,
client_secret: str,
expected_scopes: Iterable[str],
expected_audience: Optional[str] = None,
expected_audience: str | None = None,
) -> None:
self.auth_client = ConfidentialAppAuthClient(client_id, client_secret)
self.default_expected_scopes = frozenset(expected_scopes)
Expand All @@ -364,7 +366,7 @@ def __init__(
self.expected_audience = expected_audience

def check_token(
self, access_token: str, expected_scopes: Iterable[str] = None
self, access_token: str, expected_scopes: Iterable[str] | None = None
) -> AuthState:
if expected_scopes is None:
expected_scopes = self.default_expected_scopes
Expand Down
4 changes: 2 additions & 2 deletions globus_action_provider_tools/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def authorize_action_access_or_404(status: ActionStatus, auth_state: AuthState)
AuthenticationError.
"""
if status.monitor_by is None:
allowed_set = set([status.creator_id])
allowed_set = {status.creator_id}
else:
allowed_set = set(chain([status.creator_id], status.monitor_by))

Expand All @@ -40,7 +40,7 @@ def authorize_action_management_or_404(
AuthenticationError.
"""
if status.manage_by is None:
allowed_set = set([status.creator_id])
allowed_set = {status.creator_id}
else:
allowed_set = set(chain([status.creator_id], status.manage_by))

Expand Down
12 changes: 7 additions & 5 deletions globus_action_provider_tools/flask/api_helpers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import logging
from typing import List, Optional

Expand Down Expand Up @@ -105,15 +107,15 @@ def add_action_routes_to_blueprint(
blueprint: flask.Blueprint,
client_id: str,
client_secret: str,
client_name: Optional[str],
client_name: str | None,
provider_description: ActionProviderDescription,
action_run_callback: ActionRunCallback,
action_status_callback: ActionStatusCallback,
action_cancel_callback: ActionCancelCallback,
action_release_callback: ActionReleaseCallback,
action_log_callback: Optional[ActionLogCallback] = None,
additional_scopes: Optional[List[str]] = None,
action_enumeration_callback: ActionEnumerationCallback = None,
action_log_callback: ActionLogCallback | None = None,
additional_scopes: list[str] | None = None,
action_enumeration_callback: ActionEnumerationCallback | None = None,
) -> None:
"""
Add routes to a Flask Blueprint to implement the required operations of the Action
Expand Down Expand Up @@ -296,7 +298,7 @@ def action_log(action_id: str) -> ViewReturn:
def action_enumeration():
auth_state = check_token(request, checker)

valid_statuses = set(e.name.casefold() for e in ActionStatusValue)
valid_statuses = {e.name.casefold() for e in ActionStatusValue}
statuses = parse_query_args(
request,
arg_name="status",
Expand Down
10 changes: 5 additions & 5 deletions globus_action_provider_tools/flask/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def parse_query_args(
*,
arg_name: str,
default_value: str = "",
valid_vals: Set[str] = None,
) -> Set[str]:
valid_vals: set[str] | None = None,
) -> set[str]:
"""
Helper function to parse a query arg "arg_name" and return a validated
(according to the values supplied in "valid_vals"), usable set of
Expand Down Expand Up @@ -188,7 +188,7 @@ def get_input_body_validator(


def json_schema_input_validation(
action_input: Dict[str, Any], validator: jsonschema.Validator
action_input: dict[str, Any], validator: jsonschema.Validator
) -> None:
"""
Use a created JSON Validator to verify the input body of an incoming
Expand All @@ -201,7 +201,7 @@ def json_schema_input_validation(


def pydantic_input_validation(
action_input: Dict[str, Any], validator: Type[BaseModel]
action_input: dict[str, Any], validator: type[BaseModel]
) -> None:
"""
Validate input using the pydantic model itself. Raises a BadActionRequest
Expand All @@ -218,7 +218,7 @@ def pydantic_input_validation(
except ImportError:
# Flask < 2.2: Use the deprecated JSON encoder interface.
json_provider_available = False
JsonProvider: Optional["DefaultJSONProvider"] = None
JsonProvider: DefaultJSONProvider | None = None
else:
# Flask >= 2.2: Use the new JSON provider interface.
json_provider_available = True
Expand Down
6 changes: 3 additions & 3 deletions globus_action_provider_tools/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
"ActionRequest": "action_request.yaml",
"ActionStatus": "action_status.yaml",
}
_validator_map: Dict[str, jsonschema.Validator] = {}
_validator_map: Dict[str, jsonschema.protocols.Validator] = {}

HERE: Path = Path(__file__).parent
for schema_name, yaml_file in _schema_to_file_map.items():
with open(HERE / yaml_file, "r", encoding="utf-8") as specfile:
with open(HERE / yaml_file, encoding="utf-8") as specfile:
schema = yaml.safe_load(specfile)
validator_cls = jsonschema.validators.validator_for(schema)
_validator_map[schema_name] = validator_cls(schema)
Expand Down Expand Up @@ -43,7 +43,7 @@ def request_validator(request: ValidationRequest) -> ValidationResult:


def validate_data(
data: Dict[str, Any], validator: jsonschema.Validator
data: Dict[str, Any], validator: jsonschema.protocols.Validator
) -> ValidationResult:
error_messages = []
for error in validator.iter_errors(data):
Expand Down
Loading

0 comments on commit 0bf58a9

Please sign in to comment.