geo-activity-playground 1.9.2__py3-none-any.whl → 1.9.4__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.
@@ -66,8 +66,24 @@ GROUP_BY_VARIABLES = {
66
66
  VARIABLES_1 = {"": "", **DISCRETE_VARIABLES}
67
67
  VARIABLES_2 = {"": "", **DISCRETE_VARIABLES, **CONTINUOUS_VARIABLES}
68
68
 
69
+ RENAMES = {
70
+ "year(start):O": "year(start_local):O",
71
+ "yearquarter(start)": "yearquarter(start_local)",
72
+ "yearquartermonth(start)": "yearquartermonth(start_local)",
73
+ "yearmonth(start)": "yearmonth(start_local)",
74
+ "quarter(start)": "quarter(start_local)",
75
+ "quartermonth(start)": "quartermonth(start_local)",
76
+ "month(start)": "month(start_local)",
77
+ "date(start)": "date(start_local)",
78
+ "weekday(start)": "weekday(start_local)",
79
+ }
80
+
69
81
 
70
82
  def make_parametric_plot(df: pd.DataFrame, spec: PlotSpec) -> dict[str, str]:
83
+ # Update renamed fields.
84
+ for field in spec.FIELDS:
85
+ setattr(spec, field, RENAMES.get(getattr(spec, field), getattr(spec, field)))
86
+
71
87
  if spec.group_by:
72
88
  grouped = df.groupby(spec.group_by)
73
89
  else:
@@ -219,12 +219,12 @@ def read_gpx_activity(path: pathlib.Path, open) -> pd.DataFrame:
219
219
  datum.tag
220
220
  == "{http://www.garmin.com/xmlschemas/TrackPointExtension/v1}hr"
221
221
  ):
222
- row["heartrate"] = int(datum.text)
222
+ row["heartrate"] = int(float(datum.text))
223
223
  if (
224
224
  datum.tag
225
225
  == "{http://www.garmin.com/xmlschemas/TrackPointExtension/v1}cad"
226
226
  ):
227
- row["cadence"] = int(datum.text)
227
+ row["cadence"] = int(float(datum.text))
228
228
 
229
229
  points.append(row)
230
230
  df = pd.DataFrame(points)
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import logging
2
3
  import pathlib
3
4
  import re
@@ -51,6 +52,17 @@ def import_from_directory(
51
52
  is None
52
53
  ]
53
54
 
55
+ for activity in DB.session.scalars(
56
+ sqlalchemy.select(Activity).filter(
57
+ Activity.upstream_id.is_(sqlalchemy.null()),
58
+ Activity.path.is_not(sqlalchemy.null()),
59
+ )
60
+ ):
61
+ assert activity.path is not None
62
+ if pathlib.Path(activity.path).exists():
63
+ activity.upstream_id = file_sha256(pathlib.Path(activity.path))
64
+ DB.session.commit()
65
+
54
66
  for i, activity_path in enumerate(
55
67
  tqdm(paths_to_import, desc="Importing activity files", delay=0)
56
68
  ):
@@ -58,10 +70,24 @@ def import_from_directory(
58
70
  activity = DB.session.scalar(
59
71
  sqlalchemy.select(Activity).filter(Activity.path == str(activity_path))
60
72
  )
61
- if activity is None:
62
- import_from_file(
63
- activity_path, repository, tile_visit_accessor, config, i
73
+ if activity is not None:
74
+ continue
75
+
76
+ with_same_hash = DB.session.scalars(
77
+ sqlalchemy.select(Activity).filter(
78
+ Activity.upstream_id == file_sha256(activity_path)
64
79
  )
80
+ ).all()
81
+ if with_same_hash:
82
+ if len(with_same_hash) == 1:
83
+ continue
84
+ else:
85
+ logger.warning(
86
+ "The following activities are duplicates: "
87
+ + ", ".join(str(activity.id) for activity in with_same_hash)
88
+ )
89
+
90
+ import_from_file(activity_path, repository, tile_visit_accessor, config, i)
65
91
 
66
92
 
67
93
  def import_from_file(
@@ -87,6 +113,7 @@ def import_from_file(
87
113
  return
88
114
 
89
115
  activity.path = str(path)
116
+ activity.upstream_id = file_sha256(path)
90
117
  if activity.name is None:
91
118
  activity.name = path.name.removesuffix("".join(path.suffixes))
92
119
 
@@ -120,3 +147,16 @@ def _get_metadata_from_path(
120
147
  if m := re.search(regex, str(path.relative_to(ACTIVITY_DIR))):
121
148
  return m.groupdict()
122
149
  return {}
150
+
151
+
152
+ def file_sha256(filename: pathlib.Path) -> str:
153
+ """
154
+ Based on https://stackoverflow.com/a/44873382/653152.
155
+ """
156
+ h = hashlib.sha256(usedforsecurity=False)
157
+ b = bytearray(128 * 1024)
158
+ mv = memoryview(b)
159
+ with open(filename, "rb", buffering=0) as f:
160
+ while n := f.readinto(mv):
161
+ h.update(mv[:n])
162
+ return h.hexdigest()
@@ -19,8 +19,6 @@ from ..core.datamodel import get_or_make_equipment
19
19
  from ..core.datamodel import get_or_make_kind
20
20
  from ..core.enrichment import update_and_commit
21
21
  from ..core.paths import activity_extracted_meta_dir
22
- from ..core.tasks import get_state
23
- from ..core.tasks import set_state
24
22
  from ..core.tasks import work_tracker_path
25
23
  from ..core.tasks import WorkTracker
26
24
  from .activity_parsers import ActivityParseError
@@ -132,6 +130,11 @@ EXPECTED_COLUMNS = [
132
130
  "Average Grade Adjusted Pace",
133
131
  "Timer Time",
134
132
  "Total Cycles",
133
+ "Regeneration",
134
+ "Mit Haustier",
135
+ "Wettbewerb",
136
+ "Langer Lauf",
137
+ "Für einen guten Zweck",
135
138
  "Media",
136
139
  ]
137
140
 
@@ -161,7 +164,12 @@ def import_from_strava_checkout(config: Config) -> None:
161
164
  if header[0] == EXPECTED_COLUMNS[0]:
162
165
  dayfirst = False
163
166
  elif header[0] == "Aktivitäts-ID":
164
- header = EXPECTED_COLUMNS
167
+ new_header = list(EXPECTED_COLUMNS)
168
+ if len(new_header) > len(header):
169
+ new_header = new_header[: len(header)]
170
+ elif len(new_header) < len(header):
171
+ new_header += [f"Ignored_{i}" for i in range(len(header) - len(new_header))]
172
+ header = new_header
165
173
  dayfirst = True
166
174
  else:
167
175
  logger.error(
@@ -194,7 +202,7 @@ def import_from_strava_checkout(config: Config) -> None:
194
202
 
195
203
  start_datetime = dateutil.parser.parse(
196
204
  row["Activity Date"], dayfirst=dayfirst
197
- ).replace(tzinfo=zoneinfo.ZoneInfo("utc"))
205
+ ).replace(tzinfo=zoneinfo.ZoneInfo("UTC"))
198
206
 
199
207
  activity_file = checkout_path / row["Filename"]
200
208
 
@@ -8,6 +8,7 @@ from ...core.export import export_all
8
8
  from ..authenticator import Authenticator
9
9
  from ..authenticator import needs_authentication
10
10
 
11
+ from datetime import date
11
12
 
12
13
  def make_export_blueprint(authenticator: Authenticator) -> Blueprint:
13
14
  blueprint = Blueprint("export", __name__, template_folder="templates")
@@ -25,7 +26,7 @@ def make_export_blueprint(authenticator: Authenticator) -> Blueprint:
25
26
  return Response(
26
27
  bytes(export_all(meta_format, activity_format)),
27
28
  mimetype="application/zip",
28
- headers={"Content-disposition": 'attachment; filename="export.zip"'},
29
+ headers={"Content-disposition": f'attachment; filename="GAP-export-{date.today().strftime("%Y-%m-%d")}.zip"'}
29
30
  )
30
31
 
31
32
  return blueprint
@@ -23,13 +23,13 @@ column_elevation_gain = ColumnDescription(
23
23
  )
24
24
  column_hours = ColumnDescription(
25
25
  name="hours",
26
- display_name="Elapsed time",
26
+ display_name="Elapsed Time",
27
27
  unit="h",
28
28
  format=".1f",
29
29
  )
30
30
  column_hours_moving = ColumnDescription(
31
31
  name="hours_moving",
32
- display_name="Moving time",
32
+ display_name="Moving Time",
33
33
  unit="h",
34
34
  format=".1f",
35
35
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geo-activity-playground
3
- Version: 1.9.2
3
+ Version: 1.9.4
4
4
  Summary: Analysis of geo data activities like rides, runs or hikes.
5
5
  License: MIT
6
6
  Author: Martin Ueding
@@ -27,7 +27,7 @@ geo_activity_playground/core/export.py,sha256=ayOmhWL72263oP9NLIZRYCg_Db0GLUFhgN
27
27
  geo_activity_playground/core/heart_rate.py,sha256=-S3WAhS7AOywrw_Lk5jfuo_fu6zvZQ1VtjwEKSycWpU,1542
28
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
- geo_activity_playground/core/parametric_plot.py,sha256=4MFm-KF5QgzLUZHWHKHlbDWAE_IM-raT1xOl_StKmkk,5797
30
+ geo_activity_playground/core/parametric_plot.py,sha256=sPaBnrcjvbzys0s0ge5OHtSSp1bJMaLtoO0UxXdffqo,6400
31
31
  geo_activity_playground/core/paths.py,sha256=qQ4ujaIHmsxTGEWzf-76XS8FclEI2RC5COTUeuLEbDI,2938
32
32
  geo_activity_playground/core/photos.py,sha256=pHdVUpgKfbyrTddZL_mgmsXQJ3k_IHKf70jtcIjjcCA,1229
33
33
  geo_activity_playground/core/privacy_zones.py,sha256=4TumHsVUN1uW6RG3ArqTXDykPVipF98DCxVBe7YNdO8,512
@@ -52,11 +52,11 @@ geo_activity_playground/explorer/tile_visits.py,sha256=DzAmZmyLSeGe8mIg6-Kx1gXtC
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=dWtumZM4igsfWSECDOazLjTEf1YcaU04wJJ45EhfCVw,12461
55
+ geo_activity_playground/importers/activity_parsers.py,sha256=lh7B_ZwZkcwZgrwLhptobcLfxvDIiPJRgWdE9fZzKw4,12475
56
56
  geo_activity_playground/importers/csv_parser.py,sha256=O1pP5GLhWhnWcy2Lsrr9g17Zspuibpt-GtZ3ZS5eZF4,2143
57
- geo_activity_playground/importers/directory.py,sha256=sHcLIi0DOPEATt4wiE_vp00h89fO940wUQyJZUzzpnw,3978
57
+ geo_activity_playground/importers/directory.py,sha256=UBs-iWGZx_LkknytsRykAo_BaScUg0wYkfThpk5HG-8,5338
58
58
  geo_activity_playground/importers/strava_api.py,sha256=1sRb_CD4tbsW-MwP6QPg7zpATlb6XpniS4rtH72iwkw,9606
59
- geo_activity_playground/importers/strava_checkout.py,sha256=joJI_uic9fYtu7E5Odh6GUq_LyiLqQ72Ucy_Mbjr-X0,9289
59
+ geo_activity_playground/importers/strava_checkout.py,sha256=Tpln_IweoTIo-dkkTyRsVPGWesSu3S3C3ifd874NqUA,9590
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
@@ -72,7 +72,7 @@ geo_activity_playground/webui/blueprints/eddington_blueprints.py,sha256=s5o_U1rq
72
72
  geo_activity_playground/webui/blueprints/entry_views.py,sha256=slGyYokGattdG-e5Ef9s_ys4ohVVAkFLFclEQS5fEr4,2954
73
73
  geo_activity_playground/webui/blueprints/equipment_blueprint.py,sha256=6u81Hestr4FP6mix_avQp9jaK0In4WNdYaSwKL5cJDs,5757
74
74
  geo_activity_playground/webui/blueprints/explorer_blueprint.py,sha256=fe4ZNROmpks-nP4Wsw2vc9t5_X508-6Xi1dv07O_NfQ,20979
75
- geo_activity_playground/webui/blueprints/export_blueprint.py,sha256=C9yFH5gEJs2YtWE-EhcGDEyGwwaLgC1umybgIRi6duE,1036
75
+ geo_activity_playground/webui/blueprints/export_blueprint.py,sha256=Rppuyk_TkP1GeDplxgKnRkyujDR-hGhD3oWRnNNCEjc,1102
76
76
  geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py,sha256=NGVk8Xgwpt-YNX5_zgGWTMRctN_N4NCnMq10DSDteVg,3121
77
77
  geo_activity_playground/webui/blueprints/heatmap_blueprint.py,sha256=prERVBOxq2xvmgyH_dwtLwMMMFILeu-6yZE9h9U_T9g,8418
78
78
  geo_activity_playground/webui/blueprints/photo_blueprint.py,sha256=i4-AS9icK6pDypTdl-coTZyKldXtpukGiNbKsihfpl0,7299
@@ -84,7 +84,7 @@ geo_activity_playground/webui/blueprints/summary_blueprint.py,sha256=giVLJttJ2my
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
86
  geo_activity_playground/webui/blueprints/upload_blueprint.py,sha256=VLyMic2ptBRcMyunGXl-6Auxs1jglIO5fYgRGPhH25s,4816
87
- geo_activity_playground/webui/columns.py,sha256=FP0YfX-WFQk1JEXhrywv3NUEVq-x7Hv0or35X3Ltf9c,1525
87
+ geo_activity_playground/webui/columns.py,sha256=C9Bg4J2Z8xbSZKdNParm1IKoR9nHStyroiBZDFdoZT4,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
90
90
  geo_activity_playground/webui/search_util.py,sha256=gH2cOM1FTAozZUlSQ4C1dR1xlV-8e82pD1PPi_pPBNY,2647
@@ -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=5W2gpm4eSvidOyJOCSZZbvTZaTkSWNrOWux3-oIm0zI,784
177
177
  geo_activity_playground/webui/templates/upload/reload.html.j2,sha256=YZWX5eDeNyqKJdQAywDBcU8DZBm22rRBbZqFjrFrCvQ,556
178
- geo_activity_playground-1.9.2.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
179
- geo_activity_playground-1.9.2.dist-info/METADATA,sha256=yulIhsXBd3Osqgumn4RYD31XflfkZdwaojp6Y54ZTAU,1937
180
- geo_activity_playground-1.9.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
181
- geo_activity_playground-1.9.2.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
182
- geo_activity_playground-1.9.2.dist-info/RECORD,,
178
+ geo_activity_playground-1.9.4.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
179
+ geo_activity_playground-1.9.4.dist-info/METADATA,sha256=TWDOnevm__CRkjcmlnfI73azWUZey8R5clp-0w3kgi8,1937
180
+ geo_activity_playground-1.9.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
181
+ geo_activity_playground-1.9.4.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
182
+ geo_activity_playground-1.9.4.dist-info/RECORD,,