Add matched training signals, daily recovery and performance analysis
This commit is contained in:
+31
-3
@@ -37,6 +37,9 @@ def extract(text):
|
||||
"source": "runs",
|
||||
"cohorts": [],
|
||||
"comparison": "period",
|
||||
"reduce": None,
|
||||
"long_run": 10.0,
|
||||
"route": None,
|
||||
}
|
||||
seen, lines = set(), text.splitlines()
|
||||
|
||||
@@ -47,11 +50,26 @@ def extract(text):
|
||||
|
||||
for index, source in enumerate(lines):
|
||||
line, number = source.strip(), index + 1
|
||||
if line in {"runs", "laps", "segments"}:
|
||||
if line in {"runs", "laps", "segments", "intervals", "efforts", "days", "health"}:
|
||||
once("source", number)
|
||||
options["source"] = line
|
||||
lines[index] = "runs"
|
||||
continue
|
||||
elif match := re.fullmatch(r"reduce by run min (\d+(?:\.\d+)?) min", line):
|
||||
once("reduce", number)
|
||||
minutes = float(match[1])
|
||||
if not 1 <= minutes <= 180:
|
||||
raise QueryError("Use 1–180 matched minutes per run.", number)
|
||||
options["reduce"] = minutes
|
||||
elif match := re.fullmatch(r"long run distance >= (\d+(?:\.\d+)?) km", line):
|
||||
once("long_run", number)
|
||||
distance = float(match[1])
|
||||
if not 1 <= distance <= 100:
|
||||
raise QueryError("Use a long-run threshold of 1–100 km.", number)
|
||||
options["long_run"] = distance
|
||||
elif match := re.fullmatch(r"route similar to (\d+)", line):
|
||||
once("route", number)
|
||||
options["route"] = int(match[1])
|
||||
elif line == "compare previous year":
|
||||
options["comparison"] = "year"
|
||||
lines[index] = "compare previous period"
|
||||
@@ -138,6 +156,16 @@ def extract(text):
|
||||
|
||||
|
||||
def validate(q, catalog):
|
||||
if q["flag"] and q["source"] in {"laps", "segments", "intervals"} and not q["reduce"]:
|
||||
raise QueryError("Reduce recordings to independent runs before using a deviation flag.")
|
||||
if q["reduce"] and q["source"] not in {"intervals", "segments"}:
|
||||
raise QueryError("reduce by run requires intervals or segments.")
|
||||
if q["reduce"] and (q["derived"] or q["cohorts"]):
|
||||
raise QueryError("Reduce matched recordings before adding calculations or cohorts.")
|
||||
if q["route"] and q["source"] in {"days", "health"}:
|
||||
raise QueryError("Route matching requires a recording or runs source.")
|
||||
if q["source"] in {"days", "health"} and q["group"] in {"run", "hour"}:
|
||||
raise QueryError("Daily observations require calendar, all, or numeric grouping.")
|
||||
if q["plot"] and q["chart"] == "none":
|
||||
raise QueryError("A scatter plot conflicts with chart none.")
|
||||
if q["cohorts"] and (
|
||||
@@ -167,7 +195,7 @@ def validate(q, catalog):
|
||||
)
|
||||
if q["compare"]:
|
||||
raise QueryError("Stacked cohorts show the current period; use compare none.")
|
||||
if q["source"] != "runs":
|
||||
if q["source"] not in {"runs", "days", "health"}:
|
||||
temporal = {
|
||||
"gap_since_previous_run",
|
||||
"distance_change",
|
||||
@@ -231,7 +259,7 @@ def validate(q, catalog):
|
||||
*q["extra_metrics"],
|
||||
]
|
||||
supported = lambda key: (
|
||||
q["aggregates"][key]["function"] not in {"sum", "count", "stddev"}
|
||||
q["aggregates"][key]["function"] not in {"sum", "count", "stddev", "latest"}
|
||||
if key in q["aggregates"]
|
||||
else key not in additive
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user