corpus-assay 0.1.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.
- corpus_assay-0.1.0/.github/workflows/ci.yml +98 -0
- corpus_assay-0.1.0/.github/workflows/release.yml +213 -0
- corpus_assay-0.1.0/.gitignore +30 -0
- corpus_assay-0.1.0/.python-version +1 -0
- corpus_assay-0.1.0/CHANGELOG.md +32 -0
- corpus_assay-0.1.0/CITATION.cff +23 -0
- corpus_assay-0.1.0/CONTRIBUTING.md +59 -0
- corpus_assay-0.1.0/Cargo.lock +1597 -0
- corpus_assay-0.1.0/Cargo.toml +45 -0
- corpus_assay-0.1.0/LICENSE +201 -0
- corpus_assay-0.1.0/Makefile +46 -0
- corpus_assay-0.1.0/PKG-INFO +345 -0
- corpus_assay-0.1.0/README.md +311 -0
- corpus_assay-0.1.0/SECURITY.md +18 -0
- corpus_assay-0.1.0/docs/architecture.md +70 -0
- corpus_assay-0.1.0/docs/assets/README.md +34 -0
- corpus_assay-0.1.0/docs/assets/favicon.svg +8 -0
- corpus_assay-0.1.0/docs/assets/icon-dark.svg +18 -0
- corpus_assay-0.1.0/docs/assets/icon-mono.svg +17 -0
- corpus_assay-0.1.0/docs/assets/icon.svg +17 -0
- corpus_assay-0.1.0/docs/assets/logo-dark.svg +19 -0
- corpus_assay-0.1.0/docs/assets/logo.svg +19 -0
- corpus_assay-0.1.0/docs/assets/make_logos.py +239 -0
- corpus_assay-0.1.0/docs/assets/social-preview.png +0 -0
- corpus_assay-0.1.0/docs/cli.md +337 -0
- corpus_assay-0.1.0/docs/configuration.md +135 -0
- corpus_assay-0.1.0/docs/experimental-spaced-seeds.md +77 -0
- corpus_assay-0.1.0/docs/how-it-works.md +111 -0
- corpus_assay-0.1.0/docs/outputs.md +106 -0
- corpus_assay-0.1.0/examples/config.yaml +21 -0
- corpus_assay-0.1.0/pyproject.toml +105 -0
- corpus_assay-0.1.0/python/corpus_assay/__init__.py +49 -0
- corpus_assay-0.1.0/python/corpus_assay/__main__.py +7 -0
- corpus_assay-0.1.0/python/corpus_assay/_native.pyi +49 -0
- corpus_assay-0.1.0/python/corpus_assay/_version.py +16 -0
- corpus_assay-0.1.0/python/corpus_assay/attribution.py +223 -0
- corpus_assay-0.1.0/python/corpus_assay/benchmark_registry.py +97 -0
- corpus_assay-0.1.0/python/corpus_assay/benchmark_spec.py +65 -0
- corpus_assay-0.1.0/python/corpus_assay/benchmarks.py +277 -0
- corpus_assay-0.1.0/python/corpus_assay/cli.py +1229 -0
- corpus_assay-0.1.0/python/corpus_assay/config.py +230 -0
- corpus_assay-0.1.0/python/corpus_assay/constants.py +18 -0
- corpus_assay-0.1.0/python/corpus_assay/formats.py +106 -0
- corpus_assay-0.1.0/python/corpus_assay/indexing.py +302 -0
- corpus_assay-0.1.0/python/corpus_assay/inspect.py +157 -0
- corpus_assay-0.1.0/python/corpus_assay/ngram_config.json +74 -0
- corpus_assay-0.1.0/python/corpus_assay/normalization.py +38 -0
- corpus_assay-0.1.0/python/corpus_assay/py.typed +0 -0
- corpus_assay-0.1.0/python/corpus_assay/reporting.py +963 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/__init__.py +6 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/fingerprint.py +69 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/io.py +232 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/layout.py +77 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/runner.py +115 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/schema.py +84 -0
- corpus_assay-0.1.0/python/corpus_assay/scanner/worker.py +170 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/__init__.py +45 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/doc_result.py +45 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/index_meta.py +34 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/run_manifest.py +94 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/scan_summary.py +35 -0
- corpus_assay-0.1.0/python/corpus_assay/schemas/stopgrams_meta.py +27 -0
- corpus_assay-0.1.0/python/corpus_assay/services/__init__.py +0 -0
- corpus_assay-0.1.0/python/corpus_assay/services/config_validation.py +181 -0
- corpus_assay-0.1.0/python/corpus_assay/services/hf_parquet.py +76 -0
- corpus_assay-0.1.0/python/corpus_assay/services/index_cache.py +91 -0
- corpus_assay-0.1.0/python/corpus_assay/services/planning.py +46 -0
- corpus_assay-0.1.0/python/corpus_assay/spaced_index.py +259 -0
- corpus_assay-0.1.0/python/corpus_assay/spaced_seeds.py +401 -0
- corpus_assay-0.1.0/python/corpus_assay/stopgrams.py +575 -0
- corpus_assay-0.1.0/python/corpus_assay/text_utils.py +141 -0
- corpus_assay-0.1.0/python/corpus_assay/utils.py +14 -0
- corpus_assay-0.1.0/src/formats.rs +117 -0
- corpus_assay-0.1.0/src/index.rs +259 -0
- corpus_assay-0.1.0/src/items_index.rs +103 -0
- corpus_assay-0.1.0/src/lib.rs +37 -0
- corpus_assay-0.1.0/src/mmap_index.rs +205 -0
- corpus_assay-0.1.0/src/scan.rs +787 -0
- corpus_assay-0.1.0/src/spaced.rs +354 -0
- corpus_assay-0.1.0/src/stopgrams.rs +120 -0
- corpus_assay-0.1.0/src/text.rs +305 -0
- corpus_assay-0.1.0/tests/_index_helpers.py +40 -0
- corpus_assay-0.1.0/tests/e2e/test_cli_offline.py +283 -0
- corpus_assay-0.1.0/tests/fixtures/spaced_golden.json +2586 -0
- corpus_assay-0.1.0/tests/test_attrib.py +128 -0
- corpus_assay-0.1.0/tests/test_benchmark_registry.py +58 -0
- corpus_assay-0.1.0/tests/test_benchmarks_config.py +417 -0
- corpus_assay-0.1.0/tests/test_cli.py +534 -0
- corpus_assay-0.1.0/tests/test_config_validation.py +209 -0
- corpus_assay-0.1.0/tests/test_import.py +7 -0
- corpus_assay-0.1.0/tests/test_indexing.py +267 -0
- corpus_assay-0.1.0/tests/test_integration_scan.py +95 -0
- corpus_assay-0.1.0/tests/test_ngram_config.py +218 -0
- corpus_assay-0.1.0/tests/test_ngram_override.py +161 -0
- corpus_assay-0.1.0/tests/test_reporting_v1.py +283 -0
- corpus_assay-0.1.0/tests/test_scan_item_aware.py +306 -0
- corpus_assay-0.1.0/tests/test_scan_jsonl.py +109 -0
- corpus_assay-0.1.0/tests/test_scan_stream_rust.py +148 -0
- corpus_assay-0.1.0/tests/test_scanner.py +404 -0
- corpus_assay-0.1.0/tests/test_spaced_golden.py +187 -0
- corpus_assay-0.1.0/tests/test_spaced_index.py +136 -0
- corpus_assay-0.1.0/tests/test_spaced_rust_parity.py +119 -0
- corpus_assay-0.1.0/tests/test_spaced_scan_integration.py +114 -0
- corpus_assay-0.1.0/tests/test_spaced_seeds.py +258 -0
- corpus_assay-0.1.0/tests/test_spaced_wiring.py +426 -0
- corpus_assay-0.1.0/tests/test_stopgrams.py +228 -0
- corpus_assay-0.1.0/tests/test_text_utils.py +65 -0
- corpus_assay-0.1.0/uv.lock +1820 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
name: Lint
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
22
|
+
with:
|
|
23
|
+
components: rustfmt, clippy
|
|
24
|
+
- uses: Swatinem/rust-cache@v2
|
|
25
|
+
- uses: actions/setup-python@v7
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
- uses: astral-sh/setup-uv@v10.2.0
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
- name: Install (builds the extension)
|
|
32
|
+
run: uv sync --locked
|
|
33
|
+
- run: cargo fmt --all --check
|
|
34
|
+
- run: cargo clippy --locked --all-targets -- -D warnings
|
|
35
|
+
- run: uv run --no-sync ruff check .
|
|
36
|
+
- run: uv run --no-sync ruff format --check .
|
|
37
|
+
- run: uv run --no-sync pyright
|
|
38
|
+
|
|
39
|
+
test:
|
|
40
|
+
name: Test (${{ matrix.os }}, Python ${{ matrix.python }})
|
|
41
|
+
runs-on: ${{ matrix.os }}
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
os: [ubuntu-latest, macos-14, windows-latest]
|
|
46
|
+
python: ["3.12", "3.13"]
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v7
|
|
49
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
50
|
+
- uses: Swatinem/rust-cache@v2
|
|
51
|
+
- uses: actions/setup-python@v7
|
|
52
|
+
with:
|
|
53
|
+
python-version: ${{ matrix.python }}
|
|
54
|
+
- uses: astral-sh/setup-uv@v10.2.0
|
|
55
|
+
with:
|
|
56
|
+
enable-cache: true
|
|
57
|
+
- name: Install (builds the extension)
|
|
58
|
+
run: uv sync --locked --python ${{ matrix.python }}
|
|
59
|
+
- name: Test
|
|
60
|
+
run: uv run --no-sync pytest --cov=corpus_assay --cov-report=term-missing
|
|
61
|
+
|
|
62
|
+
wheel:
|
|
63
|
+
name: Wheel contents + offline e2e
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v7
|
|
67
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
68
|
+
- uses: Swatinem/rust-cache@v2
|
|
69
|
+
- uses: actions/setup-python@v7
|
|
70
|
+
with:
|
|
71
|
+
python-version: "3.12"
|
|
72
|
+
- uses: astral-sh/setup-uv@v10.2.0
|
|
73
|
+
- name: Build wheel
|
|
74
|
+
run: uvx maturin build --release --locked --out dist
|
|
75
|
+
- name: Check wheel contents
|
|
76
|
+
run: |
|
|
77
|
+
python - <<'EOF'
|
|
78
|
+
import glob, zipfile
|
|
79
|
+
(wheel,) = glob.glob("dist/*.whl")
|
|
80
|
+
names = zipfile.ZipFile(wheel).namelist()
|
|
81
|
+
print("\n".join(names))
|
|
82
|
+
leaked = [n for n in names if n.endswith(".rs") or "Cargo." in n
|
|
83
|
+
or n.startswith(("target/", "tests/", "src/"))]
|
|
84
|
+
assert not leaked, f"unexpected files in wheel: {leaked}"
|
|
85
|
+
assert "corpus_assay/ngram_config.json" in names
|
|
86
|
+
assert "corpus_assay/py.typed" in names
|
|
87
|
+
native = [n for n in names
|
|
88
|
+
if n.startswith("corpus_assay/_native") and not n.endswith(".pyi")]
|
|
89
|
+
assert len(native) == 1 and ".abi3." in native[0], native
|
|
90
|
+
EOF
|
|
91
|
+
- name: Install the wheel into a clean venv
|
|
92
|
+
run: |
|
|
93
|
+
uv venv "$RUNNER_TEMP/wheel-venv" --python 3.12
|
|
94
|
+
uv pip install --python "$RUNNER_TEMP/wheel-venv" dist/*.whl pytest
|
|
95
|
+
- name: Offline e2e against the installed wheel
|
|
96
|
+
run: |
|
|
97
|
+
"$RUNNER_TEMP/wheel-venv/bin/python" -c "import corpus_assay; print(corpus_assay.__file__)"
|
|
98
|
+
"$RUNNER_TEMP/wheel-venv/bin/python" -m pytest tests -m e2e -p no:cacheprovider
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Tag push (v*): build -> smoke-test -> TestPyPI -> verify -> PyPI -> GitHub Release.
|
|
4
|
+
# Manual run: build + smoke-test, optionally publishing to TestPyPI only.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
publish:
|
|
11
|
+
description: "Publish the built distributions to"
|
|
12
|
+
type: choice
|
|
13
|
+
options: [none, testpypi]
|
|
14
|
+
default: none
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
version-check:
|
|
21
|
+
name: Version check
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
|
+
- name: Tag matches Cargo.toml and CITATION.cff versions
|
|
26
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
27
|
+
run: |
|
|
28
|
+
version=$(python3 -c "import tomllib; print(tomllib.load(open('Cargo.toml', 'rb'))['package']['version'])")
|
|
29
|
+
if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
|
|
30
|
+
echo "Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${version}" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
# Zenodo takes the archived release's metadata from CITATION.cff.
|
|
34
|
+
cff_version=$(sed -n 's/^version: *"\{0,1\}\([^"]*\)"\{0,1\} *$/\1/p' CITATION.cff)
|
|
35
|
+
if [ "${cff_version}" != "${version}" ]; then
|
|
36
|
+
echo "CITATION.cff version '${cff_version}' does not match ${version}" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
sdist:
|
|
41
|
+
name: Build sdist
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v7
|
|
45
|
+
- uses: PyO3/maturin-action@v1
|
|
46
|
+
with:
|
|
47
|
+
command: sdist
|
|
48
|
+
args: --out dist
|
|
49
|
+
- uses: actions/upload-artifact@v7
|
|
50
|
+
with:
|
|
51
|
+
name: dist-sdist
|
|
52
|
+
path: dist
|
|
53
|
+
if-no-files-found: error
|
|
54
|
+
|
|
55
|
+
wheels:
|
|
56
|
+
name: Build wheel (${{ matrix.target }})
|
|
57
|
+
runs-on: ${{ matrix.os }}
|
|
58
|
+
strategy:
|
|
59
|
+
fail-fast: false
|
|
60
|
+
matrix:
|
|
61
|
+
include:
|
|
62
|
+
- os: ubuntu-latest
|
|
63
|
+
target: x86_64-unknown-linux-gnu
|
|
64
|
+
- os: ubuntu-24.04-arm
|
|
65
|
+
target: aarch64-unknown-linux-gnu
|
|
66
|
+
- os: macos-14
|
|
67
|
+
target: aarch64-apple-darwin
|
|
68
|
+
- os: macos-14
|
|
69
|
+
target: x86_64-apple-darwin
|
|
70
|
+
- os: windows-latest
|
|
71
|
+
target: x86_64-pc-windows-msvc
|
|
72
|
+
steps:
|
|
73
|
+
- uses: actions/checkout@v7
|
|
74
|
+
- uses: actions/setup-python@v7
|
|
75
|
+
with:
|
|
76
|
+
python-version: "3.12"
|
|
77
|
+
# abi3 (see Cargo.toml): one cp312-abi3 wheel per platform covers CPython >= 3.12.
|
|
78
|
+
- uses: PyO3/maturin-action@v1
|
|
79
|
+
with:
|
|
80
|
+
target: ${{ matrix.target }}
|
|
81
|
+
manylinux: auto
|
|
82
|
+
args: --release --locked --out dist
|
|
83
|
+
sccache: true
|
|
84
|
+
- uses: actions/upload-artifact@v7
|
|
85
|
+
with:
|
|
86
|
+
name: dist-${{ matrix.target }}
|
|
87
|
+
path: dist
|
|
88
|
+
if-no-files-found: error
|
|
89
|
+
|
|
90
|
+
smoke:
|
|
91
|
+
name: Smoke test (${{ matrix.os }}, Python ${{ matrix.python }})
|
|
92
|
+
needs: [wheels]
|
|
93
|
+
runs-on: ${{ matrix.os }}
|
|
94
|
+
strategy:
|
|
95
|
+
fail-fast: false
|
|
96
|
+
matrix:
|
|
97
|
+
os: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-15-intel, windows-latest]
|
|
98
|
+
python: ["3.12", "3.13"]
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v7
|
|
101
|
+
- uses: actions/download-artifact@v8
|
|
102
|
+
with:
|
|
103
|
+
pattern: dist-*
|
|
104
|
+
path: dist
|
|
105
|
+
merge-multiple: true
|
|
106
|
+
- uses: actions/setup-python@v7
|
|
107
|
+
with:
|
|
108
|
+
python-version: ${{ matrix.python }}
|
|
109
|
+
- name: Install the built wheel
|
|
110
|
+
shell: bash
|
|
111
|
+
run: |
|
|
112
|
+
python -m pip install --upgrade pip
|
|
113
|
+
python -m pip install --no-index --no-deps --only-binary :all: --find-links dist corpus-assay
|
|
114
|
+
python -m pip install corpus-assay pytest
|
|
115
|
+
- name: Smoke
|
|
116
|
+
shell: bash
|
|
117
|
+
run: |
|
|
118
|
+
corpus-assay --version
|
|
119
|
+
python -c "import corpus_assay, corpus_assay._native as n; print(corpus_assay.__file__, n.__version__)"
|
|
120
|
+
- name: Test suite against the installed wheel
|
|
121
|
+
run: python -m pytest tests -q -p no:cacheprovider
|
|
122
|
+
|
|
123
|
+
publish-testpypi:
|
|
124
|
+
name: Publish to TestPyPI
|
|
125
|
+
needs: [version-check, sdist, smoke]
|
|
126
|
+
if: startsWith(github.ref, 'refs/tags/v') || inputs.publish == 'testpypi'
|
|
127
|
+
runs-on: ubuntu-latest
|
|
128
|
+
environment:
|
|
129
|
+
name: testpypi
|
|
130
|
+
url: https://test.pypi.org/p/corpus-assay
|
|
131
|
+
permissions:
|
|
132
|
+
id-token: write
|
|
133
|
+
steps:
|
|
134
|
+
- uses: actions/download-artifact@v8
|
|
135
|
+
with:
|
|
136
|
+
pattern: dist-*
|
|
137
|
+
path: dist
|
|
138
|
+
merge-multiple: true
|
|
139
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
140
|
+
with:
|
|
141
|
+
repository-url: https://test.pypi.org/legacy/
|
|
142
|
+
skip-existing: true
|
|
143
|
+
|
|
144
|
+
verify-testpypi:
|
|
145
|
+
name: Verify TestPyPI install
|
|
146
|
+
needs: [publish-testpypi]
|
|
147
|
+
runs-on: ubuntu-latest
|
|
148
|
+
steps:
|
|
149
|
+
- uses: actions/checkout@v7
|
|
150
|
+
- uses: actions/setup-python@v7
|
|
151
|
+
with:
|
|
152
|
+
python-version: "3.12"
|
|
153
|
+
- name: Install corpus-assay from TestPyPI (dependencies from PyPI)
|
|
154
|
+
shell: bash
|
|
155
|
+
run: |
|
|
156
|
+
version=$(python -c "import tomllib; print(tomllib.load(open('Cargo.toml', 'rb'))['package']['version'])")
|
|
157
|
+
for attempt in 1 2 3 4 5 6 7 8 9 10; do
|
|
158
|
+
if python -m pip install --no-deps --only-binary :all: \
|
|
159
|
+
--index-url https://test.pypi.org/simple/ "corpus-assay==${version}"; then
|
|
160
|
+
break
|
|
161
|
+
fi
|
|
162
|
+
echo "TestPyPI not ready yet (attempt ${attempt}); retrying in 30s"
|
|
163
|
+
sleep 30
|
|
164
|
+
done
|
|
165
|
+
python -m pip show corpus-assay
|
|
166
|
+
# Dependencies come from PyPI; corpus-assay itself is already satisfied.
|
|
167
|
+
python -m pip install "corpus-assay==${version}" pytest
|
|
168
|
+
python -c "import corpus_assay; assert corpus_assay.__version__ == '${version}', corpus_assay.__version__"
|
|
169
|
+
- name: Offline e2e
|
|
170
|
+
run: python -m pytest tests -m e2e -q -p no:cacheprovider
|
|
171
|
+
|
|
172
|
+
publish-pypi:
|
|
173
|
+
name: Publish to PyPI
|
|
174
|
+
needs: [verify-testpypi]
|
|
175
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
176
|
+
runs-on: ubuntu-latest
|
|
177
|
+
environment:
|
|
178
|
+
name: pypi
|
|
179
|
+
url: https://pypi.org/p/corpus-assay
|
|
180
|
+
permissions:
|
|
181
|
+
id-token: write
|
|
182
|
+
steps:
|
|
183
|
+
- uses: actions/download-artifact@v8
|
|
184
|
+
with:
|
|
185
|
+
pattern: dist-*
|
|
186
|
+
path: dist
|
|
187
|
+
merge-multiple: true
|
|
188
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
189
|
+
|
|
190
|
+
github-release:
|
|
191
|
+
name: GitHub Release
|
|
192
|
+
needs: [publish-pypi]
|
|
193
|
+
runs-on: ubuntu-latest
|
|
194
|
+
permissions:
|
|
195
|
+
contents: write
|
|
196
|
+
steps:
|
|
197
|
+
- uses: actions/checkout@v7
|
|
198
|
+
- uses: actions/download-artifact@v8
|
|
199
|
+
with:
|
|
200
|
+
pattern: dist-*
|
|
201
|
+
path: dist
|
|
202
|
+
merge-multiple: true
|
|
203
|
+
- name: Create release with CHANGELOG notes
|
|
204
|
+
env:
|
|
205
|
+
GH_TOKEN: ${{ github.token }}
|
|
206
|
+
run: |
|
|
207
|
+
version="${GITHUB_REF_NAME#v}"
|
|
208
|
+
awk -v ver="$version" '
|
|
209
|
+
$0 ~ "^## \\[" ver "\\]" { found = 1; next }
|
|
210
|
+
found && /^## \[/ { exit }
|
|
211
|
+
found { print }
|
|
212
|
+
' CHANGELOG.md > notes.md
|
|
213
|
+
gh release create "$GITHUB_REF_NAME" dist/* --title "corpus-assay $version" --notes-file notes.md
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
.python-version.local
|
|
7
|
+
|
|
8
|
+
# Build outputs
|
|
9
|
+
/target/
|
|
10
|
+
/dist/
|
|
11
|
+
/build/
|
|
12
|
+
python/corpus_assay/*.so
|
|
13
|
+
python/corpus_assay/*.pyd
|
|
14
|
+
python/corpus_assay/*.dll
|
|
15
|
+
|
|
16
|
+
# Tooling caches
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.mypy_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
.coverage.*
|
|
22
|
+
coverage.xml
|
|
23
|
+
htmlcov/
|
|
24
|
+
.cache/
|
|
25
|
+
|
|
26
|
+
# Editors / OS
|
|
27
|
+
.idea/
|
|
28
|
+
.vscode/
|
|
29
|
+
*.swp
|
|
30
|
+
.DS_Store
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-10-03
|
|
10
|
+
|
|
11
|
+
Initial public release.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `build-index`: hashed word n-gram index from Hugging Face or local benchmark
|
|
16
|
+
splits, with per-benchmark and per-item attribution sidecars, subtraction splits,
|
|
17
|
+
and provenance metadata (dataset revisions, fingerprints, normalization hashes).
|
|
18
|
+
- `scan`, `run`, `run-hf`: multi-process Rust scanner over Parquet and JSONL
|
|
19
|
+
(`.gz`/`.zst`) shards, with an index-wide (`union`) or single-item (`item`) gate,
|
|
20
|
+
resumable per-shard outputs, and sampled per-document evidence.
|
|
21
|
+
- `report`: leak tables by benchmark, shard, and item (JSON, CSV, Markdown).
|
|
22
|
+
- `build-stopgrams-direct`: stop-grams learned from a background corpus, applied
|
|
23
|
+
with `--stopgrams`.
|
|
24
|
+
- `init-config`, `list-benchmarks`, `describe-benchmark`, `validate-config`,
|
|
25
|
+
`inspect-index`, `inspect-run`, `reproduce`.
|
|
26
|
+
- Global `--ngram-config` to override the bundled normalization config. Scans refuse
|
|
27
|
+
an index built with a different config unless `--allow-config-mismatch` is passed.
|
|
28
|
+
- Experimental: spaced-seed recall channel (`build-spaced-index`, `--spaced-seeds`).
|
|
29
|
+
- Prebuilt abi3 wheels for CPython 3.12+ on Linux, macOS, and Windows.
|
|
30
|
+
|
|
31
|
+
[Unreleased]: https://github.com/mrcabbage972/corpus-assay/compare/v0.1.0...HEAD
|
|
32
|
+
[0.1.0]: https://github.com/mrcabbage972/corpus-assay/releases/tag/v0.1.0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "corpus-assay: benchmark contamination detection for LLM training corpora"
|
|
5
|
+
abstract: >-
|
|
6
|
+
Fast, auditable n-gram detection of evaluation-benchmark contamination in LLM
|
|
7
|
+
training corpora, with a Rust scanner and per-benchmark and per-item attribution.
|
|
8
|
+
authors:
|
|
9
|
+
- family-names: May
|
|
10
|
+
given-names: Victor
|
|
11
|
+
repository-code: "https://github.com/mrcabbage972/corpus-assay"
|
|
12
|
+
license: Apache-2.0
|
|
13
|
+
version: 0.1.0
|
|
14
|
+
date-released: "2026-10-03"
|
|
15
|
+
# Zenodo archives every GitHub Release of this repository. Each release gets its own
|
|
16
|
+
# version DOI, and one concept DOI covers all versions (it resolves to the latest).
|
|
17
|
+
# The concept DOI goes in `doi:` once Zenodo has archived the first release (v0.1.0).
|
|
18
|
+
keywords:
|
|
19
|
+
- large language models
|
|
20
|
+
- evaluation
|
|
21
|
+
- data contamination
|
|
22
|
+
- decontamination
|
|
23
|
+
- benchmarks
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Contributing to corpus-assay
|
|
2
|
+
|
|
3
|
+
Thanks for your interest! Bug reports, feature requests, and pull requests are welcome.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
You need [uv](https://docs.astral.sh/uv/) and a stable [Rust toolchain](https://rustup.rs).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/mrcabbage972/corpus-assay
|
|
11
|
+
cd corpus-assay
|
|
12
|
+
make dev # uv sync + build the Rust extension in place
|
|
13
|
+
make check # lint (ruff, pyright, rustfmt, clippy) + tests
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The package lives in `python/corpus_assay/` and the Rust extension in `src/`.
|
|
17
|
+
`uv sync` rebuilds the extension when Rust sources change. You can also rebuild
|
|
18
|
+
explicitly with `make dev` (or `make release-dev` for an optimized build). Tests always
|
|
19
|
+
run against the built extension, so rebuild after editing Rust.
|
|
20
|
+
|
|
21
|
+
Useful targets:
|
|
22
|
+
|
|
23
|
+
| Target | What it does |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `make test` | Full test suite |
|
|
26
|
+
| `make e2e` | Offline end-to-end CLI tests only (`pytest -m e2e`) |
|
|
27
|
+
| `make test-cov` | Tests with coverage |
|
|
28
|
+
| `make lint` | Checks only; never modifies files |
|
|
29
|
+
| `make fmt` | Apply ruff and rustfmt formatting and safe fixes |
|
|
30
|
+
| `make wheel` | Build a release wheel into `dist/` |
|
|
31
|
+
|
|
32
|
+
## Pull requests
|
|
33
|
+
|
|
34
|
+
- Keep changes focused, and add or update tests for behavior changes.
|
|
35
|
+
- `make check` must pass. CI runs it on Linux, macOS, and Windows for Python 3.12 and 3.13.
|
|
36
|
+
- Update `CHANGELOG.md` under *Unreleased* for user-visible changes.
|
|
37
|
+
- Changing the normalization pipeline, hashing, or a binary format changes what existing
|
|
38
|
+
indexes mean. Call it out in the PR and the changelog.
|
|
39
|
+
- The spaced-seed golden vectors (`tests/fixtures/spaced_golden.json`) should only change
|
|
40
|
+
when spaced-seed behavior is meant to change. Regenerate them with
|
|
41
|
+
`uv run python tests/test_spaced_golden.py`.
|
|
42
|
+
|
|
43
|
+
## Releasing (maintainers)
|
|
44
|
+
|
|
45
|
+
1. Bump `version` in `Cargo.toml` (the single source of the package version), set
|
|
46
|
+
`version` and `date-released` in `CITATION.cff`, and date the CHANGELOG section. The
|
|
47
|
+
release workflow refuses a tag that doesn't match `Cargo.toml` and `CITATION.cff`.
|
|
48
|
+
2. Optionally dry-run: run the *Release* workflow manually with `publish: testpypi`.
|
|
49
|
+
3. Tag and push: `git tag -a vX.Y.Z -m "corpus-assay X.Y.Z" && git push origin vX.Y.Z`.
|
|
50
|
+
The workflow then:
|
|
51
|
+
1. builds the wheels and sdist;
|
|
52
|
+
2. smoke-tests them on every platform;
|
|
53
|
+
3. publishes to TestPyPI and verifies the install;
|
|
54
|
+
4. publishes to PyPI after approval of the `pypi` environment;
|
|
55
|
+
5. creates the GitHub Release.
|
|
56
|
+
|
|
57
|
+
Zenodo's GitHub integration archives the GitHub Release and mints a DOI for that
|
|
58
|
+
version. The concept DOI in `CITATION.cff` and the README badge covers all versions,
|
|
59
|
+
so it doesn't change between releases.
|