import dataclasses import datetime from collections.abc import Iterator, Sequence HIDDEN_LABEL_CATEGORY = '__' DEFAULT_ESTIMATED_DURATION = datetime.timedelta(hours=1) @dataclasses.dataclass(frozen=True, order=True) class Label: category: str label: str def __post_init__(self): assert self.category is not None assert ':' not in self.category assert self.label is not None @dataclasses.dataclass(frozen=True, order=True) class ActivitySample: labels: Sequence[Label] start_at: datetime.datetime | None end_at: datetime.datetime | None @dataclasses.dataclass(frozen=True, order=True) class RealizedActivitySample(ActivitySample): start_at: datetime.datetime end_at: datetime.datetime def heuristically_realize_samples( samples: list[ActivitySample], ) -> Iterator[RealizedActivitySample]: """Secret sauce. Guarentees that: * No samples overlap. """ previous_sample_end = None for sample in samples: end_at = sample.end_at if previous_sample_end is None: if end_at.tzinfo: previous_sample_end = datetime.datetime.fromtimestamp(0, datetime.UTC) else: previous_sample_end = datetime.datetime.fromtimestamp(0) assert previous_sample_end <= end_at, 'Iterating in incorrect order' # TODO: Allow end_at is None start_at = sample.start_at if start_at is None: estimated_duration: datetime.timedelta = DEFAULT_ESTIMATED_DURATION start_at = max(previous_sample_end, end_at - estimated_duration) del estimated_duration yield RealizedActivitySample( labels=sample.labels, end_at=end_at, start_at=start_at, ) previous_sample_end = sample.end_at del sample