diff --git a/src/quantifiedme/activitywatch.py b/src/quantifiedme/activitywatch.py index c4ac8e1..67e483f 100644 --- a/src/quantifiedme/activitywatch.py +++ b/src/quantifiedme/activitywatch.py @@ -70,10 +70,9 @@ def create_fake_events(start: datetime, end: datetime) -> Iterable[Event]: time_passed += duration if start + time_passed > end: break - data = random.choices( + if data := random.choices( [d[1] for d in fakedata_weights], [d[0] for d in fakedata_weights] - )[0] - if data: + )[0]: yield Event(timestamp=timestamp, duration=duration, data=data) @@ -183,12 +182,12 @@ def load_complete_timeline( # Verify that no events are older than `since` print(f"Query start: {since}") print(f"Events start: {events[0].timestamp}") - assert all([since <= e.timestamp for e in events]) + assert all(since <= e.timestamp for e in events) # Verify that no events take place in the future # FIXME: Doesn't work with fake data, atm if "fake" not in datasources: - assert all([e.timestamp + e.duration <= now for e in events]) + assert all(e.timestamp + e.duration <= now for e in events) # Verify that no events overlap verify_no_overlap(events) @@ -200,36 +199,36 @@ def load_complete_timeline( def classify(events: List[Event], personal: bool) -> List[Event]: - # TODO: Move to example config.toml - classes = [ - # (Social) Media - (r"Facebook|facebook.com", "Social Media", "Media"), - (r"Reddit|reddit.com", "Social Media", "Media"), - (r"Spotify|spotify.com", "Music", "Media"), - (r"subcategory without matching", "Video", "Media"), - (r"YouTube|youtube.com", "YouTube", "Video"), - (r"Plex|plex.tv", "Plex", "Video"), - (r"Fallout 4", "Games", "Media"), - # Work - (r"github.com|stackoverflow.com", "Programming", "Work"), - (r"[Aa]ctivity[Ww]atch|aw-.*", "ActivityWatch", "Programming"), - (r"[Qq]uantified[Mm]e", "QuantifiedMe", "Programming"), - (r"[Tt]hankful", "Thankful", "Programming"), - # School - (r"subcategory without matching", "School", "Work"), - (r"Duolingo|Brilliant|Khan Academy", "Self-directed", "School"), - (r"Analysis in One Variable", "Maths", "School"), - (r"Applied Machine Learning", "CS", "School"), - (r"Advanced Web Security", "CS", "School"), - ] - # Now load the classes from within the notebook, or from a CSV file. - load_from_file = True if personal else False + load_from_file = personal if load_from_file: # TODO: Move categories into config.toml itself aw_research.classify._init_classes(filename=load_config()["data"]["categories"]) else: logger.info("Using example categories") + # TODO: Move to example config.toml + classes = [ + # (Social) Media + (r"Facebook|facebook.com", "Social Media", "Media"), + (r"Reddit|reddit.com", "Social Media", "Media"), + (r"Spotify|spotify.com", "Music", "Media"), + (r"subcategory without matching", "Video", "Media"), + (r"YouTube|youtube.com", "YouTube", "Video"), + (r"Plex|plex.tv", "Plex", "Video"), + (r"Fallout 4", "Games", "Media"), + # Work + (r"github.com|stackoverflow.com", "Programming", "Work"), + (r"[Aa]ctivity[Ww]atch|aw-.*", "ActivityWatch", "Programming"), + (r"[Qq]uantified[Mm]e", "QuantifiedMe", "Programming"), + (r"[Tt]hankful", "Thankful", "Programming"), + # School + (r"subcategory without matching", "School", "Work"), + (r"Duolingo|Brilliant|Khan Academy", "Self-directed", "School"), + (r"Analysis in One Variable", "Maths", "School"), + (r"Applied Machine Learning", "CS", "School"), + (r"Advanced Web Security", "CS", "School"), + ] + # gives non-sensical type error on check: # Argument "new_classes" to "_init_classes" has incompatible type "List[Tuple[str, str, str]]"; expected "Optional[List[Tuple[str, str, Optional[str]]]]" aw_research.classify._init_classes(new_classes=classes) # type: ignore @@ -241,7 +240,7 @@ def classify(events: List[Event], personal: bool) -> List[Event]: def load_category_df(events: List[Event]): tss = {} - all_categories = list(set(t for e in events for t in e.data["$tags"])) + all_categories = list({t for e in events for t in e.data["$tags"]}) for cat in all_categories: try: tss[cat] = categorytime_per_day(events, cat) diff --git a/src/quantifiedme/influxdb.py b/src/quantifiedme/influxdb.py index 66aa50a..15e2244 100644 --- a/src/quantifiedme/influxdb.py +++ b/src/quantifiedme/influxdb.py @@ -33,8 +33,7 @@ def copy_bucket_to_influxdb(aw: ActivityWatchClient, bucket_id: str): def init_influxdb(): print("Creating bucket") bucket_api = client.buckets_api() - existing_bucket = bucket_api.find_bucket_by_name(bucket_name_influx) - if existing_bucket: + if existing_bucket := bucket_api.find_bucket_by_name(bucket_name_influx): print("Bucket already existed, replacing") bucket_api.delete_bucket(existing_bucket) bucket_api.create_bucket(bucket_name=bucket_name_influx) @@ -67,5 +66,5 @@ def send_events_to_influxdb(events: list[Event], bucket_id_aw: str): if __name__ == "__main__": init_influxdb() aw = ActivityWatchClient(testing=True) - copy_bucket_to_influxdb(aw, "aw-watcher-afk_" + hostname) - copy_bucket_to_influxdb(aw, "aw-watcher-window_" + hostname) + copy_bucket_to_influxdb(aw, f"aw-watcher-afk_{hostname}") + copy_bucket_to_influxdb(aw, f"aw-watcher-window_{hostname}") diff --git a/src/quantifiedme/load_toggl.py b/src/quantifiedme/load_toggl.py index 91f5512..95d1046 100644 --- a/src/quantifiedme/load_toggl.py +++ b/src/quantifiedme/load_toggl.py @@ -13,12 +13,10 @@ def load_toggl(start: datetime, stop: datetime) -> List[Event]: - # The Toggl API has a query limit of 1 year if stop - start < timedelta(days=360): return _load_toggl(start, stop) - else: - split = stop - timedelta(days=360) - return load_toggl(start, split) + _load_toggl(split, stop) + split = stop - timedelta(days=360) + return load_toggl(start, split) + _load_toggl(split, stop) def _load_toggl(start: datetime, stop: datetime) -> List[Event]: @@ -31,7 +29,7 @@ def entries_from_all_workspaces() -> List[dict]: workspaces = list(api.Workspace.objects.all()) print(workspaces) print([w.id for w in workspaces]) - print(f"Found {len(workspaces)} workspaces: {list(w.name for w in workspaces)}") + print(f"Found {len(workspaces)} workspaces: {[w.name for w in workspaces]}") entries: List[dict] = [ e.to_dict() for workspace in workspaces diff --git a/src/quantifiedme/qslang.py b/src/quantifiedme/qslang.py index 949761e..cdd51f7 100644 --- a/src/quantifiedme/qslang.py +++ b/src/quantifiedme/qslang.py @@ -48,7 +48,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): def load_df(events: List[Event] = None) -> pd.DataFrame: if events is None: events = load_events() - events = [e for e in events] + events = list(events) with DuplicateFilter(logger): for e in events: @@ -75,13 +75,13 @@ def load_df(events: List[Event] = None) -> pd.DataFrame: "date": (e.timestamp - date_offset).date(), "substance": e.data.get("substance"), "dose": e.data.get("amount_pint") or 0, - # FIXME: Only supports one tag - "tag": list(sorted(e.data.get("tags") or set(["none"])))[0], + "tag": list(sorted(e.data.get("tags") or {"none"}))[0], } for e in events ] ) + # Replace NaN with mean of non-zero doses for substance in set(df["substance"]): mean_dose = df[df["substance"] == substance].mean() @@ -99,7 +99,7 @@ def to_series(df: pd.DataFrame, tag: str = None, substance: str = None) -> pd.Se """ assert tag or substance key = "tag" if tag else "substance" - val = tag if tag else substance + val = tag or substance # Filter for the tag/substance we want df = df[df[key] == val] @@ -133,7 +133,7 @@ def to_df_daily(events: List[Event]): for tag in tags: df[f"tag:{tag}"] = to_series(df_src, tag=tag) - substances = set(s for s in df_src["substance"] if s) + substances = {s for s in df_src["substance"] if s} for subst in substances: colname = subst.lower().replace("-", "").replace(" ", "") df[colname] = to_series(df_src, substance=subst) @@ -143,8 +143,9 @@ def _missing_dates(): # Useful helper function to find dates without any entries df = load_df() dates_with_entries = sorted( - set((d + timedelta(hours=-4)).date() for d in df["timestamp"]) + {(d + timedelta(hours=-4)).date() for d in df["timestamp"]} ) + all_dates = sorted( d.date() for d in pd.date_range(min(dates_with_entries), max(dates_with_entries)) diff --git a/tests/test_load.py b/tests/test_load.py index f3cc4d9..d3c5f33 100644 --- a/tests/test_load.py +++ b/tests/test_load.py @@ -27,7 +27,7 @@ def test_load_qslang(): series_nonzero = series[series != 0] # More than 10mg - assert (10e-6 <= series_nonzero).all() + assert (series_nonzero >= 10e-6).all() # Less than 500mg assert (series_nonzero <= 500e-6).all() @@ -40,7 +40,7 @@ def test_load_qslang(): series_nonzero = series[series != 0] # More than 100mg - assert (100e-6 <= series_nonzero).all() + assert (series_nonzero >= 100e-6).all() # Less than 5000mg # FIXME: Seems some entries have >5000mg?