Gregory-L commited on
Commit
74da4f7
·
verified ·
1 Parent(s): 96126d5

v1.0.4 — close the limitations 1.0.3 listed, and correct the ones it overstated

Browse files

Correction first: 1.0.3 called every write endpoint and SSE-under-a-real-producer untested. True of its probes, not of the project — the suite already covers both (test_runs_sse.py and a dozen test_coach_*_api.py), and it passed on the refreshed lock. A new module written for those endpoints was deleted once that was checked, rather than shipped as duplicate coverage.

Real gaps closed: the Gradio surface is tested (Blocks tree built, rooms and version parity checked, launched for real under gradio 6.27) and had no coverage at all; the Hub tests no longer trust the environment for the missing-dependency path (they inverted silently once the ui extra brought huggingface-hub in); httpx2 joins the dev group so starlette 1.6 stops deprecating TestClient.

Training path verified under the refreshed lock: dream corpus tokenized, SFT run on CPU (loss 3.938, 512 tokens), a real 22 MB LoRA checkpoint written. 767 pass with the ml extra. ROCm/MI300X, multi-GPU, vLLM serving, full-length runs and the imprint->serve tail remain untested and are named as such.

docs/CHANGELOG.md CHANGED
@@ -6,6 +6,65 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
 
7
  ## [Unreleased]
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  ## [1.0.3] — 2026-09-15
10
 
11
  ### Changed
 
6
 
7
  ## [Unreleased]
8
 
9
+ ## [1.0.4] — 2026-09-16
10
+
11
+ ### Added
12
+
13
+ - **The Gradio surface is tested.** `mindxtrain ui` had no coverage at all — gradio is an
14
+ optional extra, so a base install cannot import the module, and every release note listed the
15
+ UI as untested. `tests/test_ui_app_builds.py` constructs the whole Blocks tree (which
16
+ exercises every component definition in `ui/app.py`), checks the rooms the docs promise,
17
+ asserts the surface version matches the package, and confirms the PEP 562 lazy export
18
+ resolves. It skips cleanly where the extra is absent. The UI was also launched for real
19
+ under gradio 6.27.0 and served its page and config.
20
+
21
+ ### Fixed
22
+
23
+ - **The Hub tests asserted the missing-dependency path by trusting the environment.** They
24
+ passed on a bare install and inverted silently the moment the `ui` extra arrived, because
25
+ gradio depends on huggingface-hub — three tests failed the first time they met an
26
+ environment that had it. Absence is now *forced* (`sys.modules[name] = None` makes the
27
+ import raise), so the contract holds whatever is installed, and it is verified both ways.
28
+ Introduced in 1.0.2, where the note "tested for real rather than mocked" was true only of a
29
+ bare install.
30
+
31
+ ### Changed
32
+
33
+ - **`httpx2` added to the dev group.** starlette 1.6 deprecates driving its `TestClient` with
34
+ `httpx`; 24 test modules use `TestClient`, so the dependency moves rather than the tests.
35
+ The deprecation is gone; the two warnings that remain are upstream typer → click 9.0.
36
+
37
+ ### Notes — a correction to v1.0.3, and what is now verified
38
+
39
+ **v1.0.3 overstated its own limitations.** It listed "every write endpoint" and "SSE under a
40
+ real producer" as untested. That was true of the dependency-refresh *probes* run for that
41
+ release; it was **not** true of the project. The suite already covers the coach's write
42
+ endpoints — bench, compile, cost, eval/prompt, modelfile build and create, ollama start and
43
+ stop, boardroom, dojo, datasets, mei promote, classroom, autotune feedback, dcoach, chat
44
+ stream — and SSE under a real producer, in `tests/test_runs_sse.py` and a dozen
45
+ `test_coach_*_api.py` modules, including buffer replay on late subscribe, log-kind filtering,
46
+ ingest and cancel. All of it passed on the refreshed lock. A new test module was written for
47
+ those endpoints before that was checked; every endpoint turned out to be covered already and
48
+ the in-stream error contract already asserted, so it was deleted rather than added as
49
+ duplicate coverage.
50
+
51
+ **The training path is now verified under the refreshed lock** (torch 2.11.0, transformers
52
+ 5.8.0, trl 1.3.0, peft 0.19.1, alongside starlette 1.6.0 and the pydantic downgrade). The
53
+ dream-corpus loop was run end to end on CPU — corpus read, tokenized, SFT executed
54
+ (loss 3.938, mean_token_accuracy 0.370, 512 tokens), and a real 22 MB LoRA checkpoint written
55
+ with `adapter_model.safetensors`, `adapter_config.json`, tokenizer and chat template. With the
56
+ ml extra installed the suite is **767 passed** (the two tokenizer tests stop skipping).
57
+
58
+ **Still not tested, and not claimed:**
59
+
60
+ - **MI300X / ROCm, multi-GPU, and vLLM serving.** No such hardware here; the CPU lane is what
61
+ was exercised.
62
+ - **A full-length run.** The shipped 32-sample smoke recipe projects ~70 minutes on this
63
+ shared box (8.7 min/step at 50% CPU), so the loop was closed with a reduced variant — 4
64
+ samples at seq 128, the same code path, fewer tokens. Multi-hour and multi-day behaviour is
65
+ unchanged and unverified here.
66
+ - **The `imprint` → `serve --to ollama` tail**, which needs a running daemon.
67
+
68
  ## [1.0.3] — 2026-09-15
69
 
70
  ### Changed
docs/NAV.md CHANGED
@@ -164,8 +164,9 @@ Target metrics + framework comparison.
164
  - [What's not measured (yet)](benchmarks.md#whats-not-measured-yet)
165
 
166
  ### [CHANGELOG](CHANGELOG.md)
167
- Version history (current: v1.0.3).
168
  - [[Unreleased]](CHANGELOG.md#unreleased)
 
169
  - [[1.0.3] — 2026-09-15](CHANGELOG.md#103--2026-09-15)
170
  - [[1.0.2] — 2026-09-15](CHANGELOG.md#102--2026-09-15)
171
  - [[1.0.1] — 2026-09-15](CHANGELOG.md#101--2026-09-15)
 
164
  - [What's not measured (yet)](benchmarks.md#whats-not-measured-yet)
165
 
166
  ### [CHANGELOG](CHANGELOG.md)
167
+ Version history (current: v1.0.4).
168
  - [[Unreleased]](CHANGELOG.md#unreleased)
169
+ - [[1.0.4] — 2026-09-16](CHANGELOG.md#104--2026-09-16)
170
  - [[1.0.3] — 2026-09-15](CHANGELOG.md#103--2026-09-15)
171
  - [[1.0.2] — 2026-09-15](CHANGELOG.md#102--2026-09-15)
172
  - [[1.0.1] — 2026-09-15](CHANGELOG.md#101--2026-09-15)
mindxtrain/__init__.py CHANGED
@@ -16,4 +16,4 @@ Layout per mindXtrain2.md §Part 4 "Repository layout":
16
  budget/ psutil-derived ResourceBudget (carry-over from aGLM)
17
  """
18
 
19
- __version__ = "1.0.3"
 
16
  budget/ psutil-derived ResourceBudget (carry-over from aGLM)
17
  """
18
 
19
+ __version__ = "1.0.4"
mindxtrain/ui/app.py CHANGED
@@ -36,7 +36,7 @@ import gradio as gr
36
  from .metrics import RunMetrics, parse_log # noqa: F401 (parse_log re-exported for tests)
37
  from .theme import CSS, theme
38
 
39
- VERSION = "1.0.3"
40
  HOME = Path(os.environ.get("MINDXTRAIN_HOME") or Path(__file__).resolve().parents[2])
41
  RECIPES = HOME / "mindxtrain" / "train" / "recipes"
42
  TIERS = ["Basic", "Advanced", "Scientific"]
 
36
  from .metrics import RunMetrics, parse_log # noqa: F401 (parse_log re-exported for tests)
37
  from .theme import CSS, theme
38
 
39
+ VERSION = "1.0.4"
40
  HOME = Path(os.environ.get("MINDXTRAIN_HOME") or Path(__file__).resolve().parents[2])
41
  RECIPES = HOME / "mindxtrain" / "train" / "recipes"
42
  TIERS = ["Basic", "Advanced", "Scientific"]
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
  [project]
2
  name = "mindxtrain"
3
- version = "1.0.3"
4
  description = "Production training framework for fine-tuning open-weight LLMs on AMD MI300X and serving them through an OpenAI-compatible API."
5
  requires-python = ">=3.12,<3.13"
6
  license = { text = "Apache-2.0" }
@@ -74,6 +74,9 @@ packages = ["mindxtrain"]
74
  dev = [
75
  "pytest>=8.3",
76
  "pytest-asyncio>=0.24",
 
 
 
77
  "ruff>=0.7",
78
  "mypy>=1.13",
79
  "types-PyYAML>=6.0",
 
1
  [project]
2
  name = "mindxtrain"
3
+ version = "1.0.4"
4
  description = "Production training framework for fine-tuning open-weight LLMs on AMD MI300X and serving them through an OpenAI-compatible API."
5
  requires-python = ">=3.12,<3.13"
6
  license = { text = "Apache-2.0" }
 
74
  dev = [
75
  "pytest>=8.3",
76
  "pytest-asyncio>=0.24",
77
+ # starlette 1.6 deprecates driving its TestClient with httpx and asks for httpx2.
78
+ # 24 test modules use TestClient, so the dependency moves rather than the tests.
79
+ "httpx2>=2.13",
80
  "ruff>=0.7",
81
  "mypy>=1.13",
82
  "types-PyYAML>=6.0",
tests/test_hf_extension.py CHANGED
@@ -1,12 +1,15 @@
1
  """Units for the Hugging Face extension and its CLI surface.
2
 
3
- `huggingface_hub` is an optional extra and is NOT installed in this environment, which makes
4
- the missing-dependency path a real test rather than a mocked one. Everything else runs against
5
- stubs: no token, no network, no Hub.
 
 
6
  """
7
 
8
  from __future__ import annotations
9
 
 
10
  from typing import Any
11
 
12
  import pytest
@@ -25,6 +28,16 @@ def no_ambient_token(monkeypatch: pytest.MonkeyPatch) -> None:
25
  monkeypatch.delenv(name, raising=False)
26
 
27
 
 
 
 
 
 
 
 
 
 
 
28
  # --- token resolution --------------------------------------------------------------------
29
 
30
 
@@ -47,15 +60,15 @@ def test_no_token_anywhere_is_none() -> None:
47
  # --- the optional dependency is reported, never raised -----------------------------------
48
 
49
 
50
- def test_missing_dependency_is_a_result_not_an_exception() -> None:
51
- """`huggingface_hub` is genuinely absent here — this asserts the real path."""
52
  api, err = ext._api("a-token")
53
  assert api is None
54
  assert err["ok"] is False
55
  assert "--extra hf" in err["reason"] # the extra that actually installs it
56
 
57
 
58
- def test_pull_base_reports_the_missing_dependency() -> None:
59
  out = ext.pull_base("HuggingFaceTB/SmolLM2-135M")
60
  assert out["ok"] is False and "huggingface_hub" in out["reason"]
61
 
@@ -129,7 +142,7 @@ def test_every_hf_verb_is_reachable() -> None:
129
  assert verb in result.stdout
130
 
131
 
132
- def test_failure_exits_nonzero_so_a_script_can_branch() -> None:
133
  """The ascent loop warms a base and checks $? — an `ok:false` that exits 0 would be a trap."""
134
  result = runner.invoke(app, ["hf", "whoami"])
135
  assert result.exit_code == 1
 
1
  """Units for the Hugging Face extension and its CLI surface.
2
 
3
+ `huggingface_hub` is an optional extra, so the missing-dependency path is asserted by FORCING
4
+ its absence (`sys.modules[name] = None` makes `import` raise) rather than by trusting the
5
+ ambient environment. It was trusted once: these tests passed on a bare install and inverted
6
+ silently the moment the `ui` extra arrived, because gradio depends on huggingface-hub.
7
+ Everything else runs against stubs: no token, no network, no Hub.
8
  """
9
 
10
  from __future__ import annotations
11
 
12
+ import sys
13
  from typing import Any
14
 
15
  import pytest
 
28
  monkeypatch.delenv(name, raising=False)
29
 
30
 
31
+ @pytest.fixture
32
+ def hub_absent(monkeypatch: pytest.MonkeyPatch) -> None:
33
+ """Force `import huggingface_hub` to fail, whatever is installed.
34
+
35
+ A `None` entry in `sys.modules` makes the import raise ImportError, so the
36
+ not-installed contract is testable on a machine where the extra IS installed.
37
+ """
38
+ monkeypatch.setitem(sys.modules, "huggingface_hub", None)
39
+
40
+
41
  # --- token resolution --------------------------------------------------------------------
42
 
43
 
 
60
  # --- the optional dependency is reported, never raised -----------------------------------
61
 
62
 
63
+ def test_missing_dependency_is_a_result_not_an_exception(hub_absent: None) -> None:
64
+ """A missing optional extra is reported as a result; it must never raise at the caller."""
65
  api, err = ext._api("a-token")
66
  assert api is None
67
  assert err["ok"] is False
68
  assert "--extra hf" in err["reason"] # the extra that actually installs it
69
 
70
 
71
+ def test_pull_base_reports_the_missing_dependency(hub_absent: None) -> None:
72
  out = ext.pull_base("HuggingFaceTB/SmolLM2-135M")
73
  assert out["ok"] is False and "huggingface_hub" in out["reason"]
74
 
 
142
  assert verb in result.stdout
143
 
144
 
145
+ def test_failure_exits_nonzero_so_a_script_can_branch(hub_absent: None) -> None:
146
  """The ascent loop warms a base and checks $? — an `ok:false` that exits 0 would be a trap."""
147
  result = runner.invoke(app, ["hf", "whoami"])
148
  assert result.exit_code == 1
tests/test_ui_app_builds.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """The Gradio surface: does it actually build?
2
+
3
+ `mindxtrain ui` had no coverage at all — gradio is an optional extra, so a base install
4
+ cannot import the module, and every release note honestly listed the UI as untested. This
5
+ closes that: where the extra IS installed the whole Blocks tree is constructed, which
6
+ exercises every component definition in `ui/app.py`; where it is not, the test skips and the
7
+ lazy-import contract is checked instead.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import pytest
13
+
14
+ gradio = pytest.importorskip("gradio", reason="the `ui` extra is not installed")
15
+
16
+ from mindxtrain import __version__ # noqa: E402
17
+ from mindxtrain.ui import app as ui_app # noqa: E402
18
+
19
+
20
+ def test_the_ui_builds_without_launching() -> None:
21
+ """Constructing the Blocks tree is what catches a broken component definition."""
22
+ demo = ui_app.build()
23
+ assert isinstance(demo, gradio.Blocks)
24
+
25
+
26
+ def test_the_ui_reports_the_package_version() -> None:
27
+ """The surface must not drift from the package it ships with."""
28
+ assert ui_app.VERSION == __version__
29
+
30
+
31
+ def test_the_rooms_are_present() -> None:
32
+ """Basic / Advanced / Scientific and the named rooms the docs promise."""
33
+ demo = ui_app.build()
34
+ labels = {getattr(b, "label", None) for b in demo.blocks.values()}
35
+ for room in ("Console · talk to it", "Dataset", "Quantize · CPU", "Science · MEI + research"):
36
+ assert room in labels, f"missing room: {room}"
37
+
38
+
39
+ def test_build_is_reachable_from_the_package_root() -> None:
40
+ """The PEP 562 lazy export resolves once gradio is importable."""
41
+ import mindxtrain.ui as ui_pkg
42
+
43
+ assert callable(ui_pkg.build)
44
+ assert ui_pkg.VERSION == __version__
uv.lock CHANGED
@@ -1365,6 +1365,19 @@ wheels = [
1365
  { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
1366
  ]
1367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1368
  [[package]]
1369
  name = "httptools"
1370
  version = "0.7.1"
@@ -1404,6 +1417,32 @@ wheels = [
1404
  { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" },
1405
  ]
1406
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1407
  [[package]]
1408
  name = "huggingface-hub"
1409
  version = "1.31.0"
@@ -1431,11 +1470,11 @@ hf-xet = [
1431
 
1432
  [[package]]
1433
  name = "idna"
1434
- version = "3.13"
1435
  source = { registry = "https://pypi.org/simple" }
1436
- sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" }
1437
  wheels = [
1438
- { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" },
1439
  ]
1440
 
1441
  [[package]]
@@ -1971,7 +2010,7 @@ wheels = [
1971
 
1972
  [[package]]
1973
  name = "mindxtrain"
1974
- version = "1.0.3"
1975
  source = { editable = "." }
1976
  dependencies = [
1977
  { name = "blake3" },
@@ -2051,6 +2090,7 @@ ui = [
2051
 
2052
  [package.dev-dependencies]
2053
  dev = [
 
2054
  { name = "mypy" },
2055
  { name = "pytest" },
2056
  { name = "pytest-asyncio" },
@@ -2097,6 +2137,7 @@ provides-extras = ["ml", "eval", "data", "serve", "ui", "hf", "chain", "obs", "a
2097
 
2098
  [package.metadata.requires-dev]
2099
  dev = [
 
2100
  { name = "mypy", specifier = ">=1.13" },
2101
  { name = "pytest", specifier = ">=8.3" },
2102
  { name = "pytest-asyncio", specifier = ">=0.24" },
@@ -4255,6 +4296,15 @@ wheels = [
4255
  { url = "https://files.pythonhosted.org/packages/cf/38/d13f2bc31ce1071eaf519f16f0d2e51d92d08c01895992b05ebe801385d9/trl-1.3.0-py3-none-any.whl", hash = "sha256:55d5bed9983aa3e781c2d0af3b500ea78706247ae7c1852f76ea80417a3f7d5e", size = 721624, upload-time = "2026-04-26T15:28:25.872Z" },
4256
  ]
4257
 
 
 
 
 
 
 
 
 
 
4258
  [[package]]
4259
  name = "typepy"
4260
  version = "1.3.5"
 
1365
  { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
1366
  ]
1367
 
1368
+ [[package]]
1369
+ name = "httpcore2"
1370
+ version = "2.13.0"
1371
+ source = { registry = "https://pypi.org/simple" }
1372
+ dependencies = [
1373
+ { name = "h11", marker = "sys_platform != 'emscripten'" },
1374
+ { name = "truststore", marker = "sys_platform != 'emscripten'" },
1375
+ ]
1376
+ sdist = { url = "https://files.pythonhosted.org/packages/15/8c/e925b1c92018abb3a1863ce1549d76d2381e334d21d65d4ac8f65dabd78a/httpcore2-2.13.0.tar.gz", hash = "sha256:2adc8be4fb285fbcd6d894298db3b52c177e74b6674eda3a76bd36be3292a3db", size = 67740, upload-time = "2026-09-14T14:18:04.717Z" }
1377
+ wheels = [
1378
+ { url = "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl", hash = "sha256:35ae5be347aa40467b4a5dc032ac67ebb6d27189fc97e8cebcf99616f6a1bb9e", size = 83162, upload-time = "2026-09-14T14:18:02.529Z" },
1379
+ ]
1380
+
1381
  [[package]]
1382
  name = "httptools"
1383
  version = "0.7.1"
 
1417
  { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" },
1418
  ]
1419
 
1420
+ [[package]]
1421
+ name = "httpx2"
1422
+ version = "2.13.0"
1423
+ source = { registry = "https://pypi.org/simple" }
1424
+ dependencies = [
1425
+ { name = "anyio", marker = "sys_platform != 'emscripten'" },
1426
+ { name = "httpcore2", marker = "sys_platform != 'emscripten'" },
1427
+ { name = "httpx2-jsfetch", marker = "sys_platform == 'emscripten'" },
1428
+ { name = "idna" },
1429
+ { name = "truststore", marker = "sys_platform != 'emscripten'" },
1430
+ { name = "typing-extensions" },
1431
+ ]
1432
+ sdist = { url = "https://files.pythonhosted.org/packages/b9/a0/e9deef4654132857b5a5dbe4eddd0ac59c2814500e11f2f5044cd81103ee/httpx2-2.13.0.tar.gz", hash = "sha256:81bd07dc67a3701729ef1f777a3c00c915d4539604fdb5afd327f8682f6b7b44", size = 100290, upload-time = "2026-09-14T14:18:05.486Z" }
1433
+ wheels = [
1434
+ { url = "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl", hash = "sha256:fc12720cedf72faa26cca6b4ca394e05c894e7d7933fc45cafe767960804e49a", size = 95565, upload-time = "2026-09-14T14:18:03.553Z" },
1435
+ ]
1436
+
1437
+ [[package]]
1438
+ name = "httpx2-jsfetch"
1439
+ version = "1.0"
1440
+ source = { registry = "https://pypi.org/simple" }
1441
+ sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/0e5636363151a2a1795e0a77617168b9ca438e1748ec05fc9b5687f93d64/httpx2_jsfetch-1.0.tar.gz", hash = "sha256:70a0e3eabfef7cce5ad9c629f7d01ca05e418f586646f4ddf14782e4c1454c60", size = 6872, upload-time = "2026-08-07T00:13:07.492Z" }
1442
+ wheels = [
1443
+ { url = "https://files.pythonhosted.org/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32", size = 6382, upload-time = "2026-08-07T00:13:06.567Z" },
1444
+ ]
1445
+
1446
  [[package]]
1447
  name = "huggingface-hub"
1448
  version = "1.31.0"
 
1470
 
1471
  [[package]]
1472
  name = "idna"
1473
+ version = "3.19"
1474
  source = { registry = "https://pypi.org/simple" }
1475
+ sdist = { url = "https://files.pythonhosted.org/packages/5f/f7/abb373e5757eaec4b922b92f97ec8d6d7e057cf06778247604fbc4e7c3f3/idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15", size = 215237, upload-time = "2026-08-18T05:14:24.27Z" }
1476
  wheels = [
1477
+ { url = "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4", size = 68550, upload-time = "2026-08-18T05:14:22.343Z" },
1478
  ]
1479
 
1480
  [[package]]
 
2010
 
2011
  [[package]]
2012
  name = "mindxtrain"
2013
+ version = "1.0.4"
2014
  source = { editable = "." }
2015
  dependencies = [
2016
  { name = "blake3" },
 
2090
 
2091
  [package.dev-dependencies]
2092
  dev = [
2093
+ { name = "httpx2" },
2094
  { name = "mypy" },
2095
  { name = "pytest" },
2096
  { name = "pytest-asyncio" },
 
2137
 
2138
  [package.metadata.requires-dev]
2139
  dev = [
2140
+ { name = "httpx2", specifier = ">=2.13" },
2141
  { name = "mypy", specifier = ">=1.13" },
2142
  { name = "pytest", specifier = ">=8.3" },
2143
  { name = "pytest-asyncio", specifier = ">=0.24" },
 
4296
  { url = "https://files.pythonhosted.org/packages/cf/38/d13f2bc31ce1071eaf519f16f0d2e51d92d08c01895992b05ebe801385d9/trl-1.3.0-py3-none-any.whl", hash = "sha256:55d5bed9983aa3e781c2d0af3b500ea78706247ae7c1852f76ea80417a3f7d5e", size = 721624, upload-time = "2026-04-26T15:28:25.872Z" },
4297
  ]
4298
 
4299
+ [[package]]
4300
+ name = "truststore"
4301
+ version = "0.10.4"
4302
+ source = { registry = "https://pypi.org/simple" }
4303
+ sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" }
4304
+ wheels = [
4305
+ { url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" },
4306
+ ]
4307
+
4308
  [[package]]
4309
  name = "typepy"
4310
  version = "1.3.5"