Files
paper-atlas/collect_peerread.py
T
codex-bot 4a4272219e
Metadata integrity checks / metadata (push) Successful in 2s
Collect explicit public ICLR decisions and refresh metadata indexes
2026-11-06 03:12:44 +08:00

72 lines
4.2 KiB
Python

"""Collect explicit public ICLR decisions from the authors' PeerRead release.
Review bodies and parsed full paper text are deliberately not persisted.
"""
import argparse
import json
import time
import urllib.request
from collections import defaultdict
from pathlib import Path
from collect_pmlr import fetch
def collect(cache,out):
root = Path(out)
root.mkdir(parents=True,exist_ok=True)
commit = json.loads(fetch('https://api.github.com/repos/allenai/PeerRead/commits/master',cache))['sha']
tree = json.loads(fetch(f'https://api.github.com/repos/allenai/PeerRead/git/trees/{commit}?recursive=1',cache))
if tree.get('truncated'):
raise RuntimeError('Truncated repository tree')
paths = [v['path'] for v in tree['tree'] if v['path'].startswith('data/iclr_2017/') and '/reviews/' in v['path'] and v['path'].endswith('.json')]
if not paths:
raise RuntimeError('No explicit ICLR2017 metadata files found')
cache_dir = root/'peerread-normalized'/commit
cache_dir.mkdir(parents=True,exist_ok=True)
grouped = defaultdict(list)
for number,path in enumerate(paths,1):
external = '/'.join(path.split('/')[1:])
normalized_cache = cache_dir/(path.replace('/','_'))
if normalized_cache.exists():
record = json.loads(normalized_cache.read_text())
else:
raw_url = f'https://raw.githubusercontent.com/allenai/PeerRead/{commit}/{path}'
with urllib.request.urlopen(urllib.request.Request(raw_url,headers={'User-Agent':'PaperAtlas/0.1 metadata research'}),timeout=60) as response:
payload = response.read(3*1024**2+1)
if len(payload)>3*1024**2:
raise RuntimeError('Unexpected metadata size')
data = json.loads(payload)
conference = data.get('conference','')
if 'iclr' not in conference.lower() or '2017' not in conference:
raise RuntimeError('Unexpected conference metadata: '+conference)
accepted = data.get('accepted')
status = ('accepted' if accepted else 'rejected') if isinstance(accepted,bool) else 'unknown'
authors = data.get('authors') or []
if isinstance(authors,str):
authors = [author.strip() for author in authors.split(',') if author.strip()]
record = {'source':'peerread','external_id':external,'url':f'https://github.com/allenai/PeerRead/blob/{commit}/{path}','title':data['title'],'abstract':data.get('abstract'),'authors':authors,'identifiers':{},'venue':'ICLR','year':2017,'track':'workshop' if 'workshop' in conference.lower() else 'main','status':status,'raw_decision':json.dumps({'accepted':accepted}),'metadata':{'conference':conference,'dataset_commit':commit,'dataset_path':path,'original_id':data.get('id'),'accepted':accepted,'decision_provenance':'PeerRead authors public release; explicit label, not inferred from publication absence'}}
normalized_cache.write_text(json.dumps(record,ensure_ascii=False))
time.sleep(0.25)
grouped[record['track']].append(record)
if number%25==0:
print(json.dumps({'source':'peerread','collected':number,'expected':len(paths)}),flush=True)
for track,records in grouped.items():
target = root/f'peerread-iclr2017-{track}.jsonl'
part = target.with_suffix('.part')
with part.open('w') as output:
for record in records:
output.write(json.dumps(record,ensure_ascii=False)+'\n')
part.replace(target)
manifest = {'source':'peerread','venue':'ICLR','year':2017,'track':track,'count':len(records),'list_url':f'https://github.com/allenai/PeerRead/tree/{commit}/data/iclr_2017','dataset_commit':commit,'file':str(target),'decision_counts':{status:sum(r['status']==status for r in records) for status in ('accepted','rejected','unknown')}}
target.with_suffix('.manifest.json').write_text(json.dumps(manifest,indent=2))
print(json.dumps(manifest),flush=True)
if __name__=='__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--cache',required=True)
parser.add_argument('--out',required=True)
args = parser.parse_args()
collect(args.cache,args.out)