HPI/my/body/weight.py
2024-10-19 23:41:22 +01:00

99 lines
2.2 KiB
Python

'''
Weight data (manually logged)
'''
from collections.abc import Iterator
from dataclasses import dataclass
from datetime import datetime
from typing import Any
from my import orgmode
from my.core import make_logger
from my.core.error import Res, extract_error_datetime, set_error_datetime
config = Any
def make_config() -> config:
from my.config import weight as user_config # type: ignore[attr-defined]
return user_config()
log = make_logger(__name__)
@dataclass
class Entry:
dt: datetime
value: float
# TODO comment??
Result = Res[Entry]
def from_orgmode() -> Iterator[Result]:
cfg = make_config()
orgs = orgmode.query()
for o in orgmode.query().all():
if 'weight' not in o.tags:
continue
try:
# TODO can it throw? not sure
created = o.created
assert created is not None
except Exception as e:
log.exception(e)
yield e
continue
try:
w = float(o.heading)
except Exception as e:
set_error_datetime(e, dt=created)
log.exception(e)
yield e
continue
# FIXME use timezone provider
created = cfg.default_timezone.localize(created)
assert created is not None # ??? somehow mypy wasn't happy?
yield Entry(
dt=created,
value=w,
# TODO add org note content as comment?
)
def make_dataframe(data: Iterator[Result]):
import pandas as pd
def it():
for e in data:
if isinstance(e, Exception):
dt = extract_error_datetime(e)
yield {
'dt': dt,
'error': str(e),
}
else:
yield {
'dt': e.dt,
'weight': e.value,
}
df = pd.DataFrame(it())
df = df.set_index('dt')
# TODO not sure about UTC??
df.index = pd.to_datetime(df.index, utc=True)
return df
def dataframe():
entries = from_orgmode()
return make_dataframe(entries)
# TODO move to a submodule? e.g. my.body.weight.orgmode?
# so there could be more sources
# not sure about my.body thing though