From 2bd525cf9dfb8d265456d4656eb21fb83a7c188f Mon Sep 17 00:00:00 2001 From: Stephen Rosen Date: Tue, 10 Sep 2024 10:36:52 -0500 Subject: [PATCH 1/2] Promote `consents` from 'experimental' The consents module is moved to `globus_sdk.scopes.consents`, and docs are updated as appropriate. A getattr-based rename module, with deprecation warnings, is added to `experimental`. --- .../20240910_103438_sirosen_move_consents.rst | 5 +++ .../scopes_and_consents}/consents.rst | 19 ++++++++- .../scopes_and_consents/index.rst | 1 + docs/experimental/index.rst | 1 - src/globus_sdk/experimental/consents.py | 39 +++++++++++++++++++ .../globus_app/_validating_token_storage.py | 2 +- .../consents/__init__.py | 4 +- .../consents/_errors.py | 0 .../consents/_model.py | 2 +- .../services/auth/response/consents.py | 6 +-- tests/common/consents.py | 2 +- .../test_validating_token_storage.py | 2 +- .../auth => scopes}/test_consents.py | 2 +- 13 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 changelog.d/20240910_103438_sirosen_move_consents.rst rename docs/{experimental => authorization/scopes_and_consents}/consents.rst (54%) create mode 100644 src/globus_sdk/experimental/consents.py rename src/globus_sdk/{experimental => scopes}/consents/__init__.py (94%) rename src/globus_sdk/{experimental => scopes}/consents/_errors.py (100%) rename src/globus_sdk/{experimental => scopes}/consents/_model.py (99%) rename tests/unit/{services/auth => scopes}/test_consents.py (98%) diff --git a/changelog.d/20240910_103438_sirosen_move_consents.rst b/changelog.d/20240910_103438_sirosen_move_consents.rst new file mode 100644 index 000000000..9f833397d --- /dev/null +++ b/changelog.d/20240910_103438_sirosen_move_consents.rst @@ -0,0 +1,5 @@ +Changed +~~~~~~~ + +- Consent object models have been moved from + ``globus_sdk.experimental.consents`` into ``globus_sdk.scopes.consents``. (:pr:`NUMBER`) diff --git a/docs/experimental/consents.rst b/docs/authorization/scopes_and_consents/consents.rst similarity index 54% rename from docs/experimental/consents.rst rename to docs/authorization/scopes_and_consents/consents.rst index 504808621..4aa486705 100644 --- a/docs/experimental/consents.rst +++ b/docs/authorization/scopes_and_consents/consents.rst @@ -1,5 +1,5 @@ -.. py:currentmodule:: globus_sdk.experimental.consents +.. py:currentmodule:: globus_sdk.scopes.consents Consents ======== @@ -12,6 +12,23 @@ Consents are modeled as a ``ConsentForest`` full of ``ConsentTrees`` containing provided by a user to client applications for token grants under certain scoped contexts. +Consent objects are provided from ``globus_sdk.scopes.consents``. + +They are typically produced by calling +:meth:`globus_sdk.AuthClient.get_consents` and invoking ``to_forest()`` on +the response. Example usage: + +.. code-block:: python + + import globus_sdk + from globus_sdk.scopes.consents import ConsentForest + + my_identity_id = ... + client = globus_sdk.AuthClient(...) + response = client.get_consents(my_identity_id) + + consent_forest: ConsentForest = response.to_forest() + Reference ========= diff --git a/docs/authorization/scopes_and_consents/index.rst b/docs/authorization/scopes_and_consents/index.rst index 81adef1d8..0f16517d8 100644 --- a/docs/authorization/scopes_and_consents/index.rst +++ b/docs/authorization/scopes_and_consents/index.rst @@ -31,3 +31,4 @@ which make learning about and manipulating these data easier. scopes mutable_scopes + consents diff --git a/docs/experimental/index.rst b/docs/experimental/index.rst index 483871fb4..e7ef3eace 100644 --- a/docs/experimental/index.rst +++ b/docs/experimental/index.rst @@ -16,7 +16,6 @@ Globus SDK Experimental Components auth_requirements_errors scope_parser - consents globus_app diff --git a/src/globus_sdk/experimental/consents.py b/src/globus_sdk/experimental/consents.py new file mode 100644 index 000000000..85cc295db --- /dev/null +++ b/src/globus_sdk/experimental/consents.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import sys +import typing as t + +__all__ = ( + "Consent", + "ConsentTree", + "ConsentForest", + "ConsentParseError", + "ConsentTreeConstructionError", +) + +# legacy aliases +# (when accessed, these will emit deprecation warnings in a future release) +if t.TYPE_CHECKING: + from globus_sdk.scopes.consents import ( + Consent, + ConsentForest, + ConsentParseError, + ConsentTree, + ConsentTreeConstructionError, + ) +else: + + def __getattr__(name: str) -> t.Any: + import globus_sdk.scopes.consents as consents_module + from globus_sdk.exc import warn_deprecated + + warn_deprecated( + "'globus_sdk.experimental.consents' has been renamed to " + "'globus_sdk.scopes.consents'. " + f"Importing '{name}' from `globus_sdk.experimental` is deprecated." + ) + value = getattr(consents_module, name, None) + if value is None: + raise AttributeError(f"module {__name__} has no attribute {name}") + setattr(sys.modules[__name__], name, value) + return value diff --git a/src/globus_sdk/experimental/globus_app/_validating_token_storage.py b/src/globus_sdk/experimental/globus_app/_validating_token_storage.py index f9fce49d6..7a7317147 100644 --- a/src/globus_sdk/experimental/globus_app/_validating_token_storage.py +++ b/src/globus_sdk/experimental/globus_app/_validating_token_storage.py @@ -3,8 +3,8 @@ import typing as t from globus_sdk import AuthClient, Scope -from globus_sdk.experimental.consents import ConsentForest from globus_sdk.experimental.tokenstorage import TokenData, TokenStorage +from globus_sdk.scopes.consents import ConsentForest from ..._types import UUIDLike from .errors import ( diff --git a/src/globus_sdk/experimental/consents/__init__.py b/src/globus_sdk/scopes/consents/__init__.py similarity index 94% rename from src/globus_sdk/experimental/consents/__init__.py rename to src/globus_sdk/scopes/consents/__init__.py index 837163a62..8b78f547b 100644 --- a/src/globus_sdk/experimental/consents/__init__.py +++ b/src/globus_sdk/scopes/consents/__init__.py @@ -1,10 +1,10 @@ from ._errors import ConsentParseError, ConsentTreeConstructionError from ._model import Consent, ConsentForest, ConsentTree -__all__ = [ +__all__ = ( "Consent", "ConsentTree", "ConsentForest", "ConsentParseError", "ConsentTreeConstructionError", -] +) diff --git a/src/globus_sdk/experimental/consents/_errors.py b/src/globus_sdk/scopes/consents/_errors.py similarity index 100% rename from src/globus_sdk/experimental/consents/_errors.py rename to src/globus_sdk/scopes/consents/_errors.py diff --git a/src/globus_sdk/experimental/consents/_model.py b/src/globus_sdk/scopes/consents/_model.py similarity index 99% rename from src/globus_sdk/experimental/consents/_model.py rename to src/globus_sdk/scopes/consents/_model.py index f6f05fa7f..9e5f0531d 100644 --- a/src/globus_sdk/experimental/consents/_model.py +++ b/src/globus_sdk/scopes/consents/_model.py @@ -30,9 +30,9 @@ from dataclasses import dataclass from datetime import datetime -from globus_sdk import Scope from globus_sdk._types import UUIDLike +from ..representation import Scope from ._errors import ConsentParseError, ConsentTreeConstructionError diff --git a/src/globus_sdk/services/auth/response/consents.py b/src/globus_sdk/services/auth/response/consents.py index e0b9452c4..24dd3cd20 100644 --- a/src/globus_sdk/services/auth/response/consents.py +++ b/src/globus_sdk/services/auth/response/consents.py @@ -1,5 +1,5 @@ from globus_sdk import IterableResponse -from globus_sdk.experimental.consents import ConsentForest +from globus_sdk.scopes.consents import ConsentForest class GetConsentsResponse(IterableResponse): @@ -17,9 +17,5 @@ def to_forest(self) -> ConsentForest: ConsentForest is a convenience class to make interacting with the tree of consents simpler. - - Note: - This interface relies on the experimental Consents data model which is - subject to change. """ return ConsentForest(self) diff --git a/tests/common/consents.py b/tests/common/consents.py index 927c1281d..a5cb571a0 100644 --- a/tests/common/consents.py +++ b/tests/common/consents.py @@ -7,7 +7,7 @@ from globus_sdk import Scope from globus_sdk._types import UUIDLike -from globus_sdk.experimental.consents import Consent, ConsentForest +from globus_sdk.scopes.consents import Consent, ConsentForest ScopeRepr = namedtuple("Scope", ["id", "name"]) diff --git a/tests/unit/experimental/globus_app/test_validating_token_storage.py b/tests/unit/experimental/globus_app/test_validating_token_storage.py index 5b2c13926..52868aee0 100644 --- a/tests/unit/experimental/globus_app/test_validating_token_storage.py +++ b/tests/unit/experimental/globus_app/test_validating_token_storage.py @@ -9,7 +9,6 @@ import globus_sdk from globus_sdk import MISSING, MissingType, OAuthTokenResponse, Scope -from globus_sdk.experimental.consents import ConsentForest from globus_sdk.experimental.globus_app import ValidatingTokenStorage from globus_sdk.experimental.globus_app.errors import ( IdentityMismatchError, @@ -18,6 +17,7 @@ UnmetScopeRequirementsError, ) from globus_sdk.experimental.tokenstorage import MemoryTokenStorage +from globus_sdk.scopes.consents import ConsentForest from tests.common import make_consent_forest diff --git a/tests/unit/services/auth/test_consents.py b/tests/unit/scopes/test_consents.py similarity index 98% rename from tests/unit/services/auth/test_consents.py rename to tests/unit/scopes/test_consents.py index b0396a201..431943738 100644 --- a/tests/unit/services/auth/test_consents.py +++ b/tests/unit/scopes/test_consents.py @@ -5,7 +5,7 @@ import pytest -from globus_sdk.experimental.consents import ConsentForest, ConsentTreeConstructionError +from globus_sdk.scopes.consents import ConsentForest, ConsentTreeConstructionError from tests.common import ConsentTest, ScopeRepr _zero_uuid = str(UUID(int=0)) From 1eef2b3309664ac166b9e6a56413f17c07ffff5b Mon Sep 17 00:00:00 2001 From: Stephen Rosen Date: Mon, 16 Sep 2024 10:30:25 -0500 Subject: [PATCH 2/2] Update docs/authorization/scopes_and_consents/consents.rst Co-authored-by: derek-globus <113056046+derek-globus@users.noreply.github.com> --- docs/authorization/scopes_and_consents/consents.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/authorization/scopes_and_consents/consents.rst b/docs/authorization/scopes_and_consents/consents.rst index 4aa486705..dd041ebd5 100644 --- a/docs/authorization/scopes_and_consents/consents.rst +++ b/docs/authorization/scopes_and_consents/consents.rst @@ -12,11 +12,8 @@ Consents are modeled as a ``ConsentForest`` full of ``ConsentTrees`` containing provided by a user to client applications for token grants under certain scoped contexts. -Consent objects are provided from ``globus_sdk.scopes.consents``. - -They are typically produced by calling -:meth:`globus_sdk.AuthClient.get_consents` and invoking ``to_forest()`` on -the response. Example usage: +While the consent model classes themselves are exposed here in ``globus_sdk.scopes.consents``, +most objects are actually loaded from a :meth:`globus_sdk.AuthClient.get_consents` response, using the attached :meth:`globus_sdk.GetConsentsResponse.to_forest()` method: .. code-block:: python