driverclient 0.2.32__tar.gz → 0.2.33__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.
- {driverclient-0.2.32 → driverclient-0.2.33}/PKG-INFO +32 -1
- {driverclient-0.2.32 → driverclient-0.2.33}/README.md +31 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/pyproject.toml +1 -1
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/__init__.py +1 -1
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/config.py +7 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/core/http.py +68 -43
- {driverclient-0.2.32 → driverclient-0.2.33}/.gitignore +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/__main__.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/config.json +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/core/__init__.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/core/hardware.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/core/hwid.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/core/proc.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/events.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/main.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/__init__.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/automate.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/capture.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/diagnose.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/download.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/install.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/offline.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/resolve.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/ops/scan.py +0 -0
- {driverclient-0.2.32 → driverclient-0.2.33}/src/driverclient/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: driverclient
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.33
|
|
4
4
|
Summary: Driver Server client with an embeddable connector for config injection at runtime.
|
|
5
5
|
Project-URL: Homepage, https://example.com/driverclient
|
|
6
6
|
Author-email: Raja Sanaullah <sanaullah@99technologies.com>
|
|
@@ -203,3 +203,34 @@ class Panel:
|
|
|
203
203
|
|
|
204
204
|
- Python >= 3.10
|
|
205
205
|
- Windows target for the actual driver operations (`pnputil`, WMI, DISM).
|
|
206
|
+
|
|
207
|
+
## Building & releasing
|
|
208
|
+
|
|
209
|
+
The version lives in `pyproject.toml` **and** `src/driverclient/__init__.py` (kept
|
|
210
|
+
in lockstep by `bump_version.py`). System Assistant consumes this as a pip package
|
|
211
|
+
(`driverclient>=X` in its `requirements.txt`), so a code change ships by publishing
|
|
212
|
+
a **new version** — PyPI never overwrites an existing one.
|
|
213
|
+
|
|
214
|
+
### With uv (no extra tooling to install)
|
|
215
|
+
|
|
216
|
+
`uv build` runs the hatchling backend in an isolated env; `uvx` runs `twine`
|
|
217
|
+
ephemerally — neither needs a pre-installed `build`/`twine`.
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
cd client-package
|
|
221
|
+
uv build # → dist/driverclient-<version>-py3-none-any.whl (+ .tar.gz)
|
|
222
|
+
uvx twine upload dist/* # publish (uses ~/.pypirc)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Bump vs. no-bump — pick the right one
|
|
226
|
+
|
|
227
|
+
- **Version NOT set yet** → bump then build:
|
|
228
|
+
`make release VERSION_PART=patch|minor|major` (bump → build → smoke, no upload),
|
|
229
|
+
then `twine upload dist/*` (or `uvx twine upload dist/*`).
|
|
230
|
+
- **Version already set to the exact target** (e.g. someone set it by hand): build
|
|
231
|
+
**without** bumping — `uv build` (or `make clean && make build`), then upload.
|
|
232
|
+
Do **not** run `make release`/`bump_version.py` here — it would bump *past* the
|
|
233
|
+
intended version.
|
|
234
|
+
|
|
235
|
+
Full flow (TestPyPI dry-run, `.pypirc` token, post-publish verify): see
|
|
236
|
+
[RELEASING.md](RELEASING.md).
|
|
@@ -187,3 +187,34 @@ class Panel:
|
|
|
187
187
|
|
|
188
188
|
- Python >= 3.10
|
|
189
189
|
- Windows target for the actual driver operations (`pnputil`, WMI, DISM).
|
|
190
|
+
|
|
191
|
+
## Building & releasing
|
|
192
|
+
|
|
193
|
+
The version lives in `pyproject.toml` **and** `src/driverclient/__init__.py` (kept
|
|
194
|
+
in lockstep by `bump_version.py`). System Assistant consumes this as a pip package
|
|
195
|
+
(`driverclient>=X` in its `requirements.txt`), so a code change ships by publishing
|
|
196
|
+
a **new version** — PyPI never overwrites an existing one.
|
|
197
|
+
|
|
198
|
+
### With uv (no extra tooling to install)
|
|
199
|
+
|
|
200
|
+
`uv build` runs the hatchling backend in an isolated env; `uvx` runs `twine`
|
|
201
|
+
ephemerally — neither needs a pre-installed `build`/`twine`.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
cd client-package
|
|
205
|
+
uv build # → dist/driverclient-<version>-py3-none-any.whl (+ .tar.gz)
|
|
206
|
+
uvx twine upload dist/* # publish (uses ~/.pypirc)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Bump vs. no-bump — pick the right one
|
|
210
|
+
|
|
211
|
+
- **Version NOT set yet** → bump then build:
|
|
212
|
+
`make release VERSION_PART=patch|minor|major` (bump → build → smoke, no upload),
|
|
213
|
+
then `twine upload dist/*` (or `uvx twine upload dist/*`).
|
|
214
|
+
- **Version already set to the exact target** (e.g. someone set it by hand): build
|
|
215
|
+
**without** bumping — `uv build` (or `make clean && make build`), then upload.
|
|
216
|
+
Do **not** run `make release`/`bump_version.py` here — it would bump *past* the
|
|
217
|
+
intended version.
|
|
218
|
+
|
|
219
|
+
Full flow (TestPyPI dry-run, `.pypirc` token, post-publish verify): see
|
|
220
|
+
[RELEASING.md](RELEASING.md).
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "driverclient"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.33"
|
|
8
8
|
description = "Driver Server client with an embeddable connector for config injection at runtime."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -94,6 +94,13 @@ DEFAULTS: dict = {
|
|
|
94
94
|
# driver (e.g. graphics) is never re-downloaded, while missing/extension drivers
|
|
95
95
|
# still install. Set False to force-reinstall everything the server offers.
|
|
96
96
|
"skip_installed_drivers": True,
|
|
97
|
+
# When the repo doesn't yet have a file (it returns HTTP 503 + Retry-After
|
|
98
|
+
# while it repairs/pulls that file from upstream), how long the client waits
|
|
99
|
+
# for the file to become available before giving up on that download. Bounds
|
|
100
|
+
# the per-file wait so a genuinely-absent file can't hang the pass. Raise it
|
|
101
|
+
# on slow inter-site links where a large driver (Intel/AMD GPU) is still
|
|
102
|
+
# syncing down; the client re-polls honoring the server's Retry-After.
|
|
103
|
+
"download_repair_wait_seconds": 300,
|
|
97
104
|
# ── HTTP timeouts (seconds) ───────────────────────────────────────────
|
|
98
105
|
"timeout_tiny": 10,
|
|
99
106
|
"timeout_short": 30,
|
|
@@ -222,50 +222,75 @@ def http_download(url: str, dest: Path, sha256_expected: str, timeout: int | Non
|
|
|
222
222
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
223
223
|
|
|
224
224
|
tmp = dest.with_suffix(dest.suffix + ".part")
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
hasher = hashlib.sha256()
|
|
226
|
+
received = 0
|
|
227
|
+
# A missing file on the repo is NOT a hard failure: the server returns 503 +
|
|
228
|
+
# Retry-After while it repairs the file from upstream (files.py on-demand
|
|
229
|
+
# repair). Wait out the repair honoring Retry-After instead of the old
|
|
230
|
+
# fast 3-try give-up — otherwise a big driver still syncing down (e.g. the
|
|
231
|
+
# ~1.3 GB Intel GPU) fails to download and never installs/binds. Bounded by
|
|
232
|
+
# download_repair_wait_seconds so a genuinely-absent file can't hang forever.
|
|
233
|
+
repair_deadline = time.monotonic() + float(cfg.get("download_repair_wait_seconds", 300))
|
|
234
|
+
while True:
|
|
235
|
+
hasher = hashlib.sha256()
|
|
236
|
+
received = 0
|
|
237
|
+
try:
|
|
238
|
+
with urllib.request.urlopen(req, timeout=t) as resp:
|
|
239
|
+
encoding = resp.headers.get("Content-Encoding", "")
|
|
240
|
+
content_length = resp.headers.get("Content-Length")
|
|
241
|
+
total = int(content_length) if content_length else None
|
|
242
|
+
|
|
243
|
+
if encoding == "zstd":
|
|
244
|
+
try:
|
|
245
|
+
import zstandard as zstd
|
|
246
|
+
except ImportError:
|
|
247
|
+
print(
|
|
248
|
+
f" [ERROR] zstandard package required to decompress {dest.name} "
|
|
249
|
+
"— install it with: pip install zstandard"
|
|
250
|
+
)
|
|
251
|
+
return False
|
|
252
|
+
|
|
253
|
+
dctx = zstd.ZstdDecompressor()
|
|
254
|
+
with (
|
|
255
|
+
open(tmp, "wb") as fh,
|
|
256
|
+
dctx.stream_writer(fh, closefd=False) as writer,
|
|
257
|
+
):
|
|
258
|
+
while chunk := resp.read(_CHUNK):
|
|
259
|
+
writer.write(chunk)
|
|
260
|
+
received += len(chunk)
|
|
261
|
+
_print_progress(dest.name, received, total)
|
|
262
|
+
|
|
263
|
+
with open(tmp, "rb") as rfh:
|
|
264
|
+
while chunk := rfh.read(_CHUNK):
|
|
265
|
+
hasher.update(chunk)
|
|
266
|
+
else:
|
|
267
|
+
with open(tmp, "wb") as fh:
|
|
268
|
+
while chunk := resp.read(_CHUNK):
|
|
269
|
+
fh.write(chunk)
|
|
270
|
+
hasher.update(chunk)
|
|
271
|
+
received += len(chunk)
|
|
272
|
+
_print_progress(dest.name, received, total)
|
|
273
|
+
break # streamed OK — fall through to hash verification
|
|
274
|
+
except urllib.error.HTTPError as e:
|
|
275
|
+
if e.code == 503 and time.monotonic() < repair_deadline:
|
|
235
276
|
try:
|
|
236
|
-
|
|
237
|
-
except
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
with open(tmp, "rb") as rfh:
|
|
255
|
-
while chunk := rfh.read(_CHUNK):
|
|
256
|
-
hasher.update(chunk)
|
|
257
|
-
else:
|
|
258
|
-
with open(tmp, "wb") as fh:
|
|
259
|
-
while chunk := resp.read(_CHUNK):
|
|
260
|
-
fh.write(chunk)
|
|
261
|
-
hasher.update(chunk)
|
|
262
|
-
received += len(chunk)
|
|
263
|
-
_print_progress(dest.name, received, total)
|
|
264
|
-
|
|
265
|
-
except Exception as e:
|
|
266
|
-
tmp.unlink(missing_ok=True)
|
|
267
|
-
print(f" [ERROR] Download failed {dest.name}: {e}")
|
|
268
|
-
return False
|
|
277
|
+
wait = float(e.headers.get("Retry-After", "15"))
|
|
278
|
+
except (TypeError, ValueError):
|
|
279
|
+
wait = 15.0
|
|
280
|
+
tmp.unlink(missing_ok=True)
|
|
281
|
+
print(
|
|
282
|
+
f" [repair] {dest.name} not on repo yet (503) — repo is fetching it "
|
|
283
|
+
f"from upstream, waiting {wait:.0f}s then retrying…"
|
|
284
|
+
)
|
|
285
|
+
time.sleep(wait)
|
|
286
|
+
continue
|
|
287
|
+
tmp.unlink(missing_ok=True)
|
|
288
|
+
print(f" [ERROR] Download failed {dest.name}: HTTP {e.code}")
|
|
289
|
+
return False
|
|
290
|
+
except Exception as e:
|
|
291
|
+
tmp.unlink(missing_ok=True)
|
|
292
|
+
print(f" [ERROR] Download failed {dest.name}: {e}")
|
|
293
|
+
return False
|
|
269
294
|
|
|
270
295
|
actual = hasher.hexdigest()
|
|
271
296
|
if actual != sha256_expected:
|
|
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
|