iii-sdk 0.21.0.dev1__tar.gz → 0.21.1.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.
Files changed (73) hide show
  1. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/PKG-INFO +2 -2
  2. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/pyproject.toml +2 -2
  3. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_register_function_args.py +41 -19
  4. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/.gitignore +0 -0
  5. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/README.md +0 -0
  6. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/__init__.py +0 -0
  7. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/channel.py +0 -0
  8. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/channels.py +0 -0
  9. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/engine.py +0 -0
  10. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/errors.py +0 -0
  11. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/format_utils.py +0 -0
  12. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/helpers.py +0 -0
  13. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/iii.py +0 -0
  14. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/iii_constants.py +0 -0
  15. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/iii_types.py +0 -0
  16. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/internal.py +0 -0
  17. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/otel_worker_gauges.py +0 -0
  18. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/protocol.py +0 -0
  19. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/runtime.py +0 -0
  20. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/state.py +0 -0
  21. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/stream.py +0 -0
  22. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/trigger.py +0 -0
  23. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/triggers.py +0 -0
  24. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/types.py +0 -0
  25. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/utils.py +0 -0
  26. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/src/iii/worker_metrics.py +0 -0
  27. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/conftest.py +0 -0
  28. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_api_triggers.py +0 -0
  29. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_async_api.py +0 -0
  30. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_baggage_span_processor.py +0 -0
  31. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_bridge.py +0 -0
  32. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_channel_close_delay.py +0 -0
  33. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_channel_submodule.py +0 -0
  34. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_context_propagation.py +0 -0
  35. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_data_channels.py +0 -0
  36. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_engine_constants.py +0 -0
  37. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_errors.py +0 -0
  38. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_format_utils.py +0 -0
  39. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_healthcheck.py +0 -0
  40. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_helpers.py +0 -0
  41. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_hold_process.py +0 -0
  42. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_http_external_functions_integration.py +0 -0
  43. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_iii_registration_dedup.py +0 -0
  44. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_init_api.py +0 -0
  45. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_invocation_exception.py +0 -0
  46. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_invocation_metadata.py +0 -0
  47. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_logger_function_ids.py +0 -0
  48. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_logger_otel.py +0 -0
  49. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_middleware.py +0 -0
  50. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_payload.py +0 -0
  51. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_pubsub.py +0 -0
  52. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_queue_integration.py +0 -0
  53. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_rbac_workers.py +0 -0
  54. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_runtime_submodule.py +0 -0
  55. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_span_ops.py +0 -0
  56. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_state.py +0 -0
  57. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_stream_models.py +0 -0
  58. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_stream_types.py +0 -0
  59. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_streams.py +0 -0
  60. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_streams_runtime_annotations.py +0 -0
  61. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_sync_api.py +0 -0
  62. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_telemetry.py +0 -0
  63. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_telemetry_exporters.py +0 -0
  64. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_telemetry_types.py +0 -0
  65. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_trace_helpers.py +0 -0
  66. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_trigger_metadata.py +0 -0
  67. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_trigger_registration_error.py +0 -0
  68. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_trigger_submodule.py +0 -0
  69. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_trigger_type_lifecycle.py +0 -0
  70. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_utils.py +0 -0
  71. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_worker_metadata.py +0 -0
  72. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/tests/test_worker_metrics.py +0 -0
  73. {iii_sdk-0.21.0.dev1 → iii_sdk-0.21.1.dev1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iii-sdk
3
- Version: 0.21.0.dev1
3
+ Version: 0.21.1.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-helpers==0.21.0.dev1
17
+ Requires-Dist: iii-helpers==0.21.1.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.21.0.dev1"
7
+ version = "0.21.1.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-helpers==0.21.0.dev1",
26
+ "iii-helpers==0.21.1.dev1",
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -2,6 +2,7 @@
2
2
 
3
3
  import json
4
4
  import time
5
+ from collections.abc import Callable
5
6
  from types import SimpleNamespace
6
7
  from typing import Any
7
8
 
@@ -17,6 +18,8 @@ from iii.iii_types import RegisterFunctionFormat
17
18
  # FakeWs helpers
18
19
  # ---------------------------------------------------------------------------
19
20
 
21
+ _CREATED_CLIENTS: list[III] = []
22
+
20
23
 
21
24
  class FakeWebSocket:
22
25
  def __init__(self) -> None:
@@ -51,10 +54,38 @@ def _patch_ws(monkeypatch: pytest.MonkeyPatch) -> FakeWebSocket:
51
54
 
52
55
  def _make_client() -> III:
53
56
  client = III("ws://fake", InitOptions())
54
- time.sleep(0.05)
57
+ _CREATED_CLIENTS.append(client)
58
+ _wait_for(lambda: client.get_connection_state() == "connected", "fake WebSocket client to connect")
55
59
  return client
56
60
 
57
61
 
62
+ @pytest.fixture(autouse=True)
63
+ def _shutdown_created_clients() -> None:
64
+ yield
65
+ while _CREATED_CLIENTS:
66
+ client = _CREATED_CLIENTS.pop()
67
+ if client._thread.is_alive():
68
+ client.shutdown()
69
+
70
+
71
+ def _wait_for(predicate: Callable[[], bool], what: str, timeout: float = 2.0) -> None:
72
+ deadline = time.monotonic() + timeout
73
+ while time.monotonic() < deadline:
74
+ if predicate():
75
+ return
76
+ time.sleep(0.005)
77
+ pytest.fail(f"timed out waiting for {what}")
78
+
79
+
80
+ def _registration_messages(ws: FakeWebSocket, function_id: str) -> list[dict[str, Any]]:
81
+ return [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == function_id]
82
+
83
+
84
+ def _wait_for_registration(ws: FakeWebSocket, function_id: str) -> list[dict[str, Any]]:
85
+ _wait_for(lambda: bool(_registration_messages(ws, function_id)), f"registration for {function_id}")
86
+ return _registration_messages(ws, function_id)
87
+
88
+
58
89
  # ---------------------------------------------------------------------------
59
90
  # Two-arg register_function tests
60
91
  # ---------------------------------------------------------------------------
@@ -78,9 +109,8 @@ def test_register_function_str_with_request_format(monkeypatch: pytest.MonkeyPat
78
109
  return data
79
110
 
80
111
  client.register_function("demo.with_args", handler, request_format=req_fmt)
81
- time.sleep(0.02)
82
112
 
83
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.with_args"]
113
+ reg_msgs = _wait_for_registration(ws, "demo.with_args")
84
114
  assert len(reg_msgs) == 1
85
115
 
86
116
  sent_req_fmt = reg_msgs[0].get("request_format")
@@ -127,9 +157,8 @@ def test_register_function_str_with_both_formats(monkeypatch: pytest.MonkeyPatch
127
157
  response_format=res_fmt,
128
158
  metadata={"version": "1"},
129
159
  )
130
- time.sleep(0.02)
131
160
 
132
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.both_formats"]
161
+ reg_msgs = _wait_for_registration(ws, "demo.both_formats")
133
162
  assert len(reg_msgs) == 1
134
163
  assert reg_msgs[0].get("description") == "A search function"
135
164
  assert reg_msgs[0].get("request_format") is not None
@@ -149,9 +178,8 @@ def test_register_function_str_minimal(monkeypatch: pytest.MonkeyPatch) -> None:
149
178
  return data
150
179
 
151
180
  client.register_function("demo.minimal", handler)
152
- time.sleep(0.02)
153
181
 
154
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.minimal"]
182
+ reg_msgs = _wait_for_registration(ws, "demo.minimal")
155
183
  assert len(reg_msgs) == 1
156
184
  assert "request_format" not in reg_msgs[0]
157
185
  assert "response_format" not in reg_msgs[0]
@@ -179,9 +207,8 @@ def test_register_function_str_with_http_invocation_and_format(monkeypatch: pyte
179
207
  HttpInvocationConfig(url="https://example.com/fn", method="POST"),
180
208
  request_format=req_fmt,
181
209
  )
182
- time.sleep(0.02)
183
210
 
184
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "external::with_format"]
211
+ reg_msgs = _wait_for_registration(ws, "external::with_format")
185
212
  assert len(reg_msgs) == 1
186
213
  assert reg_msgs[0].get("invocation", {}).get("url") == "https://example.com/fn"
187
214
  assert reg_msgs[0].get("request_format") is not None
@@ -230,9 +257,8 @@ def test_register_function_str_id_auto_extracts_formats(monkeypatch: pytest.Monk
230
257
  return UserOutput(message=f"Hello {data.name}")
231
258
 
232
259
  client.register_function("demo.auto", handler, description="Auto-extract demo")
233
- time.sleep(0.02)
234
260
 
235
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.auto"]
261
+ reg_msgs = _wait_for_registration(ws, "demo.auto")
236
262
  assert len(reg_msgs) == 1
237
263
  msg = reg_msgs[0]
238
264
 
@@ -282,9 +308,8 @@ def test_register_function_str_id_explicit_formats_override(monkeypatch: pytest.
282
308
  request_format=explicit_req,
283
309
  response_format=explicit_res,
284
310
  )
285
- time.sleep(0.02)
286
311
 
287
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.explicit"]
312
+ reg_msgs = _wait_for_registration(ws, "demo.explicit")
288
313
  assert len(reg_msgs) == 1
289
314
  msg = reg_msgs[0]
290
315
 
@@ -306,9 +331,8 @@ def test_register_function_str_id_no_annotations(monkeypatch: pytest.MonkeyPatch
306
331
  return data
307
332
 
308
333
  client.register_function("demo.no_hints", handler)
309
- time.sleep(0.02)
310
334
 
311
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.no_hints"]
335
+ reg_msgs = _wait_for_registration(ws, "demo.no_hints")
312
336
  assert len(reg_msgs) == 1
313
337
  assert "request_format" not in reg_msgs[0]
314
338
  assert "response_format" not in reg_msgs[0]
@@ -325,9 +349,8 @@ def test_register_function_str_id_with_metadata(monkeypatch: pytest.MonkeyPatch)
325
349
  return data
326
350
 
327
351
  client.register_function("demo.meta", handler, metadata={"version": "2.0"})
328
- time.sleep(0.02)
329
352
 
330
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.meta"]
353
+ reg_msgs = _wait_for_registration(ws, "demo.meta")
331
354
  assert len(reg_msgs) == 1
332
355
  assert reg_msgs[0]["metadata"] == {"version": "2.0"}
333
356
 
@@ -352,9 +375,8 @@ def test_register_function_str_id_with_http_invocation(monkeypatch: pytest.Monke
352
375
  HttpInvocationConfig(url="https://example.com/fn", method="POST"),
353
376
  description="HTTP function",
354
377
  )
355
- time.sleep(0.02)
356
378
 
357
- reg_msgs = [m for m in ws.sent if m.get("type") == "registerfunction" and m.get("id") == "demo.http"]
379
+ reg_msgs = _wait_for_registration(ws, "demo.http")
358
380
  assert len(reg_msgs) == 1
359
381
  assert reg_msgs[0]["invocation"]["url"] == "https://example.com/fn"
360
382
  assert reg_msgs[0]["description"] == "HTTP function"
File without changes
File without changes
File without changes