Spaces:
Running
Running
Download src/selfheal_sql/make_gate_large.py from HideIron/selfheal-sql: direct link, hf CLI and curl.
- Browser
- Download file 4.38 kB
-
https://huggingface.co/spaces/HideIron/selfheal-sql/resolve/main/src/selfheal_sql/make_gate_large.py
- Command line
-
hf download hf://spaces/HideIron/selfheal-sql/src/selfheal_sql/make_gate_large.py
-
curl -L -o make_gate_large.py https://huggingface.co/spaces/HideIron/selfheal-sql/resolve/main/src/selfheal_sql/make_gate_large.py
4.38 kB
| """Enlarge the held-out gate split (100 -> N) so small accuracy differences are measurable. | |
| The original gate has 100 questions (std. error ~ +/-5pp), too noisy to tell a 2pp | |
| regression from chance. This keeps the original 100 rows (same qids, so old results stay | |
| comparable) and adds more questions drawn from the SAME databases the gate already uses | |
| (Spider-train DB group B), so: | |
| * no database appears in pool or test (asserted), | |
| * every database is already in the HF dataset repo (no DB upload needed), | |
| * gold queries run and return >=1 row (same rule as make_splits.py). | |
| Usage (from repo root): | |
| python src/selfheal_sql/make_gate_large.py [--total 400] [--seed 1] | |
| Writes data/splits/gate_large.jsonl (absolute db_path, like the other local splits) and | |
| data/hf_dataset/splits/gate_large.jsonl (relative db_path, ready to upload). | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import random | |
| import sys | |
| HERE = os.path.dirname(os.path.abspath(__file__)) | |
| sys.path.insert(0, HERE) | |
| from execcheck import check, schema_text # noqa: E402 | |
| from make_splits import usable # noqa: E402 | |
| ROOT = os.path.abspath(os.path.join(HERE, "..", "..")) | |
| SPIDER = os.path.join(ROOT, "data", "spider", "spider_data") | |
| SPLITS = os.path.join(ROOT, "data", "splits") | |
| STAGE = os.path.join(ROOT, "data", "hf_dataset", "splits") | |
| def read(path): | |
| with open(path, encoding="utf-8") as f: | |
| return [json.loads(line) for line in f] | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--total", type=int, default=400) | |
| ap.add_argument("--seed", type=int, default=1) | |
| args = ap.parse_args() | |
| pool, gate, test = (read(os.path.join(SPLITS, f"{n}.jsonl")) for n in ("pool", "gate", "test")) | |
| gate_dbs = {r["db_id"] for r in gate} | |
| seen = {(r["db_id"], r["question"]) for r in gate} | |
| with open(os.path.join(SPIDER, "train_spider.json"), encoding="utf-8") as f: | |
| train = json.load(f) | |
| # Candidates: train questions on the gate's databases, not already in the gate. | |
| cands = [x for x in train if x["db_id"] in gate_dbs and (x["db_id"], x["question"]) not in seen] | |
| random.Random(args.seed).shuffle(cands) | |
| rows = [dict(r, split="gate_large") for r in gate] # keep original 100, same qids | |
| schemas = {r["db_id"]: r["schema"] for r in gate} | |
| n_keep = len(rows) | |
| for it in cands: | |
| if len(rows) >= args.total: | |
| break | |
| db_id = it["db_id"] | |
| db_path = os.path.join(SPIDER, "database", db_id, f"{db_id}.sqlite") | |
| if not os.path.exists(db_path) or not usable(db_path, it["query"]): | |
| continue | |
| schemas.setdefault(db_id, schema_text(db_path)) | |
| rows.append({ | |
| "qid": f"gate_{len(rows):04d}", "split": "gate_large", "db_id": db_id, | |
| "question": it["question"], "gold_sql": it["query"], | |
| "db_path": db_path, "schema": schemas[db_id], | |
| }) | |
| # Hard guarantees, asserted not assumed. | |
| dbs = {r["db_id"] for r in rows} | |
| assert dbs == gate_dbs, "gate_large introduced a new database" | |
| assert not dbs & {r["db_id"] for r in pool}, "gate_large shares a DB with pool" | |
| assert not dbs & {r["db_id"] for r in test}, "gate_large shares a DB with test" | |
| assert len({r["qid"] for r in rows}) == len(rows), "duplicate qid" | |
| assert len({(r["db_id"], r["question"]) for r in rows}) == len(rows), "duplicate question" | |
| bad = [r["qid"] for r in rows if not check(r["db_path"], r["gold_sql"], r["gold_sql"]).correct] | |
| print(f"gate_large: {len(rows)} questions ({n_keep} original + {len(rows) - n_keep} new) " | |
| f"over {len(dbs)} databases; gold-vs-gold failures: {len(bad)}") | |
| assert not bad, bad[:5] | |
| os.makedirs(SPLITS, exist_ok=True) | |
| with open(os.path.join(SPLITS, "gate_large.jsonl"), "w", encoding="utf-8") as f: | |
| for r in rows: | |
| f.write(json.dumps(r, ensure_ascii=False) + "\n") | |
| os.makedirs(STAGE, exist_ok=True) | |
| with open(os.path.join(STAGE, "gate_large.jsonl"), "w", encoding="utf-8") as f: | |
| for r in rows: | |
| r2 = dict(r, db_path=f"databases/{r['db_id']}/{r['db_id']}.sqlite") | |
| f.write(json.dumps(r2, ensure_ascii=False) + "\n") | |
| print("wrote data/splits/gate_large.jsonl and data/hf_dataset/splits/gate_large.jsonl") | |
| print("db-disjoint from pool/test: OK") | |
| if __name__ == "__main__": | |
| main() | |