span-panel-api 2.4.1__tar.gz → 2.4.2__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.
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/workflows/ci.yml +6 -7
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/workflows/dependabot-auto-approve.yml +1 -1
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/workflows/dependabot-auto-merge.yml +1 -1
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/workflows/release.yml +2 -2
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/CHANGELOG.md +7 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/PKG-INFO +1 -4
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/README.md +0 -3
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/pyproject.toml +1 -1
- span_panel_api-2.4.2/src/span_panel_api/_http.py +66 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/conftest.py +9 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_auth_and_homie_helpers.py +5 -2
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_detection_auth.py +15 -3
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/uv.lock +47 -47
- span_panel_api-2.4.1/src/span_panel_api/_http.py +0 -27
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.codefactor +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.codefactor.yml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.deps-installed +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.github/dependabot.yml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.gitignore +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.markdownlint-cli2.jsonc +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.markdownlint.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.pre-commit-config.yaml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.prettierrc.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.vscode/extensions.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/.vscode/tasks.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/DEVELOPMENT.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/LICENSE +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/SECURITY.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/conftest.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/coverage_output.log +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/debug_unmapped.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/developer_attribute_readme.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/openapi.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/pytest.ini +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/pytest_output.log +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/scripts/__init__.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/scripts/coverage.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/scripts/format.sh +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/scripts/format_markdown.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/scripts/test_live_auth.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/setup-hooks.sh +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/__init__.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/auth.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/const.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/detection.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/exceptions.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/factory.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/models.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/__init__.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/async_client.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/client.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/connection.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/const.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/field_metadata.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/homie.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/models.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/phase_validation.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/protocol.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/src/span_panel_api/py.typed +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_32_circuit.yaml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_40_circuit_with_battery.yaml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_8_tab_workshop.yaml +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/v2/README.md +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/v2/homie_schema.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/fixtures/v2/status.json +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/simulation_fixtures/circuits.response.txt +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/simulation_fixtures/panel.response.txt +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/simulation_fixtures/soe.response.txt +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/simulation_fixtures/status.response.txt +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_async_mqtt_client.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_field_metadata.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_mqtt_bridge.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_mqtt_connect_flow.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_mqtt_debounce.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_mqtt_homie.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_phase_validation_configs.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_phase_validation_errors.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_protocol_conformance.py +0 -0
- {span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/test_protocol_models.py +0 -0
|
@@ -11,7 +11,7 @@ jobs:
|
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
strategy:
|
|
13
13
|
matrix:
|
|
14
|
-
python-version: ["3.
|
|
14
|
+
python-version: ["3.14"]
|
|
15
15
|
|
|
16
16
|
steps:
|
|
17
17
|
- name: Checkout code
|
|
@@ -21,10 +21,9 @@ jobs:
|
|
|
21
21
|
uses: actions/setup-python@v6
|
|
22
22
|
with:
|
|
23
23
|
python-version: ${{ matrix.python-version }}
|
|
24
|
-
allow-prereleases: true
|
|
25
24
|
|
|
26
25
|
- name: Install uv
|
|
27
|
-
uses: astral-sh/setup-uv@
|
|
26
|
+
uses: astral-sh/setup-uv@v7
|
|
28
27
|
with:
|
|
29
28
|
enable-cache: true
|
|
30
29
|
|
|
@@ -50,10 +49,10 @@ jobs:
|
|
|
50
49
|
- name: Set up Python
|
|
51
50
|
uses: actions/setup-python@v6
|
|
52
51
|
with:
|
|
53
|
-
python-version: "3.
|
|
52
|
+
python-version: "3.14"
|
|
54
53
|
|
|
55
54
|
- name: Install uv
|
|
56
|
-
uses: astral-sh/setup-uv@
|
|
55
|
+
uses: astral-sh/setup-uv@v7
|
|
57
56
|
with:
|
|
58
57
|
enable-cache: true
|
|
59
58
|
|
|
@@ -79,10 +78,10 @@ jobs:
|
|
|
79
78
|
- name: Set up Python
|
|
80
79
|
uses: actions/setup-python@v6
|
|
81
80
|
with:
|
|
82
|
-
python-version: "3.
|
|
81
|
+
python-version: "3.14"
|
|
83
82
|
|
|
84
83
|
- name: Install uv
|
|
85
|
-
uses: astral-sh/setup-uv@
|
|
84
|
+
uses: astral-sh/setup-uv@v7
|
|
86
85
|
with:
|
|
87
86
|
enable-cache: true
|
|
88
87
|
|
|
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.4.2] - 03/2026
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Moved SSL context creation to executor** — `httpx.AsyncClient()` eagerly calls `ssl.SSLContext.load_verify_locations()` with the system CA bundle, which is a blocking file I/O operation that triggers Home Assistant's event loop protection. The SSL
|
|
12
|
+
context is now created in an executor thread and passed to httpx via `verify=ctx`.
|
|
13
|
+
|
|
7
14
|
## [2.4.1] - 03/2026
|
|
8
15
|
|
|
9
16
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: span-panel-api
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.2
|
|
4
4
|
Summary: A client library for SPAN Panel API
|
|
5
5
|
Project-URL: Homepage, https://github.com/SpanPanel/span-panel-api
|
|
6
6
|
Project-URL: Issues, https://github.com/SpanPanel/span-panel-api/issues
|
|
@@ -22,7 +22,6 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
[](https://github.com/SpanPanel/span-panel-api/actions/workflows/ci.yml)
|
|
23
23
|
|
|
24
24
|
[](https://www.codefactor.io/repository/github/spanpanel/span-panel-api)
|
|
25
|
-
[](https://snyk.io/test/github/SpanPanel/span-panel-api)
|
|
26
25
|
|
|
27
26
|
[](https://github.com/pre-commit/pre-commit)
|
|
28
27
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -51,8 +50,6 @@ pip install span-panel-api
|
|
|
51
50
|
|
|
52
51
|
## Architecture
|
|
53
52
|
|
|
54
|
-
v2.0.0 is a ground-up rewrite. The package connects to the SPAN Panel's on-device MQTT broker using the [Homie v5](https://homieiot.github.io/) convention. All panel and circuit state is delivered via retained MQTT messages — no polling required.
|
|
55
|
-
|
|
56
53
|
### Transport
|
|
57
54
|
|
|
58
55
|
The `SpanMqttClient` connects to the panel's MQTT broker (MQTTS or WebSocket) and subscribes to the Homie device tree. A `HomieDeviceConsumer` state machine parses incoming topic updates into typed `SpanPanelSnapshot` dataclasses. Changes are pushed to
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
[](https://github.com/SpanPanel/span-panel-api/actions/workflows/ci.yml)
|
|
8
8
|
|
|
9
9
|
[](https://www.codefactor.io/repository/github/spanpanel/span-panel-api)
|
|
10
|
-
[](https://snyk.io/test/github/SpanPanel/span-panel-api)
|
|
11
10
|
|
|
12
11
|
[](https://github.com/pre-commit/pre-commit)
|
|
13
12
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -36,8 +35,6 @@ pip install span-panel-api
|
|
|
36
35
|
|
|
37
36
|
## Architecture
|
|
38
37
|
|
|
39
|
-
v2.0.0 is a ground-up rewrite. The package connects to the SPAN Panel's on-device MQTT broker using the [Homie v5](https://homieiot.github.io/) convention. All panel and circuit state is delivered via retained MQTT messages — no polling required.
|
|
40
|
-
|
|
41
38
|
### Transport
|
|
42
39
|
|
|
43
40
|
The `SpanMqttClient` connects to the panel's MQTT broker (MQTTS or WebSocket) and subscribes to the Homie device tree. A `HomieDeviceConsumer` state machine parses incoming topic updates into typed `SpanPanelSnapshot` dataclasses. Changes are pushed to
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Shared HTTP helpers for SPAN Panel bootstrap REST calls."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from collections.abc import AsyncIterator
|
|
7
|
+
from contextlib import asynccontextmanager
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
import ssl
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class _SSLCache:
|
|
16
|
+
"""Mutable container for the cached SSLContext and its async lock."""
|
|
17
|
+
|
|
18
|
+
context: ssl.SSLContext | None = None
|
|
19
|
+
lock: asyncio.Lock | None = field(default=None, repr=False)
|
|
20
|
+
|
|
21
|
+
def get_lock(self) -> asyncio.Lock:
|
|
22
|
+
"""Return the async lock, creating it lazily."""
|
|
23
|
+
if self.lock is None:
|
|
24
|
+
self.lock = asyncio.Lock()
|
|
25
|
+
return self.lock
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
_ssl_cache = _SSLCache()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _build_url(host: str, port: int, path: str) -> str:
|
|
32
|
+
"""Build an HTTP URL, omitting the port when it is the default (80)."""
|
|
33
|
+
if port == 80:
|
|
34
|
+
return f"http://{host}{path}"
|
|
35
|
+
return f"http://{host}:{port}{path}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def _create_ssl_context() -> ssl.SSLContext:
|
|
39
|
+
"""Return a cached default SSL context, creating it in an executor on first call.
|
|
40
|
+
|
|
41
|
+
``ssl.create_default_context()`` calls ``load_verify_locations`` which
|
|
42
|
+
performs blocking file I/O on the system CA bundle. The resulting context
|
|
43
|
+
is thread-safe and reusable, so we cache it for the lifetime of the process.
|
|
44
|
+
"""
|
|
45
|
+
if _ssl_cache.context is not None:
|
|
46
|
+
return _ssl_cache.context
|
|
47
|
+
async with _ssl_cache.get_lock():
|
|
48
|
+
# Double-check after acquiring the lock.
|
|
49
|
+
if _ssl_cache.context is not None:
|
|
50
|
+
return _ssl_cache.context
|
|
51
|
+
loop = asyncio.get_running_loop()
|
|
52
|
+
_ssl_cache.context = await loop.run_in_executor(None, ssl.create_default_context)
|
|
53
|
+
return _ssl_cache.context
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@asynccontextmanager
|
|
57
|
+
async def _get_client(
|
|
58
|
+
httpx_client: httpx.AsyncClient | None,
|
|
59
|
+
timeout: float,
|
|
60
|
+
) -> AsyncIterator[httpx.AsyncClient]:
|
|
61
|
+
if httpx_client is not None:
|
|
62
|
+
yield httpx_client
|
|
63
|
+
return
|
|
64
|
+
ctx = await _create_ssl_context()
|
|
65
|
+
async with httpx.AsyncClient(timeout=timeout, verify=ctx) as client:
|
|
66
|
+
yield client
|
|
@@ -13,9 +13,18 @@ import pytest
|
|
|
13
13
|
from paho.mqtt.client import ConnectFlags
|
|
14
14
|
from paho.mqtt.reasoncodes import ReasonCode
|
|
15
15
|
|
|
16
|
+
import span_panel_api._http as _http_mod
|
|
16
17
|
from span_panel_api.models import V2HomieSchema
|
|
17
18
|
from span_panel_api.mqtt.const import TOPIC_PREFIX, TYPE_CORE
|
|
18
19
|
|
|
20
|
+
|
|
21
|
+
@pytest.fixture(autouse=True)
|
|
22
|
+
def _reset_ssl_cache() -> None:
|
|
23
|
+
"""Ensure the module-level SSL context cache doesn't leak between tests."""
|
|
24
|
+
_http_mod._ssl_cache.context = None
|
|
25
|
+
_http_mod._ssl_cache.lock = None
|
|
26
|
+
|
|
27
|
+
|
|
19
28
|
# ---------------------------------------------------------------------------
|
|
20
29
|
# Constants shared across MQTT tests
|
|
21
30
|
# ---------------------------------------------------------------------------
|
|
@@ -145,7 +145,10 @@ class TestHttpxClientInjectionAuthHelpers:
|
|
|
145
145
|
headers={"content-type": "text/plain"},
|
|
146
146
|
request=httpx.Request("GET", "http://test"),
|
|
147
147
|
)
|
|
148
|
-
with
|
|
148
|
+
with (
|
|
149
|
+
patch("span_panel_api._http.httpx.AsyncClient") as cls,
|
|
150
|
+
patch("span_panel_api._http._create_ssl_context", new_callable=AsyncMock) as mock_ctx,
|
|
151
|
+
):
|
|
149
152
|
mock_client = AsyncMock()
|
|
150
153
|
mock_client.get.return_value = mock_response
|
|
151
154
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
@@ -154,7 +157,7 @@ class TestHttpxClientInjectionAuthHelpers:
|
|
|
154
157
|
|
|
155
158
|
await download_ca_cert("192.168.1.1", timeout=88.5)
|
|
156
159
|
|
|
157
|
-
cls.assert_called_once_with(timeout=88.5)
|
|
160
|
+
cls.assert_called_once_with(timeout=88.5, verify=mock_ctx.return_value)
|
|
158
161
|
|
|
159
162
|
@pytest.mark.asyncio
|
|
160
163
|
async def test_get_homie_schema_injected_skips_constructor(self) -> None:
|
|
@@ -52,7 +52,10 @@ class TestHttpHelpers:
|
|
|
52
52
|
|
|
53
53
|
@pytest.mark.asyncio
|
|
54
54
|
async def test_get_client_creates_and_closes_fallback_client(self) -> None:
|
|
55
|
-
with
|
|
55
|
+
with (
|
|
56
|
+
patch("span_panel_api._http.httpx.AsyncClient") as mock_cls,
|
|
57
|
+
patch("span_panel_api._http._create_ssl_context", new_callable=AsyncMock) as mock_ctx,
|
|
58
|
+
):
|
|
56
59
|
mock_instance = AsyncMock()
|
|
57
60
|
mock_instance.__aenter__ = AsyncMock(return_value=mock_instance)
|
|
58
61
|
mock_instance.__aexit__ = AsyncMock(return_value=False)
|
|
@@ -63,6 +66,7 @@ class TestHttpHelpers:
|
|
|
63
66
|
|
|
64
67
|
mock_cls.assert_called_once_with(
|
|
65
68
|
timeout=12.5,
|
|
69
|
+
verify=mock_ctx.return_value,
|
|
66
70
|
)
|
|
67
71
|
mock_instance.__aenter__.assert_awaited_once()
|
|
68
72
|
mock_instance.__aexit__.assert_awaited_once()
|
|
@@ -135,7 +139,10 @@ class TestHttpxClientInjection:
|
|
|
135
139
|
@pytest.mark.asyncio
|
|
136
140
|
async def test_fallback_client_uses_register_v2_timeout(self) -> None:
|
|
137
141
|
mock_response = _mock_response(200, V2_AUTH_JSON)
|
|
138
|
-
with
|
|
142
|
+
with (
|
|
143
|
+
patch("span_panel_api._http.httpx.AsyncClient") as mock_client_cls,
|
|
144
|
+
patch("span_panel_api._http._create_ssl_context", new_callable=AsyncMock) as mock_ctx,
|
|
145
|
+
):
|
|
139
146
|
mock_client = AsyncMock()
|
|
140
147
|
mock_client.post.return_value = mock_response
|
|
141
148
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
@@ -146,6 +153,7 @@ class TestHttpxClientInjection:
|
|
|
146
153
|
|
|
147
154
|
mock_client_cls.assert_called_once_with(
|
|
148
155
|
timeout=42.5,
|
|
156
|
+
verify=mock_ctx.return_value,
|
|
149
157
|
)
|
|
150
158
|
|
|
151
159
|
@pytest.mark.asyncio
|
|
@@ -179,7 +187,10 @@ class TestHttpxClientInjection:
|
|
|
179
187
|
@pytest.mark.asyncio
|
|
180
188
|
async def test_detect_api_version_fallback_uses_timeout(self) -> None:
|
|
181
189
|
mock_response = _mock_response(200, V2_STATUS_JSON)
|
|
182
|
-
with
|
|
190
|
+
with (
|
|
191
|
+
patch("span_panel_api._http.httpx.AsyncClient") as mock_client_cls,
|
|
192
|
+
patch("span_panel_api._http._create_ssl_context", new_callable=AsyncMock) as mock_ctx,
|
|
193
|
+
):
|
|
183
194
|
mock_client = AsyncMock()
|
|
184
195
|
mock_client.get.return_value = mock_response
|
|
185
196
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
@@ -190,6 +201,7 @@ class TestHttpxClientInjection:
|
|
|
190
201
|
|
|
191
202
|
mock_client_cls.assert_called_once_with(
|
|
192
203
|
timeout=3.25,
|
|
204
|
+
verify=mock_ctx.return_value,
|
|
193
205
|
)
|
|
194
206
|
|
|
195
207
|
|
|
@@ -427,51 +427,51 @@ toml = [
|
|
|
427
427
|
|
|
428
428
|
[[package]]
|
|
429
429
|
name = "cryptography"
|
|
430
|
-
version = "46.0.
|
|
430
|
+
version = "46.0.6"
|
|
431
431
|
source = { registry = "https://pypi.org/simple" }
|
|
432
432
|
dependencies = [
|
|
433
433
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
|
434
434
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
435
435
|
]
|
|
436
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
437
|
-
wheels = [
|
|
438
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
439
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
440
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
441
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
442
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
443
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
444
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
445
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
446
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
447
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
448
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
449
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
450
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
451
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
452
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
453
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
454
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
455
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
456
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
457
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
458
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
459
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
460
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
461
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
462
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
463
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
464
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
465
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
466
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
467
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
468
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
469
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
470
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
471
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
472
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
473
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
474
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
436
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a4/ba/04b1bd4218cbc58dc90ce967106d51582371b898690f3ae0402876cc4f34/cryptography-46.0.6.tar.gz", hash = "sha256:27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759", size = 750542, upload-time = "2026-03-25T23:34:53.396Z" }
|
|
437
|
+
wheels = [
|
|
438
|
+
{ url = "https://files.pythonhosted.org/packages/60/f8/e61f8f13950ab6195b31913b42d39f0f9afc7d93f76710f299b5ec286ae6/cryptography-46.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30", size = 4275275, upload-time = "2026-03-25T23:33:23.844Z" },
|
|
439
|
+
{ url = "https://files.pythonhosted.org/packages/19/69/732a736d12c2631e140be2348b4ad3d226302df63ef64d30dfdb8db7ad1c/cryptography-46.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a", size = 4425320, upload-time = "2026-03-25T23:33:25.703Z" },
|
|
440
|
+
{ url = "https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175", size = 4278082, upload-time = "2026-03-25T23:33:27.423Z" },
|
|
441
|
+
{ url = "https://files.pythonhosted.org/packages/5b/ba/d5e27f8d68c24951b0a484924a84c7cdaed7502bac9f18601cd357f8b1d2/cryptography-46.0.6-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463", size = 4926514, upload-time = "2026-03-25T23:33:29.206Z" },
|
|
442
|
+
{ url = "https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97", size = 4457766, upload-time = "2026-03-25T23:33:30.834Z" },
|
|
443
|
+
{ url = "https://files.pythonhosted.org/packages/01/59/562be1e653accee4fdad92c7a2e88fced26b3fdfce144047519bbebc299e/cryptography-46.0.6-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c", size = 3986535, upload-time = "2026-03-25T23:33:33.02Z" },
|
|
444
|
+
{ url = "https://files.pythonhosted.org/packages/d6/8b/b1ebfeb788bf4624d36e45ed2662b8bd43a05ff62157093c1539c1288a18/cryptography-46.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507", size = 4277618, upload-time = "2026-03-25T23:33:34.567Z" },
|
|
445
|
+
{ url = "https://files.pythonhosted.org/packages/dd/52/a005f8eabdb28df57c20f84c44d397a755782d6ff6d455f05baa2785bd91/cryptography-46.0.6-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19", size = 4890802, upload-time = "2026-03-25T23:33:37.034Z" },
|
|
446
|
+
{ url = "https://files.pythonhosted.org/packages/ec/4d/8e7d7245c79c617d08724e2efa397737715ca0ec830ecb3c91e547302555/cryptography-46.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738", size = 4457425, upload-time = "2026-03-25T23:33:38.904Z" },
|
|
447
|
+
{ url = "https://files.pythonhosted.org/packages/1d/5c/f6c3596a1430cec6f949085f0e1a970638d76f81c3ea56d93d564d04c340/cryptography-46.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c", size = 4405530, upload-time = "2026-03-25T23:33:40.842Z" },
|
|
448
|
+
{ url = "https://files.pythonhosted.org/packages/7e/c9/9f9cea13ee2dbde070424e0c4f621c091a91ffcc504ffea5e74f0e1daeff/cryptography-46.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f", size = 4667896, upload-time = "2026-03-25T23:33:42.781Z" },
|
|
449
|
+
{ url = "https://files.pythonhosted.org/packages/fa/87/887f35a6fca9dde90cad08e0de0c89263a8e59b2d2ff904fd9fcd8025b6f/cryptography-46.0.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4", size = 4266221, upload-time = "2026-03-25T23:33:49.874Z" },
|
|
450
|
+
{ url = "https://files.pythonhosted.org/packages/aa/a8/0a90c4f0b0871e0e3d1ed126aed101328a8a57fd9fd17f00fb67e82a51ca/cryptography-46.0.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b", size = 4408952, upload-time = "2026-03-25T23:33:52.128Z" },
|
|
451
|
+
{ url = "https://files.pythonhosted.org/packages/16/0b/b239701eb946523e4e9f329336e4ff32b1247e109cbab32d1a7b61da8ed7/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707", size = 4270141, upload-time = "2026-03-25T23:33:54.11Z" },
|
|
452
|
+
{ url = "https://files.pythonhosted.org/packages/0f/a8/976acdd4f0f30df7b25605f4b9d3d89295351665c2091d18224f7ad5cdbf/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361", size = 4904178, upload-time = "2026-03-25T23:33:55.725Z" },
|
|
453
|
+
{ url = "https://files.pythonhosted.org/packages/b1/1b/bf0e01a88efd0e59679b69f42d4afd5bced8700bb5e80617b2d63a3741af/cryptography-46.0.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b", size = 4441812, upload-time = "2026-03-25T23:33:57.364Z" },
|
|
454
|
+
{ url = "https://files.pythonhosted.org/packages/bb/8b/11df86de2ea389c65aa1806f331cae145f2ed18011f30234cc10ca253de8/cryptography-46.0.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca", size = 3963923, upload-time = "2026-03-25T23:33:59.361Z" },
|
|
455
|
+
{ url = "https://files.pythonhosted.org/packages/91/e0/207fb177c3a9ef6a8108f234208c3e9e76a6aa8cf20d51932916bd43bda0/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013", size = 4269695, upload-time = "2026-03-25T23:34:00.909Z" },
|
|
456
|
+
{ url = "https://files.pythonhosted.org/packages/21/5e/19f3260ed1e95bced52ace7501fabcd266df67077eeb382b79c81729d2d3/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4", size = 4869785, upload-time = "2026-03-25T23:34:02.796Z" },
|
|
457
|
+
{ url = "https://files.pythonhosted.org/packages/10/38/cd7864d79aa1d92ef6f1a584281433419b955ad5a5ba8d1eb6c872165bcb/cryptography-46.0.6-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a", size = 4441404, upload-time = "2026-03-25T23:34:04.35Z" },
|
|
458
|
+
{ url = "https://files.pythonhosted.org/packages/09/0a/4fe7a8d25fed74419f91835cf5829ade6408fd1963c9eae9c4bce390ecbb/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d", size = 4397549, upload-time = "2026-03-25T23:34:06.342Z" },
|
|
459
|
+
{ url = "https://files.pythonhosted.org/packages/5f/a0/7d738944eac6513cd60a8da98b65951f4a3b279b93479a7e8926d9cd730b/cryptography-46.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736", size = 4651874, upload-time = "2026-03-25T23:34:07.916Z" },
|
|
460
|
+
{ url = "https://files.pythonhosted.org/packages/49/b3/dc27efd8dcc4bff583b3f01d4a3943cd8b5821777a58b3a6a5f054d61b79/cryptography-46.0.6-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8", size = 4270529, upload-time = "2026-03-25T23:34:15.019Z" },
|
|
461
|
+
{ url = "https://files.pythonhosted.org/packages/e6/05/e8d0e6eb4f0d83365b3cb0e00eb3c484f7348db0266652ccd84632a3d58d/cryptography-46.0.6-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77", size = 4414827, upload-time = "2026-03-25T23:34:16.604Z" },
|
|
462
|
+
{ url = "https://files.pythonhosted.org/packages/2f/97/daba0f5d2dc6d855e2dcb70733c812558a7977a55dd4a6722756628c44d1/cryptography-46.0.6-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290", size = 4271265, upload-time = "2026-03-25T23:34:18.586Z" },
|
|
463
|
+
{ url = "https://files.pythonhosted.org/packages/89/06/fe1fce39a37ac452e58d04b43b0855261dac320a2ebf8f5260dd55b201a9/cryptography-46.0.6-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410", size = 4916800, upload-time = "2026-03-25T23:34:20.561Z" },
|
|
464
|
+
{ url = "https://files.pythonhosted.org/packages/ff/8a/b14f3101fe9c3592603339eb5d94046c3ce5f7fc76d6512a2d40efd9724e/cryptography-46.0.6-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d", size = 4448771, upload-time = "2026-03-25T23:34:22.406Z" },
|
|
465
|
+
{ url = "https://files.pythonhosted.org/packages/01/b3/0796998056a66d1973fd52ee89dc1bb3b6581960a91ad4ac705f182d398f/cryptography-46.0.6-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70", size = 3978333, upload-time = "2026-03-25T23:34:24.281Z" },
|
|
466
|
+
{ url = "https://files.pythonhosted.org/packages/c5/3d/db200af5a4ffd08918cd55c08399dc6c9c50b0bc72c00a3246e099d3a849/cryptography-46.0.6-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d", size = 4271069, upload-time = "2026-03-25T23:34:25.895Z" },
|
|
467
|
+
{ url = "https://files.pythonhosted.org/packages/d7/18/61acfd5b414309d74ee838be321c636fe71815436f53c9f0334bf19064fa/cryptography-46.0.6-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa", size = 4878358, upload-time = "2026-03-25T23:34:27.67Z" },
|
|
468
|
+
{ url = "https://files.pythonhosted.org/packages/8b/65/5bf43286d566f8171917cae23ac6add941654ccf085d739195a4eacf1674/cryptography-46.0.6-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58", size = 4448061, upload-time = "2026-03-25T23:34:29.375Z" },
|
|
469
|
+
{ url = "https://files.pythonhosted.org/packages/e0/25/7e49c0fa7205cf3597e525d156a6bce5b5c9de1fd7e8cb01120e459f205a/cryptography-46.0.6-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb", size = 4399103, upload-time = "2026-03-25T23:34:32.036Z" },
|
|
470
|
+
{ url = "https://files.pythonhosted.org/packages/44/46/466269e833f1c4718d6cd496ffe20c56c9c8d013486ff66b4f69c302a68d/cryptography-46.0.6-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72", size = 4659255, upload-time = "2026-03-25T23:34:33.679Z" },
|
|
471
|
+
{ url = "https://files.pythonhosted.org/packages/bc/1f/4c926f50df7749f000f20eede0c896769509895e2648db5da0ed55db711d/cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a3e84d5ec9ba01f8fd03802b2147ba77f0c8f2617b2aff254cedd551844209c8", size = 4218227, upload-time = "2026-03-25T23:34:40.871Z" },
|
|
472
|
+
{ url = "https://files.pythonhosted.org/packages/c6/65/707be3ffbd5f786028665c3223e86e11c4cda86023adbc56bd72b1b6bab5/cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:12f0fa16cc247b13c43d56d7b35287ff1569b5b1f4c5e87e92cc4fcc00cd10c0", size = 4381399, upload-time = "2026-03-25T23:34:42.609Z" },
|
|
473
|
+
{ url = "https://files.pythonhosted.org/packages/f3/6d/73557ed0ef7d73d04d9aba745d2c8e95218213687ee5e76b7d236a5030fc/cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:50575a76e2951fe7dbd1f56d181f8c5ceeeb075e9ff88e7ad997d2f42af06e7b", size = 4217595, upload-time = "2026-03-25T23:34:44.205Z" },
|
|
474
|
+
{ url = "https://files.pythonhosted.org/packages/9e/c5/e1594c4eec66a567c3ac4400008108a415808be2ce13dcb9a9045c92f1a0/cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:90e5f0a7b3be5f40c3a0a0eafb32c681d8d2c181fc2a1bdabe9b3f611d9f6b1a", size = 4380912, upload-time = "2026-03-25T23:34:46.328Z" },
|
|
475
475
|
]
|
|
476
476
|
|
|
477
477
|
[[package]]
|
|
@@ -988,11 +988,11 @@ wheels = [
|
|
|
988
988
|
|
|
989
989
|
[[package]]
|
|
990
990
|
name = "pygments"
|
|
991
|
-
version = "2.
|
|
991
|
+
version = "2.20.0"
|
|
992
992
|
source = { registry = "https://pypi.org/simple" }
|
|
993
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
993
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
|
994
994
|
wheels = [
|
|
995
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
995
|
+
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
996
996
|
]
|
|
997
997
|
|
|
998
998
|
[[package]]
|
|
@@ -1214,7 +1214,7 @@ wheels = [
|
|
|
1214
1214
|
|
|
1215
1215
|
[[package]]
|
|
1216
1216
|
name = "requests"
|
|
1217
|
-
version = "2.
|
|
1217
|
+
version = "2.33.0"
|
|
1218
1218
|
source = { registry = "https://pypi.org/simple" }
|
|
1219
1219
|
dependencies = [
|
|
1220
1220
|
{ name = "certifi" },
|
|
@@ -1222,9 +1222,9 @@ dependencies = [
|
|
|
1222
1222
|
{ name = "idna" },
|
|
1223
1223
|
{ name = "urllib3" },
|
|
1224
1224
|
]
|
|
1225
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1225
|
+
sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" }
|
|
1226
1226
|
wheels = [
|
|
1227
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1227
|
+
{ url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" },
|
|
1228
1228
|
]
|
|
1229
1229
|
|
|
1230
1230
|
[[package]]
|
|
@@ -1310,7 +1310,7 @@ wheels = [
|
|
|
1310
1310
|
|
|
1311
1311
|
[[package]]
|
|
1312
1312
|
name = "span-panel-api"
|
|
1313
|
-
version = "2.4.
|
|
1313
|
+
version = "2.4.2"
|
|
1314
1314
|
source = { editable = "." }
|
|
1315
1315
|
dependencies = [
|
|
1316
1316
|
{ name = "httpx" },
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""Shared HTTP helpers for SPAN Panel bootstrap REST calls."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from collections.abc import AsyncIterator
|
|
6
|
-
from contextlib import asynccontextmanager
|
|
7
|
-
|
|
8
|
-
import httpx
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def _build_url(host: str, port: int, path: str) -> str:
|
|
12
|
-
"""Build an HTTP URL, omitting the port when it is the default (80)."""
|
|
13
|
-
if port == 80:
|
|
14
|
-
return f"http://{host}{path}"
|
|
15
|
-
return f"http://{host}:{port}{path}"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@asynccontextmanager
|
|
19
|
-
async def _get_client(
|
|
20
|
-
httpx_client: httpx.AsyncClient | None,
|
|
21
|
-
timeout: float,
|
|
22
|
-
) -> AsyncIterator[httpx.AsyncClient]:
|
|
23
|
-
if httpx_client is not None:
|
|
24
|
-
yield httpx_client
|
|
25
|
-
return
|
|
26
|
-
async with httpx.AsyncClient(timeout=timeout) as client:
|
|
27
|
-
yield client
|
|
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
|
|
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
|
{span_panel_api-2.4.1 → span_panel_api-2.4.2}/tests/simulation_fixtures/circuits.response.txt
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
|