#!/usr/bin/env python3 from datetime import datetime from typing import Iterable, NamedTuple, Optional from itertools import chain import porg from kython import listify from kython.org import parse_org_date from kython.kerror import Res, echain from mycfg import paths import pandas as pd # type: ignore class Entry(NamedTuple): dt: datetime ket: Optional[float]=None glu: Optional[float]=None vitd: Optional[float]=None b12: Optional[float]=None hdl: Optional[float]=None ldl: Optional[float]=None trig: Optional[float]=None extra: Optional[str]=None Result = Res[Entry] class ParseError(Exception): pass def try_float(s: str) -> Optional[float]: l = s.split() if len(l) == 0: return None x = l[0].strip() if len(x) == 0: return None return float(x) def iter_gluc_keto_data() -> Iterable[Result]: o = porg.Org.from_file(str(paths.blood.blood_log)) tbl = o.xpath('//table') for l in tbl.lines: kets = l['ket'].strip() glus = l['glu'].strip() extra = l['notes'] dt = parse_org_date(l['datetime']) assert isinstance(dt, datetime) ket = try_float(kets) glu = try_float(glus) yield Entry( dt=dt, ket=ket, glu=glu, extra=extra, ) def iter_tests_data() -> Iterable[Result]: o = porg.Org.from_file(str(paths.blood.blood_tests_log)) tbl = o.xpath('//table') for d in tbl.lines: try: dt = parse_org_date(d['datetime']) assert isinstance(dt, datetime) # TODO rest F = lambda n: try_float(d[n]) yield Entry( dt=dt, vitd=F('VD nm/L'), b12 =F('B12 pm/L'), hdl =F('HDL mm/L'), ldl =F('LDL mm/L'), trig=F('Trig mm/L'), extra=d['misc'], ) except Exception as e: print(e) yield echain(ParseError(str(d)), e) def data(): datas = list(chain(iter_gluc_keto_data(), iter_tests_data())) return list(sorted(datas, key=lambda d: getattr(d, 'dt', datetime.min))) @listify(wrapper=pd.DataFrame) def dataframe(): for d in data(): if isinstance(d, Exception): yield {'error': str(d)} else: yield d._asdict() def test(): print(dataframe()) assert len(dataframe()) > 10 def main(): print(data()) if __name__ == '__main__': main()