my.rescuetime: use rescuexport directly, add error handling & dataframe
This commit is contained in:
parent
e34c04ebc8
commit
28fcc1d9b6
3 changed files with 27 additions and 16 deletions
|
@ -28,7 +28,7 @@ def echain(ex: E, cause: Exception) -> E:
|
||||||
|
|
||||||
|
|
||||||
def split_errors(l: Iterable[ResT[T, E]], ET: Type[E]) -> Tuple[Iterable[T], Iterable[E]]:
|
def split_errors(l: Iterable[ResT[T, E]], ET: Type[E]) -> Tuple[Iterable[T], Iterable[E]]:
|
||||||
# TODO would be nice to have ET=Exception default?
|
# TODO would be nice to have ET=Exception default? but it causes some mypy complaints?
|
||||||
vit, eit = tee(l)
|
vit, eit = tee(l)
|
||||||
# TODO ugh, not sure if I can reconcile type checking and runtime and convince mypy that ET and E are the same type?
|
# TODO ugh, not sure if I can reconcile type checking and runtime and convince mypy that ET and E are the same type?
|
||||||
values: Iterable[T] = (
|
values: Iterable[T] = (
|
||||||
|
|
|
@ -40,8 +40,6 @@ def setup_logger(logger: logging.Logger, level: LevelIsh) -> None:
|
||||||
|
|
||||||
|
|
||||||
class LazyLogger(logging.Logger):
|
class LazyLogger(logging.Logger):
|
||||||
# TODO perhaps should use __new__?
|
|
||||||
|
|
||||||
def __new__(cls, name, level: LevelIsh = 'DEBUG'):
|
def __new__(cls, name, level: LevelIsh = 'DEBUG'):
|
||||||
logger = logging.getLogger(name)
|
logger = logging.getLogger(name)
|
||||||
# this is called prior to all _log calls so makes sense to do it here?
|
# this is called prior to all _log calls so makes sense to do it here?
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
'''
|
'''
|
||||||
Rescuetime (activity tracking) data
|
Rescuetime (phone activity tracking) data.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -9,8 +9,7 @@ from typing import Sequence, Iterable
|
||||||
from .core import get_files, LazyLogger
|
from .core import get_files, LazyLogger
|
||||||
from .core.common import mcachew
|
from .core.common import mcachew
|
||||||
from .core.error import Res, split_errors
|
from .core.error import Res, split_errors
|
||||||
|
from .core.pandas import check_dataframe as cdf
|
||||||
import more_itertools
|
|
||||||
|
|
||||||
from my.config import rescuetime as config
|
from my.config import rescuetime as config
|
||||||
|
|
||||||
|
@ -22,27 +21,40 @@ def inputs() -> Sequence[Path]:
|
||||||
return get_files(config.export_path)
|
return get_files(config.export_path)
|
||||||
|
|
||||||
|
|
||||||
import my.config.repos.rescuexport.dal as dal
|
# pip git+https://github.com/karlicoss/rescuexport
|
||||||
|
import rescuexport.dal as dal
|
||||||
DAL = dal.DAL
|
DAL = dal.DAL
|
||||||
Entry = dal.Entry
|
Entry = dal.Entry
|
||||||
|
|
||||||
|
|
||||||
@mcachew(hashf=lambda: inputs())
|
@mcachew(hashf=lambda: inputs())
|
||||||
def entries() -> Iterable[Entry]:
|
def entries() -> Iterable[Res[Entry]]:
|
||||||
dal = DAL(inputs())
|
dal = DAL(inputs())
|
||||||
it = dal.entries()
|
it = dal.entries()
|
||||||
vit, eit = split_errors(it, ET=Exception)
|
yield from dal.entries()
|
||||||
# todo handle errors, I guess initially I didn't because it's unclear how to easily group?
|
|
||||||
# todo would be nice if logger unwrapped causes by default??
|
|
||||||
yield from vit
|
|
||||||
|
|
||||||
|
|
||||||
def groups(gap=timedelta(hours=3)):
|
def groups(gap=timedelta(hours=3)) -> Iterable[Res[Sequence[Entry]]]:
|
||||||
vit = entries()
|
vit, eit = split_errors(entries(), ET=Exception)
|
||||||
|
yield from eit
|
||||||
|
import more_itertools
|
||||||
from more_itertools import split_when
|
from more_itertools import split_when
|
||||||
yield from split_when(vit, lambda a, b: (b.dt - a.dt) > gap)
|
yield from split_when(vit, lambda a, b: (b.dt - a.dt) > gap)
|
||||||
|
|
||||||
|
|
||||||
|
@cdf
|
||||||
|
def dataframe():
|
||||||
|
import pandas as pd # type: ignore
|
||||||
|
# type: ignore[call-arg, attr-defined]
|
||||||
|
def it():
|
||||||
|
for e in entries():
|
||||||
|
if isinstance(e, Exception):
|
||||||
|
yield dict(error=str(e))
|
||||||
|
else:
|
||||||
|
yield e._asdict()
|
||||||
|
return pd.DataFrame(it())
|
||||||
|
|
||||||
|
|
||||||
def stats():
|
def stats():
|
||||||
from .core import stat
|
from .core import stat
|
||||||
return {
|
return {
|
||||||
|
@ -71,7 +83,7 @@ def fake_data(rows=1000):
|
||||||
f.write_text(json.dumps(dal.fake_data_generator(rows=rows)))
|
f.write_text(json.dumps(dal.fake_data_generator(rows=rows)))
|
||||||
yield
|
yield
|
||||||
# TODO ok, now it's something that actually could run on CI!
|
# TODO ok, now it's something that actually could run on CI!
|
||||||
|
# todo would be kinda nice if doctor could run against the fake data, to have a basic health check of the module?
|
||||||
|
|
||||||
|
|
||||||
# todo not sure if I want to keep these here? vvv
|
# todo not sure if I want to keep these here? vvv
|
||||||
|
@ -83,7 +95,8 @@ def fill_influxdb():
|
||||||
db = 'test'
|
db = 'test'
|
||||||
client.drop_database(db)
|
client.drop_database(db)
|
||||||
client.create_database(db)
|
client.create_database(db)
|
||||||
vit = entries()
|
# todo handle errors
|
||||||
|
vit = (e for e in entries() if isinstance(e, dal.Entry))
|
||||||
jsons = [{
|
jsons = [{
|
||||||
"measurement": 'phone',
|
"measurement": 'phone',
|
||||||
"tags": {},
|
"tags": {},
|
||||||
|
|
Loading…
Add table
Reference in a new issue