iii-sdk 0.19.7.dev1__tar.gz → 0.20.0.dev1__tar.gz
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.
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/PKG-INFO +2 -2
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/pyproject.toml +3 -3
- iii_sdk-0.20.0.dev1/src/iii/__init__.py +44 -0
- iii_sdk-0.20.0.dev1/src/iii/channel.py +7 -0
- iii_sdk-0.20.0.dev1/src/iii/engine.py +6 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/errors.py +6 -6
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/format_utils.py +2 -2
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/helpers.py +2 -2
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/iii.py +36 -36
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/iii_constants.py +25 -4
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/iii_types.py +3 -231
- iii_sdk-0.20.0.dev1/src/iii/internal.py +5 -0
- iii_sdk-0.20.0.dev1/src/iii/protocol.py +25 -0
- iii_sdk-0.20.0.dev1/src/iii/runtime.py +6 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/state.py +2 -9
- iii_sdk-0.20.0.dev1/src/iii/stream.py +54 -0
- iii_sdk-0.20.0.dev1/src/iii/trigger.py +6 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/triggers.py +3 -3
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/types.py +6 -26
- iii_sdk-0.20.0.dev1/src/iii/utils.py +25 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_api_triggers.py +9 -9
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_baggage_span_processor.py +1 -1
- iii_sdk-0.20.0.dev1/tests/test_channel_submodule.py +14 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_context_propagation.py +1 -1
- iii_sdk-0.20.0.dev1/tests/test_engine_constants.py +20 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_errors.py +35 -20
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_helpers.py +3 -3
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_hold_process.py +6 -6
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_http_external_functions_integration.py +4 -4
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_iii_registration_dedup.py +7 -7
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_init_api.py +3 -3
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_logger_function_ids.py +1 -1
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_logger_otel.py +8 -8
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_payload.py +1 -1
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_rbac_workers.py +11 -10
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_register_function_args.py +7 -8
- iii_sdk-0.20.0.dev1/tests/test_runtime_submodule.py +15 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_span_ops.py +1 -1
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_stream_models.py +1 -1
- iii_sdk-0.20.0.dev1/tests/test_stream_types.py +15 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_streams.py +2 -2
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_sync_api.py +4 -3
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_telemetry.py +6 -6
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_telemetry_exporters.py +2 -2
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_telemetry_types.py +1 -1
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_trace_helpers.py +1 -1
- iii_sdk-0.20.0.dev1/tests/test_trigger_submodule.py +31 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_trigger_type_lifecycle.py +2 -1
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/uv.lock +8 -6
- iii_sdk-0.19.7.dev1/src/iii/__init__.py +0 -120
- iii_sdk-0.19.7.dev1/src/iii/stream.py +0 -333
- iii_sdk-0.19.7.dev1/src/iii/utils.py +0 -61
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/.gitignore +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/README.md +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/channels.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/otel_worker_gauges.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/src/iii/worker_metrics.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/conftest.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_async_api.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_bridge.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_channel_close_delay.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_data_channels.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_format_utils.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_healthcheck.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_invocation_exception.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_middleware.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_pubsub.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_queue_integration.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_state.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_streams_runtime_annotations.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_trigger_metadata.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_trigger_registration_error.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_utils.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_worker_metadata.py +0 -0
- {iii_sdk-0.19.7.dev1 → iii_sdk-0.20.0.dev1}/tests/test_worker_metrics.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iii-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.0.dev1
|
|
4
4
|
Summary: III SDK for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/iii-hq/iii
|
|
6
6
|
Project-URL: Repository, https://github.com/iii-hq/iii
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
|
-
Requires-Dist: iii-
|
|
17
|
+
Requires-Dist: iii-helpers==0.20.0.dev1
|
|
18
18
|
Requires-Dist: opentelemetry-api>=1.25
|
|
19
19
|
Requires-Dist: pydantic>=2.0
|
|
20
20
|
Requires-Dist: websockets>=12.0
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iii-sdk"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.20.0.dev1"
|
|
8
8
|
description = "III SDK for Python"
|
|
9
9
|
authors = [{ name = "III" }]
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -23,7 +23,7 @@ dependencies = [
|
|
|
23
23
|
"websockets>=12.0",
|
|
24
24
|
"pydantic>=2.0",
|
|
25
25
|
"opentelemetry-api>=1.25",
|
|
26
|
-
"iii-
|
|
26
|
+
"iii-helpers==0.20.0.dev1",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
@@ -31,7 +31,7 @@ Homepage = "https://github.com/iii-hq/iii"
|
|
|
31
31
|
Repository = "https://github.com/iii-hq/iii"
|
|
32
32
|
|
|
33
33
|
[tool.uv.sources]
|
|
34
|
-
iii-
|
|
34
|
+
iii-helpers = { path = "../helpers", editable = true }
|
|
35
35
|
|
|
36
36
|
[project.optional-dependencies]
|
|
37
37
|
dev = [
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""III SDK for Python."""
|
|
2
|
+
|
|
3
|
+
from iii_helpers.queue import EnqueueResult
|
|
4
|
+
|
|
5
|
+
from .errors import InvocationError
|
|
6
|
+
from .iii import TriggerAction, register_worker
|
|
7
|
+
from .iii_constants import (
|
|
8
|
+
InitOptions,
|
|
9
|
+
TelemetryOptions,
|
|
10
|
+
)
|
|
11
|
+
from .iii_types import (
|
|
12
|
+
MiddlewareFunctionInput,
|
|
13
|
+
TriggerActionEnqueue,
|
|
14
|
+
TriggerActionVoid,
|
|
15
|
+
)
|
|
16
|
+
from .stream import IStream
|
|
17
|
+
from .types import (
|
|
18
|
+
IIIClient,
|
|
19
|
+
StreamRequest,
|
|
20
|
+
StreamResponse,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
# Errors
|
|
25
|
+
"InvocationError",
|
|
26
|
+
# Core
|
|
27
|
+
"InitOptions",
|
|
28
|
+
"register_worker",
|
|
29
|
+
"TelemetryOptions",
|
|
30
|
+
"TriggerAction",
|
|
31
|
+
# RBAC types
|
|
32
|
+
"MiddlewareFunctionInput",
|
|
33
|
+
# Message types
|
|
34
|
+
"TriggerActionEnqueue",
|
|
35
|
+
"TriggerActionVoid",
|
|
36
|
+
# Queue
|
|
37
|
+
"EnqueueResult",
|
|
38
|
+
# Types
|
|
39
|
+
"IIIClient",
|
|
40
|
+
"StreamRequest",
|
|
41
|
+
"StreamResponse",
|
|
42
|
+
# Stream
|
|
43
|
+
"IStream",
|
|
44
|
+
]
|
|
@@ -3,13 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class InvocationError(Exception):
|
|
7
7
|
"""Raised when an invocation dispatched by the SDK fails.
|
|
8
8
|
|
|
9
9
|
Inspect ``err.code`` to react to a specific category (e.g.
|
|
10
10
|
``'FORBIDDEN'`` for RBAC denials, ``'TIMEOUT'`` for timeouts). Catch
|
|
11
11
|
this class to handle every rejection. ``except Exception`` continues to
|
|
12
|
-
work because ``
|
|
12
|
+
work because ``InvocationError`` inherits from ``Exception``.
|
|
13
13
|
|
|
14
14
|
Attributes are read-only after construction. ``stacktrace`` is the
|
|
15
15
|
engine-side trace when the remote handler raised; it may include
|
|
@@ -38,8 +38,8 @@ def _wrap_wire_error(
|
|
|
38
38
|
*,
|
|
39
39
|
function_id: str | None,
|
|
40
40
|
invocation_id: str | None,
|
|
41
|
-
) ->
|
|
42
|
-
"""Convert a wire ``ErrorBody``-shaped dict into an ``
|
|
41
|
+
) -> InvocationError:
|
|
42
|
+
"""Convert a wire ``ErrorBody``-shaped dict into an ``InvocationError``.
|
|
43
43
|
|
|
44
44
|
The ``code`` field distinguishes categories (e.g. ``'FORBIDDEN'``,
|
|
45
45
|
``'TIMEOUT'``). Malformed shapes (non-dict, missing fields, non-string
|
|
@@ -56,7 +56,7 @@ def _wrap_wire_error(
|
|
|
56
56
|
raw_stacktrace = error.get("stacktrace")
|
|
57
57
|
stacktrace = raw_stacktrace if isinstance(raw_stacktrace, str) else None
|
|
58
58
|
|
|
59
|
-
return
|
|
59
|
+
return InvocationError(
|
|
60
60
|
code=code,
|
|
61
61
|
message=message,
|
|
62
62
|
function_id=function_id,
|
|
@@ -64,7 +64,7 @@ def _wrap_wire_error(
|
|
|
64
64
|
invocation_id=invocation_id,
|
|
65
65
|
)
|
|
66
66
|
|
|
67
|
-
return
|
|
67
|
+
return InvocationError(
|
|
68
68
|
code="UNKNOWN",
|
|
69
69
|
message=str(error),
|
|
70
70
|
function_id=function_id,
|
|
@@ -44,7 +44,7 @@ def _to_json_schema(annotation: Any) -> dict[str, Any] | None:
|
|
|
44
44
|
if annotation is inspect.Parameter.empty or annotation is Any:
|
|
45
45
|
return None
|
|
46
46
|
|
|
47
|
-
# Handle Optional[X]
|
|
47
|
+
# Handle Optional[X], produce {"type": ["<inner>", "null"]}
|
|
48
48
|
is_opt, inner = _is_optional(annotation)
|
|
49
49
|
if is_opt:
|
|
50
50
|
inner_schema = _to_json_schema(inner)
|
|
@@ -82,7 +82,7 @@ def _to_json_schema(annotation: Any) -> dict[str, Any] | None:
|
|
|
82
82
|
schema_dict["additionalProperties"] = value_schema
|
|
83
83
|
return schema_dict
|
|
84
84
|
|
|
85
|
-
# Handle Pydantic BaseModel
|
|
85
|
+
# Handle Pydantic BaseModel, use its built-in JSON Schema generation
|
|
86
86
|
if _is_pydantic_model(annotation):
|
|
87
87
|
model_schema: dict[str, Any] = annotation.model_json_schema()
|
|
88
88
|
return model_schema
|
|
@@ -34,7 +34,7 @@ class _IIIWithHelperShims(IIIClient, Protocol):
|
|
|
34
34
|
|
|
35
35
|
The free functions below delegate to these private methods on the
|
|
36
36
|
concrete :class:`III` instance. Defining the Protocol here mirrors the
|
|
37
|
-
Node SDK's ``IIIWithHelperShims`` intersection type
|
|
37
|
+
Node SDK's ``IIIWithHelperShims`` intersection type, callers see the
|
|
38
38
|
public :class:`IIIClient` Protocol; helpers see the shims internally.
|
|
39
39
|
"""
|
|
40
40
|
|
|
@@ -46,7 +46,7 @@ class _IIIWithHelperShims(IIIClient, Protocol):
|
|
|
46
46
|
|
|
47
47
|
def _helpers_create_stream(
|
|
48
48
|
self, stream_name: str, stream: IStream[Any]
|
|
49
|
-
) -> None: ... # noqa: D401
|
|
49
|
+
) -> None: ... # noqa: D401 (internal shim, generic erased at the boundary)
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def create_channel(iii: IIIClient, buffer_size: int | None = None) -> Channel:
|
|
@@ -14,11 +14,19 @@ from importlib.metadata import version
|
|
|
14
14
|
from typing import Any, Awaitable, Callable, Coroutine, TypeVar, cast
|
|
15
15
|
|
|
16
16
|
import websockets
|
|
17
|
-
from
|
|
17
|
+
from iii_helpers.http import HttpInvocationConfig
|
|
18
|
+
from iii_helpers.observability import OtelConfig
|
|
19
|
+
from iii_helpers.stream import (
|
|
20
|
+
StreamDeleteInput,
|
|
21
|
+
StreamGetInput,
|
|
22
|
+
StreamListGroupsInput,
|
|
23
|
+
StreamListInput,
|
|
24
|
+
StreamSetInput,
|
|
25
|
+
)
|
|
18
26
|
from websockets.asyncio.client import ClientConnection
|
|
19
27
|
|
|
20
28
|
from .channels import ChannelReader, ChannelWriter
|
|
21
|
-
from .errors import
|
|
29
|
+
from .errors import InvocationError, _wrap_wire_error
|
|
22
30
|
from .format_utils import extract_request_format, extract_response_format
|
|
23
31
|
from .iii_constants import (
|
|
24
32
|
DEFAULT_RECONNECTION_CONFIG,
|
|
@@ -28,7 +36,6 @@ from .iii_constants import (
|
|
|
28
36
|
InitOptions,
|
|
29
37
|
)
|
|
30
38
|
from .iii_types import (
|
|
31
|
-
HttpInvocationConfig,
|
|
32
39
|
InvocationResultMessage,
|
|
33
40
|
InvokeFunctionMessage,
|
|
34
41
|
MessageType,
|
|
@@ -47,14 +54,7 @@ from .iii_types import (
|
|
|
47
54
|
UnregisterTriggerMessage,
|
|
48
55
|
UnregisterTriggerTypeMessage,
|
|
49
56
|
)
|
|
50
|
-
from .stream import
|
|
51
|
-
IStream,
|
|
52
|
-
StreamDeleteInput,
|
|
53
|
-
StreamGetInput,
|
|
54
|
-
StreamListGroupsInput,
|
|
55
|
-
StreamListInput,
|
|
56
|
-
StreamSetInput,
|
|
57
|
-
)
|
|
57
|
+
from .stream import IStream
|
|
58
58
|
from .triggers import Trigger, TriggerConfig, TriggerHandler, TriggerTypeRef
|
|
59
59
|
from .types import Channel, RemoteFunctionData, RemoteTriggerTypeData, is_channel_ref
|
|
60
60
|
|
|
@@ -83,7 +83,7 @@ def _detect_project_name(cwd: str | None = None) -> str | None:
|
|
|
83
83
|
when both signals are unavailable (e.g. cwd is the filesystem root, or
|
|
84
84
|
the Python runtime has no TOML parser and no readable cwd basename).
|
|
85
85
|
|
|
86
|
-
No directory walking
|
|
86
|
+
No directory walking, only inspects ``cwd`` itself, so the SDK never
|
|
87
87
|
reads files outside the user's explicit working directory.
|
|
88
88
|
"""
|
|
89
89
|
try:
|
|
@@ -142,7 +142,7 @@ class III:
|
|
|
142
142
|
|
|
143
143
|
Examples:
|
|
144
144
|
>>> from iii import register_worker, InitOptions
|
|
145
|
-
>>>
|
|
145
|
+
>>> worker = register_worker('ws://localhost:49134', InitOptions(worker_name='my-worker'))
|
|
146
146
|
"""
|
|
147
147
|
|
|
148
148
|
def __init__(self, address: str, options: InitOptions | None = None) -> None:
|
|
@@ -207,9 +207,9 @@ class III:
|
|
|
207
207
|
instance must not be reused.
|
|
208
208
|
|
|
209
209
|
Examples:
|
|
210
|
-
>>>
|
|
210
|
+
>>> worker = register_worker('ws://localhost:49134')
|
|
211
211
|
>>> # ... do work ...
|
|
212
|
-
>>>
|
|
212
|
+
>>> worker.shutdown()
|
|
213
213
|
"""
|
|
214
214
|
self._run_on_loop(self.shutdown_async())
|
|
215
215
|
self._loop.call_soon_threadsafe(self._loop.stop)
|
|
@@ -224,7 +224,7 @@ class III:
|
|
|
224
224
|
from an async context.
|
|
225
225
|
"""
|
|
226
226
|
self._running = True
|
|
227
|
-
from
|
|
227
|
+
from iii_helpers.observability.telemetry import attach_event_loop, init_otel
|
|
228
228
|
|
|
229
229
|
loop = asyncio.get_running_loop()
|
|
230
230
|
otel_cfg: OtelConfig | None = None
|
|
@@ -247,9 +247,9 @@ class III:
|
|
|
247
247
|
instance must not be reused.
|
|
248
248
|
|
|
249
249
|
Examples:
|
|
250
|
-
>>>
|
|
250
|
+
>>> worker = register_worker('ws://localhost:49134')
|
|
251
251
|
>>> # ... do work ...
|
|
252
|
-
>>> await
|
|
252
|
+
>>> await worker.shutdown_async()
|
|
253
253
|
"""
|
|
254
254
|
self._running = False
|
|
255
255
|
|
|
@@ -265,7 +265,7 @@ class III:
|
|
|
265
265
|
for invocation_id, pending in list(self._pending.items()):
|
|
266
266
|
if not pending.future.done():
|
|
267
267
|
pending.future.set_exception(
|
|
268
|
-
|
|
268
|
+
InvocationError(
|
|
269
269
|
code="SHUTDOWN",
|
|
270
270
|
message="iii is shutting down",
|
|
271
271
|
function_id=pending.function_id,
|
|
@@ -280,7 +280,7 @@ class III:
|
|
|
280
280
|
|
|
281
281
|
self._set_connection_state("disconnected")
|
|
282
282
|
|
|
283
|
-
from
|
|
283
|
+
from iii_helpers.observability.telemetry import shutdown_otel_async
|
|
284
284
|
|
|
285
285
|
await shutdown_otel_async()
|
|
286
286
|
|
|
@@ -502,7 +502,7 @@ class III:
|
|
|
502
502
|
tracer = trace.get_tracer("iii-python-sdk")
|
|
503
503
|
import os
|
|
504
504
|
|
|
505
|
-
from
|
|
505
|
+
from iii_helpers.observability import redact_and_truncate, resolve_max_bytes_from_env
|
|
506
506
|
|
|
507
507
|
trace_payloads = os.environ.get("III_DISABLE_TRACE_PAYLOADS", "").lower() not in (
|
|
508
508
|
"1",
|
|
@@ -800,7 +800,7 @@ class III:
|
|
|
800
800
|
``register_function`` methods.
|
|
801
801
|
|
|
802
802
|
Examples:
|
|
803
|
-
>>> webhook =
|
|
803
|
+
>>> webhook = worker.register_trigger_type(
|
|
804
804
|
... RegisterTriggerTypeInput(
|
|
805
805
|
... id="webhook",
|
|
806
806
|
... description="Webhook trigger",
|
|
@@ -853,8 +853,8 @@ class III:
|
|
|
853
853
|
trigger_type: A ``RegisterTriggerTypeInput`` or dict with ``id`` and optional ``description``.
|
|
854
854
|
|
|
855
855
|
Examples:
|
|
856
|
-
>>>
|
|
857
|
-
>>>
|
|
856
|
+
>>> worker.unregister_trigger_type({"id": "webhook", "description": "Webhook trigger"})
|
|
857
|
+
>>> worker.unregister_trigger_type(RegisterTriggerTypeInput(id="webhook", description="Webhook trigger"))
|
|
858
858
|
"""
|
|
859
859
|
if isinstance(trigger_type, dict):
|
|
860
860
|
type_id = trigger_type["id"]
|
|
@@ -878,12 +878,12 @@ class III:
|
|
|
878
878
|
the engine as part of the registration message.
|
|
879
879
|
|
|
880
880
|
Examples:
|
|
881
|
-
>>> trigger =
|
|
881
|
+
>>> trigger = worker.register_trigger({
|
|
882
882
|
... 'type': 'http',
|
|
883
883
|
... 'function_id': 'greet',
|
|
884
884
|
... 'config': {'api_path': '/greet', 'http_method': 'GET'}
|
|
885
885
|
... })
|
|
886
|
-
>>> trigger =
|
|
886
|
+
>>> trigger = worker.register_trigger(RegisterTriggerInput(
|
|
887
887
|
... type="http", function_id="greet",
|
|
888
888
|
... config={'api_path': '/greet', 'http_method': 'GET'}
|
|
889
889
|
... ))
|
|
@@ -967,7 +967,7 @@ class III:
|
|
|
967
967
|
Examples:
|
|
968
968
|
>>> def greet(data):
|
|
969
969
|
... return {'message': f"Hello, {data['name']}!"}
|
|
970
|
-
>>> fn =
|
|
970
|
+
>>> fn = worker.register_function("greet", greet, description="Greets a user")
|
|
971
971
|
>>> fn.unregister()
|
|
972
972
|
|
|
973
973
|
>>> from pydantic import BaseModel
|
|
@@ -977,7 +977,7 @@ class III:
|
|
|
977
977
|
... message: str
|
|
978
978
|
>>> async def greet(data: GreetInput) -> GreetOutput:
|
|
979
979
|
... return GreetOutput(message=f"Hello, {data.name}!")
|
|
980
|
-
>>> fn =
|
|
980
|
+
>>> fn = worker.register_function("greet", greet, description="Greets a user")
|
|
981
981
|
"""
|
|
982
982
|
if not isinstance(function_id, str):
|
|
983
983
|
raise TypeError(
|
|
@@ -1081,13 +1081,13 @@ class III:
|
|
|
1081
1081
|
actions.
|
|
1082
1082
|
|
|
1083
1083
|
Raises:
|
|
1084
|
-
|
|
1084
|
+
InvocationError: For any engine rejection. Inspect ``code``:
|
|
1085
1085
|
``'TIMEOUT'`` if the invocation timed out, ``'FORBIDDEN'`` if
|
|
1086
1086
|
RBAC denied it.
|
|
1087
1087
|
|
|
1088
1088
|
Examples:
|
|
1089
|
-
>>> result =
|
|
1090
|
-
>>>
|
|
1089
|
+
>>> result = worker.trigger({'function_id': 'greet', 'payload': {'name': 'World'}})
|
|
1090
|
+
>>> worker.trigger({'function_id': 'notify', 'payload': {}, 'action': TriggerAction.Void()})
|
|
1091
1091
|
"""
|
|
1092
1092
|
return self._run_on_loop(self.trigger_async(request))
|
|
1093
1093
|
|
|
@@ -1108,7 +1108,7 @@ class III:
|
|
|
1108
1108
|
The result of the function invocation, or ``None`` for void calls.
|
|
1109
1109
|
|
|
1110
1110
|
Raises:
|
|
1111
|
-
|
|
1111
|
+
InvocationError: For any engine rejection. Inspect ``code``:
|
|
1112
1112
|
``'TIMEOUT'`` if the invocation timed out, ``'FORBIDDEN'`` if
|
|
1113
1113
|
RBAC denied it.
|
|
1114
1114
|
|
|
@@ -1171,7 +1171,7 @@ class III:
|
|
|
1171
1171
|
return await asyncio.wait_for(future, timeout=timeout_secs)
|
|
1172
1172
|
except asyncio.TimeoutError:
|
|
1173
1173
|
self._pending.pop(invocation_id, None)
|
|
1174
|
-
raise
|
|
1174
|
+
raise InvocationError(
|
|
1175
1175
|
code="TIMEOUT",
|
|
1176
1176
|
message=f"invocation timed out after {timeout_ms}ms",
|
|
1177
1177
|
function_id=function_id,
|
|
@@ -1308,8 +1308,8 @@ class TriggerAction:
|
|
|
1308
1308
|
|
|
1309
1309
|
Examples:
|
|
1310
1310
|
>>> from iii import TriggerAction
|
|
1311
|
-
>>>
|
|
1312
|
-
>>>
|
|
1311
|
+
>>> worker.trigger({'function_id': 'process', 'payload': {}, 'action': TriggerAction.Enqueue(queue='jobs')})
|
|
1312
|
+
>>> worker.trigger({'function_id': 'notify', 'payload': {}, 'action': TriggerAction.Void()})
|
|
1313
1313
|
"""
|
|
1314
1314
|
|
|
1315
1315
|
@staticmethod
|
|
@@ -1344,7 +1344,7 @@ def register_worker(address: str, options: InitOptions | None = None) -> III:
|
|
|
1344
1344
|
|
|
1345
1345
|
Examples:
|
|
1346
1346
|
>>> from iii import register_worker, InitOptions
|
|
1347
|
-
>>>
|
|
1347
|
+
>>> worker = register_worker('ws://localhost:49134', InitOptions(worker_name='my-worker'))
|
|
1348
1348
|
"""
|
|
1349
1349
|
client = III(address, options)
|
|
1350
1350
|
client._wait_until_connected()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Constants and configuration types for the III SDK (mirrors iii-constants.ts)."""
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Callable, Literal
|
|
4
|
+
from typing import Any, Callable, Final, Literal
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from iii_helpers.observability import OtelConfig, ReconnectionConfig
|
|
7
7
|
|
|
8
8
|
IIIConnectionState = Literal["disconnected", "connecting", "connected", "reconnecting", "failed"]
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ class FunctionRef:
|
|
|
26
26
|
|
|
27
27
|
@dataclass
|
|
28
28
|
class TelemetryOptions:
|
|
29
|
-
"""
|
|
29
|
+
"""Worker metadata reported to the engine.
|
|
30
30
|
|
|
31
31
|
Attributes:
|
|
32
32
|
language: Programming language of the worker (e.g. ``python``).
|
|
@@ -54,7 +54,7 @@ class InitOptions:
|
|
|
54
54
|
reconnection_config: WebSocket reconnection behavior.
|
|
55
55
|
otel: OpenTelemetry configuration. Enabled by default.
|
|
56
56
|
Set ``{'enabled': False}`` or env ``OTEL_ENABLED=false`` to disable.
|
|
57
|
-
telemetry: Internal
|
|
57
|
+
telemetry: Internal worker metadata reported to the engine.
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
worker_name: str | None = None
|
|
@@ -65,3 +65,24 @@ class InitOptions:
|
|
|
65
65
|
otel: OtelConfig | dict[str, Any] | None = None
|
|
66
66
|
headers: dict[str, str] | None = None
|
|
67
67
|
telemetry: TelemetryOptions | None = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class EngineFunctions:
|
|
71
|
+
"""Engine function ids for internal operations (parity with the Node SDK)."""
|
|
72
|
+
|
|
73
|
+
LIST_FUNCTIONS: Final[str] = "engine::functions::list"
|
|
74
|
+
INFO_FUNCTIONS: Final[str] = "engine::functions::info"
|
|
75
|
+
LIST_WORKERS: Final[str] = "engine::workers::list"
|
|
76
|
+
INFO_WORKERS: Final[str] = "engine::workers::info"
|
|
77
|
+
LIST_TRIGGERS: Final[str] = "engine::triggers::list"
|
|
78
|
+
INFO_TRIGGERS: Final[str] = "engine::triggers::info"
|
|
79
|
+
LIST_REGISTERED_TRIGGERS: Final[str] = "engine::registered-triggers::list"
|
|
80
|
+
INFO_REGISTERED_TRIGGERS: Final[str] = "engine::registered-triggers::info"
|
|
81
|
+
REGISTER_WORKER: Final[str] = "engine::workers::register"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class EngineTriggers:
|
|
85
|
+
"""Engine trigger ids (parity with the Node SDK)."""
|
|
86
|
+
|
|
87
|
+
FUNCTIONS_AVAILABLE: Final[str] = "engine::functions-available"
|
|
88
|
+
LOG: Final[str] = "log"
|