Skip to content

Commit

Permalink
Support metric!
Browse files Browse the repository at this point in the history
  • Loading branch information
gazpachoking committed Nov 3, 2020
1 parent fb7fad8 commit aa5911f
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 21 deletions.
50 changes: 49 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "trainaspower"
version = "0.2.5"
version = "0.3.0"
description = "Convert TrainAsOne plans to power and upload to Final Surge for use with Stryd pod."
authors = ["Chase Sterling <[email protected]>"]
license = "MIT"
Expand All @@ -12,6 +12,7 @@ requests-html = "^0.10.0"
dateparser = "^0.7.6"
PyYAML = "^5.3.1"
loguru = "^0.5.3"
Pint = "^0.16.1"

[tool.poetry.dev-dependencies]
pyinstaller = "^4.0"
Expand Down
12 changes: 6 additions & 6 deletions trainaspower/finalsurge.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ def convert_step(step, id_counter):
"type": "step",
"id": next(id_counter),
"name": None,
"durationType": "TIME" if isinstance(step.length, timedelta) else "DISTANCE",
"duration": str(step.length) if isinstance(step.length, timedelta) else 0,
"durationType": "TIME" if step.length.check("[time]") else "DISTANCE",
"duration": str(step.length.magnitude) if step.length.check("[time]") else 0,
"targetAbsOrPct": "",
"durationDist": 0 if isinstance(step.length, timedelta) else step.length,
"durationDist": 0 if step.length.check("[time]") else step.length.magnitude,
"data": [],
"distUnit": "mi",
"distUnit": f"{step.length.units:~}" if step.length.check("[length]") else "mi",
"target": [
{
"targetType": "power",
Expand Down Expand Up @@ -139,8 +139,8 @@ def add_workout(workout):
"Activity": {
"activity_type_key": "00000001-0001-0001-0001-000000000001",
"activity_type_name": "Run",
"planned_amount": workout.distance,
"planned_amount_type": "mi",
"planned_amount": workout.distance.magnitude,
"planned_amount_type": f"{workout.distance.units:~}",
"planned_duration": workout.duration.total_seconds(),
},
},
Expand Down
12 changes: 10 additions & 2 deletions trainaspower/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import datetime
from typing import List, NamedTuple, Union

from pint import UnitRegistry, Quantity


ureg = UnitRegistry()
mile = ureg.mile
kilometer = ureg.kilometer
second = ureg.second


class PowerRange(NamedTuple):
min: Union[float, int]
Expand All @@ -19,7 +27,7 @@ class Workout:
date: datetime.date
id: str
duration: datetime.timedelta
distance: float
distance: Quantity


class Step:
Expand All @@ -30,7 +38,7 @@ class Step:
class ConcreteStep(Step):
power_range: PowerRange
pace_range: PaceRange
length: datetime.timedelta
length: Quantity


class RepeatStep(Step):
Expand Down
6 changes: 3 additions & 3 deletions trainaspower/stryd.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ def convert_pace_range_to_power(pace_range: models.PaceRange) -> models.PowerRan
)


def suggested_power_range_for_distance(distance: float) -> models.PowerRange:
logger.debug(f"Getting suggested power range for {distance} miles")
def suggested_power_range_for_distance(distance: models.Quantity) -> models.PowerRange:
logger.debug(f"Getting suggested power range for {distance}")
r = stryd_session.get(
prediction_url, params={**params, "race_distance": 1609.34 * distance}
prediction_url, params={**params, "race_distance": distance.to(models.ureg.meter).magnitude}
)
suggested_range = r.json()["power_range_suggested"]
return models.PowerRange(suggested_range["min"], suggested_range["max"])
Expand Down
20 changes: 12 additions & 8 deletions trainaspower/trainasone.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def convert_steps(steps) -> Generator[models.Step, None, None]:
out_step.type = "ACTIVE"

try:
out_step.length = parse_duration(step.text)
out_step.length = parse_duration(step.text) * models.second
except ValueError:
# 3.2km assessments are the only steps that do not have a duration
distance = parse_distance(step.text)
Expand Down Expand Up @@ -146,21 +146,25 @@ def parse_pace_range(step_string: str) -> models.PaceRange:
range_match = re.search(r"\[(.*)\]", step_string)
if not range_match:
raise ValueError(f"Could not find pace range in `{step_string}`")
range_string = range_match.group(1).strip(" /mi")
range_string = range_match.group(1).strip()
conversion = 1
if range_string.endswith("km"):
conversion = 1.60934
range_string = range_string[:-4]
min, max = range_string.split("-")
if range_string.startswith(">"):
max = parse_pace(max)
max = parse_pace(max) * conversion
min = -1
else:
min, max = parse_pace(min), parse_pace(max)
return models.PaceRange(min, max)
min, max = parse_pace(min) * conversion, parse_pace(max) * conversion
return models.PaceRange(round(min), round(max))


def parse_distance(text: str) -> float:
match = re.search(r"\(~?([\d.]+) mi\)", text)
def parse_distance(text: str) -> models.Quantity:
match = re.search(r"\(~?([\d.]+ (mi|km))\)", text)
if not match:
raise ValueError(f"No distance found in `{text}`")
return float(match.group(1))
return models.ureg.parse_expression(match.group(1))


def parse_duration(step_string: str) -> timedelta:
Expand Down

0 comments on commit aa5911f

Please sign in to comment.