Skip to content

location fallback system #262

@purarue

Description

@purarue

Am just posting/ideating this here to see if its something you're interested in adding, since this is a bit more state-ful than HPI typically is (this would include a CLI which saves data to disk based on prompting the user). I thought about making this a separate project but I think dealing with all this messy data is sort of HPI is good for, so it would be nice to have an interface thats easily extendible in here

Ive been creating something similar for my where_db CLI and we already have home locations as fallback, so I thought it would be nice to formalize it into an API thats easier to extend, like:

my/location/fallback/all.py
my/location/fallback/via_home.py (rename locations/homes.py to here)
my/location/fallback/common.py
my/location/fallback/via_prompt.py
my/location/fallback/via_photos.py
my/location/fallback/via_ip.py

via_photos because I have lots of photos on disk but not all of them I actually want to use for location, so this would let me confirm which ones to do that for (could also maybe improve on photos.py somehow)

via_prompt being a manual entry of the namedtuple described below

Namedtuple would be something like:

class FallbackLocation(NamedTuple):
    lat: float
    lon: float
    dt: datetime
    accuracy: Optional[float]
    elevation: Optional[float]
    duration: Optional[timedelta]
    end_dt: Optional[datetime]

    def to_location(self) -> Location:
          return Location(...)

Either duration (how long this location is valid for) or end_dt (when this location is no longer valid) has to be set.

And then all would call some function that prioritizes/picks which source to use, based on the order theyre returned in, like:

def estimate_location(dt: time) -> FallbackLocation:
    return estimate_from(
         dt,
         fallbacks=(via_prompt, via_photos, via_ip, via_home)
    )

It would call each fallback function, and then use the one with the closest accuracy (which typically would be entered or estimated through a config block in each module)

This would require the user to prompt the user, so could probably just have a main function and run this like python3 -m my.location.fallback.via_prompt? Or could hook it into the CLI, either way.

Strategy in general Ive thought of:

  • sort all valid locations by some accuracy threshold, find dates which dont have accurate locations
  • use other sources (ips, manual entry (via_prompt), homes) as fallbacks for each of those days
  • pick the one with the highest accuracy

The choices the user picks would cached (so they arent re-prompted), so this would need to save to a JSON file or something, e.g. to ~/data/locations/via_prompt.json, ~/data/locations/via_ip.json

Im a bit split between actually saving data, or saving a 'sourcemap/transform' of sorts -- I recently did something similar for my scramble_history project, which lets me define keys to look for on any object, and then it defines a mapping file which converts one model into another -- that way were not actually duplicating data, its a bit more programatic, and you can sort of define 'behavior' to transform one piece of data (e.g. IPs) into locations

Not heavily attached to any of these ideas

--

As a sidenote, I had another idea for sorted locations as we discussed in #237 -- I had an idea to create a custom class which just yields the iterator, but then in the merge in all.py, we can just do an isinstance check on the iterator itself to check if its the class, like

class SortedLocationIterator:
    def __init__(self, sorted_locations):
        self.location = iter(sorted_locations)

    def __iter__(self):
        return self

    def __next__(self):
        return next(self.location)


In [1]: import test

In [2]: x = test.SortedLocationIterator(range(5))

In [3]: x.__class__
Out[3]: test.SortedLocationIterator

In [4]: next(x)
Out[4]: 0

That way its still all backwards compatible and only if all sources are SortedLocationIterator do we do a mergesort of sorts.

This could all be added behind a flag as well, but would really speed up sorting locations

Then in tz.via_location for example, if all.py return type is a SortedLocationIterator, we know its been sorted by the user and we dont have to sort it ourself

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions