convert fallback location estimators to be iterators
This commit is contained in:
parent
1cf9dfe5dd
commit
da8f541cdc
4 changed files with 32 additions and 20 deletions
|
@ -1,17 +1,24 @@
|
|||
# TODO: add config here which passes kwargs to estimate_from (under_accuracy)
|
||||
# overwritable by passing the kwarg name here to the top-level estimate_location
|
||||
|
||||
from typing import Union
|
||||
from datetime import datetime
|
||||
from typing import Iterator
|
||||
|
||||
from my.location.fallback.common import estimate_from, FallbackLocation
|
||||
from my.core.source import import_source
|
||||
from my.location.fallback.common import estimate_from, FallbackLocation, DateExact
|
||||
|
||||
def estimate_location(dt: Union[datetime, float, int]) -> FallbackLocation:
|
||||
# note: the import_source returns an iterator
|
||||
@import_source(module_name="my.location.fallback.via_home")
|
||||
def _home_estimate(dt: DateExact) -> Iterator[FallbackLocation]:
|
||||
from my.location.fallback.via_home import estimate_location as via_home
|
||||
|
||||
yield from via_home(dt)
|
||||
|
||||
|
||||
|
||||
def estimate_location(dt: DateExact) -> FallbackLocation:
|
||||
loc = estimate_from(
|
||||
dt,
|
||||
estimators=(via_home,)
|
||||
estimators=(_home_estimate,)
|
||||
)
|
||||
if loc is None:
|
||||
raise ValueError("Could not estimate location")
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Callable, Sequence, Iterator, List, Union
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, date
|
||||
|
||||
from ..common import LocationProtocol, Location
|
||||
DateIsh = Union[datetime, float, int]
|
||||
DateExact = Union[datetime, float, int] # float/int as epoch timestamps
|
||||
|
||||
@dataclass
|
||||
class FallbackLocation(LocationProtocol):
|
||||
|
@ -62,28 +62,31 @@ class FallbackLocation(LocationProtocol):
|
|||
)
|
||||
|
||||
|
||||
LocationEstimator = Callable[[DateIsh], Optional[FallbackLocation]]
|
||||
# a location estimator can return multiple fallbacks, incase there are
|
||||
# differing accuracies/to allow for possible matches to be computed
|
||||
# iteratively
|
||||
LocationEstimator = Callable[[DateExact], Iterator[FallbackLocation]]
|
||||
LocationEstimators = Sequence[LocationEstimator]
|
||||
|
||||
# helper function, instead of dealing with datetimes while comparing, just use epoch timestamps
|
||||
def _datetime_timestamp(dt: DateIsh) -> float:
|
||||
def _datetime_timestamp(dt: DateExact) -> float:
|
||||
if isinstance(dt, datetime):
|
||||
return dt.timestamp()
|
||||
return float(dt)
|
||||
|
||||
def _iter_estimate_from(
|
||||
dt: DateIsh,
|
||||
dt: DateExact,
|
||||
estimators: LocationEstimators,
|
||||
) -> Iterator[FallbackLocation]:
|
||||
for est in estimators:
|
||||
loc = est(dt)
|
||||
if loc is None:
|
||||
loc = list(est(dt))
|
||||
if not loc:
|
||||
continue
|
||||
yield loc
|
||||
yield from loc
|
||||
|
||||
|
||||
def estimate_from(
|
||||
dt: DateIsh,
|
||||
dt: DateExact,
|
||||
estimators: LocationEstimators,
|
||||
*,
|
||||
first_match: bool = False,
|
||||
|
|
|
@ -5,12 +5,12 @@ Simple location provider, serving as a fallback when more detailed data isn't av
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime, time, timezone
|
||||
from functools import lru_cache
|
||||
from typing import Sequence, Tuple, Union, cast, List
|
||||
from typing import Sequence, Tuple, Union, cast, List, Iterator
|
||||
|
||||
from my.config import location as user_config
|
||||
|
||||
from my.location.common import LatLon, DateIsh
|
||||
from my.location.fallback.common import FallbackLocation
|
||||
from my.location.fallback.common import FallbackLocation, DateExact
|
||||
|
||||
@dataclass
|
||||
class Config(user_config):
|
||||
|
@ -85,24 +85,26 @@ def homes_cached() -> List[Tuple[datetime, LatLon]]:
|
|||
return list(config._history)
|
||||
|
||||
|
||||
def estimate_location(dt: Union[datetime, int, float]) -> FallbackLocation:
|
||||
def estimate_location(dt: DateExact) -> Iterator[FallbackLocation]:
|
||||
from my.location.fallback.common import _datetime_timestamp
|
||||
d: float = _datetime_timestamp(dt)
|
||||
hist = list(reversed(homes_cached()))
|
||||
for pdt, (lat, lon) in hist:
|
||||
if d >= pdt.timestamp():
|
||||
return FallbackLocation(
|
||||
yield FallbackLocation(
|
||||
lat=lat,
|
||||
lon=lon,
|
||||
accuracy=config.home_accuracy,
|
||||
dt=datetime.fromtimestamp(d, timezone.utc),
|
||||
datasource='via_home')
|
||||
return
|
||||
else:
|
||||
# I guess the most reasonable is to fallback on the first location
|
||||
lat, lon = hist[-1][1]
|
||||
return FallbackLocation(
|
||||
yield FallbackLocation(
|
||||
lat=lat,
|
||||
lon=lon,
|
||||
accuracy=config.home_accuracy,
|
||||
dt=datetime.fromtimestamp(d, timezone.utc),
|
||||
datasource='via_home')
|
||||
return
|
||||
|
|
|
@ -199,7 +199,7 @@ def _get_day_tz(d: date) -> Optional[pytz.BaseTzInfo]:
|
|||
|
||||
# ok to cache, there are only a few home locations?
|
||||
@lru_cache(maxsize=None)
|
||||
def _get_home_tz(loc) -> Optional[pytz.BaseTzInfo]:
|
||||
def _get_home_tz(loc: LatLon) -> Optional[pytz.BaseTzInfo]:
|
||||
(lat, lng) = loc
|
||||
finder = _timezone_finder(fast=False) # ok to use slow here for better precision
|
||||
zone = finder.timezone_at(lat=lat, lng=lng)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue