span-panel-api 2.4.0__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.
Files changed (81) hide show
  1. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/workflows/ci.yml +6 -7
  2. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/workflows/dependabot-auto-approve.yml +1 -1
  3. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/workflows/dependabot-auto-merge.yml +1 -1
  4. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/workflows/release.yml +2 -2
  5. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/CHANGELOG.md +14 -0
  6. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/PKG-INFO +3 -5
  7. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/README.md +0 -3
  8. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/pyproject.toml +4 -2
  9. span_panel_api-2.4.2/src/span_panel_api/_http.py +66 -0
  10. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/conftest.py +9 -0
  11. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_auth_and_homie_helpers.py +5 -2
  12. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_detection_auth.py +15 -3
  13. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/uv.lock +60 -42
  14. span_panel_api-2.4.0/src/span_panel_api/_http.py +0 -27
  15. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.codefactor +0 -0
  16. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.codefactor.yml +0 -0
  17. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.deps-installed +0 -0
  18. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  19. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  20. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.github/dependabot.yml +0 -0
  21. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.gitignore +0 -0
  22. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.markdownlint-cli2.jsonc +0 -0
  23. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.markdownlint.json +0 -0
  24. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.pre-commit-config.yaml +0 -0
  25. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.prettierrc.json +0 -0
  26. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.vscode/extensions.json +0 -0
  27. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/.vscode/tasks.json +0 -0
  28. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/DEVELOPMENT.md +0 -0
  29. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/LICENSE +0 -0
  30. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/SECURITY.md +0 -0
  31. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/conftest.py +0 -0
  32. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/coverage_output.log +0 -0
  33. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/debug_unmapped.py +0 -0
  34. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/developer_attribute_readme.md +0 -0
  35. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/openapi.json +0 -0
  36. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/pytest.ini +0 -0
  37. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/pytest_output.log +0 -0
  38. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/scripts/__init__.py +0 -0
  39. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/scripts/coverage.py +0 -0
  40. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/scripts/format.sh +0 -0
  41. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/scripts/format_markdown.py +0 -0
  42. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/scripts/test_live_auth.py +0 -0
  43. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/setup-hooks.sh +0 -0
  44. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/__init__.py +0 -0
  45. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/auth.py +0 -0
  46. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/const.py +0 -0
  47. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/detection.py +0 -0
  48. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/exceptions.py +0 -0
  49. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/factory.py +0 -0
  50. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/models.py +0 -0
  51. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/__init__.py +0 -0
  52. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/async_client.py +0 -0
  53. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/client.py +0 -0
  54. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/connection.py +0 -0
  55. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/const.py +0 -0
  56. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/field_metadata.py +0 -0
  57. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/homie.py +0 -0
  58. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/mqtt/models.py +0 -0
  59. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/phase_validation.py +0 -0
  60. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/protocol.py +0 -0
  61. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/src/span_panel_api/py.typed +0 -0
  62. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_32_circuit.yaml +0 -0
  63. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_40_circuit_with_battery.yaml +0 -0
  64. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/configs/simulation_config_8_tab_workshop.yaml +0 -0
  65. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/v2/README.md +0 -0
  66. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/v2/homie_schema.json +0 -0
  67. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/fixtures/v2/status.json +0 -0
  68. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/simulation_fixtures/circuits.response.txt +0 -0
  69. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/simulation_fixtures/panel.response.txt +0 -0
  70. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/simulation_fixtures/soe.response.txt +0 -0
  71. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/simulation_fixtures/status.response.txt +0 -0
  72. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_async_mqtt_client.py +0 -0
  73. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_field_metadata.py +0 -0
  74. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_mqtt_bridge.py +0 -0
  75. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_mqtt_connect_flow.py +0 -0
  76. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_mqtt_debounce.py +0 -0
  77. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_mqtt_homie.py +0 -0
  78. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_phase_validation_configs.py +0 -0
  79. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_phase_validation_errors.py +0 -0
  80. {span_panel_api-2.4.0 → span_panel_api-2.4.2}/tests/test_protocol_conformance.py +0 -0
  81. {span_panel_api-2.4.0 → 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.13", "3.14"]
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@v5
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.13"
52
+ python-version: "3.14"
54
53
 
55
54
  - name: Install uv
56
- uses: astral-sh/setup-uv@v5
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.13"
81
+ python-version: "3.14"
83
82
 
84
83
  - name: Install uv
85
- uses: astral-sh/setup-uv@v5
84
+ uses: astral-sh/setup-uv@v7
86
85
  with:
87
86
  enable-cache: true
88
87
 
@@ -15,7 +15,7 @@ jobs:
15
15
  steps:
16
16
  - name: Dependabot metadata
17
17
  id: metadata
18
- uses: dependabot/fetch-metadata@v2.5.0
18
+ uses: dependabot/fetch-metadata@v3.0.0
19
19
  with:
20
20
  github-token: "${{ secrets.GITHUB_TOKEN }}"
21
21
 
@@ -15,7 +15,7 @@ jobs:
15
15
  steps:
16
16
  - name: Dependabot metadata
17
17
  id: metadata
18
- uses: dependabot/fetch-metadata@v2.5.0
18
+ uses: dependabot/fetch-metadata@v3.0.0
19
19
  with:
20
20
  github-token: "${{ secrets.GITHUB_TOKEN }}"
21
21
 
@@ -18,10 +18,10 @@ jobs:
18
18
  - name: Set up Python
19
19
  uses: actions/setup-python@v6
20
20
  with:
21
- python-version: "3.13"
21
+ python-version: "3.14"
22
22
 
23
23
  - name: Install uv
24
- uses: astral-sh/setup-uv@v5
24
+ uses: astral-sh/setup-uv@v7
25
25
  with:
26
26
  enable-cache: true
27
27
 
@@ -4,6 +4,20 @@ 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
+
14
+ ## [2.4.1] - 03/2026
15
+
16
+ ### Fixed
17
+
18
+ - **Added `license = "MIT"` to package metadata** — the `pyproject.toml` was missing the license field, causing license audit failures in downstream projects (HA core hassfest).
19
+ - **Loosened httpx version constraint** — changed from `>=0.28.1,<0.29.0` to `>=0.28.1` to satisfy HA core hassfest version restriction checks.
20
+
7
21
  ## [2.4.0] - 03/2026
8
22
 
9
23
  ### Added
@@ -1,13 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: span-panel-api
3
- Version: 2.4.0
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
7
7
  Author: SpanPanel
8
+ License-Expression: MIT
8
9
  License-File: LICENSE
9
10
  Requires-Python: <4.0,>=3.10
10
- Requires-Dist: httpx<0.29.0,>=0.28.1
11
+ Requires-Dist: httpx>=0.28.1
11
12
  Requires-Dist: paho-mqtt<3.0.0,>=2.0.0
12
13
  Requires-Dist: pyyaml>=6.0.0
13
14
  Description-Content-Type: text/markdown
@@ -21,7 +22,6 @@ Description-Content-Type: text/markdown
21
22
  [![CI Status](https://img.shields.io/github/actions/workflow/status/SpanPanel/span-panel-api/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/SpanPanel/span-panel-api/actions/workflows/ci.yml)
22
23
 
23
24
  [![Code Quality](https://img.shields.io/codefactor/grade/github/SpanPanel/span-panel-api?style=flat-square)](https://www.codefactor.io/repository/github/spanpanel/span-panel-api)
24
- [![Security](https://img.shields.io/snyk/vulnerabilities/github/SpanPanel/span-panel-api?style=flat-square)](https://snyk.io/test/github/SpanPanel/span-panel-api)
25
25
 
26
26
  [![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&style=flat-square)](https://github.com/pre-commit/pre-commit)
27
27
  [![Linting: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=flat-square)](https://github.com/astral-sh/ruff)
@@ -50,8 +50,6 @@ pip install span-panel-api
50
50
 
51
51
  ## Architecture
52
52
 
53
- 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.
54
-
55
53
  ### Transport
56
54
 
57
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
  [![CI Status](https://img.shields.io/github/actions/workflow/status/SpanPanel/span-panel-api/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/SpanPanel/span-panel-api/actions/workflows/ci.yml)
8
8
 
9
9
  [![Code Quality](https://img.shields.io/codefactor/grade/github/SpanPanel/span-panel-api?style=flat-square)](https://www.codefactor.io/repository/github/spanpanel/span-panel-api)
10
- [![Security](https://img.shields.io/snyk/vulnerabilities/github/SpanPanel/span-panel-api?style=flat-square)](https://snyk.io/test/github/SpanPanel/span-panel-api)
11
10
 
12
11
  [![Pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&style=flat-square)](https://github.com/pre-commit/pre-commit)
13
12
  [![Linting: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=flat-square)](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
@@ -1,14 +1,16 @@
1
1
  [project]
2
2
  name = "span-panel-api"
3
- version = "2.4.0"
3
+ version = "2.4.2"
4
4
  description = "A client library for SPAN Panel API"
5
5
  authors = [
6
6
  {name = "SpanPanel"}
7
7
  ]
8
8
  readme = "README.md"
9
+ license = "MIT"
10
+ license-files = ["LICENSE"]
9
11
  requires-python = ">=3.10,<4.0"
10
12
  dependencies = [
11
- "httpx>=0.28.1,<0.29.0",
13
+ "httpx>=0.28.1",
12
14
  "paho-mqtt>=2.0.0,<3.0.0",
13
15
  "pyyaml>=6.0.0",
14
16
  ]
@@ -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 patch("span_panel_api._http.httpx.AsyncClient") as cls:
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 patch("span_panel_api._http.httpx.AsyncClient") as mock_cls:
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 patch("span_panel_api._http.httpx.AsyncClient") as mock_client_cls:
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 patch("span_panel_api._http.httpx.AsyncClient") as mock_client_cls:
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
 
@@ -130,31 +130,43 @@ sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8
130
130
  wheels = [
131
131
  { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" },
132
132
  { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" },
133
+ { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" },
134
+ { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" },
133
135
  { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" },
134
136
  { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" },
135
137
  { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" },
136
138
  { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" },
137
139
  { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" },
138
140
  { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" },
141
+ { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" },
142
+ { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" },
139
143
  { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" },
140
144
  { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" },
141
145
  { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" },
142
146
  { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" },
143
147
  { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
144
148
  { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
149
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
150
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
145
151
  { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
146
152
  { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
147
153
  { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
148
154
  { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
149
155
  { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
156
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
157
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
150
158
  { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
151
159
  { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
152
160
  { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
153
161
  { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
162
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
163
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
154
164
  { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
155
165
  { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
156
166
  { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
157
167
  { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
168
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
169
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
158
170
  { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
159
171
  { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
160
172
  { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
@@ -415,45 +427,51 @@ toml = [
415
427
 
416
428
  [[package]]
417
429
  name = "cryptography"
418
- version = "46.0.5"
430
+ version = "46.0.6"
419
431
  source = { registry = "https://pypi.org/simple" }
420
432
  dependencies = [
421
433
  { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
422
434
  { name = "typing-extensions", marker = "python_full_version < '3.11'" },
423
435
  ]
424
- sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" }
425
- wheels = [
426
- { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" },
427
- { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" },
428
- { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" },
429
- { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" },
430
- { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" },
431
- { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" },
432
- { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" },
433
- { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" },
434
- { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" },
435
- { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" },
436
- { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" },
437
- { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" },
438
- { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" },
439
- { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" },
440
- { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" },
441
- { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" },
442
- { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" },
443
- { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" },
444
- { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" },
445
- { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" },
446
- { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" },
447
- { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" },
448
- { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" },
449
- { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" },
450
- { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" },
451
- { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" },
452
- { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" },
453
- { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" },
454
- { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" },
455
- { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" },
456
- { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" },
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" },
457
475
  ]
458
476
 
459
477
  [[package]]
@@ -970,11 +988,11 @@ wheels = [
970
988
 
971
989
  [[package]]
972
990
  name = "pygments"
973
- version = "2.19.2"
991
+ version = "2.20.0"
974
992
  source = { registry = "https://pypi.org/simple" }
975
- sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
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" }
976
994
  wheels = [
977
- { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
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" },
978
996
  ]
979
997
 
980
998
  [[package]]
@@ -1196,7 +1214,7 @@ wheels = [
1196
1214
 
1197
1215
  [[package]]
1198
1216
  name = "requests"
1199
- version = "2.32.5"
1217
+ version = "2.33.0"
1200
1218
  source = { registry = "https://pypi.org/simple" }
1201
1219
  dependencies = [
1202
1220
  { name = "certifi" },
@@ -1204,9 +1222,9 @@ dependencies = [
1204
1222
  { name = "idna" },
1205
1223
  { name = "urllib3" },
1206
1224
  ]
1207
- sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
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" }
1208
1226
  wheels = [
1209
- { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
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" },
1210
1228
  ]
1211
1229
 
1212
1230
  [[package]]
@@ -1292,7 +1310,7 @@ wheels = [
1292
1310
 
1293
1311
  [[package]]
1294
1312
  name = "span-panel-api"
1295
- version = "2.4.0"
1313
+ version = "2.4.2"
1296
1314
  source = { editable = "." }
1297
1315
  dependencies = [
1298
1316
  { name = "httpx" },
@@ -1320,7 +1338,7 @@ dev = [
1320
1338
 
1321
1339
  [package.metadata]
1322
1340
  requires-dist = [
1323
- { name = "httpx", specifier = ">=0.28.1,<0.29.0" },
1341
+ { name = "httpx", specifier = ">=0.28.1" },
1324
1342
  { name = "paho-mqtt", specifier = ">=2.0.0,<3.0.0" },
1325
1343
  { name = "pyyaml", specifier = ">=6.0.0" },
1326
1344
  ]
@@ -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