Download build_snapshot.py from HuggingFaceBio/carbon-a-database-explorer: direct link, hf CLI and curl.
- Browser
- Download file 3.07 kB
-
https://huggingface.co/spaces/HuggingFaceBio/carbon-a-database-explorer/resolve/main/build_snapshot.py
- Command line
-
hf download hf://spaces/HuggingFaceBio/carbon-a-database-explorer/build_snapshot.py
-
curl -L -o build_snapshot.py https://huggingface.co/spaces/HuggingFaceBio/carbon-a-database-explorer/resolve/main/build_snapshot.py
3.07 kB
| """Build a full accession snapshot in resumable parallel partitions. | |
| Run list_annotation_objects.py first. This command indexes the captured inventory, | |
| merges all partitions, and leaves publication to the operator. | |
| """ | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import sqlite3 | |
| import subprocess | |
| import sys | |
| ROOT=Path(__file__).resolve().parent | |
| def main(): | |
| p=argparse.ArgumentParser(description=__doc__) | |
| p.add_argument('--inventory',type=Path,required=True) | |
| p.add_argument('--cache-dir',type=Path,default=ROOT/'.cache/full-index') | |
| p.add_argument('--output',type=Path,default=ROOT/'data/catalog.sqlite') | |
| p.add_argument('--parts',type=int,default=8) | |
| p.add_argument('--workers-per-part',type=int,default=32) | |
| args=p.parse_args() | |
| if not 1<=args.parts<=32 or not 1<=args.workers_per_part<=128: p.error('Invalid concurrency') | |
| work=args.cache_dir.resolve(); work.mkdir(parents=True,exist_ok=True) | |
| config=work/'partition-config.json' | |
| if config.exists() and json.loads(config.read_text())['parts']!=args.parts: | |
| p.error('Use the same partition count when resuming, or a new cache directory.') | |
| config.write_text(json.dumps({'parts':args.parts})) | |
| items=[json.loads(s) for s in args.inventory.open()] | |
| expected={x['path']:x['hash'] for x in items} | |
| seen=set(); assigned=[[] for _ in range(args.parts)] | |
| for i in range(args.parts): | |
| done=work/f'part-{i}.sqlite'; checkpoint=work/f'part-{i}.building.sqlite' | |
| if done.exists() and not checkpoint.exists(): done.rename(checkpoint) | |
| if checkpoint.exists(): | |
| with sqlite3.connect(checkpoint) as c: | |
| retained={r[0] for r in c.execute('SELECT path,hash FROM files') if expected.get(r[0])==r[1]} | |
| if retained & seen: raise ValueError('Duplicate checkpoint objects') | |
| assigned[i]=[x for x in items if x['path'] in retained] | |
| seen.update(retained) | |
| for n,item in enumerate(x for x in items if x['path'] not in seen): | |
| assigned[n%args.parts].append(item) | |
| processes=[] | |
| for i in range(args.parts): | |
| inventory=work/f'inventory-{i}.jsonl' | |
| inventory.write_text(''.join(json.dumps(x)+'\n' for x in assigned[i])) | |
| log=(work/f'part-{i}.log').open('w') | |
| command=[sys.executable,str(ROOT/'build_full_index.py'),'--inventory',str(inventory), | |
| '--output',str(work/f'part-{i}.sqlite'),'--workers',str(args.workers_per_part)] | |
| processes.append((i,subprocess.Popen(command,stdout=log,stderr=subprocess.STDOUT),log)) | |
| failed=[] | |
| for i,process,log in processes: | |
| status=process.wait(); log.close() | |
| if status: failed.append(i) | |
| if failed: raise RuntimeError(f'Partitions {failed} failed; inspect logs and rerun to resume.') | |
| subprocess.run([sys.executable,str(ROOT/'merge_full_index.py'),'--inventory',str(args.inventory.resolve()), | |
| '--parts',*[str(work/f'part-{i}.sqlite') for i in range(args.parts)],'--output',str(args.output.resolve())],check=True) | |
| if __name__=='__main__': main() | |