diff --git a/body/blood.py b/body/blood.py new file mode 100755 index 0000000..9919030 --- /dev/null +++ b/body/blood.py @@ -0,0 +1,121 @@ +#!/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 ..paths import LOGS, MY + +import pandas as pd # type: ignore + + +blood_tests_log = MY / 'blood.org' +blood_log = LOGS / 'blood.org' + +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(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(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()