"""Extract the fixed printed TableC5 in two native text modes; no OCR or hidden catalogue.""" import signal signal.alarm(120) import argparse,hashlib,json,re,subprocess from pathlib import Path from io_helpers import PACKAGE,read_json,write_json def parse(text): rows=[];text=text[text.index('Table C.5. Chemical abundances.'):] for line in text.splitlines(): tokens=line.split() if not tokens or not re.fullmatch(r'U?ET\d{4}',tokens[0]):continue if len(tokens)!=37:raise ValueError('Unexpected originalC5width: '+tokens[0]) values=[None if value=='...'else float(value.replace('−','-'))for value in tokens[1:]] rows.append({'id':tokens[0],'feh':values[0],'fehError':values[1],'mgfe':values[6],'mgfeError':values[7],'allOriginalValues':values}) if len(rows)!=99 or len({row['id']for row in rows})!=99:raise ValueError('Expected99unique originalC5rows') return rows def main(): parser=argparse.ArgumentParser();parser.add_argument('--pdf',type=Path,required=True);parser.add_argument('--output',type=Path,default=Path('reader-private/hill-saved-observations.json'));args=parser.parse_args();identities=read_json(PACKAGE/'source-identities.json');expected=next(row for row in identities['sources']if row['file']=='hill-v2.pdf');body=args.pdf.read_bytes() if len(body)!=expected['bytes']or hashlib.sha256(body).hexdigest()!=expected['sha256']:raise ValueError('Fixed originalPDFidentity mismatch; stop without reinterpretation') modes=[] for mode in ['-layout','-raw']: result=subprocess.run(['pdftotext','-f','33','-l','34',mode,str(args.pdf),'-'],capture_output=True,text=True,check=True,timeout=30);modes.append(parse(result.stdout)) if modes[0]!=modes[1]:raise ValueError('All36native values must match both extraction modes') finite=sum(all(row.get(key)is not None for key in ['feh','mgfe','fehError','mgfeError'])for row in modes[0]) if finite!=96:raise ValueError('Expected96finiteMgFepairs; missing values are not imputed') write_json(args.output,{'kind':'Hill1812.01486v2-original-private','sourcePdfSha256':expected['sha256'],'pages':[33,34],'rows':modes[0],'all36OriginalFieldsAgree':True,'finiteMgFeRows':finite,'selection':'Methods§2:central25arcmin-diameterFLAMESfield,upperRGBI<17.5,quality/member cuts; not an unbiasedbirthmasssample','covariance':'Fullperstarcovarianceunavailable; anyrhoisexplicitlyassumed','solarZeroPoint':'Originalcoordinatesunchanged; numericaloffsettoVICE/Asplundnotestablished'});print('PASS:99native rows/96finiteMgFe; all36fieldsagree in two modes') if __name__=='__main__':main()