geo-activity-playground 1.6.0__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geo_activity_playground/__main__.py +8 -0
- geo_activity_playground/core/datamodel.py +28 -9
- geo_activity_playground/core/meta_search.py +1 -3
- geo_activity_playground/core/test_meta_search.py +4 -4
- geo_activity_playground/explorer/tile_visits.py +19 -11
- geo_activity_playground/importers/activity_parsers.py +15 -8
- geo_activity_playground/importers/strava_api.py +24 -6
- geo_activity_playground/webui/app.py +18 -3
- geo_activity_playground/webui/blueprints/eddington_blueprints.py +1 -5
- geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py +1 -1
- geo_activity_playground/webui/blueprints/heatmap_blueprint.py +1 -1
- geo_activity_playground/webui/blueprints/photo_blueprint.py +1 -0
- geo_activity_playground/webui/blueprints/search_blueprint.py +1 -1
- geo_activity_playground/webui/blueprints/summary_blueprint.py +1 -1
- geo_activity_playground/webui/blueprints/upload_blueprint.py +6 -1
- {geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/METADATA +1 -1
- {geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/RECORD +20 -20
- {geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/LICENSE +0 -0
- {geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/WHEEL +0 -0
- {geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/entry_points.txt +0 -0
@@ -53,6 +53,8 @@ def main() -> None:
|
|
53
53
|
options.skip_reload,
|
54
54
|
host=options.host,
|
55
55
|
port=options.port,
|
56
|
+
strava_begin=options.strava_begin,
|
57
|
+
strava_end=options.strava_end,
|
56
58
|
)
|
57
59
|
)
|
58
60
|
subparser.add_argument(
|
@@ -62,6 +64,12 @@ def main() -> None:
|
|
62
64
|
"--port", default=5000, type=int, help="the port to run listen on"
|
63
65
|
)
|
64
66
|
subparser.add_argument("--skip-reload", action=argparse.BooleanOptionalAction)
|
67
|
+
subparser.add_argument(
|
68
|
+
"--strava-begin", help="Start date to limit Strava sync, format YYYY-MM-DD"
|
69
|
+
)
|
70
|
+
subparser.add_argument(
|
71
|
+
"--strava-end", help="End date to limit Strava sync, format YYYY-MM-DD"
|
72
|
+
)
|
65
73
|
|
66
74
|
subparser = subparsers.add_parser(
|
67
75
|
"heatmap-video", help="Create a video with the evolution of the heatmap"
|
@@ -231,7 +231,7 @@ class Activity(DB.Model):
|
|
231
231
|
return self.start
|
232
232
|
|
233
233
|
@property
|
234
|
-
def
|
234
|
+
def start_local(self) -> Optional[datetime.datetime]:
|
235
235
|
if self.start:
|
236
236
|
return self.start.replace(microsecond=0, tzinfo=zoneinfo.ZoneInfo("UTC"))
|
237
237
|
else:
|
@@ -270,6 +270,7 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
270
270
|
Activity.path,
|
271
271
|
Activity.distance_km,
|
272
272
|
Activity.start,
|
273
|
+
Activity.iana_timezone,
|
273
274
|
Activity.elapsed_time,
|
274
275
|
Activity.moving_time,
|
275
276
|
Activity.start_latitude,
|
@@ -302,6 +303,24 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
302
303
|
# df["start"] = pd.Series(start)
|
303
304
|
df["elapsed_time"] = pd.to_timedelta(df["elapsed_time"])
|
304
305
|
|
306
|
+
start_local = []
|
307
|
+
for start, iana_timezone in zip(df["start"], df["iana_timezone"]):
|
308
|
+
if pd.isna(start) or iana_timezone is None:
|
309
|
+
start_local.append(start)
|
310
|
+
else:
|
311
|
+
start_local.append(
|
312
|
+
start.tz_localize(zoneinfo.ZoneInfo("UTC"))
|
313
|
+
.tz_convert(iana_timezone)
|
314
|
+
.tz_localize(None)
|
315
|
+
)
|
316
|
+
df["start_local"] = start_local
|
317
|
+
|
318
|
+
# Work around bytes stored in DB.
|
319
|
+
df["calories"] = [
|
320
|
+
sum(a * 256**b for b, a in enumerate(c)) if isinstance(c, bytes) else c
|
321
|
+
for c in df["calories"]
|
322
|
+
]
|
323
|
+
|
305
324
|
for old, new in [
|
306
325
|
("elapsed_time", "average_speed_elapsed_kmh"),
|
307
326
|
("moving_time", "average_speed_moving_kmh"),
|
@@ -312,14 +331,14 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
312
331
|
df.loc[mask, old].dt.total_seconds() / 3_600
|
313
332
|
)
|
314
333
|
|
315
|
-
df["date"] = df["
|
316
|
-
df["year"] = df["
|
317
|
-
df["month"] = df["
|
318
|
-
df["day"] = df["
|
319
|
-
df["week"] = df["
|
320
|
-
df["day_of_week"] = df["
|
321
|
-
df["iso_year"] = df["
|
322
|
-
df["iso_day"] = df["
|
334
|
+
df["date"] = df["start_local"].dt.date
|
335
|
+
df["year"] = df["start_local"].dt.year
|
336
|
+
df["month"] = df["start_local"].dt.month
|
337
|
+
df["day"] = df["start_local"].dt.day
|
338
|
+
df["week"] = df["start_local"].dt.isocalendar().week
|
339
|
+
df["day_of_week"] = df["start_local"].dt.day_of_week
|
340
|
+
df["iso_year"] = df["start_local"].dt.isocalendar().year
|
341
|
+
df["iso_day"] = df["start_local"].dt.isocalendar().day
|
323
342
|
df["hours"] = df["elapsed_time"].dt.total_seconds() / 3_600
|
324
343
|
df["hours_moving"] = df["moving_time"].dt.total_seconds() / 3_600
|
325
344
|
df["iso_year_week"] = [
|
@@ -24,7 +24,7 @@ def test_empty_query() -> None:
|
|
24
24
|
|
25
25
|
search_query = SearchQuery()
|
26
26
|
|
27
|
-
actual = apply_search_query(
|
27
|
+
actual = apply_search_query(search_query)
|
28
28
|
assert (actual["id"] == activity_meta["id"]).all()
|
29
29
|
|
30
30
|
|
@@ -43,7 +43,7 @@ def test_equipment_query() -> None:
|
|
43
43
|
}
|
44
44
|
)
|
45
45
|
search_query = SearchQuery(equipment=["B"])
|
46
|
-
actual = apply_search_query(
|
46
|
+
actual = apply_search_query(search_query)
|
47
47
|
assert set(actual["id"]) == {2, 3}
|
48
48
|
|
49
49
|
|
@@ -62,7 +62,7 @@ def test_date_query() -> None:
|
|
62
62
|
}
|
63
63
|
)
|
64
64
|
search_query = SearchQuery(start_begin=datetime.date(2024, 12, 31))
|
65
|
-
actual = apply_search_query(
|
65
|
+
actual = apply_search_query(search_query)
|
66
66
|
assert set(actual["id"]) == {2}
|
67
67
|
|
68
68
|
|
@@ -81,7 +81,7 @@ def test_name_query() -> None:
|
|
81
81
|
}
|
82
82
|
)
|
83
83
|
search_query = SearchQuery(name="Test1")
|
84
|
-
actual = apply_search_query(
|
84
|
+
actual = apply_search_query(search_query)
|
85
85
|
assert set(actual["id"]) == {1}
|
86
86
|
|
87
87
|
|
@@ -185,10 +185,13 @@ def compute_tile_visits_new(
|
|
185
185
|
|
186
186
|
for zoom in reversed(range(20)):
|
187
187
|
tile_state = tile_visit_accessor.tile_state
|
188
|
-
if
|
189
|
-
tile_state["tile_history"][zoom]
|
190
|
-
|
191
|
-
|
188
|
+
if (
|
189
|
+
len(tile_state["tile_history"][zoom])
|
190
|
+
and not (
|
191
|
+
tile_state["tile_history"][zoom]["time"].dropna().diff().dropna()
|
192
|
+
>= datetime.timedelta(seconds=0)
|
193
|
+
).all()
|
194
|
+
):
|
192
195
|
logger.warning(
|
193
196
|
f"The order of the tile history at {zoom=} is not chronological, resetting."
|
194
197
|
)
|
@@ -251,12 +254,17 @@ def _process_activity(
|
|
251
254
|
|
252
255
|
first_time = tile_visit.get("first_time", None)
|
253
256
|
last_time = tile_visit.get("last_time", None)
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
257
|
+
try:
|
258
|
+
if first_time is None or time < first_time:
|
259
|
+
tile_visit["first_id"] = activity_id
|
260
|
+
tile_visit["first_time"] = time
|
261
|
+
if last_time is None or time > last_time:
|
262
|
+
tile_visit["last_id"] = activity_id
|
263
|
+
tile_visit["last_time"] = time
|
264
|
+
except TypeError as e:
|
265
|
+
raise TypeError(
|
266
|
+
f"Mismatch in timezone awareness: {time=}, {first_time=}, {last_time=}"
|
267
|
+
) from e
|
260
268
|
|
261
269
|
activities_per_tile[tile].add(activity_id)
|
262
270
|
|
@@ -273,7 +281,7 @@ def _process_activity(
|
|
273
281
|
def _tiles_from_points(
|
274
282
|
time_series: pd.DataFrame, zoom: int
|
275
283
|
) -> Iterator[tuple[datetime.datetime, int, int]]:
|
276
|
-
# Some people haven't localized their time series yet. This breaks the tile history part. Just assume that it is UTC, should be good enough for tiles.
|
284
|
+
# XXX Some people haven't localized their time series yet. This breaks the tile history part. Just assume that it is UTC, should be good enough for tiles.
|
277
285
|
if time_series["time"].dt.tz is None:
|
278
286
|
time_series = time_series.copy()
|
279
287
|
time_series["time"].dt.tz_localize(zoneinfo.ZoneInfo("UTC"))
|
@@ -4,6 +4,7 @@ import logging
|
|
4
4
|
import pathlib
|
5
5
|
import xml
|
6
6
|
from collections.abc import Iterator
|
7
|
+
from typing import Union
|
7
8
|
|
8
9
|
import charset_normalizer
|
9
10
|
import dateutil.parser
|
@@ -127,7 +128,9 @@ def read_fit_activity(path: pathlib.Path, open) -> tuple[Activity, pd.DataFrame]
|
|
127
128
|
if "altitude" in fields:
|
128
129
|
row["elevation"] = values["altitude"]
|
129
130
|
if "enhanced_altitude" in fields:
|
130
|
-
row["elevation"] =
|
131
|
+
row["elevation"] = _first_of_tuple(
|
132
|
+
values["enhanced_altitude"]
|
133
|
+
)
|
131
134
|
if "speed" in fields:
|
132
135
|
factor = _fit_speed_unit_factor(fields["speed"].units)
|
133
136
|
row["speed"] = values["speed"] * factor
|
@@ -135,12 +138,9 @@ def read_fit_activity(path: pathlib.Path, open) -> tuple[Activity, pd.DataFrame]
|
|
135
138
|
factor = _fit_speed_unit_factor(
|
136
139
|
fields["enhanced_speed"].units
|
137
140
|
)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
logger.warning(
|
142
|
-
f'Cannot work with {values["enhanced_speed"]!r}, {factor!r}'
|
143
|
-
)
|
141
|
+
row["speed"] = (
|
142
|
+
_first_of_tuple(values["enhanced_speed"]) * factor
|
143
|
+
)
|
144
144
|
if "grade" in fields:
|
145
145
|
row["grade"] = values["grade"]
|
146
146
|
if "temperature" in fields:
|
@@ -158,7 +158,7 @@ def read_fit_activity(path: pathlib.Path, open) -> tuple[Activity, pd.DataFrame]
|
|
158
158
|
kind_name += " " + str(values["sub_sport"])
|
159
159
|
activity.kind = get_or_make_kind(kind_name)
|
160
160
|
if "total_calories" in fields:
|
161
|
-
activity.calories = values["total_calories"]
|
161
|
+
activity.calories = int(str(values["total_calories"]))
|
162
162
|
if "total_strides" in fields:
|
163
163
|
activity.steps = 2 * int(values["total_strides"])
|
164
164
|
|
@@ -174,6 +174,13 @@ def _fit_speed_unit_factor(unit: str) -> float:
|
|
174
174
|
raise ActivityParseError(f"Unknown speed unit {unit}")
|
175
175
|
|
176
176
|
|
177
|
+
def _first_of_tuple(value: Union[float, tuple[float, float]]) -> float:
|
178
|
+
try:
|
179
|
+
return float(value)
|
180
|
+
except TypeError:
|
181
|
+
return float(value[0])
|
182
|
+
|
183
|
+
|
177
184
|
def read_gpx_activity(path: pathlib.Path, open) -> pd.DataFrame:
|
178
185
|
points = []
|
179
186
|
with open(path, "rb") as f:
|
@@ -4,6 +4,7 @@ import pathlib
|
|
4
4
|
import pickle
|
5
5
|
import time
|
6
6
|
import zoneinfo
|
7
|
+
from typing import Optional
|
7
8
|
|
8
9
|
import pandas as pd
|
9
10
|
from stravalib import Client
|
@@ -80,8 +81,12 @@ def import_from_strava_api(
|
|
80
81
|
config: Config,
|
81
82
|
repository: ActivityRepository,
|
82
83
|
tile_visit_accessor: TileVisitAccessor,
|
84
|
+
strava_begin: Optional[str] = None,
|
85
|
+
strava_end: Optional[str] = None,
|
83
86
|
) -> None:
|
84
|
-
while try_import_strava(
|
87
|
+
while try_import_strava(
|
88
|
+
config, repository, tile_visit_accessor, strava_begin, strava_end
|
89
|
+
):
|
85
90
|
now = datetime.datetime.now()
|
86
91
|
next_quarter = round_to_next_quarter_hour(now)
|
87
92
|
seconds_to_wait = (next_quarter - now).total_seconds() + 10
|
@@ -95,8 +100,13 @@ def try_import_strava(
|
|
95
100
|
config: Config,
|
96
101
|
repository: ActivityRepository,
|
97
102
|
tile_visit_accessor: TileVisitAccessor,
|
103
|
+
strava_begin: Optional[str] = None,
|
104
|
+
strava_end: Optional[str] = None,
|
98
105
|
) -> bool:
|
99
|
-
|
106
|
+
if strava_begin:
|
107
|
+
get_after = f"{strava_begin}T00:00:00Z"
|
108
|
+
else:
|
109
|
+
get_after = get_state(strava_last_activity_date_path(), "2000-01-01T00:00:00Z")
|
100
110
|
|
101
111
|
gear_names = {None: "None"}
|
102
112
|
|
@@ -106,6 +116,13 @@ def try_import_strava(
|
|
106
116
|
for strava_activity in tqdm(
|
107
117
|
client.get_activities(after=get_after), desc="Downloading Strava activities"
|
108
118
|
):
|
119
|
+
if (
|
120
|
+
strava_end
|
121
|
+
and strava_activity.start_date is not None
|
122
|
+
and str(strava_activity.start_date) > strava_end
|
123
|
+
):
|
124
|
+
break
|
125
|
+
|
109
126
|
cache_file = (
|
110
127
|
pathlib.Path("Cache")
|
111
128
|
/ "Strava Activity Metadata"
|
@@ -171,10 +188,11 @@ def try_import_strava(
|
|
171
188
|
compute_tile_evolution(tile_visit_accessor.tile_state, config)
|
172
189
|
tile_visit_accessor.save()
|
173
190
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
191
|
+
if strava_begin is None and strava_end is None:
|
192
|
+
set_state(
|
193
|
+
strava_last_activity_date_path(),
|
194
|
+
strava_activity.start_date.isoformat().replace("+00:00", "Z"),
|
195
|
+
)
|
178
196
|
|
179
197
|
limit_exceeded = False
|
180
198
|
except RateLimitExceeded:
|
@@ -11,15 +11,16 @@ import threading
|
|
11
11
|
import urllib.parse
|
12
12
|
import uuid
|
13
13
|
import warnings
|
14
|
+
from typing import Optional
|
14
15
|
|
15
16
|
import pandas as pd
|
16
17
|
import sqlalchemy
|
17
|
-
from flask import Config
|
18
18
|
from flask import Flask
|
19
19
|
from flask import request
|
20
20
|
from flask_alembic import Alembic
|
21
21
|
|
22
22
|
from ..core.activities import ActivityRepository
|
23
|
+
from ..core.config import Config
|
23
24
|
from ..core.config import ConfigAccessor
|
24
25
|
from ..core.config import import_old_config
|
25
26
|
from ..core.config import import_old_strava_config
|
@@ -84,9 +85,13 @@ def importer_thread(
|
|
84
85
|
repository: ActivityRepository,
|
85
86
|
tile_visit_accessor: TileVisitAccessor,
|
86
87
|
config: Config,
|
88
|
+
strava_begin: Optional[str],
|
89
|
+
strava_end: Optional[str],
|
87
90
|
) -> None:
|
88
91
|
with app.app_context():
|
89
|
-
scan_for_activities(
|
92
|
+
scan_for_activities(
|
93
|
+
repository, tile_visit_accessor, config, strava_begin, strava_end
|
94
|
+
)
|
90
95
|
logger.info("Importer thread is done.")
|
91
96
|
|
92
97
|
|
@@ -95,6 +100,8 @@ def web_ui_main(
|
|
95
100
|
skip_reload: bool,
|
96
101
|
host: str,
|
97
102
|
port: int,
|
103
|
+
strava_begin: Optional[str],
|
104
|
+
strava_end: Optional[str],
|
98
105
|
) -> None:
|
99
106
|
os.chdir(basedir)
|
100
107
|
|
@@ -109,6 +116,7 @@ def web_ui_main(
|
|
109
116
|
database_path = pathlib.Path("database.sqlite")
|
110
117
|
logger.info(f"Using database file at '{database_path.absolute()}'.")
|
111
118
|
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{database_path.absolute()}"
|
119
|
+
# app.config["SQLALCHEMY_ECHO"] = True
|
112
120
|
app.config["ALEMBIC"] = {"script_location": "../alembic/versions"}
|
113
121
|
DB.init_app(app)
|
114
122
|
|
@@ -144,7 +152,14 @@ def web_ui_main(
|
|
144
152
|
if not skip_reload:
|
145
153
|
thread = threading.Thread(
|
146
154
|
target=importer_thread,
|
147
|
-
args=(
|
155
|
+
args=(
|
156
|
+
app,
|
157
|
+
repository,
|
158
|
+
tile_visit_accessor,
|
159
|
+
config_accessor(),
|
160
|
+
strava_begin,
|
161
|
+
strava_end,
|
162
|
+
),
|
148
163
|
)
|
149
164
|
thread.start()
|
150
165
|
|
@@ -64,11 +64,7 @@ def _render_eddington_template(
|
|
64
64
|
|
65
65
|
query = search_query_from_form(request.args)
|
66
66
|
search_query_history.register_query(query)
|
67
|
-
activities = (
|
68
|
-
apply_search_query(repository.meta, query)
|
69
|
-
.dropna(subset=["start", column_name])
|
70
|
-
.copy()
|
71
|
-
)
|
67
|
+
activities = apply_search_query(query).dropna(subset=["start", column_name]).copy()
|
72
68
|
|
73
69
|
assert (
|
74
70
|
len(activities) > 0
|
@@ -26,7 +26,7 @@ def make_hall_of_fame_blueprint(
|
|
26
26
|
def index() -> str:
|
27
27
|
query = search_query_from_form(request.args)
|
28
28
|
search_query_history.register_query(query)
|
29
|
-
activities = apply_search_query(
|
29
|
+
activities = apply_search_query(query)
|
30
30
|
df = activities
|
31
31
|
|
32
32
|
nominations = nominate_activities(df)
|
@@ -183,7 +183,7 @@ def _get_counts(
|
|
183
183
|
tile_count_cache_path.unlink(missing_ok=True)
|
184
184
|
tmp_path.rename(tile_count_cache_path)
|
185
185
|
else:
|
186
|
-
activities = apply_search_query(
|
186
|
+
activities = apply_search_query(query)
|
187
187
|
activity_ids = activities_per_tile[z].get((x, y), set())
|
188
188
|
for activity_id in activity_ids:
|
189
189
|
if activity_id not in activities["id"]:
|
@@ -42,6 +42,7 @@ def make_photo_blueprint(
|
|
42
42
|
if not small_path.exists():
|
43
43
|
with Image.open(original_path) as im:
|
44
44
|
target_size = (size, size)
|
45
|
+
im = ImageOps.exif_transpose(im)
|
45
46
|
im = ImageOps.contain(im, target_size)
|
46
47
|
small_path.parent.mkdir(exist_ok=True)
|
47
48
|
im.save(small_path)
|
@@ -35,7 +35,7 @@ def make_search_blueprint(
|
|
35
35
|
def index():
|
36
36
|
query = search_query_from_form(request.args)
|
37
37
|
search_query_history.register_query(query)
|
38
|
-
activities = apply_search_query(
|
38
|
+
activities = apply_search_query(query)
|
39
39
|
|
40
40
|
return render_template(
|
41
41
|
"search/index.html.j2",
|
@@ -178,7 +178,7 @@ def make_summary_blueprint(
|
|
178
178
|
def index():
|
179
179
|
query = search_query_from_form(request.args)
|
180
180
|
search_query_history.register_query(query)
|
181
|
-
df = apply_search_query(
|
181
|
+
df = apply_search_query(query)
|
182
182
|
|
183
183
|
kind_scale = make_kind_scale(repository.meta, config)
|
184
184
|
df_without_nan = df.loc[~pd.isna(df["start"])]
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import pathlib
|
3
|
+
from typing import Optional
|
3
4
|
|
4
5
|
import sqlalchemy
|
5
6
|
from flask import Blueprint
|
@@ -115,6 +116,8 @@ def scan_for_activities(
|
|
115
116
|
repository: ActivityRepository,
|
116
117
|
tile_visit_accessor: TileVisitAccessor,
|
117
118
|
config: Config,
|
119
|
+
strava_begin: Optional[str] = None,
|
120
|
+
strava_end: Optional[str] = None,
|
118
121
|
skip_strava: bool = False,
|
119
122
|
) -> None:
|
120
123
|
if pathlib.Path("Activities").exists():
|
@@ -122,7 +125,9 @@ def scan_for_activities(
|
|
122
125
|
if pathlib.Path("Strava Export").exists():
|
123
126
|
import_from_strava_checkout(config)
|
124
127
|
if config.strava_client_code and not skip_strava:
|
125
|
-
import_from_strava_api(
|
128
|
+
import_from_strava_api(
|
129
|
+
config, repository, tile_visit_accessor, strava_begin, strava_end
|
130
|
+
)
|
126
131
|
|
127
132
|
if len(repository) > 0:
|
128
133
|
compute_tile_visits_new(repository, tile_visit_accessor)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
geo_activity_playground/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
geo_activity_playground/__main__.py,sha256=
|
2
|
+
geo_activity_playground/__main__.py,sha256=KZr5_l6K3mqTqGKU9mUsI1y6UZokxgcq7fLPwEUCMJY,3531
|
3
3
|
geo_activity_playground/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
|
4
4
|
geo_activity_playground/alembic/env.py,sha256=46oMzwSROaAsYuYWTd46txFdRLD3adm_SCn01A_ex8Q,2081
|
5
5
|
geo_activity_playground/alembic/script.py.mako,sha256=g1k4U3D8y4PPYRzW3DH7GEu6yN4EiAr62GgCu6cRpBo,524
|
@@ -21,11 +21,11 @@ geo_activity_playground/core/activities.py,sha256=apP_-Rg1ub3lh7RARMGXf2BOmJTiah
|
|
21
21
|
geo_activity_playground/core/config.py,sha256=mmdMQ5iCLNGnAlriT1ETEVS-gM6Aq_9sg22QECHj4n8,5358
|
22
22
|
geo_activity_playground/core/coordinates.py,sha256=rW_OmMRpTUyIsQwrT6mgT9Y6uPGuwqTo5XDDMS7mGuo,1140
|
23
23
|
geo_activity_playground/core/copernicus_dem.py,sha256=t6Bc9fsyGyx1awdePXvlN-Zc-tiT2eGSJ80SV5B1Z9A,2944
|
24
|
-
geo_activity_playground/core/datamodel.py,sha256=
|
24
|
+
geo_activity_playground/core/datamodel.py,sha256=DVKgvS8nIuvGBUiXGJbNci3xdY1TxXrFGhsYin86E5Q,16730
|
25
25
|
geo_activity_playground/core/enrichment.py,sha256=b27E_KK30xjq8MuGFZyIpKzz8fO2LwLVaGGTP0mb5N0,8618
|
26
26
|
geo_activity_playground/core/export.py,sha256=ayOmhWL72263oP9NLIZRYCg_Db0GLUFhgNIL_MCrV-E,4435
|
27
27
|
geo_activity_playground/core/heart_rate.py,sha256=-S3WAhS7AOywrw_Lk5jfuo_fu6zvZQ1VtjwEKSycWpU,1542
|
28
|
-
geo_activity_playground/core/meta_search.py,sha256=
|
28
|
+
geo_activity_playground/core/meta_search.py,sha256=Sevl4AtBwJZMW3VJ6ihRqwjC0M9fhJqX3MN6tw_hIFQ,6627
|
29
29
|
geo_activity_playground/core/missing_values.py,sha256=HjonaLV0PFMICnuMrbdUNnK9uy_8PBh_RxI5GuEMQK0,250
|
30
30
|
geo_activity_playground/core/parametric_plot.py,sha256=8CKB8dey7EmZtQnl6IOgBhpxkw0UCpQPWeiBw5PqW8k,5737
|
31
31
|
geo_activity_playground/core/paths.py,sha256=qQ4ujaIHmsxTGEWzf-76XS8FclEI2RC5COTUeuLEbDI,2938
|
@@ -36,7 +36,7 @@ geo_activity_playground/core/similarity.py,sha256=L2de3DPRdDeDY5AxZwLDcH7FjHWRWk
|
|
36
36
|
geo_activity_playground/core/summary_stats.py,sha256=v5FtWnE1imDF5axI6asVN55wCrlD73oZ6lvqzxsTN2c,1006
|
37
37
|
geo_activity_playground/core/tasks.py,sha256=-_9cxekoHSWzCW4XblNeqrwi2tTqr5AE7_-p8fdqhwc,2886
|
38
38
|
geo_activity_playground/core/test_datamodel.py,sha256=-VrGHgx5Z3MSQPqHGmmm7atRJYbg5y_ukvRHKxk22PI,569
|
39
|
-
geo_activity_playground/core/test_meta_search.py,sha256=
|
39
|
+
geo_activity_playground/core/test_meta_search.py,sha256=R0fvFvXR3N23HFcACidixe3Dl1CwBZMNRnOjG3cT39s,3031
|
40
40
|
geo_activity_playground/core/test_missing_values.py,sha256=7yvg6dUu7p8PR_rxUxgFaJCrGzfYUcF8Zf6y7bCEYKw,356
|
41
41
|
geo_activity_playground/core/test_pandas_timezone.py,sha256=-MDiLoLG5tDMqkI0iKno24kFn9X3tslh9ZpoDYLWNJU,771
|
42
42
|
geo_activity_playground/core/test_summary_stats.py,sha256=qH_45mPRFD2H-Rr0Ku-RYc67vhC7qKxbPr7J2F36uV8,3081
|
@@ -48,42 +48,42 @@ geo_activity_playground/core/tiles.py,sha256=LBn2V6WAvMxZeXSIQ8ruZL71iyvOXoFZMz7
|
|
48
48
|
geo_activity_playground/core/time_conversion.py,sha256=f5CByqyWSthCplrbXZThSFbt3eY-t1g-2H5lkfBlgc0,1556
|
49
49
|
geo_activity_playground/explorer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
geo_activity_playground/explorer/grid_file.py,sha256=YNL_c4O1-kxaajATJwj4ZLywCL5Hpj9qy2h-F7rk8Yg,3260
|
51
|
-
geo_activity_playground/explorer/tile_visits.py,sha256=
|
51
|
+
geo_activity_playground/explorer/tile_visits.py,sha256=QlotWptXgv_uvtBr4qSdGpC4as6PR5Idharv_utwNyU,16943
|
52
52
|
geo_activity_playground/explorer/video.py,sha256=7j6Qv3HG6On7Tn7xh7Olwrx_fbQnfzS7CeRg3TEApHg,4397
|
53
53
|
geo_activity_playground/heatmap_video.py,sha256=I8i1uVvbbPUXVtvLAROaLy58nQoUPnuMCZkERWNkQjg,3318
|
54
54
|
geo_activity_playground/importers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
geo_activity_playground/importers/activity_parsers.py,sha256=
|
55
|
+
geo_activity_playground/importers/activity_parsers.py,sha256=NAK_Fv_zy75WuNa1bgYgzjc7Dnsj1oVah6DW0faLCG4,11403
|
56
56
|
geo_activity_playground/importers/csv_parser.py,sha256=O1pP5GLhWhnWcy2Lsrr9g17Zspuibpt-GtZ3ZS5eZF4,2143
|
57
57
|
geo_activity_playground/importers/directory.py,sha256=sHcLIi0DOPEATt4wiE_vp00h89fO940wUQyJZUzzpnw,3978
|
58
|
-
geo_activity_playground/importers/strava_api.py,sha256=
|
58
|
+
geo_activity_playground/importers/strava_api.py,sha256=0lUmC6u829vJpaIs7plQq4mOPgc7yQI65vN9qhAEqVs,9015
|
59
59
|
geo_activity_playground/importers/strava_checkout.py,sha256=joJI_uic9fYtu7E5Odh6GUq_LyiLqQ72Ucy_Mbjr-X0,9289
|
60
60
|
geo_activity_playground/importers/test_csv_parser.py,sha256=nOTVTdlzIY0TDcbWp7xNyNaIO6Mkeu55hVziVl22QE4,1092
|
61
61
|
geo_activity_playground/importers/test_directory.py,sha256=_fn_-y98ZyElbG0BRxAmGFdtGobUShPU86SdEOpuv-A,691
|
62
62
|
geo_activity_playground/importers/test_strava_api.py,sha256=7b8bl5Rh2BctCmvTPEhCadxtUOq3mfzuadD6F5XxRio,398
|
63
63
|
geo_activity_playground/webui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
64
|
-
geo_activity_playground/webui/app.py,sha256=
|
64
|
+
geo_activity_playground/webui/app.py,sha256=YxzUhvAgmSHiUfIEmvbey1PNStgB5Wcdj-b734OehdY,11087
|
65
65
|
geo_activity_playground/webui/authenticator.py,sha256=dhREYOu_TCD_nzFNuSlHIbf5K6TmwKdXtr1wxD8fBcc,1491
|
66
66
|
geo_activity_playground/webui/blueprints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
67
67
|
geo_activity_playground/webui/blueprints/activity_blueprint.py,sha256=tFy0GpOBhIP8xlmYc9PF4kAng-0MosXMJudVupGz2Yw,26771
|
68
68
|
geo_activity_playground/webui/blueprints/auth_blueprint.py,sha256=iCm3hZphQKR9qFgytOrfnSmr-Og1gHuQ1Djiv2o_bkE,1031
|
69
69
|
geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py,sha256=8R1rUVoyofGhUgesPunys1HoLPYinvhA46BBnMvEn9Q,2880
|
70
70
|
geo_activity_playground/webui/blueprints/calendar_blueprint.py,sha256=SmOu5AfNNoWcJJNduEfPtaPRvr4EZLYAeIDLUK9P1LY,2939
|
71
|
-
geo_activity_playground/webui/blueprints/eddington_blueprints.py,sha256=
|
71
|
+
geo_activity_playground/webui/blueprints/eddington_blueprints.py,sha256=m0IhM1cr_LbAOP0us4MXUbSAuT5nx_yiHljpWTrz-js,8936
|
72
72
|
geo_activity_playground/webui/blueprints/entry_views.py,sha256=SDCzpUSb1FAb84tM0SnmrZQvtaTlO-Rqdj94hyIMDSc,2936
|
73
73
|
geo_activity_playground/webui/blueprints/equipment_blueprint.py,sha256=8L_7NZGErvu4jyigi2gg7HN_gegZRdsSFahUH7Dz6Lw,5727
|
74
74
|
geo_activity_playground/webui/blueprints/explorer_blueprint.py,sha256=6ldVAKhYLNSnkI4X_NbuKtnV_Pm9t_Bm5UZOJoiLN_s,20835
|
75
75
|
geo_activity_playground/webui/blueprints/export_blueprint.py,sha256=C9yFH5gEJs2YtWE-EhcGDEyGwwaLgC1umybgIRi6duE,1036
|
76
|
-
geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py,sha256=
|
77
|
-
geo_activity_playground/webui/blueprints/heatmap_blueprint.py,sha256=
|
78
|
-
geo_activity_playground/webui/blueprints/photo_blueprint.py,sha256=
|
76
|
+
geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py,sha256=NGVk8Xgwpt-YNX5_zgGWTMRctN_N4NCnMq10DSDteVg,3121
|
77
|
+
geo_activity_playground/webui/blueprints/heatmap_blueprint.py,sha256=prERVBOxq2xvmgyH_dwtLwMMMFILeu-6yZE9h9U_T9g,8418
|
78
|
+
geo_activity_playground/webui/blueprints/photo_blueprint.py,sha256=i4-AS9icK6pDypTdl-coTZyKldXtpukGiNbKsihfpl0,7299
|
79
79
|
geo_activity_playground/webui/blueprints/plot_builder_blueprint.py,sha256=nGtYblRTJ0rasJvl_L35cs1Iry4LONPy_9TY4ytXB-Q,3838
|
80
|
-
geo_activity_playground/webui/blueprints/search_blueprint.py,sha256=
|
80
|
+
geo_activity_playground/webui/blueprints/search_blueprint.py,sha256=hY3hfGTip24AEf7NVTPtQt2hj7MEAcG3gbJd42NY3Ic,2258
|
81
81
|
geo_activity_playground/webui/blueprints/settings_blueprint.py,sha256=cwes3QmRrC_HMP1g-Yc-x2BJycF4jF3StJl75v9acWo,20377
|
82
82
|
geo_activity_playground/webui/blueprints/square_planner_blueprint.py,sha256=xVaxJxmt8Dysl3UL9f2y__LVLtTH2Np1Ust4OSXKRAk,4746
|
83
|
-
geo_activity_playground/webui/blueprints/summary_blueprint.py,sha256=
|
83
|
+
geo_activity_playground/webui/blueprints/summary_blueprint.py,sha256=7aJYvo8EERGnItL9PFCMLM6T26xiQa3VP2RUvWglgy4,6734
|
84
84
|
geo_activity_playground/webui/blueprints/tile_blueprint.py,sha256=YzZf9OrNdjhc1_j4MtO1DMcw1uCv29ueNsYd-mWqgbg,837
|
85
85
|
geo_activity_playground/webui/blueprints/time_zone_fixer_blueprint.py,sha256=PEHsk3kRHx2EvQ-6VPD4xeOmXGjh64GMAagFkQ0wbeg,2301
|
86
|
-
geo_activity_playground/webui/blueprints/upload_blueprint.py,sha256=
|
86
|
+
geo_activity_playground/webui/blueprints/upload_blueprint.py,sha256=mwoLeanW8oN6u7msE_Lx0grxDOYev4beqPbkPZRemkM,4763
|
87
87
|
geo_activity_playground/webui/columns.py,sha256=FP0YfX-WFQk1JEXhrywv3NUEVq-x7Hv0or35X3Ltf9c,1525
|
88
88
|
geo_activity_playground/webui/flasher.py,sha256=Covc1D9cO_jjokRWnvyiXCc2tfp3aZ8XkNqFdA1AXtk,500
|
89
89
|
geo_activity_playground/webui/plot_util.py,sha256=5Uesjj-xcMskQX2z9viDZYHSxLGrH2a5dHA1ogsJW9U,261
|
@@ -175,8 +175,8 @@ geo_activity_playground/webui/templates/summary/vega-chart.html.j2,sha256=mw8Hti
|
|
175
175
|
geo_activity_playground/webui/templates/time_zone_fixer/index.html.j2,sha256=s9r6BJMXmd7kLSyjkvH4xLi6e01S5bpGRcMgMMJyCAE,1760
|
176
176
|
geo_activity_playground/webui/templates/upload/index.html.j2,sha256=I1Ix8tDS3YBdi-HdaNfjkzYXVVCjfUTe5PFTnap1ydc,775
|
177
177
|
geo_activity_playground/webui/templates/upload/reload.html.j2,sha256=YZWX5eDeNyqKJdQAywDBcU8DZBm22rRBbZqFjrFrCvQ,556
|
178
|
-
geo_activity_playground-1.
|
179
|
-
geo_activity_playground-1.
|
180
|
-
geo_activity_playground-1.
|
181
|
-
geo_activity_playground-1.
|
182
|
-
geo_activity_playground-1.
|
178
|
+
geo_activity_playground-1.7.0.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
|
179
|
+
geo_activity_playground-1.7.0.dist-info/METADATA,sha256=HCy1RVSW8KTPYzUWo9XW5ozzP9HV87ueYQO3Aq6mXjY,1937
|
180
|
+
geo_activity_playground-1.7.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
181
|
+
geo_activity_playground-1.7.0.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
|
182
|
+
geo_activity_playground-1.7.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{geo_activity_playground-1.6.0.dist-info → geo_activity_playground-1.7.0.dist-info}/entry_points.txt
RENAMED
File without changes
|