volcano-sdk-python 0.9.2__py3-none-any.whl → 0.9.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
volcano_sdk/_transport.py CHANGED
@@ -99,10 +99,12 @@ from ._generated.api.database_queries.query_database_update import (
99
99
  from ._generated.api.database_queries.query_database_update import (
100
100
  _get_kwargs as database_update_kwargs,
101
101
  )
102
- from ._generated.api.functions import resolve_function_for_invocation
103
102
  from ._generated.api.functions.invoke_function import (
104
103
  _get_kwargs as invoke_function_kwargs,
105
104
  )
105
+ from ._generated.api.functions.resolve_function_for_invocation import (
106
+ _get_kwargs as resolve_function_kwargs,
107
+ )
106
108
  from ._generated.api.locks import (
107
109
  force_release_project_lock,
108
110
  get_project_lock,
@@ -1643,11 +1645,10 @@ class GeneratedTransport:
1643
1645
  name: str,
1644
1646
  ) -> TransportResponse:
1645
1647
  with self._client(authorization) as client:
1646
- response = resolve_function_for_invocation.sync_detailed(
1647
- client=client,
1648
- name=name,
1648
+ response = client.get_httpx_client().request(
1649
+ **resolve_function_kwargs(name=name)
1649
1650
  )
1650
- return self._response(response)
1651
+ return self._raw_response(response)
1651
1652
 
1652
1653
  def invoke_function(
1653
1654
  self,
volcano_sdk/functions.py CHANGED
@@ -4,14 +4,19 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import re
7
- from collections.abc import Mapping
8
- from typing import TYPE_CHECKING, Protocol, cast
7
+ from collections.abc import Callable, Mapping
8
+ from typing import TYPE_CHECKING, Protocol, TypeVar, cast
9
9
 
10
10
  from . import _function_resolution
11
11
  from ._function_resolution import FunctionResolution
12
12
  from ._transport import TransportResponse, invoke, response_payload
13
- from .errors import NotFoundError
14
- from .models import FunctionResponse, JSONValue
13
+ from .errors import (
14
+ AuthenticationError,
15
+ NotFoundError,
16
+ SessionChangedError,
17
+ VolcanoError,
18
+ )
19
+ from .models import FunctionResponse, JSONValue, _freeze_json
15
20
 
16
21
  if TYPE_CHECKING:
17
22
  from .client import VolcanoClient
@@ -27,10 +32,57 @@ _UNKNOWN_FUNCTION = "Function was not found"
27
32
  _HTTP_SUCCESS_MIN = 200
28
33
  _HTTP_SUCCESS_MAX = 300
29
34
  _HTTP_NOT_FOUND = 404
35
+ _HTTP_UNAUTHORIZED = 401
30
36
  # Present only once the platform has dispatched to the function.
31
37
  _FUNCTION_INVOKED_HEADER = "X-Volcano-Function-Invoked"
32
38
 
33
39
 
40
+ _Result = TypeVar("_Result")
41
+
42
+
43
+ class _FunctionAuth:
44
+ def __init__(self, client: VolcanoClient) -> None:
45
+ self._client = client
46
+ self._binding = client._capture_session_binding()
47
+ self._fallback_token = client._function_token()
48
+
49
+ def run(self, operation: Callable[[str], _Result]) -> _Result:
50
+ if self._binding[2] is not None:
51
+ self._binding = self._client.auth._owned_refresh_session(self._binding)
52
+ try:
53
+ return self._run(operation)
54
+ finally:
55
+ if self._binding[2] is not None:
56
+ self._client.auth._validate_read_failure(self._binding)
57
+ elif self._client._capture_session_binding()[1] != self._binding[1]:
58
+ raise SessionChangedError
59
+
60
+ def _run(self, operation: Callable[[str], _Result]) -> _Result:
61
+ try:
62
+ return operation(self._token())
63
+ except AuthenticationError as original:
64
+ if self._binding[2] is None or original.status != _HTTP_UNAUTHORIZED:
65
+ raise
66
+ try:
67
+ # Resolve has released its cache lock before refresh callbacks run.
68
+ self._client.auth._refresh_session_for_binding(self._binding)
69
+ except SessionChangedError:
70
+ raise
71
+ except VolcanoError:
72
+ raise original from None
73
+ return operation(self._token())
74
+
75
+ def _token(self) -> str:
76
+ if self._binding[2] is None:
77
+ if self._client._capture_session_binding()[1] != self._binding[1]:
78
+ raise SessionChangedError
79
+ return self._fallback_token
80
+ session = self._client.auth._owned_refresh_session(self._binding)[2]
81
+ if session is None:
82
+ raise SessionChangedError
83
+ return session.access_token
84
+
85
+
34
86
  class FunctionsTransport(Protocol):
35
87
  """Transport operations required by the functions facade."""
36
88
 
@@ -77,13 +129,17 @@ class Functions:
77
129
  payload: Mapping[str, JSONValue] | None = None,
78
130
  ) -> FunctionResponse:
79
131
  """Resolve and invoke a function with an optional JSON object payload."""
132
+ auth = _FunctionAuth(self._client)
80
133
  name = _function_name(name)
81
134
  request_payload = _function_payload(payload)
82
- authorization = self._client._function_token()
83
135
  transport = cast("FunctionsTransport", self._client._transport)
84
- resolution = self._resolve(transport, authorization, name)
85
- response = self._invoke_resolved(
86
- transport, authorization, resolution, request_payload
136
+ authorization, resolution = auth.run(
137
+ lambda token: (token, self._resolve(transport, token, name))
138
+ )
139
+ response = auth.run(
140
+ lambda token: self._invoke_resolved(
141
+ transport, token, resolution, request_payload
142
+ )
87
143
  )
88
144
  if _stale_mapping(response):
89
145
  # The function was deleted and recreated, so the cached identity no
@@ -91,9 +147,13 @@ class Functions:
91
147
  _function_resolution.forget(
92
148
  self._client._api_base_url(), authorization, name
93
149
  )
94
- resolution = self._resolve(transport, authorization, name)
95
- response = self._invoke_resolved(
96
- transport, authorization, resolution, request_payload
150
+ _, resolution = auth.run(
151
+ lambda token: (token, self._resolve(transport, token, name))
152
+ )
153
+ response = auth.run(
154
+ lambda token: self._invoke_resolved(
155
+ transport, token, resolution, request_payload
156
+ )
97
157
  )
98
158
  return self._response(response)
99
159
 
@@ -118,7 +178,13 @@ class Functions:
118
178
  invoke_url=resolution.invoke_url,
119
179
  payload=payload,
120
180
  )
121
- return cast("TransportResponse", response)
181
+ response = cast("TransportResponse", response)
182
+ if (
183
+ response.status_code == _HTTP_UNAUTHORIZED
184
+ and _header(response.headers, _FUNCTION_INVOKED_HEADER) is None
185
+ ):
186
+ response_payload(response, _HTTP_SUCCESS_MIN)
187
+ return response
122
188
 
123
189
  def _resolve(
124
190
  self,
@@ -269,9 +335,9 @@ def _function_name(value: object) -> str:
269
335
  return value
270
336
 
271
337
 
272
- def _function_payload(value: object) -> dict[str, JSONValue]:
338
+ def _function_payload(value: object) -> Mapping[str, JSONValue]:
273
339
  if value is None:
274
340
  return {}
275
341
  if not isinstance(value, Mapping):
276
342
  raise TypeError(_INVALID_FUNCTION_PAYLOAD)
277
- return dict(cast("Mapping[str, JSONValue]", value))
343
+ return cast("Mapping[str, JSONValue]", _freeze_json(cast("JSONValue", value)))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: volcano-sdk-python
3
- Version: 0.9.2
3
+ Version: 0.9.3
4
4
  Summary: Official Python SDK for Volcano
5
5
  Project-URL: Homepage, https://volcano.dev
6
6
  Project-URL: Repository, https://github.com/Kong/volcano-sdk-python
@@ -224,8 +224,16 @@ user session; the function receives no user identity. The immutable result
224
224
  includes the response body, status, headers, and `X-Volcano-Version`. The body
225
225
  can be a JSON object, array, scalar, or text; an empty body returns `None`.
226
226
  JSON arrays become immutable tuples. Invalid JSON is returned as text. A
227
- function's own non-2xx response is returned when the version header proves it
228
- ran; platform failures raise typed SDK errors.
227
+ function's own non-2xx response is returned when Volcano confirms it ran;
228
+ non-success platform HTTP responses raise typed SDK errors.
229
+
230
+
231
+ Function resolution and invocation recover from a platform HTTP 401 before dispatch:
232
+ the SDK refreshes the captured session and retries the rejected request once.
233
+ Concurrent calls share successful recovery. Replacing or signing out that session
234
+ prevents replay under another identity. The call preserves its original payload values.
235
+ A function's own response, HTTP 403, or a network failure never triggers this retry.
236
+ Anonymous and service keys do not refresh.
229
237
 
230
238
  `logs.search()` returns an immutable page of retained runtime or deployment log
231
239
  events. Pass `next_cursor` back as `cursor` to continue a search. `logs.activity()`
@@ -6,13 +6,13 @@ volcano_sdk/_lock_worker.py,sha256=QhSmwR0WcwgT-7ueJMlbCogLqOakQ5eRAtyWV74fgV0,3
6
6
  volcano_sdk/_realtime_fetch_worker.py,sha256=zQTgFF4cIUBeAL4J2OpWAlz_sIynv2BLfu588EogAdo,9269
7
7
  volcano_sdk/_session.py,sha256=LYCv2NCDlL5Slh2YLEG8VQ8z-kDaKDYWW4vGdMvUf1U,2474
8
8
  volcano_sdk/_session_operations.py,sha256=1vI9gtwjxG2eUGT-nIYnMEgRldJqgIj2lRLukBbG64E,5518
9
- volcano_sdk/_transport.py,sha256=AFd47C3X1WAHwq3f9V2ux0WNzwGIn4NBxrwgaIN-xl0,58296
9
+ volcano_sdk/_transport.py,sha256=ox_wKKEW42gm2307uK9vIiQFB5l8pzb0ifWXxkzPiHQ,58331
10
10
  volcano_sdk/auth.py,sha256=iKq8o0K8geVKXrnLzhvOjAQoX_Nd0yQDJqDH4bemWaM,47366
11
11
  volcano_sdk/client.py,sha256=CJJnf_iTcXnyY2Y57LXJVAn39mTUsepblUg9op-Thzo,12283
12
12
  volcano_sdk/connection_string.py,sha256=LlTZigsrCF4IfAqQ8SDTWJv35hnnzNu1MfeVv5JW-Kk,2331
13
13
  volcano_sdk/database.py,sha256=p_5OaqlBjKAtIUfKQCflXM_CGqokrVmpOMsp6KHiJ8A,9493
14
14
  volcano_sdk/errors.py,sha256=ffs66FIN_jhyh5SMj7KdXb-zVV3DSgVK6xJEPNA5h9Y,1613
15
- volcano_sdk/functions.py,sha256=zDeAKyCieNnI6wzb9iZMlg9_cbjaYWXYbXHb7jzCle4,10126
15
+ volcano_sdk/functions.py,sha256=bk523Ss80nREwMD1wk6_pO2XKqOIXqDKylq0fQvMmb0,12540
16
16
  volcano_sdk/locks.py,sha256=eSkidfHQ_wml5-1LT2hBtHxeALP6E1cGYK0FzHjbrNk,9241
17
17
  volcano_sdk/logs.py,sha256=lxORRQBvsnJ0BdMau19MXrIeig5_mEucQSyJ4F1CZxU,4666
18
18
  volcano_sdk/models.py,sha256=n5EdzkWzmOstXsuFlvfGOILRemQAqG2P4VCLMelW8SA,8690
@@ -775,7 +775,7 @@ volcano_sdk/_generated/models/usage_data_point.py,sha256=d4U08JbVTiIMM_l2BmRILL1
775
775
  volcano_sdk/_generated/models/variable.py,sha256=tvGDOMv77gW6j5skufnfrlNAhzCzA1F7nuPCQWx79yY,5926
776
776
  volcano_sdk/_generated/models/variable_deploy_source.py,sha256=G_aCiFHzQx8WhJFs0GvYZEFclfTrfkDvd3kT1e3vty8,463
777
777
  volcano_sdk/_generated/models/variable_status.py,sha256=THSsKBSiAYG4kAtBzGA4TZqxjgx8hdL0Q4qCdZfOj00,391
778
- volcano_sdk_python-0.9.2.dist-info/METADATA,sha256=rJFF7ZXI76Kjkc_CyNAl6Dg5ryRKy2VjiOV4HBtIGLQ,35536
779
- volcano_sdk_python-0.9.2.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
780
- volcano_sdk_python-0.9.2.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
781
- volcano_sdk_python-0.9.2.dist-info/RECORD,,
778
+ volcano_sdk_python-0.9.3.dist-info/METADATA,sha256=AmqFIPDJDOmZgEWKZUIn0jW8EK4ITcvAG92gKMDl1Mk,36008
779
+ volcano_sdk_python-0.9.3.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
780
+ volcano_sdk_python-0.9.3.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
781
+ volcano_sdk_python-0.9.3.dist-info/RECORD,,