Fix VO2 max extraction: values nested under entry['generic'] not top-level
The maxmet/daily range query returns entries shaped as:
{"generic": {"calendarDate": "...", "vo2MaxPreciseValue": 42.7, ...}, ...}
The extractor was looking at the top level of each entry, finding nothing, and
falling through to the single-point training_status fallback every time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -342,17 +342,16 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
|||||||
len(mm_raw) if isinstance(mm_raw, (list, dict)) else "n/a")
|
len(mm_raw) if isinstance(mm_raw, (list, dict)) else "n/a")
|
||||||
if isinstance(mm_raw, list):
|
if isinstance(mm_raw, list):
|
||||||
mm_entries = mm_raw
|
mm_entries = mm_raw
|
||||||
if mm_entries and isinstance(mm_entries[0], dict):
|
|
||||||
logger.info("maxmet first entry keys: %s", list(mm_entries[0].keys()))
|
|
||||||
logger.info("maxmet first entry: %s", mm_entries[0])
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info("maxmet history fetch failed: %s", exc)
|
logger.info("maxmet history fetch failed: %s", exc)
|
||||||
|
|
||||||
# Check whether the range query yielded any usable vo2max values
|
# Each entry has the vo2max data nested under entry["generic"]
|
||||||
|
def _extract_generic(entry):
|
||||||
|
return (entry.get("generic") or {}) if isinstance(entry, dict) else {}
|
||||||
|
|
||||||
valid_from_range = any(
|
valid_from_range = any(
|
||||||
(entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue") or 0)
|
(_extract_generic(e).get("vo2MaxPreciseValue") or _extract_generic(e).get("vo2MaxValue") or 0)
|
||||||
for entry in mm_entries
|
for e in mm_entries
|
||||||
if isinstance(entry, dict)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Always fall back to training_status when the range query had no valid data
|
# Always fall back to training_status when the range query had no valid data
|
||||||
@@ -362,17 +361,16 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
|||||||
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
||||||
logger.info("training_status vo2max=%s at %s", v, generic.get("calendarDate"))
|
logger.info("training_status vo2max=%s at %s", v, generic.get("calendarDate"))
|
||||||
if v and float(v) > 0:
|
if v and float(v) > 0:
|
||||||
mm_entries = [{"calendarDate": generic.get("calendarDate") or today_str,
|
mm_entries = [{"generic": {"calendarDate": generic.get("calendarDate") or today_str,
|
||||||
"vo2MaxPreciseValue": float(v)}]
|
"vo2MaxPreciseValue": float(v)}}]
|
||||||
|
|
||||||
stored = 0
|
stored = 0
|
||||||
for entry in mm_entries:
|
for entry in mm_entries:
|
||||||
if not isinstance(entry, dict):
|
generic = _extract_generic(entry)
|
||||||
continue
|
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
||||||
v = entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue")
|
|
||||||
if not v or float(v) <= 0:
|
if not v or float(v) <= 0:
|
||||||
continue
|
continue
|
||||||
entry_date = entry.get("calendarDate") or today_str
|
entry_date = generic.get("calendarDate") or today_str
|
||||||
try:
|
try:
|
||||||
fa_row = {"vo2max": float(v)}
|
fa_row = {"vo2max": float(v)}
|
||||||
if fa_age and entry_date == today_str:
|
if fa_age and entry_date == today_str:
|
||||||
|
|||||||
@@ -345,11 +345,13 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.info("maxmet history fetch failed: %s", exc)
|
logger.info("maxmet history fetch failed: %s", exc)
|
||||||
|
|
||||||
# Check whether the range query yielded any usable vo2max values
|
# Each entry has the vo2max data nested under entry["generic"]
|
||||||
|
def _extract_generic(entry):
|
||||||
|
return (entry.get("generic") or {}) if isinstance(entry, dict) else {}
|
||||||
|
|
||||||
valid_from_range = any(
|
valid_from_range = any(
|
||||||
(entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue") or 0)
|
(_extract_generic(e).get("vo2MaxPreciseValue") or _extract_generic(e).get("vo2MaxValue") or 0)
|
||||||
for entry in mm_entries
|
for e in mm_entries
|
||||||
if isinstance(entry, dict)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Always fall back to training_status when the range query had no valid data
|
# Always fall back to training_status when the range query had no valid data
|
||||||
@@ -359,17 +361,16 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
|||||||
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
||||||
logger.info("training_status vo2max=%s at %s", v, generic.get("calendarDate"))
|
logger.info("training_status vo2max=%s at %s", v, generic.get("calendarDate"))
|
||||||
if v and float(v) > 0:
|
if v and float(v) > 0:
|
||||||
mm_entries = [{"calendarDate": generic.get("calendarDate") or today_str,
|
mm_entries = [{"generic": {"calendarDate": generic.get("calendarDate") or today_str,
|
||||||
"vo2MaxPreciseValue": float(v)}]
|
"vo2MaxPreciseValue": float(v)}}]
|
||||||
|
|
||||||
stored = 0
|
stored = 0
|
||||||
for entry in mm_entries:
|
for entry in mm_entries:
|
||||||
if not isinstance(entry, dict):
|
generic = _extract_generic(entry)
|
||||||
continue
|
v = generic.get("vo2MaxPreciseValue") or generic.get("vo2MaxValue")
|
||||||
v = entry.get("vo2MaxPreciseValue") or entry.get("vo2MaxValue")
|
|
||||||
if not v or float(v) <= 0:
|
if not v or float(v) <= 0:
|
||||||
continue
|
continue
|
||||||
entry_date = entry.get("calendarDate") or today_str
|
entry_date = generic.get("calendarDate") or today_str
|
||||||
try:
|
try:
|
||||||
fa_row = {"vo2max": float(v)}
|
fa_row = {"vo2max": float(v)}
|
||||||
if fa_age and entry_date == today_str:
|
if fa_age and entry_date == today_str:
|
||||||
|
|||||||
Reference in New Issue
Block a user