iii-sdk 0.11.6.dev2__tar.gz → 0.11.6.dev4__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.11.6.dev2 → iii_sdk-0.11.6.dev4}/PKG-INFO +1 -1
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/pyproject.toml +1 -1
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/iii.py +40 -1
- iii_sdk-0.11.6.dev4/tests/test_worker_metadata.py +113 -0
- iii_sdk-0.11.6.dev2/tests/test_worker_metadata.py +0 -33
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/.gitignore +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/README.md +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/__init__.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/channels.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/errors.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/format_utils.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/iii_constants.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/iii_types.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/logger.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/otel_worker_gauges.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/state.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/stream.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/telemetry.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/telemetry_exporters.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/telemetry_types.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/triggers.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/types.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/utils.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/src/iii/worker_metrics.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/conftest.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_api_triggers.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_async_api.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_bridge.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_channel_close_delay.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_context_propagation.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_data_channels.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_errors.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_format_utils.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_healthcheck.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_hold_process.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_http_external_functions_integration.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_iii_registration_dedup.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_init_api.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_invocation_exception.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_logger_function_ids.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_logger_otel.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_middleware.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_pubsub.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_queue_integration.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_rbac_workers.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_register_function_args.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_state.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_stream_models.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_streams.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_streams_runtime_annotations.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_sync_api.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_telemetry.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_telemetry_exporters.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_telemetry_types.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_trace_helpers.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_trigger_metadata.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_utils.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_worker_metrics.py +0 -0
- {iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/uv.lock +0 -0
|
@@ -77,6 +77,42 @@ def _resolve_format(fmt: Any) -> Any | None:
|
|
|
77
77
|
return fmt
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
def _detect_project_name(cwd: str | None = None) -> str | None:
|
|
81
|
+
"""Return a project identifier for telemetry, derived from the current working directory.
|
|
82
|
+
|
|
83
|
+
Reads ``[project] name`` from ``pyproject.toml`` if present at ``cwd``;
|
|
84
|
+
otherwise falls back to the basename of ``cwd``. Returns ``None`` only
|
|
85
|
+
when both signals are unavailable (e.g. cwd is the filesystem root, or
|
|
86
|
+
the Python runtime has no TOML parser and no readable cwd basename).
|
|
87
|
+
|
|
88
|
+
No directory walking — only inspects ``cwd`` itself, so the SDK never
|
|
89
|
+
reads files outside the user's explicit working directory.
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
cwd = cwd or os.getcwd()
|
|
93
|
+
manifest = os.path.join(cwd, "pyproject.toml")
|
|
94
|
+
if os.path.isfile(manifest):
|
|
95
|
+
import importlib
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
tomllib = importlib.import_module("tomllib") # Python 3.11+
|
|
99
|
+
except ImportError:
|
|
100
|
+
tomllib = None
|
|
101
|
+
if tomllib is not None:
|
|
102
|
+
with open(manifest, "rb") as fh:
|
|
103
|
+
data = tomllib.load(fh)
|
|
104
|
+
name = data.get("project", {}).get("name")
|
|
105
|
+
if isinstance(name, str) and name.strip():
|
|
106
|
+
return name.strip()
|
|
107
|
+
except Exception:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
if not cwd:
|
|
111
|
+
return None
|
|
112
|
+
base = os.path.basename(cwd).strip()
|
|
113
|
+
return base or None
|
|
114
|
+
|
|
115
|
+
|
|
80
116
|
class _TraceContextError(Exception):
|
|
81
117
|
"""Wraps a handler exception with the response traceparent from the active span."""
|
|
82
118
|
|
|
@@ -1163,7 +1199,10 @@ class III:
|
|
|
1163
1199
|
|
|
1164
1200
|
telemetry: dict[str, Any] = {
|
|
1165
1201
|
"language": language,
|
|
1166
|
-
"project_name":
|
|
1202
|
+
"project_name": (
|
|
1203
|
+
(telemetry_opts.project_name if telemetry_opts else None)
|
|
1204
|
+
or _detect_project_name()
|
|
1205
|
+
),
|
|
1167
1206
|
"framework": (telemetry_opts.framework if telemetry_opts else None) or "iii-py",
|
|
1168
1207
|
"amplitude_api_key": (
|
|
1169
1208
|
telemetry_opts.amplitude_api_key if telemetry_opts else None
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from iii import InitOptions
|
|
11
|
+
from iii.iii import III, _detect_project_name
|
|
12
|
+
from iii.iii_constants import TelemetryOptions
|
|
13
|
+
|
|
14
|
+
# pyproject.toml parsing relies on stdlib tomllib (Python 3.11+).
|
|
15
|
+
# On 3.10 the SDK intentionally falls back to the cwd basename, so
|
|
16
|
+
# tests that assert the parsed name are skipped on that runtime.
|
|
17
|
+
requires_tomllib = pytest.mark.skipif(
|
|
18
|
+
sys.version_info < (3, 11),
|
|
19
|
+
reason="pyproject.toml parsing requires stdlib tomllib (Python 3.11+)",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _call_metadata_method(options: InitOptions | None = None) -> dict[str, object]:
|
|
24
|
+
stub = III.__new__(III)
|
|
25
|
+
stub._options = options or InitOptions()
|
|
26
|
+
return stub._get_worker_metadata()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_get_worker_metadata_isolation_is_none_when_env_unset(
|
|
30
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
31
|
+
) -> None:
|
|
32
|
+
monkeypatch.delenv("III_ISOLATION", raising=False)
|
|
33
|
+
|
|
34
|
+
metadata = _call_metadata_method()
|
|
35
|
+
|
|
36
|
+
assert "isolation" in metadata
|
|
37
|
+
assert metadata["isolation"] is None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_get_worker_metadata_forwards_iii_isolation_env_var(
|
|
41
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
42
|
+
) -> None:
|
|
43
|
+
monkeypatch.setenv("III_ISOLATION", "docker")
|
|
44
|
+
|
|
45
|
+
metadata = _call_metadata_method()
|
|
46
|
+
|
|
47
|
+
assert metadata["isolation"] == "docker"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@requires_tomllib
|
|
51
|
+
def test_detect_project_name_reads_pyproject_name(tmp_path: Path) -> None:
|
|
52
|
+
(tmp_path / "pyproject.toml").write_text('[project]\nname = "my-pkg"\n')
|
|
53
|
+
|
|
54
|
+
assert _detect_project_name(str(tmp_path)) == "my-pkg"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_detect_project_name_falls_back_to_cwd_basename_when_no_manifest(
|
|
58
|
+
tmp_path: Path,
|
|
59
|
+
) -> None:
|
|
60
|
+
assert _detect_project_name(str(tmp_path)) == tmp_path.name
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_detect_project_name_falls_back_to_cwd_basename_when_name_missing(
|
|
64
|
+
tmp_path: Path,
|
|
65
|
+
) -> None:
|
|
66
|
+
(tmp_path / "pyproject.toml").write_text('[project]\nversion = "1.0.0"\n')
|
|
67
|
+
|
|
68
|
+
assert _detect_project_name(str(tmp_path)) == tmp_path.name
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_detect_project_name_falls_back_to_cwd_basename_when_pyproject_malformed(
|
|
72
|
+
tmp_path: Path,
|
|
73
|
+
) -> None:
|
|
74
|
+
(tmp_path / "pyproject.toml").write_text("not valid toml [[[")
|
|
75
|
+
|
|
76
|
+
assert _detect_project_name(str(tmp_path)) == tmp_path.name
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@requires_tomllib
|
|
80
|
+
def test_get_worker_metadata_auto_detects_project_name_from_pyproject(
|
|
81
|
+
tmp_path: Path,
|
|
82
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
83
|
+
) -> None:
|
|
84
|
+
(tmp_path / "pyproject.toml").write_text('[project]\nname = "auto-detected-pkg"\n')
|
|
85
|
+
monkeypatch.chdir(tmp_path)
|
|
86
|
+
|
|
87
|
+
metadata = _call_metadata_method()
|
|
88
|
+
|
|
89
|
+
assert metadata["telemetry"]["project_name"] == "auto-detected-pkg" # type: ignore[index]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_get_worker_metadata_user_provided_project_name_wins(
|
|
93
|
+
tmp_path: Path,
|
|
94
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
95
|
+
) -> None:
|
|
96
|
+
(tmp_path / "pyproject.toml").write_text('[project]\nname = "auto-detected-pkg"\n')
|
|
97
|
+
monkeypatch.chdir(tmp_path)
|
|
98
|
+
options = InitOptions(telemetry=TelemetryOptions(project_name="explicit-override"))
|
|
99
|
+
|
|
100
|
+
metadata = _call_metadata_method(options)
|
|
101
|
+
|
|
102
|
+
assert metadata["telemetry"]["project_name"] == "explicit-override" # type: ignore[index]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_get_worker_metadata_falls_back_to_cwd_basename_without_pyproject(
|
|
106
|
+
tmp_path: Path,
|
|
107
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
108
|
+
) -> None:
|
|
109
|
+
monkeypatch.chdir(tmp_path)
|
|
110
|
+
|
|
111
|
+
metadata = _call_metadata_method()
|
|
112
|
+
|
|
113
|
+
assert metadata["telemetry"]["project_name"] == tmp_path.name # type: ignore[index]
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
from iii import InitOptions
|
|
6
|
-
from iii.iii import III
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def _call_metadata_method() -> dict[str, object]:
|
|
10
|
-
stub = III.__new__(III)
|
|
11
|
-
stub._options = InitOptions()
|
|
12
|
-
return stub._get_worker_metadata()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def test_get_worker_metadata_isolation_is_none_when_env_unset(
|
|
16
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
17
|
-
) -> None:
|
|
18
|
-
monkeypatch.delenv("III_ISOLATION", raising=False)
|
|
19
|
-
|
|
20
|
-
metadata = _call_metadata_method()
|
|
21
|
-
|
|
22
|
-
assert "isolation" in metadata
|
|
23
|
-
assert metadata["isolation"] is None
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def test_get_worker_metadata_forwards_iii_isolation_env_var(
|
|
27
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
28
|
-
) -> None:
|
|
29
|
-
monkeypatch.setenv("III_ISOLATION", "docker")
|
|
30
|
-
|
|
31
|
-
metadata = _call_metadata_method()
|
|
32
|
-
|
|
33
|
-
assert metadata["isolation"] == "docker"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iii_sdk-0.11.6.dev2 → iii_sdk-0.11.6.dev4}/tests/test_http_external_functions_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|