Skip to content

Commit 6a6c220

Browse files
committed
put CreateTunnelData back and add TunnelCreateDocument and TunnelUpdateDocument
1 parent c9a1e76 commit 6a6c220

12 files changed

Lines changed: 154 additions & 85 deletions

File tree

changelog.d/20260226_154303_aaschaer_transfer_v2.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Added
22
-----
33

4-
- Added the experimental ``TransferClientV2`` client class (:pr:`NUMBER`)
4+
- Added the experimental ``TransferClientV2`` client class along with helper
5+
classes ``TunnelCreateDocument`` and ``TunnelUpdateDocument`` (:pr:`NUMBER`)
56
- JSON:API iteration and pagination is now supported through
67
``IterableJSONAPIResponse`` and ``JSONAPIPaginator`` (:pr:`NUMBER`)
78

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from .transfer_v2 import CreateTunnelData, TransferClientV2
1+
from .transfer_v2 import TransferClientV2, TunnelCreateDocument, TunnelUpdateDocument
22

33
__all__ = (
44
"TransferClientV2",
5-
"CreateTunnelData",
5+
"TunnelCreateDocument",
6+
"TunnelUpdateDocument",
67
)
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from .client import TransferClientV2
2-
from .data import CreateTunnelData
2+
from .data import TunnelCreateDocument, TunnelUpdateDocument
33

44
__all__ = (
55
"TransferClientV2",
6-
"CreateTunnelData",
6+
"TunnelCreateDocument",
7+
"TunnelUpdateDocument",
78
)

src/globus_sdk/experimental/transfer_v2/client.py

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
import typing as t
55
import uuid
66

7-
from globus_sdk import client, exc, paging, response
8-
from globus_sdk._missing import MISSING
7+
from globus_sdk import client, paging, response
98
from globus_sdk.response import IterableJSONAPIResponse
109
from globus_sdk.scopes import TransferScopes
1110
from globus_sdk.services.transfer.errors import TransferAPIError
1211
from globus_sdk.transport import RetryConfig
1312

14-
from .data import CreateTunnelData
13+
from .data import TunnelCreateDocument, TunnelUpdateDocument
1514
from .transport import TRANSFER_V2_DEFAULT_RETRY_CHECKS
1615

1716
log = logging.getLogger(__name__)
@@ -46,7 +45,7 @@ class TransferClientV2(client.BaseClient):
4645
for stream_access_point in page:
4746
print(stream_access_point["attributes"]["display_name"])
4847
49-
.. automethodlist:: globus_sdk.TransferClient
48+
.. automethodlist:: globus_sdk.experimental.TransferClientV2
5049
"""
5150

5251
service_name = "transfer"
@@ -62,7 +61,7 @@ def _register_standard_retry_checks(self, retry_config: RetryConfig) -> None:
6261

6362
def create_tunnel(
6463
self,
65-
data: dict[str, t.Any] | CreateTunnelData,
64+
data: dict[str, t.Any] | TunnelCreateDocument,
6665
) -> response.GlobusHTTPResponse:
6766
"""
6867
:param data: Parameters for the tunnel creation
@@ -73,7 +72,8 @@ def create_tunnel(
7372
7473
.. code-block:: python
7574
76-
tc = globus_sdk.TrasferClientV2(...)
75+
tc = globus_sdk.experimental.TrasferClientV2(...)
76+
data = globus_sdk.experimental.TunnelCreateDocument(...)
7777
result = tc.create_tunnel(data)
7878
print(result["data"]["id"])
7979
@@ -82,30 +82,13 @@ def create_tunnel(
8282
``POST /v2/tunnels``
8383
"""
8484
log.debug("TransferClientV2.create_tunnel(...)")
85-
try:
86-
data_element = data["data"]
87-
except KeyError as e:
88-
raise exc.GlobusSDKUsageError(
89-
"create_tunnel() body was malformed (missing the 'data' key). "
90-
"Use CreateTunnelData to easily create correct documents."
91-
) from e
92-
93-
try:
94-
attributes = data_element["attributes"]
95-
except KeyError:
96-
data_element["attributes"] = {}
97-
attributes = data_element["attributes"]
98-
if attributes.get("submission_id", MISSING) is MISSING:
99-
log.debug("create_tunnel auto-creating submission_id")
100-
attributes["submission_id"] = str(uuid.uuid1())
101-
10285
r = self.post("/v2/tunnels", data=data)
10386
return r
10487

10588
def update_tunnel(
10689
self,
10790
tunnel_id: str | uuid.UUID,
108-
update_doc: dict[str, t.Any],
91+
update_doc: dict[str, t.Any] | TunnelUpdateDocument,
10992
) -> response.GlobusHTTPResponse:
11093
r"""
11194
:param tunnel_id: The ID of the Tunnel.
@@ -117,13 +100,8 @@ def update_tunnel(
117100
118101
.. code-block:: python
119102
120-
tc = globus_sdk.TrasferClientV2(...)
121-
"data" = {
122-
"type": "Tunnel",
123-
"attributes": {
124-
"state": "STOPPING",
125-
},
126-
}
103+
tc = globus_sdk.experimental.TrasferClientV2(...)
104+
data = globus_sdk.experimental.TunnelUpdateDocument(...)
127105
result = tc.update_tunnel(tunnel_id, data)
128106
print(result["data"])
129107
@@ -152,7 +130,7 @@ def get_tunnel(
152130
153131
.. code-block:: python
154132
155-
tc = globus_sdk.TrasferClientV2(...)
133+
tc = globus_sdk.experimental.TrasferClientV2(...)
156134
result = tc.show_tunnel(tunnel_id)
157135
print(result["data"])
158136
@@ -180,7 +158,7 @@ def delete_tunnel(
180158
181159
.. code-block:: python
182160
183-
tc = globus_sdk.TrasferClientV2(...)
161+
tc = globus_sdk.experimental.TrasferClientV2(...)
184162
tc.delete_tunnel(tunnel_id)
185163
186164
.. tab-item:: API Info
@@ -208,7 +186,7 @@ def list_tunnels(
208186
209187
.. code-block:: python
210188
211-
tc = globus_sdk.TrasferClientV2(...)
189+
tc = globus_sdk.experimental.TrasferClientV2(...)
212190
tc.list_tunnels(tunnel_id)
213191
214192
.. tab-item:: API Info
@@ -236,7 +214,7 @@ def get_tunnel_events(
236214
237215
.. code-block:: python
238216
239-
tc = globus_sdk.TrasferClientV2(...)
217+
tc = globus_sdk.experimental.TrasferClientV2(...)
240218
result = tc.get_tunnel_events(tunnel_id)
241219
print(result["data"])
242220
@@ -269,7 +247,7 @@ def get_stream_access_point(
269247
270248
.. code-block:: python
271249
272-
tc = globus_sdk.TrasferClientV2(...)
250+
tc = globus_sdk.experimental.TrasferClientV2(...)
273251
tc.get_stream_access_point(stream_ap_id)
274252
275253
.. tab-item:: API Info
@@ -302,7 +280,7 @@ def list_stream_access_points(
302280
303281
.. code-block:: python
304282
305-
tc = globus_sdk.TrasferClientV2(...)
283+
tc = globus_sdk.experimental.TrasferClientV2(...)
306284
tc.list_stream_access_points()
307285
308286
.. tab-item:: API Info

src/globus_sdk/experimental/transfer_v2/data/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
:class:`TransferClient <globus_sdk.TransferClient>` methods without conversion.
55
"""
66

7-
from .tunnel_data import CreateTunnelData
7+
from .tunnel_documents import TunnelCreateDocument, TunnelUpdateDocument
88

9-
__all__ = ("CreateTunnelData",)
9+
__all__ = ("TunnelCreateDocument", "TunnelUpdateDocument")
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
import typing as t
5+
import uuid
6+
7+
from globus_sdk._missing import MISSING, MissingType
8+
from globus_sdk._payload import GlobusPayload
9+
10+
log = logging.getLogger(__name__)
11+
12+
13+
class TunnelCreateDocument(GlobusPayload):
14+
"""
15+
Convenience class for constructing a tunnel document to use as the
16+
``data`` parameter to
17+
:meth:`create_tunnel <globus_sdk.TransferClientV2.create_tunnel>`.
18+
"""
19+
20+
def __init__(
21+
self,
22+
initiator_stream_access_point: uuid.UUID | str,
23+
listener_stream_access_point: uuid.UUID | str,
24+
*,
25+
label: str | MissingType = MISSING,
26+
listener_port: int | MissingType = MISSING,
27+
listener_ip_address: str | MissingType = MISSING,
28+
submission_id: uuid.UUID | str | MissingType = MISSING,
29+
lifetime_mins: int | MissingType = MISSING,
30+
restartable: bool | MissingType = MISSING,
31+
additional_fields: dict[str, t.Any] | None = None,
32+
) -> None:
33+
super().__init__()
34+
log.debug("Creating a new TunnelCreateDocument object")
35+
36+
# Auto-create submission_id if not given now so that the same
37+
# submission_id will be used across retries
38+
if submission_id is MISSING:
39+
submission_id = uuid.uuid1()
40+
41+
relationships = {
42+
"listener": {
43+
"data": {
44+
"type": "StreamAccessPoint",
45+
"id": listener_stream_access_point,
46+
}
47+
},
48+
"initiator": {
49+
"data": {
50+
"type": "StreamAccessPoint",
51+
"id": initiator_stream_access_point,
52+
}
53+
},
54+
}
55+
attributes = {
56+
"label": label,
57+
"listener_port": listener_port,
58+
"listener_ip_address": listener_ip_address,
59+
"submission_id": submission_id,
60+
"restartable": restartable,
61+
"lifetime_mins": lifetime_mins,
62+
}
63+
if additional_fields is not None:
64+
attributes.update(additional_fields)
65+
66+
self["data"] = {
67+
"type": "Tunnel",
68+
"relationships": relationships,
69+
"attributes": attributes,
70+
}
71+
72+
73+
class TunnelUpdateDocument(GlobusPayload):
74+
"""
75+
Convenience class for constructing a tunnel document to use as the
76+
``data`` parameter to
77+
:meth:`update_tunnel <globus_sdk.TransferClientV2.update_tunnel>`.
78+
"""
79+
80+
def __init__(
81+
self,
82+
*,
83+
label: str | MissingType = MISSING,
84+
listener_port: int | MissingType = MISSING,
85+
listener_ip_address: str | MissingType = MISSING,
86+
state: t.Literal["STOPPING"] | MissingType = MISSING,
87+
additional_fields: dict[str, t.Any] | None = None,
88+
) -> None:
89+
super().__init__()
90+
log.debug("Creating a new TunnelUpdateDocument object")
91+
92+
attributes = {
93+
"label": label,
94+
"listener_port": listener_port,
95+
"listener_ip_address": listener_ip_address,
96+
"state": state,
97+
}
98+
if additional_fields is not None:
99+
attributes.update(additional_fields)
100+
101+
self["data"] = {
102+
"type": "Tunnel",
103+
"attributes": attributes,
104+
}

src/globus_sdk/services/transfer/data/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
:class:`TransferClient <globus_sdk.TransferClient>` methods without conversion.
55
"""
66

7-
# CreateTunnelData has been moved to experimental but is provided here for
8-
# backwards compatibility
9-
from globus_sdk.experimental.transfer_v2.data import CreateTunnelData
10-
117
from .delete_data import DeleteData
128
from .transfer_data import TransferData
9+
from .tunnel_data import CreateTunnelData
1310

1411
__all__ = ("TransferData", "DeleteData", "CreateTunnelData")

src/globus_sdk/experimental/transfer_v2/data/tunnel_data.py renamed to src/globus_sdk/services/transfer/data/tunnel_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class CreateTunnelData(GlobusPayload):
1414
"""
1515
Convenience class for constructing a tunnel document to use as the
1616
``data`` parameter to
17-
:meth:`create_tunnel <globus_sdk.TransferClientV2.create_tunnel>`.
17+
:meth:`create_tunnel <globus_sdk.TransferClient.create_tunnel>`.
1818
"""
1919

2020
def __init__(
Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
import json
22
import uuid
33

4-
import pytest
5-
6-
from globus_sdk import exc
7-
from globus_sdk.experimental import CreateTunnelData
4+
from globus_sdk.experimental import TunnelCreateDocument
85
from globus_sdk.testing import get_last_request, load_response
96

107

118
def test_create_tunnel(client):
129
meta = load_response(client.create_tunnel).metadata
1310

1411
submission_id = uuid.uuid4()
15-
data = CreateTunnelData(
12+
data = TunnelCreateDocument(
1613
meta["initiator_ap"],
1714
meta["listener_ap"],
1815
submission_id=submission_id,
@@ -38,33 +35,17 @@ def test_create_tunnel(client):
3835
def test_create_tunnel_no_submission(client):
3936
meta = load_response(client.create_tunnel).metadata
4037

41-
data = CreateTunnelData(
38+
data = TunnelCreateDocument(
4239
meta["initiator_ap"], meta["listener_ap"], label=meta["display_name"]
4340
)
4441

42+
# confirm TunnelCreateDocument auto-generated a submission_id
43+
generated_uuid = data["data"]["attributes"]["submission_id"]
44+
assert isinstance(generated_uuid, uuid.UUID)
45+
4546
res = client.create_tunnel(data)
4647
assert res.http_status == 200
4748

4849
req = get_last_request()
4950
sent = json.loads(req.body)
50-
assert sent["data"]["attributes"]["submission_id"] is not None
51-
52-
53-
def test_create_tunnel_bad_input(client):
54-
data = {
55-
"relationships": {
56-
"listener": {
57-
"data": {
58-
"type": "StreamAccessPoint",
59-
}
60-
},
61-
"initiator": {
62-
"data": {
63-
"type": "StreamAccessPoint",
64-
}
65-
},
66-
}
67-
}
68-
69-
with pytest.raises(exc.GlobusSDKUsageError):
70-
client.create_tunnel(data)
51+
assert sent["data"]["attributes"]["submission_id"] == str(generated_uuid)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from globus_sdk.testing import get_last_request, load_response
2+
3+
4+
def test_get_tunnel_events(client):
5+
meta = load_response(client.get_tunnel_events).metadata
6+
res = client.get_tunnel_events(meta["tunnel_id"])
7+
assert res.http_status == 200
8+
assert res["data"][0]["type"] == "TunnelEvent"
9+
assert res["data"][1]["type"] == "TunnelEvent"
10+
11+
req = get_last_request()
12+
assert req.body is None

0 commit comments

Comments
 (0)