lange-python 0.3.26__tar.gz → 0.3.28__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.
- {lange_python-0.3.26 → lange_python-0.3.28}/PKG-INFO +1 -1
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/distribution/_client.py +50 -2
- {lange_python-0.3.26 → lange_python-0.3.28}/pyproject.toml +1 -1
- {lange_python-0.3.26 → lange_python-0.3.28}/README.md +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/__main__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/_util/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/_util/_base_client.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/_util/_key_handling.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/_command.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/_discovery.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/_docker.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/_poetry.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/build/_types.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/_stats.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/audit/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/audit/_command.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/audit/_discovery.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/audit/_runner.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/code/audit/_types.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/distribution/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/cli/distribution/_command.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/distribution/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/distribution/_update_macos.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/distribution/_util.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/tunnel/__init__.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/tunnel/_client.py +0 -0
- {lange_python-0.3.26 → lange_python-0.3.28}/lange/tunnel/_util.py +0 -0
|
@@ -6,6 +6,8 @@ import mimetypes
|
|
|
6
6
|
import shutil
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any
|
|
9
|
+
from urllib.parse import quote
|
|
10
|
+
from uuid import UUID
|
|
9
11
|
|
|
10
12
|
import httpx
|
|
11
13
|
|
|
@@ -64,6 +66,9 @@ class DistributionClient(BaseLangeLabsClient):
|
|
|
64
66
|
raise ValueError("check your distribution name again. spaces are not allowed by design")
|
|
65
67
|
|
|
66
68
|
self.distribution_name = normalized_distribution_name
|
|
69
|
+
self.distribution_id: UUID | None = None
|
|
70
|
+
if self.api_key is not None:
|
|
71
|
+
self.distribution_id = self._resolve_distribution_id()
|
|
67
72
|
self._refresh_capabilities()
|
|
68
73
|
|
|
69
74
|
@property
|
|
@@ -109,6 +114,9 @@ class DistributionClient(BaseLangeLabsClient):
|
|
|
109
114
|
"""
|
|
110
115
|
super().reload(api_key=api_key)
|
|
111
116
|
self._last_error = None
|
|
117
|
+
self.distribution_id = (
|
|
118
|
+
self._resolve_distribution_id() if self.api_key is not None else None
|
|
119
|
+
)
|
|
112
120
|
|
|
113
121
|
if self.api_key is None:
|
|
114
122
|
self._last_update_result = None
|
|
@@ -210,13 +218,52 @@ class DistributionClient(BaseLangeLabsClient):
|
|
|
210
218
|
f"/versions/{version}/artifacts/{os_name}/download"
|
|
211
219
|
)
|
|
212
220
|
|
|
221
|
+
def _build_distribution_name_url(self) -> str:
|
|
222
|
+
"""
|
|
223
|
+
Build the authenticated distribution lookup endpoint URL.
|
|
224
|
+
|
|
225
|
+
:returns: Fully qualified distribution name lookup URL.
|
|
226
|
+
"""
|
|
227
|
+
encoded_name = quote(self.distribution_name, safe="")
|
|
228
|
+
return f"{self.host}/api/v1/distributions/names/{encoded_name}"
|
|
229
|
+
|
|
213
230
|
def _build_versions_url(self) -> str:
|
|
214
231
|
"""
|
|
215
232
|
Build the authenticated distribution versions endpoint URL.
|
|
216
233
|
|
|
217
234
|
:returns: Fully qualified versions collection URL.
|
|
235
|
+
:raises ValueError: If the authenticated distribution has not been resolved.
|
|
218
236
|
"""
|
|
219
|
-
|
|
237
|
+
if self.distribution_id is None:
|
|
238
|
+
raise ValueError("Distribution id is required for this operation.")
|
|
239
|
+
|
|
240
|
+
return f"{self.host}/api/v1/distributions/{self.distribution_id}/versions"
|
|
241
|
+
|
|
242
|
+
def _resolve_distribution_id(self) -> UUID:
|
|
243
|
+
"""
|
|
244
|
+
Resolve the configured distribution name into its authenticated distribution id.
|
|
245
|
+
|
|
246
|
+
:returns: Distribution UUID returned by the API service.
|
|
247
|
+
:raises httpx.HTTPError: If the lookup request fails.
|
|
248
|
+
:raises ValueError: If the response does not include a valid distribution id.
|
|
249
|
+
"""
|
|
250
|
+
client = httpx.Client(timeout=self.timeout)
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
response = client.get(
|
|
254
|
+
self._build_distribution_name_url(),
|
|
255
|
+
headers=self._build_connection_headers(),
|
|
256
|
+
)
|
|
257
|
+
response.raise_for_status()
|
|
258
|
+
payload = response.json()
|
|
259
|
+
finally:
|
|
260
|
+
client.close()
|
|
261
|
+
|
|
262
|
+
distribution_id = str(payload.get("id", "")).strip()
|
|
263
|
+
if not distribution_id:
|
|
264
|
+
raise ValueError("Distribution lookup response did not include an id.")
|
|
265
|
+
|
|
266
|
+
return UUID(distribution_id)
|
|
220
267
|
|
|
221
268
|
def _get_newest_version_artifact(self, os_name: str) -> tuple[str, dict[str, Any]] | None:
|
|
222
269
|
"""
|
|
@@ -499,6 +546,7 @@ class DistributionClient(BaseLangeLabsClient):
|
|
|
499
546
|
if not artifact_path.is_file():
|
|
500
547
|
raise ValueError("Artifact path must point to a file.")
|
|
501
548
|
|
|
549
|
+
headers = self._build_connection_headers()
|
|
502
550
|
content_type = mimetypes.guess_type(artifact_path.name)[0] or "application/octet-stream"
|
|
503
551
|
file_field_name = f"{normalized_os_name}File"
|
|
504
552
|
|
|
@@ -508,7 +556,7 @@ class DistributionClient(BaseLangeLabsClient):
|
|
|
508
556
|
with artifact_path.open("rb") as artifact_file:
|
|
509
557
|
response = client.post(
|
|
510
558
|
self._build_versions_url(),
|
|
511
|
-
headers=
|
|
559
|
+
headers=headers,
|
|
512
560
|
data={"version": normalized_version_name},
|
|
513
561
|
files={
|
|
514
562
|
file_field_name: (
|
|
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
|