iii-sdk 0.14.0.dev1__tar.gz → 0.14.0.dev2__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 (65) hide show
  1. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/PKG-INFO +1 -1
  2. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/pyproject.toml +1 -1
  3. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/__init__.py +0 -8
  4. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/iii.py +17 -39
  5. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/iii_types.py +0 -139
  6. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/logger.py +5 -5
  7. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/telemetry.py +8 -8
  8. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/types.py +0 -3
  9. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_bridge.py +4 -4
  10. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_logger_otel.py +3 -3
  11. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_rbac_workers.py +4 -5
  12. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_sync_api.py +1 -23
  13. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_telemetry.py +14 -14
  14. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_trigger_metadata.py +2 -18
  15. iii_sdk-0.14.0.dev2/tests/test_trigger_registration_error.py +57 -0
  16. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/uv.lock +1078 -1078
  17. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/.gitignore +0 -0
  18. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/README.md +0 -0
  19. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/baggage_span_processor.py +0 -0
  20. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/channels.py +0 -0
  21. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/errors.py +0 -0
  22. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/format_utils.py +0 -0
  23. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/iii_constants.py +0 -0
  24. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/otel_worker_gauges.py +0 -0
  25. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/payload.py +0 -0
  26. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/span_ops.py +0 -0
  27. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/state.py +0 -0
  28. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/stream.py +0 -0
  29. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/telemetry_exporters.py +0 -0
  30. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/telemetry_types.py +0 -0
  31. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/triggers.py +0 -0
  32. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/utils.py +0 -0
  33. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/src/iii/worker_metrics.py +0 -0
  34. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/conftest.py +0 -0
  35. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_api_triggers.py +0 -0
  36. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_async_api.py +0 -0
  37. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_baggage_span_processor.py +0 -0
  38. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_channel_close_delay.py +0 -0
  39. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_context_propagation.py +0 -0
  40. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_data_channels.py +0 -0
  41. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_errors.py +0 -0
  42. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_format_utils.py +0 -0
  43. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_healthcheck.py +0 -0
  44. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_hold_process.py +0 -0
  45. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_http_external_functions_integration.py +0 -0
  46. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_iii_registration_dedup.py +0 -0
  47. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_init_api.py +0 -0
  48. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_invocation_exception.py +0 -0
  49. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_logger_function_ids.py +0 -0
  50. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_middleware.py +0 -0
  51. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_payload.py +0 -0
  52. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_pubsub.py +0 -0
  53. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_queue_integration.py +0 -0
  54. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_register_function_args.py +0 -0
  55. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_span_ops.py +0 -0
  56. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_state.py +0 -0
  57. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_stream_models.py +0 -0
  58. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_streams.py +0 -0
  59. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_streams_runtime_annotations.py +0 -0
  60. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_telemetry_exporters.py +0 -0
  61. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_telemetry_types.py +0 -0
  62. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_trace_helpers.py +0 -0
  63. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_utils.py +0 -0
  64. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/tests/test_worker_metadata.py +0 -0
  65. {iii_sdk-0.14.0.dev1 → iii_sdk-0.14.0.dev2}/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.14.0.dev1
3
+ Version: 0.14.0.dev2
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "iii-sdk"
7
- version = "0.14.0.dev1"
7
+ version = "0.14.0.dev2"
8
8
  description = "III SDK for Python"
9
9
  authors = [{ name = "III" }]
10
10
  license = { text = "Apache-2.0" }
@@ -10,7 +10,6 @@ from .iii_types import (
10
10
  AuthInput,
11
11
  AuthResult,
12
12
  EnqueueResult,
13
- FunctionInfo,
14
13
  HttpAuthConfig,
15
14
  HttpInvocationConfig,
16
15
  MessageType,
@@ -23,7 +22,6 @@ from .iii_types import (
23
22
  OnTriggerTypeRegistrationResult,
24
23
  RegisterFunctionFormat,
25
24
  RegisterFunctionMessage,
26
- RegisterServiceInput,
27
25
  RegisterTriggerInput,
28
26
  RegisterTriggerMessage,
29
27
  RegisterTriggerTypeInput,
@@ -31,9 +29,7 @@ from .iii_types import (
31
29
  StreamChannelRef,
32
30
  TriggerActionEnqueue,
33
31
  TriggerActionVoid,
34
- TriggerInfo,
35
32
  TriggerRequest,
36
- TriggerTypeInfo,
37
33
  )
38
34
  from .logger import Logger
39
35
  from .payload import (
@@ -110,13 +106,11 @@ __all__ = [
110
106
  "OnTriggerTypeRegistrationResult",
111
107
  # Message types
112
108
  "EnqueueResult",
113
- "FunctionInfo",
114
109
  "HttpAuthConfig",
115
110
  "HttpInvocationConfig",
116
111
  "MessageType",
117
112
  "RegisterFunctionFormat",
118
113
  "RegisterFunctionMessage",
119
- "RegisterServiceInput",
120
114
  "RegisterTriggerInput",
121
115
  "RegisterTriggerMessage",
122
116
  "RegisterTriggerTypeInput",
@@ -124,9 +118,7 @@ __all__ = [
124
118
  "StreamChannelRef",
125
119
  "TriggerActionEnqueue",
126
120
  "TriggerActionVoid",
127
- "TriggerInfo",
128
121
  "TriggerRequest",
129
- "TriggerTypeInfo",
130
122
  # Logger
131
123
  "Logger",
132
124
  # Triggers
@@ -34,8 +34,6 @@ from .iii_types import (
34
34
  RegisterFunctionFormat,
35
35
  RegisterFunctionInput,
36
36
  RegisterFunctionMessage,
37
- RegisterServiceInput,
38
- RegisterServiceMessage,
39
37
  RegisterTriggerInput,
40
38
  RegisterTriggerMessage,
41
39
  RegisterTriggerTypeInput,
@@ -152,7 +150,6 @@ class III:
152
150
  self._options = options or InitOptions()
153
151
  self._ws: ClientConnection | None = None
154
152
  self._functions: dict[str, RemoteFunctionData] = {}
155
- self._services: dict[str, RegisterServiceMessage] = {}
156
153
  self._pending: dict[str, _PendingInvocation] = {}
157
154
  self._triggers: dict[str, RegisterTriggerMessage] = {}
158
155
  self._trigger_types: dict[str, RemoteTriggerTypeData] = {}
@@ -344,8 +341,6 @@ class III:
344
341
  # Re-register all (snapshot to avoid mutation from caller thread)
345
342
  for trigger_type_data in list(self._trigger_types.values()):
346
343
  await self._send(trigger_type_data.message)
347
- for svc in list(self._services.values()):
348
- await self._send(svc)
349
344
  for function_data in list(self._functions.values()):
350
345
  await self._send(function_data.message)
351
346
  for trigger in list(self._triggers.values()):
@@ -443,6 +438,8 @@ class III:
443
438
  )
444
439
  elif msg_type == MessageType.REGISTER_TRIGGER.value:
445
440
  asyncio.create_task(self._handle_trigger_registration(data))
441
+ elif msg_type == MessageType.TRIGGER_REGISTRATION_RESULT.value:
442
+ self._handle_trigger_registration_result(data)
446
443
  elif msg_type == MessageType.WORKER_REGISTERED.value:
447
444
  worker_id = data.get("worker_id", "")
448
445
  self._worker_id = worker_id
@@ -706,6 +703,21 @@ class III:
706
703
  }
707
704
  )
708
705
 
706
+ def _handle_trigger_registration_result(self, data: dict[str, Any]) -> None:
707
+ error = data.get("error")
708
+ if not error:
709
+ return
710
+
711
+ trigger_id = data.get("id", "")
712
+ trigger_type = data.get("trigger_type", "")
713
+ message = error.get("message", "")
714
+ log.error(
715
+ "[iii] Trigger registration failed for %r (%s): %s",
716
+ trigger_id,
717
+ trigger_type,
718
+ message,
719
+ )
720
+
709
721
  # Connection state management
710
722
 
711
723
  def _set_connection_state(self, state: IIIConnectionState) -> None:
@@ -1014,40 +1026,6 @@ class III:
1014
1026
 
1015
1027
  return FunctionRef(id=func_id, unregister=unregister)
1016
1028
 
1017
- def register_service(self, service: RegisterServiceInput | dict[str, Any]) -> None:
1018
- """Register a logical service grouping with the engine.
1019
-
1020
- Services provide an organisational hierarchy for functions. A
1021
- service can optionally reference a ``parent_service_id`` to form
1022
- a tree visible in the engine dashboard.
1023
-
1024
- Note:
1025
- Services are organizational groupings visible in the engine
1026
- dashboard. They do not affect function invocation behavior.
1027
-
1028
- Args:
1029
- service: A ``RegisterServiceInput`` or dict with ``id`` and
1030
- optional ``name``, ``description``, ``parent_service_id``.
1031
-
1032
- Examples:
1033
- >>> iii.register_service({"id": "payments", "description": "Payment processing"})
1034
- >>> iii.register_service({
1035
- ... "id": "payments::refunds",
1036
- ... "description": "Refund sub-service",
1037
- ... "parent_service_id": "payments",
1038
- ... })
1039
- """
1040
- if isinstance(service, dict):
1041
- service = RegisterServiceInput(**service)
1042
- msg = RegisterServiceMessage(
1043
- id=service.id,
1044
- name=service.name or service.id,
1045
- description=service.description,
1046
- parent_service_id=service.parent_service_id,
1047
- )
1048
- self._services[service.id] = msg
1049
- self._send_if_connected(msg)
1050
-
1051
1029
  def trigger(self, request: "dict[str, Any] | TriggerRequest") -> Any:
1052
1030
  """Invoke a remote function.
1053
1031
 
@@ -148,25 +148,6 @@ class RegisterTriggerInput(BaseModel):
148
148
  )
149
149
 
150
150
 
151
- class RegisterServiceInput(BaseModel):
152
- """Input for registering a service (matches Node SDK's RegisterServiceInput).
153
-
154
- Attributes:
155
- id: Unique service identifier.
156
- name: Human-readable service name.
157
- description: Description of the service.
158
- parent_service_id: ID of the parent service for hierarchical grouping.
159
- """
160
-
161
- id: str = Field(description="Unique service identifier.")
162
- name: str | None = Field(default=None, description="Human-readable service name.")
163
- description: str | None = Field(default=None, description="Description of the service.")
164
- parent_service_id: str | None = Field(
165
- default=None,
166
- description="ID of the parent service for hierarchical grouping.",
167
- )
168
-
169
-
170
151
  class RegisterTriggerMessage(BaseModel):
171
152
  model_config = ConfigDict(populate_by_name=True)
172
153
 
@@ -178,16 +159,6 @@ class RegisterTriggerMessage(BaseModel):
178
159
  message_type: MessageType = Field(default=MessageType.REGISTER_TRIGGER, alias="type")
179
160
 
180
161
 
181
- class RegisterServiceMessage(BaseModel):
182
- model_config = ConfigDict(populate_by_name=True)
183
-
184
- id: str
185
- name: str | None = None
186
- description: str | None = None
187
- parent_service_id: str | None = Field(default=None)
188
- message_type: MessageType = Field(default=MessageType.REGISTER_SERVICE, alias="type")
189
-
190
-
191
162
  class RegisterFunctionFormat(BaseModel):
192
163
  """Format definition for function parameters.
193
164
 
@@ -533,115 +504,6 @@ class UnregisterFunctionMessage(BaseModel):
533
504
  message_type: MessageType = Field(default=MessageType.UNREGISTER_FUNCTION, alias="type")
534
505
 
535
506
 
536
- class FunctionInfo(BaseModel):
537
- """Information about a registered function.
538
-
539
- Attributes:
540
- function_id: Unique identifier of the function.
541
- description: Human-readable description.
542
- request_format: Schema describing expected input (JSON Schema or custom format).
543
- response_format: Schema describing expected output (JSON Schema or custom format).
544
- metadata: Arbitrary metadata attached to the function.
545
- """
546
-
547
- function_id: str = Field(description="Unique identifier of the function.")
548
- description: str | None = Field(default=None, description="Human-readable description.")
549
- request_format: dict[str, Any] | None = Field(
550
- default=None, description="Schema describing expected input (JSON Schema or custom format)."
551
- )
552
- response_format: dict[str, Any] | None = Field(
553
- default=None, description="Schema describing expected output (JSON Schema or custom format)."
554
- )
555
- metadata: dict[str, Any] | None = Field(
556
- default=None, description="Arbitrary metadata attached to the function."
557
- )
558
-
559
-
560
- class TriggerInfo(BaseModel):
561
- """Information about a registered trigger.
562
-
563
- Attributes:
564
- id: Unique trigger identifier.
565
- trigger_type: Type of trigger (e.g. ``http``, ``queue``, ``cron``).
566
- function_id: ID of the function this trigger invokes.
567
- config: Trigger-type-specific configuration.
568
- metadata: Arbitrary metadata attached to the trigger.
569
- """
570
-
571
- id: str = Field(description="Unique trigger identifier.")
572
- trigger_type: str = Field(description="Type of trigger (e.g. ``http``, ``queue``, ``cron``).")
573
- function_id: str = Field(description="ID of the function this trigger invokes.")
574
- config: Any = Field(default=None, description="Trigger-type-specific configuration.")
575
- metadata: dict[str, Any] | None = Field(
576
- default=None, description="Arbitrary metadata attached to the trigger."
577
- )
578
-
579
-
580
- class TriggerTypeInfo(BaseModel):
581
- """Information about a registered trigger type.
582
-
583
- Attributes:
584
- id: Trigger type identifier (e.g. ``http``, ``cron``, ``queue``).
585
- description: Human-readable description of the trigger type.
586
- trigger_request_format: JSON Schema for the trigger configuration.
587
- call_request_format: JSON Schema for the call request payload.
588
- """
589
-
590
- id: str = Field(description="Trigger type identifier.")
591
- description: str = Field(description="Human-readable description.")
592
- trigger_request_format: Any | None = Field(
593
- default=None, description="JSON Schema for trigger configuration."
594
- )
595
- call_request_format: Any | None = Field(
596
- default=None, description="JSON Schema for the call request payload."
597
- )
598
-
599
-
600
- WorkerStatus = Literal["connected", "available", "busy", "disconnected"]
601
-
602
-
603
- class WorkerInfo(BaseModel):
604
- """Information about a connected worker.
605
-
606
- Attributes:
607
- id: Engine-assigned unique worker ID.
608
- name: Worker name from InitOptions.
609
- runtime: SDK runtime (``python``, ``node``, ``rust``).
610
- version: SDK version string.
611
- os: Operating system identifier.
612
- ip_address: Worker's IP address as seen by the engine.
613
- status: Current status (``connected``, ``available``, ``busy``, ``disconnected``).
614
- connected_at_ms: Connection timestamp in milliseconds since epoch.
615
- function_count: Number of registered functions.
616
- functions: List of registered function IDs.
617
- active_invocations: Number of currently executing invocations.
618
- """
619
-
620
- id: str = Field(description="Engine-assigned unique worker ID.")
621
- name: str | None = Field(default=None, description="Worker name from InitOptions.")
622
- runtime: str | None = Field(
623
- default=None,
624
- description="SDK runtime (``python``, ``node``, ``rust``).",
625
- )
626
- version: str | None = Field(default=None, description="SDK version string.")
627
- os: str | None = Field(default=None, description="Operating system identifier.")
628
- ip_address: str | None = Field(
629
- default=None,
630
- description="Worker's IP address as seen by the engine.",
631
- )
632
- status: WorkerStatus = Field(
633
- description="Current status (``connected``, ``available``, ``busy``, ``disconnected``)."
634
- )
635
- connected_at_ms: int = Field(description="Connection timestamp in milliseconds since epoch.")
636
- function_count: int = Field(description="Number of registered functions.")
637
- functions: list[str] = Field(description="List of registered function IDs.")
638
- active_invocations: int = Field(description="Number of currently executing invocations.")
639
- isolation: str | None = Field(
640
- default=None,
641
- description="Self-reported isolation context (e.g. ``libkrun``, ``docker``, ``k8s``).",
642
- )
643
-
644
-
645
507
  class StreamChannelRef(BaseModel):
646
508
  """Reference to a streaming channel for worker-to-worker data transfer.
647
509
 
@@ -678,7 +540,6 @@ IIIMessage = (
678
540
  | UnregisterFunctionMessage
679
541
  | InvokeFunctionMessage
680
542
  | InvocationResultMessage
681
- | RegisterServiceMessage
682
543
  | RegisterTriggerMessage
683
544
  | RegisterTriggerTypeMessage
684
545
  | UnregisterTriggerMessage
@@ -16,11 +16,11 @@ _SEVERITY_MAP = {
16
16
  }
17
17
 
18
18
 
19
- def is_initialized() -> bool:
20
- """Return True if OTel has been initialized (importable without circular dep)."""
21
- from .telemetry import is_initialized as _is_init
19
+ def _is_initialized() -> bool:
20
+ """Internal: True if OTel has been initialized. Imported lazily to avoid a circular import."""
21
+ from .telemetry import _is_initialized as _check
22
22
 
23
- return _is_init()
23
+ return _check()
24
24
 
25
25
 
26
26
  class Logger:
@@ -60,7 +60,7 @@ class Logger:
60
60
 
61
61
  def _emit_otel(self, level: str, message: str, data: Any = None) -> bool:
62
62
  """Emit an OTel LogRecord. Returns True if emitted, False if OTel not active."""
63
- if not is_initialized():
63
+ if not _is_initialized():
64
64
  return False
65
65
  try:
66
66
  from opentelemetry import _logs, trace
@@ -247,7 +247,7 @@ def _enable_fetch_instrumentation() -> None:
247
247
  original = _original_opener_open
248
248
 
249
249
  def _patched_open(self: Any, fullurl: Any, data: Any = None, timeout: Any = socket.getdefaulttimeout()) -> Any:
250
- tracer = get_tracer()
250
+ tracer = _get_tracer()
251
251
  if tracer is None:
252
252
  return original(self, fullurl, data, timeout)
253
253
 
@@ -391,13 +391,13 @@ def attach_event_loop(loop: asyncio.AbstractEventLoop) -> None:
391
391
  _connection.start(loop)
392
392
 
393
393
 
394
- def get_tracer() -> Any:
395
- """Return the active tracer, or None if OTel has not been initialized."""
394
+ def _get_tracer() -> Any:
395
+ """Internal: return the active tracer, or None if OTel has not been initialized."""
396
396
  return _tracer
397
397
 
398
398
 
399
- def get_meter() -> Any:
400
- """Return the active meter, or None if OTel metrics have not been initialized."""
399
+ def _get_meter() -> Any:
400
+ """Internal: return the active meter, or None if OTel metrics have not been initialized."""
401
401
  return _meter
402
402
 
403
403
 
@@ -421,8 +421,8 @@ def current_span_id() -> str | None:
421
421
  return None
422
422
 
423
423
 
424
- def is_initialized() -> bool:
425
- """Return True if OTel has been successfully initialized."""
424
+ def _is_initialized() -> bool:
425
+ """Internal: return True if OTel has been successfully initialized."""
426
426
  return _initialized
427
427
 
428
428
 
@@ -456,7 +456,7 @@ async def with_span(
456
456
  Returns:
457
457
  The value returned by *fn*.
458
458
  """
459
- tracer = get_tracer()
459
+ tracer = _get_tracer()
460
460
  if tracer is None:
461
461
 
462
462
  class _NoopSpan:
@@ -12,7 +12,6 @@ from pydantic import BaseModel, ConfigDict, Field
12
12
  from .iii_types import (
13
13
  HttpInvocationConfig,
14
14
  RegisterFunctionMessage,
15
- RegisterServiceInput,
16
15
  RegisterTriggerInput,
17
16
  RegisterTriggerTypeInput,
18
17
  RegisterTriggerTypeMessage,
@@ -82,8 +81,6 @@ class IIIClient(Protocol):
82
81
 
83
82
  def register_trigger(self, trigger: RegisterTriggerInput | dict[str, Any]) -> Trigger: ...
84
83
 
85
- def register_service(self, service: RegisterServiceInput | dict[str, Any]) -> None: ...
86
-
87
84
  def register_function(
88
85
  self,
89
86
  function_id: str,
@@ -4,7 +4,7 @@ import asyncio
4
4
 
5
5
  import pytest
6
6
 
7
- from iii import FunctionInfo, TriggerAction
7
+ from iii import TriggerAction
8
8
  from iii.iii import III
9
9
 
10
10
 
@@ -22,7 +22,7 @@ async def wait_for(condition, timeout=5.0, interval=0.1):
22
22
  async def test_connect_successfully(iii_client: III):
23
23
  """SDK connects to the engine and can list functions."""
24
24
  result = iii_client.trigger({"function_id": "engine::functions::list", "payload": {}})
25
- functions = [FunctionInfo(**f) for f in result.get("functions", [])]
25
+ functions = result.get("functions", [])
26
26
  assert isinstance(functions, list)
27
27
 
28
28
 
@@ -93,8 +93,8 @@ async def test_list_registered_functions(iii_client: III):
93
93
 
94
94
  try:
95
95
  result = iii_client.trigger({"function_id": "engine::functions::list", "payload": {}})
96
- functions = [FunctionInfo(**f) for f in result.get("functions", [])]
97
- function_ids = [f.function_id for f in functions]
96
+ functions = result.get("functions", [])
97
+ function_ids = [f["function_id"] for f in functions]
98
98
 
99
99
  assert "test.bridge.py.list.func1" in function_ids
100
100
  assert "test.bridge.py.list.func2" in function_ids
@@ -72,7 +72,7 @@ def test_logger_emits_warn_severity():
72
72
 
73
73
  log_exporter = _setup_in_memory_log_provider()
74
74
 
75
- with patch("iii.logger.is_initialized", return_value=True):
75
+ with patch("iii.logger._is_initialized", return_value=True):
76
76
  logger = Logger()
77
77
  logger.warn("watch out")
78
78
 
@@ -94,7 +94,7 @@ def test_logger_attaches_trace_context_from_active_span():
94
94
  trace.set_tracer_provider(tracer_provider)
95
95
  tracer = tracer_provider.get_tracer("test")
96
96
 
97
- with patch("iii.logger.is_initialized", return_value=True):
97
+ with patch("iii.logger._is_initialized", return_value=True):
98
98
  with tracer.start_as_current_span("test-span") as span:
99
99
  logger = Logger(service_name="fn1")
100
100
  logger.info("inside span")
@@ -114,7 +114,7 @@ def test_logger_no_trace_context_outside_span():
114
114
 
115
115
  log_exporter = _setup_in_memory_log_provider()
116
116
 
117
- with patch("iii.logger.is_initialized", return_value=True):
117
+ with patch("iii.logger._is_initialized", return_value=True):
118
118
  logger = Logger(service_name="fn1")
119
119
  logger.info("outside span")
120
120
 
@@ -8,7 +8,6 @@ import pytest
8
8
  from iii import (
9
9
  AuthInput,
10
10
  AuthResult,
11
- FunctionInfo,
12
11
  IIIForbiddenError,
13
12
  IIIInvocationError,
14
13
  InitOptions,
@@ -291,8 +290,8 @@ class TestRbacWorkers:
291
290
  result = iii_client.trigger(
292
291
  {"function_id": "engine::functions::list", "payload": {}}
293
292
  )
294
- functions = [FunctionInfo(**f) for f in result.get("functions", [])]
295
- function_ids = [f.function_id for f in functions]
293
+ functions = result.get("functions", [])
294
+ function_ids = [f["function_id"] for f in functions]
296
295
 
297
296
  assert "test::ew::valid-token-echo" in function_ids
298
297
  assert "test::ew::public::echo" in function_ids
@@ -315,8 +314,8 @@ class TestRbacWorkers:
315
314
  result = iii_client.trigger(
316
315
  {"function_id": "engine::functions::list", "payload": {}}
317
316
  )
318
- functions = [FunctionInfo(**f) for f in result.get("functions", [])]
319
- function_ids = [f.function_id for f in functions]
317
+ functions = result.get("functions", [])
318
+ function_ids = [f["function_id"] for f in functions]
320
319
 
321
320
  assert "test::ew::public::echo" in function_ids
322
321
  assert "test::ew::meta-public" in function_ids
@@ -8,7 +8,7 @@ from typing import Any
8
8
  import pytest
9
9
 
10
10
  import iii.iii as iii_module
11
- from iii import InitOptions, RegisterServiceInput, RegisterTriggerTypeInput
11
+ from iii import InitOptions, RegisterTriggerTypeInput
12
12
  from iii.iii import III
13
13
  from iii.triggers import TriggerConfig, TriggerHandler
14
14
 
@@ -158,28 +158,6 @@ def test_register_function_accepts_async_handler(monkeypatch: pytest.MonkeyPatch
158
158
  client.shutdown()
159
159
 
160
160
 
161
- def test_register_service_accepts_input_object(monkeypatch: pytest.MonkeyPatch) -> None:
162
- """register_service should store services by the provided service id."""
163
- _patch_ws(monkeypatch)
164
- client = III("ws://fake", InitOptions())
165
- time.sleep(0.05)
166
-
167
- client.register_service(
168
- RegisterServiceInput(
169
- id="svc.test",
170
- name="Test Service",
171
- description="service description",
172
- parent_service_id="svc.parent",
173
- )
174
- )
175
-
176
- assert "svc.test" in client._services
177
- service = client._services["svc.test"]
178
- assert service.name == "Test Service"
179
- assert service.parent_service_id == "svc.parent"
180
-
181
- client.shutdown()
182
-
183
161
 
184
162
  def test_register_and_unregister_trigger_type_accept_input_object(monkeypatch: pytest.MonkeyPatch) -> None:
185
163
  """Trigger type registration should accept input objects symmetrically."""
@@ -4,7 +4,7 @@ import urllib.request
4
4
 
5
5
  import pytest
6
6
 
7
- from iii.telemetry import get_tracer, init_otel, is_initialized, shutdown_otel, shutdown_otel_async
7
+ from iii.telemetry import _get_tracer, _is_initialized, init_otel, shutdown_otel, shutdown_otel_async
8
8
  from iii.telemetry_types import OtelConfig
9
9
 
10
10
  # URLLibInstrumentor patches OpenerDirector.open, not urlopen directly
@@ -35,20 +35,20 @@ def cleanup():
35
35
 
36
36
 
37
37
  def test_not_initialized_by_default():
38
- assert not is_initialized()
39
- assert get_tracer() is None
38
+ assert not _is_initialized()
39
+ assert _get_tracer() is None
40
40
 
41
41
 
42
42
  def test_init_disabled_when_enabled_is_false():
43
43
  init_otel(OtelConfig(enabled=False))
44
- assert not is_initialized()
45
- assert get_tracer() is None
44
+ assert not _is_initialized()
45
+ assert _get_tracer() is None
46
46
 
47
47
 
48
48
  def test_init_enabled():
49
49
  init_otel(OtelConfig(enabled=True))
50
- assert is_initialized()
51
- assert get_tracer() is not None
50
+ assert _is_initialized()
51
+ assert _get_tracer() is not None
52
52
 
53
53
 
54
54
  def test_init_patches_urlopen_by_default():
@@ -71,15 +71,15 @@ def test_shutdown_restores_urlopen():
71
71
  def test_shutdown_clears_state():
72
72
  init_otel(OtelConfig(enabled=True))
73
73
  shutdown_otel()
74
- assert not is_initialized()
75
- assert get_tracer() is None
74
+ assert not _is_initialized()
75
+ assert _get_tracer() is None
76
76
 
77
77
 
78
78
  def test_init_is_idempotent():
79
79
  init_otel(OtelConfig(enabled=True))
80
- tracer1 = get_tracer()
80
+ tracer1 = _get_tracer()
81
81
  init_otel(OtelConfig(enabled=True)) # second call must be no-op
82
- assert get_tracer() is tracer1
82
+ assert _get_tracer() is tracer1
83
83
 
84
84
 
85
85
  def test_shutdown_without_init_is_safe():
@@ -87,13 +87,13 @@ def test_shutdown_without_init_is_safe():
87
87
 
88
88
 
89
89
  def test_telemetry_apis_importable_from_submodules():
90
- from iii.telemetry import get_tracer, init_otel, is_initialized, shutdown_otel
90
+ from iii.telemetry import _get_tracer, _is_initialized, init_otel, shutdown_otel
91
91
  from iii.telemetry_types import OtelConfig
92
92
 
93
93
  assert callable(init_otel)
94
94
  assert callable(shutdown_otel)
95
- assert callable(get_tracer)
96
- assert callable(is_initialized)
95
+ assert callable(_get_tracer)
96
+ assert callable(_is_initialized)
97
97
  assert OtelConfig is not None
98
98
 
99
99
 
@@ -1,5 +1,5 @@
1
- """Tests for metadata support in trigger registration types."""
2
- from iii.iii_types import RegisterTriggerInput, RegisterTriggerMessage, TriggerInfo
1
+ """Tests for metadata support in trigger registration protocol types."""
2
+ from iii.iii_types import RegisterTriggerInput, RegisterTriggerMessage
3
3
 
4
4
 
5
5
  def test_register_trigger_input_accepts_metadata():
@@ -26,19 +26,3 @@ def test_register_trigger_message_includes_metadata():
26
26
  metadata={"env": "prod"},
27
27
  )
28
28
  assert msg.metadata == {"env": "prod"}
29
-
30
-
31
- def test_trigger_info_includes_metadata():
32
- info = TriggerInfo(
33
- id="t1",
34
- trigger_type="http",
35
- function_id="fn",
36
- config={},
37
- metadata={"team": "api"},
38
- )
39
- assert info.metadata == {"team": "api"}
40
-
41
-
42
- def test_trigger_info_metadata_defaults_none():
43
- info = TriggerInfo(id="t2", trigger_type="cron", function_id="fn")
44
- assert info.metadata is None