eval-toolkit 0.40.0__tar.gz → 0.41.0__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.
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/CHANGELOG.md +78 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/PKG-INFO +1 -1
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/pyproject.toml +1 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/_version.py +1 -1
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/loaders.py +148 -12
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/public_api/snapshot.json +2 -2
- eval_toolkit-0.41.0/tests/test_croissant_e2e.py +145 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_loaders_coverage.py +11 -3
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/.gitignore +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/LICENSE +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/STYLE.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/archive/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/datasets/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/papers/data-integrity/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/papers/eval-ecosystem/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/papers/inference/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/research/papers/prompt-injection/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/docs/source/methodology/README.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/__init__.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/__main__.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/_deprecated.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/_parallel.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/analysis.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/artifacts.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/bootstrap.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/calibration.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/claims.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/config.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/docs.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/embeddings.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/evidence.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/harness.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/leakage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/manifest.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/metrics.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/operating_points.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/paths.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/plotting.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/protocols.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/provenance.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/py.typed +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/schemas/manifest.v1.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/schemas/manifest.v2.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/schemas/manifest.v3.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/schemas/results.v1.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/schemas/results_full.v1.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/seeds.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/splits.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/text_dedup.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/src/eval_toolkit/thresholds.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_bootstrap_distribution.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_confusion_matrix_grid.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_lift_ci.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_metric_bars.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_pareto_frontier.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_pr_curve.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_reliability_diagram.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_roc_curve.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_score_histograms.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_slice_metric_heatmap.png +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/benchmarks/__init__.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/benchmarks/test_kernel_benchmarks.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/conftest.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/bootstrap_ci/cases.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/data/dedup_holdout.jsonl +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/data/dedup_holdout_expected.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/data/dedup_holdout_provenance.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/docs/expected.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/docs/input.md +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/docs/metrics.json +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/golden/test_dedup_holdout_calibration.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/strategies.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_analysis.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_artifacts.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_block_bootstrap_on_folds.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_calibration_mc.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_edge_cases.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_golden.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_njobs.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_research_grounded.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_bootstrap_unit.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_binary_adapters.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_bootstrap_chain.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_determinism.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_optimization_failures.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_research_grounded.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_calibration_unit.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_claims.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_claims_coverage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_claims_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_cli.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_config.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_coverage_bootstrap.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_coverage_calibration.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_coverage_harness.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_coverage_metrics.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_coverage_plotting.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_dedup_split_leakage_chain.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_deprecations.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_docs_golden.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_docs_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_embeddings.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_evidence_validators.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_edge_cases.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_fault_injection.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_folded.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_internals.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_metric_options.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_parallelism.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_harness_smoke.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_import_boundaries.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_is_metric_defined_for_slice.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_leakage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_leakage_error_paths.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_leakage_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_loaders.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_loaders_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_logging.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_manifest.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_manifest_contamination_round_trip.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_manifest_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_manifest_validation.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_metrics_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_metrics_stratified_subsets.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_metrics_unit.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_misc_coverage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_numeric_edge_cases.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_operating_points.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_operating_points_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_parallel.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_paths.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_pipeline_e2e.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_plotting_edge.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_plotting_smoke.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_plotting_visual.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_protocol_conformance.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_provenance.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_public_api.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_recall_at_fpr.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_reference_equivalence.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_reproducibility_integration.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_schemas.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_seeds.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_splits.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_splits_leakage_integration.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_splits_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_text_dedup.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_text_dedup_coverage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_text_dedup_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_text_dedup_strategies.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_thresholds.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_thresholds_constant_score.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_thresholds_coverage.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_thresholds_props.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_thresholds_research_grounded.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_tokenization_leakage_check.py +0 -0
- {eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/test_v09_contracts.py +0 -0
|
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.41.0] — 2026-05-18 — Croissant end-to-end (closes #42, v1.0 Gate 4 MET)
|
|
11
|
+
|
|
12
|
+
Closes v1.0 readiness Gate 4 — "Croissant interop verified end-to-end."
|
|
13
|
+
`HFDatasetsLoader.describe()` now fetches per-file `sha256` hashes
|
|
14
|
+
from HF Hub and exposes them in `distribution[].sha256`. The
|
|
15
|
+
integration test (`tests/test_croissant_e2e.py`) downloads a real
|
|
16
|
+
parquet shard from `stanfordnlp/sst2` and verifies the bytes hash
|
|
17
|
+
bit-exactly to the value `describe()` reports.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`HFDatasetsLoader.describe()` Croissant + tree-API enrichment.**
|
|
22
|
+
When `fetch_remote_metadata=True` (default), the loader fetches from
|
|
23
|
+
two HF Hub endpoints:
|
|
24
|
+
- `/api/datasets/{repo}/croissant` — JSON-LD metadata (name,
|
|
25
|
+
description, license, citeAs, schema).
|
|
26
|
+
- `/api/datasets/{repo}/tree/refs%2Fconvert%2Fparquet?recursive=true`
|
|
27
|
+
— per-file `sha256` (read from each file's `lfs.oid` field — the
|
|
28
|
+
git-LFS content hash, equal to `sha256sum` of the raw bytes).
|
|
29
|
+
Caller-provided fields (`name=`, `cite_as=`, etc.) win over
|
|
30
|
+
Croissant fetches; Croissant fills only gaps. Network failures
|
|
31
|
+
degrade gracefully (warning emitted; sha256 empty as in pre-v0.41).
|
|
32
|
+
- **`fetch_remote_metadata: bool = True`** constructor field on
|
|
33
|
+
`HFDatasetsLoader`. Set `False` for offline / unit-test paths.
|
|
34
|
+
- **`tests/test_croissant_e2e.py`** — 5 integration tests against
|
|
35
|
+
live HF Hub:
|
|
36
|
+
1. `describe()` returns real `sha256:<64-hex>` per shard.
|
|
37
|
+
2. **Bit-exact verification**: download shard from `contentUrl`,
|
|
38
|
+
hash bytes, assert equals `describe()`'s sha256. This is the
|
|
39
|
+
literal v1.0 Gate 4 check.
|
|
40
|
+
3. Croissant metadata enriches name/citeAs/license/description.
|
|
41
|
+
4. Caller overrides win over remote.
|
|
42
|
+
5. `fetch_remote_metadata=False` preserves v0.40 behavior.
|
|
43
|
+
All pass against `stanfordnlp/sst2` (~3 MB train shard).
|
|
44
|
+
- **New `integration` pytest marker** for network-dependent tests.
|
|
45
|
+
Excluded from `make coverage` (PR CI); runs explicitly via
|
|
46
|
+
`pytest -m integration`.
|
|
47
|
+
|
|
48
|
+
### Why dual-sourced
|
|
49
|
+
|
|
50
|
+
HF Hub's Croissant emitter currently fills `distribution[].sha256`
|
|
51
|
+
with a placeholder URL pointing at MLCommons Croissant spec issue
|
|
52
|
+
[#80](https://github.com/mlcommons/croissant/issues/80) ("In
|
|
53
|
+
<Download>, check SHA256 or MD5"), which is **open**. The Croissant
|
|
54
|
+
spec doesn't yet require per-file checksums from emitters; HF Hub is
|
|
55
|
+
honest and punts the field. The authoritative hash IS available via
|
|
56
|
+
HF Hub's tree API: `lfs.oid` is precisely sha256 of the file content
|
|
57
|
+
(verified bit-exact via `sha256sum`).
|
|
58
|
+
|
|
59
|
+
When MLCommons #80 resolves and HF Hub starts populating Croissant
|
|
60
|
+
`sha256` with real values (which will equal the existing `lfs.oid`),
|
|
61
|
+
the loader's source switches in ~5 LOC. Same downstream contract.
|
|
62
|
+
|
|
63
|
+
### Documentation
|
|
64
|
+
|
|
65
|
+
- `docs/source/methodology/reproducibility.md` §"Croissant
|
|
66
|
+
interoperability": replaces v0.7-era "subset" framing with the
|
|
67
|
+
end-to-end-verified narrative + dual-source rationale.
|
|
68
|
+
- `docs/source/roadmap.md` §"v1.0.0 path":
|
|
69
|
+
- **Gate 2 (Protocol stability) ✅ MET** — v0.41 = minor 2 of 2
|
|
70
|
+
without Protocol shape edits (v0.40 fit_*_binary additives +
|
|
71
|
+
v0.41 HFDatasetsLoader enrichment leave Tier-2 Protocols
|
|
72
|
+
untouched).
|
|
73
|
+
- **Gate 4 (Croissant end-to-end) ✅ MET** — with dual-source caveat
|
|
74
|
+
documented; one-line migration path when MLCommons #80 resolves.
|
|
75
|
+
|
|
76
|
+
### v1.0 readiness state after v0.41.0
|
|
77
|
+
|
|
78
|
+
- Gate 1 (real consumer ≥1 review cycle on v0.7+): partial — consumer
|
|
79
|
+
pinned to v0.34.0; needs bump + cycle. **External**.
|
|
80
|
+
- Gate 2 ✅ MET (v0.41 is minor 2 of 2 stable).
|
|
81
|
+
- Gate 3 (methodology peer review): not met — needs external reader.
|
|
82
|
+
**External**.
|
|
83
|
+
- Gate 4 ✅ MET — see this release.
|
|
84
|
+
|
|
85
|
+
Two of four gates closed in-repo. The remaining two require external
|
|
86
|
+
coordination (consumer review cycle, methodology peer reviewer).
|
|
87
|
+
|
|
10
88
|
## [0.40.0] — 2026-05-18 — fit_platt_binary + fit_beta_binary (closes #43)
|
|
11
89
|
|
|
12
90
|
Completes the binary scalar-prob calibrator family started in v0.35.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eval-toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.41.0
|
|
4
4
|
Summary: Reusable evaluation contracts for binary classification: metrics, bootstrap CIs, calibration, artifacts, and evidence gates.
|
|
5
5
|
Project-URL: Homepage, https://github.com/brandon-behring/eval-toolkit
|
|
6
6
|
Project-URL: Documentation, https://brandon-behring.github.io/eval-toolkit/
|
|
@@ -188,6 +188,7 @@ markers = [
|
|
|
188
188
|
"slow: Tests > 2s (bootstrap-t studentized, multi-seed K-fold). Opt out with `pytest -m 'not slow'`.",
|
|
189
189
|
"monte_carlo: Monte Carlo calibration suite (~14 min). Skipped in PR CI; runs only in the nightly-mc workflow via `-m monte_carlo`.",
|
|
190
190
|
"benchmark: pytest-benchmark perf-regression tests on math kernels. Skipped in PR CI; runs in the nightly-benchmarks workflow via `-m benchmark`. Per v0.29.0 plan Tier γ #1.",
|
|
191
|
+
"integration: Network-dependent integration tests (HF Hub API, Croissant endpoints, etc.). Excluded from PR CI to avoid network-flake; runs in nightly. Opt in via `-m integration`. Added v0.41.0 (#42 Croissant Gate 4).",
|
|
191
192
|
]
|
|
192
193
|
|
|
193
194
|
[tool.coverage.run]
|
|
@@ -29,7 +29,9 @@ References
|
|
|
29
29
|
from __future__ import annotations
|
|
30
30
|
|
|
31
31
|
import glob as _glob
|
|
32
|
+
import json as _json
|
|
32
33
|
import logging
|
|
34
|
+
import urllib.request as _urlrequest
|
|
33
35
|
from collections.abc import Mapping, Sequence
|
|
34
36
|
from dataclasses import dataclass
|
|
35
37
|
from pathlib import Path
|
|
@@ -38,6 +40,24 @@ from typing import TYPE_CHECKING, Any, Protocol, cast, runtime_checkable
|
|
|
38
40
|
from eval_toolkit.harness import EvalSlice
|
|
39
41
|
from eval_toolkit.provenance import file_sha256
|
|
40
42
|
|
|
43
|
+
_HF_HUB_BASE = "https://huggingface.co"
|
|
44
|
+
_HF_FETCH_TIMEOUT_SEC = 15
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _hf_get_json(path: str) -> Any:
|
|
48
|
+
"""GET ``https://huggingface.co{path}`` and return parsed JSON.
|
|
49
|
+
|
|
50
|
+
Stdlib-only (no ``requests`` / ``huggingface_hub`` dep). Raises
|
|
51
|
+
``OSError`` (urllib error) or ``ValueError`` (JSON decode) on
|
|
52
|
+
failure — callers catch both. The 15-second timeout caps any one
|
|
53
|
+
fetch so CI doesn't hang on a slow HF Hub.
|
|
54
|
+
"""
|
|
55
|
+
url = f"{_HF_HUB_BASE}{path}"
|
|
56
|
+
req = _urlrequest.Request(url, headers={"User-Agent": "eval-toolkit"})
|
|
57
|
+
with _urlrequest.urlopen(req, timeout=_HF_FETCH_TIMEOUT_SEC) as resp:
|
|
58
|
+
return _json.loads(resp.read().decode("utf-8"))
|
|
59
|
+
|
|
60
|
+
|
|
41
61
|
_logger = logging.getLogger(__name__)
|
|
42
62
|
|
|
43
63
|
if TYPE_CHECKING:
|
|
@@ -367,10 +387,22 @@ class HFDatasetsLoader:
|
|
|
367
387
|
raised at :meth:`load_splits` time with a clear install hint. This is
|
|
368
388
|
intentional — eval-toolkit's core deps are numpy / scipy / sklearn only.
|
|
369
389
|
|
|
390
|
+
Since v0.41.0, :meth:`describe` enriches its output with per-file
|
|
391
|
+
``sha256`` hashes fetched from the HF Hub tree API (the ``lfs.oid``
|
|
392
|
+
field), plus Croissant metadata fetched from HF Hub's Croissant
|
|
393
|
+
endpoint. The dual-source design is documented in
|
|
394
|
+
``methodology/reproducibility.md`` §"Croissant interoperability";
|
|
395
|
+
in short: HF Hub's Croissant emitter currently punts the
|
|
396
|
+
``distribution[].sha256`` field per MLCommons Croissant issue #80
|
|
397
|
+
(open), so we read the authoritative sha256 from the tree API's
|
|
398
|
+
``lfs.oid`` instead. When #80 resolves and HF Hub starts populating
|
|
399
|
+
Croissant ``sha256`` with real values, the implementation collapses
|
|
400
|
+
to a single source.
|
|
401
|
+
|
|
370
402
|
Parameters
|
|
371
403
|
----------
|
|
372
404
|
repo_id : str
|
|
373
|
-
HuggingFace dataset repo, e.g. ``"
|
|
405
|
+
HuggingFace dataset repo, e.g. ``"stanfordnlp/sst2"``.
|
|
374
406
|
splits : sequence of str or None, optional
|
|
375
407
|
Subset of HF splits to load. ``None`` = every split the repo defines.
|
|
376
408
|
feature_col : str, optional
|
|
@@ -381,7 +413,12 @@ class HFDatasetsLoader:
|
|
|
381
413
|
config_name : str or None, optional
|
|
382
414
|
HF dataset config name (some datasets have multiple configs).
|
|
383
415
|
name, description, cite_as, license, url : str, optional
|
|
384
|
-
Croissant metadata
|
|
416
|
+
Croissant metadata overrides. If empty, :meth:`describe` will
|
|
417
|
+
fall back to fetching from HF Hub's Croissant endpoint.
|
|
418
|
+
fetch_remote_metadata : bool, optional
|
|
419
|
+
If ``True`` (default), :meth:`describe` fetches Croissant + tree
|
|
420
|
+
metadata from HF Hub. Set ``False`` to disable network calls
|
|
421
|
+
(useful for offline / unit testing).
|
|
385
422
|
"""
|
|
386
423
|
|
|
387
424
|
repo_id: str
|
|
@@ -395,6 +432,7 @@ class HFDatasetsLoader:
|
|
|
395
432
|
cite_as: str = ""
|
|
396
433
|
license: str = ""
|
|
397
434
|
url: str = ""
|
|
435
|
+
fetch_remote_metadata: bool = True
|
|
398
436
|
|
|
399
437
|
def _load_dataset(self) -> Mapping[str, Any]:
|
|
400
438
|
"""Soft-import ``datasets`` and return the loaded DatasetDict.
|
|
@@ -447,20 +485,118 @@ class HFDatasetsLoader:
|
|
|
447
485
|
return out
|
|
448
486
|
|
|
449
487
|
def describe(self) -> dict[str, object]:
|
|
450
|
-
"""Croissant-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
488
|
+
"""Croissant-compatible metadata + per-file sha256 from HF Hub.
|
|
489
|
+
|
|
490
|
+
When ``fetch_remote_metadata=True`` (default), enriches the
|
|
491
|
+
baseline metadata with two HF Hub API fetches:
|
|
492
|
+
|
|
493
|
+
- **Croissant endpoint** (``/api/datasets/{repo}/croissant``) —
|
|
494
|
+
provides ``name``, ``description``, ``citeAs``, ``license``,
|
|
495
|
+
``url`` defaults when the loader's fields are empty.
|
|
496
|
+
- **Tree API** (``/api/datasets/{repo}/tree/...?recursive=true``) —
|
|
497
|
+
provides per-file ``sha256`` (from ``lfs.oid``) and
|
|
498
|
+
``contentSize`` for each parquet shard under the
|
|
499
|
+
``refs/convert/parquet`` branch.
|
|
500
|
+
|
|
501
|
+
Network failures degrade gracefully (warning emitted; sha256
|
|
502
|
+
empty as in pre-v0.41 behavior). See class docstring for the
|
|
503
|
+
dual-source rationale (MLCommons Croissant issue #80).
|
|
504
|
+
"""
|
|
505
|
+
remote_meta: dict[str, object] = {}
|
|
506
|
+
distribution: list[dict[str, object]] = []
|
|
507
|
+
if self.fetch_remote_metadata:
|
|
508
|
+
remote_meta = self._fetch_croissant_metadata_safe()
|
|
509
|
+
distribution = self._fetch_tree_distribution_safe()
|
|
510
|
+
|
|
511
|
+
# Caller-provided fields win; Croissant fills gaps.
|
|
512
|
+
def _pick(local: str, key: str) -> str:
|
|
513
|
+
if local:
|
|
514
|
+
return local
|
|
515
|
+
val = remote_meta.get(key)
|
|
516
|
+
return val if isinstance(val, str) else ""
|
|
517
|
+
|
|
518
|
+
if not distribution:
|
|
519
|
+
distribution = [
|
|
458
520
|
{
|
|
459
521
|
"name": f"hf:{self.repo_id}",
|
|
460
522
|
"contentUrl": f"https://huggingface.co/datasets/{self.repo_id}",
|
|
461
|
-
"sha256": "",
|
|
523
|
+
"sha256": "",
|
|
462
524
|
"contentSize": 0,
|
|
463
525
|
}
|
|
464
|
-
]
|
|
526
|
+
]
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
"name": _pick(self.name, "name") or self.repo_id,
|
|
530
|
+
"description": _pick(self.description, "description"),
|
|
531
|
+
"citeAs": _pick(self.cite_as, "citeAs"),
|
|
532
|
+
"license": _pick(self.license, "license"),
|
|
533
|
+
"url": self.url or f"https://huggingface.co/datasets/{self.repo_id}",
|
|
534
|
+
"distribution": distribution,
|
|
465
535
|
"config_name": self.config_name,
|
|
466
536
|
}
|
|
537
|
+
|
|
538
|
+
def _fetch_croissant_metadata_safe(self) -> dict[str, object]:
|
|
539
|
+
"""Fetch HF Hub Croissant JSON-LD; return empty dict on any failure."""
|
|
540
|
+
try:
|
|
541
|
+
data = _hf_get_json(f"/api/datasets/{self.repo_id}/croissant")
|
|
542
|
+
return data if isinstance(data, dict) else {}
|
|
543
|
+
except (OSError, ValueError) as exc: # urllib.URLError, JSONDecodeError, etc.
|
|
544
|
+
_logger.warning(
|
|
545
|
+
"HFDatasetsLoader %s: Croissant fetch failed (%s); proceeding without",
|
|
546
|
+
self.repo_id,
|
|
547
|
+
exc,
|
|
548
|
+
)
|
|
549
|
+
return {}
|
|
550
|
+
|
|
551
|
+
def _fetch_tree_distribution_safe(self) -> list[dict[str, object]]:
|
|
552
|
+
"""Fetch HF Hub tree API for the parquet-convert branch; return ``cr:FileObject`` entries.
|
|
553
|
+
|
|
554
|
+
Each entry carries ``sha256`` (from ``lfs.oid`` — the git-LFS
|
|
555
|
+
content hash, equal to ``sha256sum`` of the file content) and
|
|
556
|
+
``contentSize`` (from the tree response's ``size`` field).
|
|
557
|
+
|
|
558
|
+
Falls back to an empty list on any failure — callers should
|
|
559
|
+
treat empty distribution as "no remote provenance available."
|
|
560
|
+
"""
|
|
561
|
+
# HF stores native parquet (or auto-converts) under
|
|
562
|
+
# refs/convert/parquet; that's the canonical hash target.
|
|
563
|
+
path = f"/api/datasets/{self.repo_id}/tree/refs%2Fconvert%2Fparquet?recursive=true"
|
|
564
|
+
try:
|
|
565
|
+
entries = _hf_get_json(path)
|
|
566
|
+
except (OSError, ValueError) as exc:
|
|
567
|
+
_logger.warning(
|
|
568
|
+
"HFDatasetsLoader %s: tree-API fetch failed (%s); sha256 unavailable",
|
|
569
|
+
self.repo_id,
|
|
570
|
+
exc,
|
|
571
|
+
)
|
|
572
|
+
return []
|
|
573
|
+
if not isinstance(entries, list):
|
|
574
|
+
return []
|
|
575
|
+
out: list[dict[str, object]] = []
|
|
576
|
+
for entry in entries:
|
|
577
|
+
if not isinstance(entry, dict):
|
|
578
|
+
continue
|
|
579
|
+
if entry.get("type") != "file":
|
|
580
|
+
continue
|
|
581
|
+
path_val = entry.get("path", "")
|
|
582
|
+
if not isinstance(path_val, str) or not path_val.endswith(".parquet"):
|
|
583
|
+
continue
|
|
584
|
+
lfs = entry.get("lfs")
|
|
585
|
+
sha = ""
|
|
586
|
+
if isinstance(lfs, dict):
|
|
587
|
+
oid = lfs.get("oid")
|
|
588
|
+
if isinstance(oid, str) and len(oid) == 64: # sha256 hex
|
|
589
|
+
sha = f"sha256:{oid}"
|
|
590
|
+
size = entry.get("size", 0)
|
|
591
|
+
out.append(
|
|
592
|
+
{
|
|
593
|
+
"name": path_val,
|
|
594
|
+
"contentUrl": (
|
|
595
|
+
f"https://huggingface.co/datasets/{self.repo_id}"
|
|
596
|
+
f"/resolve/refs%2Fconvert%2Fparquet/{path_val}"
|
|
597
|
+
),
|
|
598
|
+
"sha256": sha,
|
|
599
|
+
"contentSize": int(size) if isinstance(size, (int, float)) else 0,
|
|
600
|
+
}
|
|
601
|
+
)
|
|
602
|
+
return out
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
],
|
|
554
554
|
"doc_first_line": "Load a HuggingFace ``datasets`` repo as ``{split: EvalSlice}``.",
|
|
555
555
|
"kind": "class",
|
|
556
|
-
"signature": "(repo_id: 'str', splits: 'Sequence[str] | None' = None, feature_col: 'str' = 'text', label_col: 'str' = 'label', strata_col: 'str | None' = None, config_name: 'str | None' = None, name: 'str' = '', description: 'str' = '', cite_as: 'str' = '', license: 'str' = '', url: 'str' = '') -> None"
|
|
556
|
+
"signature": "(repo_id: 'str', splits: 'Sequence[str] | None' = None, feature_col: 'str' = 'text', label_col: 'str' = 'label', strata_col: 'str | None' = None, config_name: 'str | None' = None, name: 'str' = '', description: 'str' = '', cite_as: 'str' = '', license: 'str' = '', url: 'str' = '', fetch_remote_metadata: 'bool' = True) -> None"
|
|
557
557
|
},
|
|
558
558
|
"HoldoutSplitter": {
|
|
559
559
|
"bases": [
|
|
@@ -1036,7 +1036,7 @@
|
|
|
1036
1036
|
"doc_first_line": "str(object='') -> str",
|
|
1037
1037
|
"kind": "value",
|
|
1038
1038
|
"type": "str",
|
|
1039
|
-
"value": "'0.
|
|
1039
|
+
"value": "'0.41.0'"
|
|
1040
1040
|
},
|
|
1041
1041
|
"apply_operating_points": {
|
|
1042
1042
|
"doc_first_line": "Apply fitted thresholds to a mixed-class or single-class target slice.",
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""End-to-end Croissant interop verification (v0.41.0, closes #42, v1.0 Gate 4).
|
|
2
|
+
|
|
3
|
+
Verifies that ``HFDatasetsLoader.describe()`` returns per-file ``sha256``
|
|
4
|
+
hashes that match the actual bytes of the underlying parquet shards on
|
|
5
|
+
HF Hub.
|
|
6
|
+
|
|
7
|
+
Background on the dual-source design (Croissant + tree API):
|
|
8
|
+
- HF Hub's Croissant emitter (``/api/datasets/{repo}/croissant``) ships
|
|
9
|
+
metadata (name, license, citation, schema) but **does not** populate
|
|
10
|
+
per-file ``distribution[].sha256`` — instead, the field carries a
|
|
11
|
+
placeholder URL pointing at the MLCommons Croissant issue tracking
|
|
12
|
+
the eventual checksum addition (issue #80, open).
|
|
13
|
+
- HF Hub's tree API (``/api/datasets/{repo}/tree/...``) exposes
|
|
14
|
+
``lfs.oid`` per file: a 64-hex sha256 of the raw file content.
|
|
15
|
+
- ``HFDatasetsLoader.describe()`` reads sha256 from the tree API today,
|
|
16
|
+
and will pick up Croissant's eventual sha256 with a one-line change
|
|
17
|
+
when #80 resolves (same downstream contract; same hash format).
|
|
18
|
+
|
|
19
|
+
Tests are marked ``@pytest.mark.integration`` — network-dependent;
|
|
20
|
+
excluded from PR CI via ``-m "not integration"`` in ``make coverage``.
|
|
21
|
+
Run explicitly via ``pytest -m integration`` (nightly or local dev).
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import hashlib
|
|
27
|
+
import urllib.request
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
import pytest
|
|
31
|
+
|
|
32
|
+
from eval_toolkit.loaders import HFDatasetsLoader
|
|
33
|
+
|
|
34
|
+
# Small public Croissant-compliant dataset. ~50 KB test split (1 parquet
|
|
35
|
+
# shard). Pinned via repo_id; HF retains revisions, so even if the dataset
|
|
36
|
+
# is updated the test only fails if HF re-shards (rare for popular
|
|
37
|
+
# datasets) — which is a real signal we want to catch in nightly.
|
|
38
|
+
_TEST_REPO_ID = "stanfordnlp/sst2"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _download_and_hash(url: str) -> str:
|
|
42
|
+
"""GET the URL, return ``sha256:<hex>`` of the body."""
|
|
43
|
+
req = urllib.request.Request(url, headers={"User-Agent": "eval-toolkit-test"})
|
|
44
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
45
|
+
body = resp.read()
|
|
46
|
+
return f"sha256:{hashlib.sha256(body).hexdigest()}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.mark.integration
|
|
50
|
+
def test_hfdatasets_describe_returns_real_sha256_from_tree_api() -> None:
|
|
51
|
+
"""``describe()`` populates per-file sha256 from HF Hub's tree API.
|
|
52
|
+
|
|
53
|
+
Closes the infrastructure half of v1.0 Gate 4: prove the loader can
|
|
54
|
+
surface authoritative file hashes from HF Hub.
|
|
55
|
+
"""
|
|
56
|
+
loader = HFDatasetsLoader(repo_id=_TEST_REPO_ID)
|
|
57
|
+
desc = loader.describe()
|
|
58
|
+
|
|
59
|
+
distribution = desc["distribution"]
|
|
60
|
+
assert isinstance(distribution, list)
|
|
61
|
+
assert distribution, "expected at least one parquet shard in distribution[]"
|
|
62
|
+
|
|
63
|
+
# Every entry should have a real sha256 (64 hex chars after the prefix).
|
|
64
|
+
for entry in distribution:
|
|
65
|
+
sha = entry["sha256"]
|
|
66
|
+
assert isinstance(sha, str)
|
|
67
|
+
assert sha.startswith("sha256:"), f"unexpected hash format: {sha!r}"
|
|
68
|
+
hex_part = sha.removeprefix("sha256:")
|
|
69
|
+
assert len(hex_part) == 64, f"expected 64-hex sha256, got {len(hex_part)}"
|
|
70
|
+
assert all(c in "0123456789abcdef" for c in hex_part), f"non-hex: {hex_part!r}"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@pytest.mark.integration
|
|
74
|
+
def test_hfdatasets_describe_sha256_matches_actual_file_bytes() -> None:
|
|
75
|
+
"""End-to-end Gate 4 verification: hash a downloaded shard, assert match.
|
|
76
|
+
|
|
77
|
+
For each shard in ``describe()['distribution']``, fetch the raw
|
|
78
|
+
parquet bytes from ``contentUrl`` and verify ``sha256(bytes) ==
|
|
79
|
+
entry['sha256']``. This proves the source-of-truth chain:
|
|
80
|
+
HF Hub tree API → ``describe()`` → real file content.
|
|
81
|
+
"""
|
|
82
|
+
loader = HFDatasetsLoader(repo_id=_TEST_REPO_ID)
|
|
83
|
+
desc = loader.describe()
|
|
84
|
+
distribution = desc["distribution"]
|
|
85
|
+
assert isinstance(distribution, list)
|
|
86
|
+
|
|
87
|
+
# Only verify the first shard to keep CI cost bounded (sst2 train is
|
|
88
|
+
# ~3 MB; we just need one matched pair to prove the contract).
|
|
89
|
+
entry: dict[str, Any] = distribution[0]
|
|
90
|
+
content_url = entry["contentUrl"]
|
|
91
|
+
expected_sha = entry["sha256"]
|
|
92
|
+
assert content_url and expected_sha
|
|
93
|
+
|
|
94
|
+
actual_sha = _download_and_hash(content_url)
|
|
95
|
+
assert actual_sha == expected_sha, (
|
|
96
|
+
f"sha256 mismatch for {entry['name']!r}: "
|
|
97
|
+
f"describe() reported {expected_sha}, actual file hashed to {actual_sha}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@pytest.mark.integration
|
|
102
|
+
def test_hfdatasets_describe_returns_croissant_metadata() -> None:
|
|
103
|
+
"""``describe()`` enriches with Croissant metadata (name, license, citeAs).
|
|
104
|
+
|
|
105
|
+
Even though Croissant's ``distribution[].sha256`` is unusable today
|
|
106
|
+
(placeholder URL per MLCommons #80), the metadata fields are valid
|
|
107
|
+
and should pass through to ``describe()`` output.
|
|
108
|
+
"""
|
|
109
|
+
loader = HFDatasetsLoader(repo_id=_TEST_REPO_ID)
|
|
110
|
+
desc = loader.describe()
|
|
111
|
+
|
|
112
|
+
# Either Croissant provided a non-empty name or we fell back to repo_id.
|
|
113
|
+
name = desc["name"]
|
|
114
|
+
assert isinstance(name, str) and name
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@pytest.mark.integration
|
|
118
|
+
def test_hfdatasets_caller_overrides_win() -> None:
|
|
119
|
+
"""Caller-provided fields override Croissant fetches.
|
|
120
|
+
|
|
121
|
+
Explicit ``name=...`` / ``cite_as=...`` are not overwritten by
|
|
122
|
+
remote metadata even when ``fetch_remote_metadata=True``.
|
|
123
|
+
"""
|
|
124
|
+
loader = HFDatasetsLoader(
|
|
125
|
+
repo_id=_TEST_REPO_ID,
|
|
126
|
+
name="my-custom-name",
|
|
127
|
+
cite_as="my-citation",
|
|
128
|
+
)
|
|
129
|
+
desc = loader.describe()
|
|
130
|
+
assert desc["name"] == "my-custom-name"
|
|
131
|
+
assert desc["citeAs"] == "my-citation"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@pytest.mark.integration
|
|
135
|
+
def test_hfdatasets_fetch_remote_metadata_disabled_skips_network() -> None:
|
|
136
|
+
"""``fetch_remote_metadata=False`` produces the v0.40-era empty-sha256 output."""
|
|
137
|
+
loader = HFDatasetsLoader(
|
|
138
|
+
repo_id=_TEST_REPO_ID,
|
|
139
|
+
fetch_remote_metadata=False,
|
|
140
|
+
)
|
|
141
|
+
desc = loader.describe()
|
|
142
|
+
distribution = desc["distribution"]
|
|
143
|
+
assert isinstance(distribution, list)
|
|
144
|
+
assert len(distribution) == 1
|
|
145
|
+
assert distribution[0]["sha256"] == ""
|
|
@@ -156,8 +156,12 @@ def test_hf_datasets_loader_subset_splits() -> None:
|
|
|
156
156
|
|
|
157
157
|
@pytest.mark.unit
|
|
158
158
|
def test_hf_datasets_loader_describe_uses_url_or_default() -> None:
|
|
159
|
-
"""Describe(): url falls back to huggingface.co/datasets/<repo_id>.
|
|
160
|
-
|
|
159
|
+
"""Describe(): url falls back to huggingface.co/datasets/<repo_id>.
|
|
160
|
+
|
|
161
|
+
``fetch_remote_metadata=False`` keeps this a unit test (no network).
|
|
162
|
+
The network-enabled path is exercised in test_croissant_e2e.py.
|
|
163
|
+
"""
|
|
164
|
+
loader = HFDatasetsLoader(repo_id="dummy/example", fetch_remote_metadata=False)
|
|
161
165
|
out = loader.describe()
|
|
162
166
|
assert out["url"] == "https://huggingface.co/datasets/dummy/example"
|
|
163
167
|
assert out["distribution"][0]["sha256"] == ""
|
|
@@ -165,6 +169,10 @@ def test_hf_datasets_loader_describe_uses_url_or_default() -> None:
|
|
|
165
169
|
|
|
166
170
|
@pytest.mark.unit
|
|
167
171
|
def test_hf_datasets_loader_describe_with_explicit_url() -> None:
|
|
168
|
-
loader = HFDatasetsLoader(
|
|
172
|
+
loader = HFDatasetsLoader(
|
|
173
|
+
repo_id="dummy/example",
|
|
174
|
+
url="https://example.com",
|
|
175
|
+
fetch_remote_metadata=False,
|
|
176
|
+
)
|
|
169
177
|
out = loader.describe()
|
|
170
178
|
assert out["url"] == "https://example.com"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_lift_ci.png
RENAMED
|
File without changes
|
{eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_metric_bars.png
RENAMED
|
File without changes
|
|
File without changes
|
{eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_pr_curve.png
RENAMED
|
File without changes
|
|
File without changes
|
{eval_toolkit-0.40.0 → eval_toolkit-0.41.0}/tests/baseline/test_plotting_visual/plot_roc_curve.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|