from pathlib import Path from fractions import Fraction as F import json, hashlib, datetime ROOT=Path(__file__).resolve().parent.parent E,P,J=F(25,23),F(70,69),F(300,299) def inv(n): if not isinstance(n,int) or n<0: raise ValueError('nonnegative integer duration required') if n==0:return 0 k=1 while n%10==0:n//=10;k*=10 return k*int(str(n)[::-1]) def clean(x): if isinstance(x,F):return x.numerator if x.denominator==1 else str(x) if isinstance(x,dict):return {str(k):clean(v) for k,v in x.items()} if isinstance(x,(list,tuple)):return [clean(v) for v in x] return x def begin(n,title,question,inputs,sources): previous=ROOT/'journal.json' rows=json.loads(previous.read_text()) if previous.exists() else [] if n!=532+len(rows):raise ValueError('Sequential research step required') pending=ROOT/'pending.json' if pending.exists(): saved=json.loads(pending.read_text()) assert (saved['step'],saved['title'],saved['question'],saved['inputs'],saved['sources'])==(n,title,question,clean(inputs),sources) return saved item=dict(step=n,title=title,question=question,inputs=clean(inputs),sources=sources, opened_utc=datetime.datetime.now(datetime.timezone.utc).isoformat(), predecessor_sha256=rows[-1]['sha256'] if rows else 'C531:646c8bb822355b60f1110fbb059453a1f0ebfaf7294c715f338ca64cf2bf5216') (ROOT/'pending.json').write_text(json.dumps(item,indent=2)+'\n') return item def finish(item,results,finding,next_question,checks): assert all(checks.values()),checks item.update(results=clean(results),finding=finding,reassessment=next_question,checks=checks, closed_utc=datetime.datetime.now(datetime.timezone.utc).isoformat()) item['sha256']=hashlib.sha256(json.dumps(item,sort_keys=True).encode()).hexdigest() p=ROOT/'journal.json'; rows=json.loads(p.read_text()) if p.exists() else [] rows.append(item);p.write_text(json.dumps(rows,indent=2,ensure_ascii=False)+'\n') (ROOT/'pending.json').unlink() print(json.dumps(dict(step=item['step'],results=item['results'],finding=finding,next=next_question),ensure_ascii=False))