volcano-sdk-python 0.9.1__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 +6 -5
- volcano_sdk/functions.py +80 -14
- volcano_sdk/realtime.py +5 -2
- {volcano_sdk_python-0.9.1.dist-info → volcano_sdk_python-0.9.3.dist-info}/METADATA +23 -9
- {volcano_sdk_python-0.9.1.dist-info → volcano_sdk_python-0.9.3.dist-info}/RECORD +7 -7
- {volcano_sdk_python-0.9.1.dist-info → volcano_sdk_python-0.9.3.dist-info}/WHEEL +0 -0
- {volcano_sdk_python-0.9.1.dist-info → volcano_sdk_python-0.9.3.dist-info}/licenses/LICENSE +0 -0
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 =
|
|
1647
|
-
|
|
1648
|
-
name=name,
|
|
1648
|
+
response = client.get_httpx_client().request(
|
|
1649
|
+
**resolve_function_kwargs(name=name)
|
|
1649
1650
|
)
|
|
1650
|
-
return self.
|
|
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
|
|
14
|
-
|
|
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 =
|
|
85
|
-
|
|
86
|
-
|
|
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 =
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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) ->
|
|
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
|
|
343
|
+
return cast("Mapping[str, JSONValue]", _freeze_json(cast("JSONValue", value)))
|
volcano_sdk/realtime.py
CHANGED
|
@@ -768,7 +768,6 @@ class Channel:
|
|
|
768
768
|
not self._fetch_config.enabled
|
|
769
769
|
or change.mode != "lightweight"
|
|
770
770
|
or change.type == "DELETE"
|
|
771
|
-
or change.schema != "public"
|
|
772
771
|
or change.id is None
|
|
773
772
|
or database_name is None
|
|
774
773
|
):
|
|
@@ -776,7 +775,11 @@ class Channel:
|
|
|
776
775
|
return _PostgresFetchRequest(
|
|
777
776
|
database_name=database_name,
|
|
778
777
|
access_token=self._realtime._connection_token(),
|
|
779
|
-
table=
|
|
778
|
+
table=(
|
|
779
|
+
change.table
|
|
780
|
+
if change.schema == "public"
|
|
781
|
+
else f"{change.schema}.{change.table}"
|
|
782
|
+
),
|
|
780
783
|
row_id=change.id,
|
|
781
784
|
)
|
|
782
785
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: volcano-sdk-python
|
|
3
|
-
Version: 0.9.
|
|
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
|
|
@@ -79,14 +79,18 @@ function = client.functions.invoke(
|
|
|
79
79
|
)
|
|
80
80
|
print(function.status, function.version, function.data)
|
|
81
81
|
|
|
82
|
-
logs
|
|
82
|
+
# Project logs use a control-plane project token, not this end-user session.
|
|
83
|
+
logs_client = VolcanoClient(
|
|
84
|
+
anon_key="ak_your_anon_key", access_token="vpat_your_project_token"
|
|
85
|
+
)
|
|
86
|
+
logs = logs_client.logs.search(
|
|
83
87
|
"00000000-0000-4000-8000-000000000001",
|
|
84
88
|
{"resource": {"type": "function"}, "limit": 100},
|
|
85
89
|
)
|
|
86
90
|
for event in logs.data:
|
|
87
91
|
print(event["timestamp"], event["body"])
|
|
88
92
|
|
|
89
|
-
activity =
|
|
93
|
+
activity = logs_client.logs.activity(
|
|
90
94
|
"00000000-0000-4000-8000-000000000001",
|
|
91
95
|
{"resource": {"type": "function"}, "bucket_count": 24},
|
|
92
96
|
)
|
|
@@ -220,13 +224,23 @@ user session; the function receives no user identity. The immutable result
|
|
|
220
224
|
includes the response body, status, headers, and `X-Volcano-Version`. The body
|
|
221
225
|
can be a JSON object, array, scalar, or text; an empty body returns `None`.
|
|
222
226
|
JSON arrays become immutable tuples. Invalid JSON is returned as text. A
|
|
223
|
-
function's own non-2xx response is returned when
|
|
224
|
-
|
|
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.
|
|
225
237
|
|
|
226
238
|
`logs.search()` returns an immutable page of retained runtime or deployment log
|
|
227
239
|
events. Pass `next_cursor` back as `cursor` to continue a search. `logs.activity()`
|
|
228
240
|
returns immutable time buckets using the same resource selector and query syntax.
|
|
229
|
-
Both methods require
|
|
241
|
+
Both methods require a platform user token or a project access token.
|
|
242
|
+
A `read_only` project token is sufficient; end-user sessions cannot read project logs.
|
|
243
|
+
See the [logs guide](https://github.com/Kong/volcano-sdk-python/blob/main/docs/logs.md).
|
|
230
244
|
|
|
231
245
|
Database selects, inserts, updates, deletes, log reads, and authenticated storage
|
|
232
246
|
requests (including upload sessions and parts) refresh the captured
|
|
@@ -784,12 +798,12 @@ stop_changes()
|
|
|
784
798
|
```
|
|
785
799
|
|
|
786
800
|
Binding a database automatically fetches the matching row for lightweight
|
|
787
|
-
`INSERT` and `UPDATE` notifications in
|
|
801
|
+
`INSERT` and `UPDATE` notifications in public or custom schemas. The fetch uses the
|
|
788
802
|
realtime connection's RLS-scoped access token. Compatible row lookups are
|
|
789
803
|
batched while callback delivery preserves publication order.
|
|
790
804
|
If the row is absent or the query fails, the callback receives the lightweight
|
|
791
|
-
notification with its `id` and `mode` intact.
|
|
792
|
-
|
|
805
|
+
notification with its `id` and `mode` intact. Custom-schema row lookups preserve
|
|
806
|
+
the schema from the notification. Lightweight deletes never query the database; they
|
|
793
807
|
preserve `old_record`, or provide `{"id": change.id}` when no old row was
|
|
794
808
|
included. Tune a channel's batching with `fetch_batch_window_ms` and
|
|
795
809
|
`fetch_max_batch_size`; the defaults are 20 milliseconds and 50 rows. Set
|
|
@@ -6,18 +6,18 @@ 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=
|
|
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=
|
|
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
|
|
19
19
|
volcano_sdk/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
20
|
-
volcano_sdk/realtime.py,sha256=
|
|
20
|
+
volcano_sdk/realtime.py,sha256=KJbEMEpCYqlbE4YYtu6Wt5YM379LQmWtXU-wRhni1T0,59597
|
|
21
21
|
volcano_sdk/storage.py,sha256=p16OV5ADI6JjMAJ7gx2gcmwk9t8--YiIZcOSLQLVlDY,26238
|
|
22
22
|
volcano_sdk/_generated/__init__.py,sha256=ZlB8wMYdN6EjpUS5W_lX3jsxq9G1kOcmUr-j3Fccfn8,164
|
|
23
23
|
volcano_sdk/_generated/client.py,sha256=GDzw6T2uRmPlUb1DImpBGxwy0dNbhmBknfvvIQW0GuU,12387
|
|
@@ -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.
|
|
779
|
-
volcano_sdk_python-0.9.
|
|
780
|
-
volcano_sdk_python-0.9.
|
|
781
|
-
volcano_sdk_python-0.9.
|
|
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,,
|
|
File without changes
|
|
File without changes
|