Skip to content

Commit

Permalink
Merge pull request #1096 from rjmello/versioned-compute-clients
Browse files Browse the repository at this point in the history
Create versioned Compute clients
  • Loading branch information
kurtmckee authored Nov 6, 2024
2 parents 5e11def + 7d63262 commit 2ba95ce
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Added
~~~~~

- Created ``ComputeClientV2`` and ``ComputeClientV3`` classes to support Globus Compute
API versions 2 and 3, respectively. The canonical ``ComputeClient`` is now a subclass
of ``ComputeClientV2``, preserving backward compatibility. (:pr:`NUMBER`)
30 changes: 30 additions & 0 deletions docs/services/compute.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,47 @@ Globus Compute

.. currentmodule:: globus_sdk

The standard way to interact with the Globus Compute service is through the
`Globus Compute SDK <https://globus-compute.readthedocs.io/en/stable/sdk.html>`_,
a separate, specialized toolkit that offers enhanced functionality for Globus Compute.
Under the hood, the Globus Compute SDK uses the following clients to interact with
the Globus Compute API. Advanced users may choose to work directly with these clients
for custom implementations.

The canonical :class:`ComputeClient` is a subclass of :class:`ComputeClientV2`,
which supports version 2 of the Globus Compute API. When feasible, new projects
should use :class:`ComputeClientV3`, which supports version 3 and includes the
latest API features and improvements.

.. autoclass:: ComputeClient
:members:
:member-order: bysource
:show-inheritance:
:exclude-members: error_class, scopes

.. autoclass:: ComputeClientV2
:members:
:member-order: bysource
:show-inheritance:
:exclude-members: error_class, scopes

.. attribute:: scopes

.. listknownscopes:: globus_sdk.scopes.ComputeScopes
:base_name: ComputeClient.scopes

.. autoclass:: ComputeClientV3
:members:
:member-order: bysource
:show-inheritance:
:exclude-members: error_class, scopes

.. attribute:: scopes

.. listknownscopes:: globus_sdk.scopes.ComputeScopes
:base_name: ComputeClient.scopes


Client Errors
-------------

Expand Down
6 changes: 6 additions & 0 deletions src/globus_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def _force_eager_imports() -> None:
},
"services.compute": {
"ComputeClient",
"ComputeClientV2",
"ComputeClientV3",
"ComputeAPIError",
"ComputeFunctionDocument",
"ComputeFunctionMetadata",
Expand Down Expand Up @@ -206,6 +208,8 @@ def _force_eager_imports() -> None:
from .services.auth import OAuthTokenResponse
from .services.auth import DependentScopeSpec
from .services.compute import ComputeClient
from .services.compute import ComputeClientV2
from .services.compute import ComputeClientV3
from .services.compute import ComputeAPIError
from .services.compute import ComputeFunctionDocument
from .services.compute import ComputeFunctionMetadata
Expand Down Expand Up @@ -333,6 +337,8 @@ def __getattr__(name: str) -> t.Any:
"CollectionPolicies",
"ComputeAPIError",
"ComputeClient",
"ComputeClientV2",
"ComputeClientV3",
"ComputeFunctionDocument",
"ComputeFunctionMetadata",
"ConfidentialAppAuthClient",
Expand Down
2 changes: 2 additions & 0 deletions src/globus_sdk/_generate_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ def __getattr__(name: str) -> t.Any:
"services.compute",
(
"ComputeClient",
"ComputeClientV2",
"ComputeClientV3",
"ComputeAPIError",
"ComputeFunctionDocument",
"ComputeFunctionMetadata",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from globus_sdk._testing.models import RegisteredResponse, ResponseSet

from ._common import FUNCTION_ID
from .._common import FUNCTION_ID

RESPONSES = ResponseSet(
metadata={"function_id": FUNCTION_ID},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from globus_sdk._testing.models import RegisteredResponse, ResponseSet

from ._common import FUNCTION_CODE, FUNCTION_ID, FUNCTION_NAME
from .._common import FUNCTION_CODE, FUNCTION_ID, FUNCTION_NAME

FUNCTION_DOC = {
"function_uuid": FUNCTION_ID,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from globus_sdk._testing.models import RegisteredResponse, ResponseSet

from ._common import FUNCTION_CODE, FUNCTION_ID, FUNCTION_NAME
from .._common import FUNCTION_CODE, FUNCTION_ID, FUNCTION_NAME

RESPONSES = ResponseSet(
metadata={
Expand Down
15 changes: 15 additions & 0 deletions src/globus_sdk/_testing/registry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import importlib
import re
import typing as t

import responses
Expand All @@ -9,6 +10,10 @@

from .models import RegisteredResponse, ResponseList, ResponseSet

# matches "V2", "V11", etc as a string suffix
# see usage in _resolve_qualname for details
_SUFFIX_VERSION_MATCH_PATTERN = re.compile(r"V\d+$")

_RESPONSE_SET_REGISTRY: dict[t.Any, ResponseSet] = {}


Expand Down Expand Up @@ -53,6 +58,16 @@ def _resolve_qualname(name: str) -> str:

assert issubclass(maybe_client, globus_sdk.BaseClient)
service_name = maybe_client.service_name

# TODO: Consider alternative strategies for mapping versioned clients
# to subdirs. For now, we do it by name matching.
#
# 'prefix' is the client name, and it may end in `V2`, `V3`, etc.
# in which case we want to map it to a subdir
suffix_version_match = _SUFFIX_VERSION_MATCH_PATTERN.search(prefix)
if suffix_version_match:
suffix = f"{suffix_version_match.group(0).lower()}.{suffix}"

return f"{service_name}.{suffix}"


Expand Down
4 changes: 3 additions & 1 deletion src/globus_sdk/services/compute/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from .client import ComputeClient
from .client import ComputeClient, ComputeClientV2, ComputeClientV3
from .data import ComputeFunctionDocument, ComputeFunctionMetadata
from .errors import ComputeAPIError

__all__ = (
"ComputeAPIError",
"ComputeClient",
"ComputeClientV2",
"ComputeClientV3",
"ComputeFunctionDocument",
"ComputeFunctionMetadata",
)
28 changes: 25 additions & 3 deletions src/globus_sdk/services/compute/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
log = logging.getLogger(__name__)


class ComputeClient(client.BaseClient):
class ComputeClientV2(client.BaseClient):
r"""
Client for the Globus Compute API.
Client for the Globus Compute API, version 2.
.. automethodlist:: globus_sdk.ComputeClient
.. automethodlist:: globus_sdk.ComputeClientV2
"""

error_class = ComputeAPIError
Expand Down Expand Up @@ -71,3 +71,25 @@ def delete_function(self, function_id: UUIDLike) -> GlobusHTTPResponse:
:ref: Functions/operation/delete_function_v2_functions__function_uuid__delete
""" # noqa: E501
return self.delete(f"/v2/functions/{function_id}")


class ComputeClientV3(client.BaseClient):
r"""
Client for the Globus Compute API, version 3.
.. automethodlist:: globus_sdk.ComputeClientV3
"""

error_class = ComputeAPIError
service_name = "compute"
scopes = ComputeScopes
default_scope_requirements = [Scope(ComputeScopes.all)]


class ComputeClient(ComputeClientV2):
r"""
Canonical client for the Globus Compute API, with support exclusively for
API version 2.
.. automethodlist:: globus_sdk.ComputeClient
"""
6 changes: 3 additions & 3 deletions tests/functional/services/compute/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@


@pytest.fixture
def compute_client(no_retry_transport):
class CustomComputeClient(globus_sdk.ComputeClient):
def compute_client_v2(no_retry_transport):
class CustomComputeClientV2(globus_sdk.ComputeClientV2):
transport_class = no_retry_transport

return CustomComputeClient()
return CustomComputeClientV2()
9 changes: 0 additions & 9 deletions tests/functional/services/compute/test_delete_function.py

This file was deleted.

9 changes: 9 additions & 0 deletions tests/functional/services/compute/v2/test_delete_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import globus_sdk
from globus_sdk._testing import load_response


def test_delete_function(compute_client_v2: globus_sdk.ComputeClientV2):
meta = load_response(compute_client_v2.delete_function).metadata
res = compute_client_v2.delete_function(function_id=meta["function_id"])
assert res.http_status == 200
assert res.data == {"result": 302}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from globus_sdk._testing import load_response


def test_get_function(compute_client: globus_sdk.ComputeClient):
meta = load_response(compute_client.get_function).metadata
res = compute_client.get_function(function_id=meta["function_id"])
def test_get_function(compute_client_v2: globus_sdk.ComputeClientV2):
meta = load_response(compute_client_v2.get_function).metadata
res = compute_client_v2.get_function(function_id=meta["function_id"])
assert res.http_status == 200
assert res.data["function_uuid"] == meta["function_id"]
assert res.data["function_name"] == meta["function_name"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from globus_sdk._testing import load_response


def test_register_function(compute_client: globus_sdk.ComputeClient):
meta = load_response(compute_client.register_function).metadata
def test_register_function(compute_client_v2: globus_sdk.ComputeClientV2):
meta = load_response(compute_client_v2.register_function).metadata
registration_doc = {
"function_name": meta["function_name"],
"function_code": meta["function_code"],
}
res = compute_client.register_function(function_data=registration_doc)
res = compute_client_v2.register_function(function_data=registration_doc)
assert res.http_status == 200
assert res.data["function_uuid"] == meta["function_id"]
6 changes: 6 additions & 0 deletions tests/unit/services/compute/test_canononical_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from globus_sdk.services.compute.client import ComputeClient, ComputeClientV2


def test_canonical_client_is_v2():
client = ComputeClient()
assert isinstance(client, ComputeClientV2)

0 comments on commit 2ba95ce

Please sign in to comment.