sweatstack 0.45.0__tar.gz → 0.47.0__tar.gz
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.
- {sweatstack-0.45.0 → sweatstack-0.47.0}/CHANGELOG.md +16 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/PKG-INFO +2 -1
- {sweatstack-0.45.0 → sweatstack-0.47.0}/pyproject.toml +2 -1
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/client.py +67 -2
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/openapi_schemas.py +316 -6
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/schemas.py +1 -1
- {sweatstack-0.45.0 → sweatstack-0.47.0}/uv.lock +744 -738
- {sweatstack-0.45.0 → sweatstack-0.47.0}/.gitignore +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/.python-version +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/DEVELOPMENT.md +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/Makefile +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/README.md +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/.ipynb_checkpoints/Untitled-checkpoint.ipynb +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/README.md +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/Sweat Stack examples/Getting started.ipynb +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/Untitled.ipynb +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/hello.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/playground/pyproject.toml +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/Sweat Stack examples/Getting started.ipynb +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/__init__.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/cli.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/constants.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/ipython_init.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/jupyterlab_oauth2_startup.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/py.typed +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/streamlit.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/sweatshell.py +0 -0
- {sweatstack-0.45.0 → sweatstack-0.47.0}/src/sweatstack/utils.py +0 -0
|
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
## [0.47.0] - 2025-08-07
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added a new `ss.get_backfill_status()` method that returns the current backfill status from the activities backfill-status endpoint.
|
|
14
|
+
- Added a new `ss.watch_backfill_status()` method that watches the backfill status from the activities backfill-status endpoint.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [0.46.0] - 2025-08-01
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Added a new `registered_at` field to the `UserInfoResponse` model that is returned by `ss.get_userinfo()`. This field is the timestamp of the user's registration with SweatStack.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
9
25
|
## [0.45.0] - 2025-06-24
|
|
10
26
|
|
|
11
27
|
### Added
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sweatstack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.47.0
|
|
4
4
|
Summary: The official Python client for SweatStack
|
|
5
5
|
Author-email: Aart Goossens <aart@gssns.io>
|
|
6
6
|
Requires-Python: >=3.9
|
|
7
|
+
Requires-Dist: email-validator>=2.2.0
|
|
7
8
|
Requires-Dist: httpx>=0.28.1
|
|
8
9
|
Requires-Dist: pandas>=2.2.3
|
|
9
10
|
Requires-Dist: platformdirs>=4.0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sweatstack"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.47.0"
|
|
4
4
|
description = "The official Python client for SweatStack"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -8,6 +8,7 @@ authors = [
|
|
|
8
8
|
]
|
|
9
9
|
requires-python = ">=3.9"
|
|
10
10
|
dependencies = [
|
|
11
|
+
"email-validator>=2.2.0",
|
|
11
12
|
"httpx>=0.28.1",
|
|
12
13
|
"pandas>=2.2.3",
|
|
13
14
|
"platformdirs>=4.0.0",
|
|
@@ -16,7 +16,7 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
|
16
16
|
from importlib.metadata import version
|
|
17
17
|
from io import BytesIO
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import Any, Generator, get_type_hints, List, Literal
|
|
19
|
+
from typing import Any, Dict, Generator, get_type_hints, List, Literal
|
|
20
20
|
from urllib.parse import parse_qs, urlparse
|
|
21
21
|
|
|
22
22
|
import httpx
|
|
@@ -25,7 +25,8 @@ from platformdirs import user_data_dir
|
|
|
25
25
|
|
|
26
26
|
from .constants import DEFAULT_URL
|
|
27
27
|
from .schemas import (
|
|
28
|
-
ActivityDetails, ActivitySummary, Metric, Sport,
|
|
28
|
+
ActivityDetails, ActivitySummary, BackfillStatus, Metric, Sport,
|
|
29
|
+
TraceDetails, UserInfoResponse, UserSummary
|
|
29
30
|
)
|
|
30
31
|
from .utils import decode_jwt_body, make_dataframe_streamlit_compatible
|
|
31
32
|
|
|
@@ -1230,6 +1231,67 @@ class Client(OAuth2Mixin, DelegationMixin, TokenStorageMixin):
|
|
|
1230
1231
|
|
|
1231
1232
|
return self._get_user_by_id(user_id)
|
|
1232
1233
|
|
|
1234
|
+
def _parse_backfill_line(self, line: str) -> BackfillStatus | None:
|
|
1235
|
+
"""Parse a single NDJSON line from backfill status stream."""
|
|
1236
|
+
try:
|
|
1237
|
+
return BackfillStatus.model_validate_json(line)
|
|
1238
|
+
except Exception:
|
|
1239
|
+
pass
|
|
1240
|
+
return None
|
|
1241
|
+
|
|
1242
|
+
def watch_backfill_status(self, *, auto_reconnect: bool = False) -> Generator[BackfillStatus, None, None]:
|
|
1243
|
+
"""Watches backfill status from the activities backfill-status endpoint.
|
|
1244
|
+
|
|
1245
|
+
This method connects to the backfill status event stream and yields
|
|
1246
|
+
backfill_loaded_until timestamps as they are received. The connection
|
|
1247
|
+
automatically closes after 60 seconds, but can be configured to auto-reconnect.
|
|
1248
|
+
|
|
1249
|
+
Args:
|
|
1250
|
+
auto_reconnect: Whether to automatically reconnect when the connection
|
|
1251
|
+
closes and continue receiving updates. Defaults to False.
|
|
1252
|
+
|
|
1253
|
+
Yields:
|
|
1254
|
+
BackfillStatus: A BackfillStatus object for each received message.
|
|
1255
|
+
|
|
1256
|
+
Raises:
|
|
1257
|
+
HTTPStatusError: If the API request fails.
|
|
1258
|
+
"""
|
|
1259
|
+
while True:
|
|
1260
|
+
try:
|
|
1261
|
+
with self._http_client() as client:
|
|
1262
|
+
with client.stream("GET", "/api/v1/activities/backfill-status") as response:
|
|
1263
|
+
self._raise_for_status(response)
|
|
1264
|
+
|
|
1265
|
+
for line in response.iter_lines():
|
|
1266
|
+
if line.strip():
|
|
1267
|
+
parsed = self._parse_backfill_line(line)
|
|
1268
|
+
if parsed:
|
|
1269
|
+
yield parsed
|
|
1270
|
+
|
|
1271
|
+
except httpx.RequestError:
|
|
1272
|
+
if not auto_reconnect:
|
|
1273
|
+
raise
|
|
1274
|
+
time.sleep(1)
|
|
1275
|
+
if not auto_reconnect:
|
|
1276
|
+
break
|
|
1277
|
+
|
|
1278
|
+
def get_backfill_status(self) -> BackfillStatus:
|
|
1279
|
+
"""Gets the current backfill status from the activities backfill-status endpoint.
|
|
1280
|
+
|
|
1281
|
+
This method connects to the backfill status event stream and returns
|
|
1282
|
+
the first backfill_loaded_until timestamp received.
|
|
1283
|
+
|
|
1284
|
+
Returns:
|
|
1285
|
+
BackfillStatus: A BackfillStatus object containing the current backfill status.
|
|
1286
|
+
|
|
1287
|
+
Raises:
|
|
1288
|
+
HTTPStatusError: If the API request fails.
|
|
1289
|
+
ValueError: If no status message is received.
|
|
1290
|
+
"""
|
|
1291
|
+
for status in self.watch_backfill_status(auto_reconnect=False):
|
|
1292
|
+
return status
|
|
1293
|
+
raise ValueError("No backfill status received")
|
|
1294
|
+
|
|
1233
1295
|
|
|
1234
1296
|
_default_client = Client()
|
|
1235
1297
|
|
|
@@ -1276,6 +1338,9 @@ _generate_singleton_methods(
|
|
|
1276
1338
|
"get_userinfo",
|
|
1277
1339
|
"whoami",
|
|
1278
1340
|
|
|
1341
|
+
"get_backfill_status",
|
|
1342
|
+
"watch_backfill_status",
|
|
1343
|
+
|
|
1279
1344
|
"get_activities",
|
|
1280
1345
|
|
|
1281
1346
|
"get_activity",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: openapi.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-08-07T11:42:52+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -8,19 +8,50 @@ from datetime import datetime, timedelta
|
|
|
8
8
|
from enum import Enum
|
|
9
9
|
from typing import List, Literal, Optional, Union
|
|
10
10
|
|
|
11
|
-
from pydantic import
|
|
11
|
+
from pydantic import (
|
|
12
|
+
AnyUrl,
|
|
13
|
+
BaseModel,
|
|
14
|
+
EmailStr,
|
|
15
|
+
Field,
|
|
16
|
+
RootModel,
|
|
17
|
+
SecretStr,
|
|
18
|
+
confloat,
|
|
19
|
+
conint,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Activity(BaseModel):
|
|
24
|
+
id: str = Field(..., title='Id')
|
|
25
|
+
start_date_local: datetime = Field(..., title='Start Date Local')
|
|
12
26
|
|
|
13
27
|
|
|
14
28
|
class ActivityUpdate(BaseModel):
|
|
15
29
|
tags: Optional[List[str]] = Field(None, title='Tags')
|
|
16
30
|
|
|
17
31
|
|
|
32
|
+
class Prompt(Enum):
|
|
33
|
+
none = 'none'
|
|
34
|
+
login = 'login'
|
|
35
|
+
consent = 'consent'
|
|
36
|
+
select_account = 'select_account'
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class BackfillStatus(BaseModel):
|
|
40
|
+
backfill_loaded_until: Optional[datetime] = Field(
|
|
41
|
+
..., title='Backfill Loaded Until'
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BodyAddEmailPartialsAddEmailPost(BaseModel):
|
|
46
|
+
email: EmailStr = Field(..., title='Email')
|
|
47
|
+
|
|
48
|
+
|
|
18
49
|
class BodyCreateApplicationApplicationsPost(BaseModel):
|
|
19
50
|
name: str = Field(..., title='Name')
|
|
20
51
|
description: str = Field(..., title='Description')
|
|
21
52
|
url: AnyUrl = Field(..., title='Url')
|
|
22
53
|
image: AnyUrl = Field(..., title='Image')
|
|
23
|
-
redirect_uris: List[
|
|
54
|
+
redirect_uris: List[str] = Field(..., title='Redirect Uris')
|
|
24
55
|
privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
|
|
25
56
|
published: Optional[bool] = Field(False, title='Published')
|
|
26
57
|
|
|
@@ -133,6 +164,7 @@ class Tz(Enum):
|
|
|
133
164
|
America_Coral_Harbour = 'America/Coral_Harbour'
|
|
134
165
|
America_Cordoba = 'America/Cordoba'
|
|
135
166
|
America_Costa_Rica = 'America/Costa_Rica'
|
|
167
|
+
America_Coyhaique = 'America/Coyhaique'
|
|
136
168
|
America_Creston = 'America/Creston'
|
|
137
169
|
America_Cuiaba = 'America/Cuiaba'
|
|
138
170
|
America_Curacao = 'America/Curacao'
|
|
@@ -635,13 +667,14 @@ class Tz(Enum):
|
|
|
635
667
|
|
|
636
668
|
|
|
637
669
|
class BodyLoginPostLoginPost(BaseModel):
|
|
638
|
-
email:
|
|
670
|
+
email: EmailStr = Field(..., title='Email')
|
|
639
671
|
password: SecretStr = Field(..., title='Password')
|
|
640
672
|
tz: Tz = Field(..., title='Tz')
|
|
673
|
+
state: Optional[str] = Field(None, title='State')
|
|
641
674
|
|
|
642
675
|
|
|
643
676
|
class BodyRegisterPostRegisterPost(BaseModel):
|
|
644
|
-
email:
|
|
677
|
+
email: EmailStr = Field(..., title='Email')
|
|
645
678
|
password: SecretStr = Field(..., title='Password')
|
|
646
679
|
tz: Tz = Field(..., title='Tz')
|
|
647
680
|
|
|
@@ -654,12 +687,17 @@ class BodySaveOrUpdateIntegrationProviderTenantsTenantIdIntegrationProvidersInte
|
|
|
654
687
|
redirect_url: str = Field(..., title='Redirect Url')
|
|
655
688
|
|
|
656
689
|
|
|
690
|
+
class BodySendVerificationEmailPartialsSendVerificationEmailPost(BaseModel):
|
|
691
|
+
email: EmailStr = Field(..., title='Email')
|
|
692
|
+
tz: Tz = Field(..., title='Tz')
|
|
693
|
+
|
|
694
|
+
|
|
657
695
|
class BodyUpdateApplicationApplicationsApplicationIdPut(BaseModel):
|
|
658
696
|
name: str = Field(..., title='Name')
|
|
659
697
|
description: str = Field(..., title='Description')
|
|
660
698
|
url: AnyUrl = Field(..., title='Url')
|
|
661
699
|
image: AnyUrl = Field(..., title='Image')
|
|
662
|
-
redirect_uris: List[
|
|
700
|
+
redirect_uris: List[str] = Field(..., title='Redirect Uris')
|
|
663
701
|
privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
|
|
664
702
|
published: Optional[bool] = Field(False, title='Published')
|
|
665
703
|
|
|
@@ -669,6 +707,10 @@ class BodyUpdateUserUsersUserIdPut(BaseModel):
|
|
|
669
707
|
last_name: str = Field(..., title='Last Name')
|
|
670
708
|
|
|
671
709
|
|
|
710
|
+
class BodyUploadActivityFileApiV1ActivitiesUploadPost(BaseModel):
|
|
711
|
+
files: List[bytes] = Field(..., max_length=10, title='Files')
|
|
712
|
+
|
|
713
|
+
|
|
672
714
|
class BodyUploadActivityFileDataUploadPost(BaseModel):
|
|
673
715
|
files: List[bytes] = Field(..., title='Files')
|
|
674
716
|
|
|
@@ -690,6 +732,13 @@ class ElevationSummary(BaseModel):
|
|
|
690
732
|
max: Optional[int] = Field(None, title='Max')
|
|
691
733
|
|
|
692
734
|
|
|
735
|
+
class GarminBackfillBody(BaseModel):
|
|
736
|
+
start: datetime = Field(..., title='Start')
|
|
737
|
+
end: datetime = Field(..., title='End')
|
|
738
|
+
user_id__in: Optional[List[str]] = Field(None, title='User Id In')
|
|
739
|
+
user_id__not_in: Optional[List[str]] = Field(None, title='User Id Not In')
|
|
740
|
+
|
|
741
|
+
|
|
693
742
|
class GarminDeregistration(BaseModel):
|
|
694
743
|
userId: str = Field(..., title='Userid')
|
|
695
744
|
userAccessToken: str = Field(..., title='Useraccesstoken')
|
|
@@ -718,8 +767,33 @@ class HeartRateSummary(BaseModel):
|
|
|
718
767
|
end: Optional[float] = Field(None, title='End')
|
|
719
768
|
|
|
720
769
|
|
|
770
|
+
class Instruction(BaseModel):
|
|
771
|
+
type: Literal['instruction'] = Field('instruction', title='Type')
|
|
772
|
+
text: str = Field(..., title='Text')
|
|
773
|
+
|
|
774
|
+
|
|
721
775
|
class IntegrationName(Enum):
|
|
722
776
|
garmin_connect = 'garmin_connect'
|
|
777
|
+
intervals_icu = 'intervals_icu'
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
class IntensityQuantity(Enum):
|
|
781
|
+
speed = 'speed'
|
|
782
|
+
power = 'power'
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
class IntervalsIcuWebhookEventType(Enum):
|
|
786
|
+
APP_SCOPE_CHANGED = 'APP_SCOPE_CHANGED'
|
|
787
|
+
CALENDAR_UPDATED = 'CALENDAR_UPDATED'
|
|
788
|
+
CALENDAR_EVENT_UPDATED = 'CALENDAR_EVENT_UPDATED'
|
|
789
|
+
CALENDAR_EVENT_DELETED = 'CALENDAR_EVENT_DELETED'
|
|
790
|
+
ACTIVITY_UPLOADED = 'ACTIVITY_UPLOADED'
|
|
791
|
+
ACTIVITY_ANALYZED = 'ACTIVITY_ANALYZED'
|
|
792
|
+
ACTIVITY_UPDATED = 'ACTIVITY_UPDATED'
|
|
793
|
+
ACTIVITY_DELETED = 'ACTIVITY_DELETED'
|
|
794
|
+
ACTIVITY_ACHIEVEMENTS = 'ACTIVITY_ACHIEVEMENTS'
|
|
795
|
+
WELLNESS_UPDATED = 'WELLNESS_UPDATED'
|
|
796
|
+
FITNESS_UPDATED = 'FITNESS_UPDATED'
|
|
723
797
|
|
|
724
798
|
|
|
725
799
|
class Metric(Enum):
|
|
@@ -748,6 +822,16 @@ class PowerSummary(BaseModel):
|
|
|
748
822
|
max: Optional[float] = Field(None, title='Max')
|
|
749
823
|
|
|
750
824
|
|
|
825
|
+
class Reference(Enum):
|
|
826
|
+
absolute = 'absolute'
|
|
827
|
+
tte = 'tte'
|
|
828
|
+
parameter = 'parameter'
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
class RepeatQuantity(Enum):
|
|
832
|
+
number = 'number'
|
|
833
|
+
|
|
834
|
+
|
|
751
835
|
class Scope(Enum):
|
|
752
836
|
data_read = 'data:read'
|
|
753
837
|
data_write = 'data:write'
|
|
@@ -819,6 +903,22 @@ class TemperatureSummary(BaseModel):
|
|
|
819
903
|
max: Optional[float] = Field(None, title='Max')
|
|
820
904
|
|
|
821
905
|
|
|
906
|
+
class TemplateDay(BaseModel):
|
|
907
|
+
sports: List[Sport] = Field(..., title='Sports')
|
|
908
|
+
avg_training_duration: timedelta = Field(..., title='Avg Training Duration')
|
|
909
|
+
typical_training_duration: timedelta = Field(..., title='Typical Training Duration')
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
class TemplateWeekResponse(BaseModel):
|
|
913
|
+
monday: TemplateDay
|
|
914
|
+
tuesday: TemplateDay
|
|
915
|
+
wednesday: TemplateDay
|
|
916
|
+
thursday: TemplateDay
|
|
917
|
+
friday: TemplateDay
|
|
918
|
+
saturday: TemplateDay
|
|
919
|
+
sunday: TemplateDay
|
|
920
|
+
|
|
921
|
+
|
|
822
922
|
class TokenRequest(BaseModel):
|
|
823
923
|
grant_type: GrantType
|
|
824
924
|
client_id: Optional[str] = Field(None, title='Client Id')
|
|
@@ -850,11 +950,18 @@ class TraceCreateOrUpdate(BaseModel):
|
|
|
850
950
|
sport: Optional[Sport] = None
|
|
851
951
|
|
|
852
952
|
|
|
953
|
+
class UserFlow(Enum):
|
|
954
|
+
session = 'session'
|
|
955
|
+
signup = 'signup'
|
|
956
|
+
login = 'login'
|
|
957
|
+
|
|
958
|
+
|
|
853
959
|
class UserInfoResponse(BaseModel):
|
|
854
960
|
sub: str = Field(..., title='Sub')
|
|
855
961
|
given_name: Optional[str] = Field(None, title='Given Name')
|
|
856
962
|
family_name: Optional[str] = Field(None, title='Family Name')
|
|
857
963
|
email: Optional[str] = Field(None, title='Email')
|
|
964
|
+
registered_at: datetime = Field(..., title='Registered At')
|
|
858
965
|
name: str = Field(..., title='Name')
|
|
859
966
|
|
|
860
967
|
|
|
@@ -872,6 +979,17 @@ class ValidationError(BaseModel):
|
|
|
872
979
|
type: str = Field(..., title='Error Type')
|
|
873
980
|
|
|
874
981
|
|
|
982
|
+
class Value(BaseModel):
|
|
983
|
+
reference: Reference
|
|
984
|
+
value: Union[int, float] = Field(..., title='Value')
|
|
985
|
+
parameter: Optional[str] = Field(None, title='Parameter')
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
class VolumeQuantity(Enum):
|
|
989
|
+
duration = 'duration'
|
|
990
|
+
distance = 'distance'
|
|
991
|
+
|
|
992
|
+
|
|
875
993
|
class ActivitySummarySummary(BaseModel):
|
|
876
994
|
power: Optional[PowerSummary] = None
|
|
877
995
|
speed: Optional[SpeedSummary] = None
|
|
@@ -883,6 +1001,18 @@ class ActivitySummarySummary(BaseModel):
|
|
|
883
1001
|
smo2: Optional[Smo2Summary] = None
|
|
884
1002
|
|
|
885
1003
|
|
|
1004
|
+
class AuthorizeQueryParams(BaseModel):
|
|
1005
|
+
client_id: str = Field(..., title='Client Id')
|
|
1006
|
+
redirect_uri: Optional[str] = Field(None, title='Redirect Uri')
|
|
1007
|
+
scope: List[Scope] = Field(..., min_length=1, title='Scope')
|
|
1008
|
+
state: Optional[str] = Field(None, title='State')
|
|
1009
|
+
nonce: Optional[str] = Field(None, title='Nonce')
|
|
1010
|
+
code_challenge: Optional[str] = Field(None, title='Code Challenge')
|
|
1011
|
+
code_challenge_method: Optional[str] = Field(None, title='Code Challenge Method')
|
|
1012
|
+
prompt: Optional[Prompt] = Field('consent', title='Prompt')
|
|
1013
|
+
user_flow: Optional[UserFlow] = 'session'
|
|
1014
|
+
|
|
1015
|
+
|
|
886
1016
|
class BodyAuthorizeOauthAuthorizePost(BaseModel):
|
|
887
1017
|
client_id: str = Field(..., title='Client Id')
|
|
888
1018
|
redirect_uri: Optional[str] = Field(None, title='Redirect Uri')
|
|
@@ -893,10 +1023,32 @@ class BodyAuthorizeOauthAuthorizePost(BaseModel):
|
|
|
893
1023
|
code_challenge_method: Optional[str] = Field(None, title='Code Challenge Method')
|
|
894
1024
|
|
|
895
1025
|
|
|
1026
|
+
class BodyExpressAddEmailPostExpressAddEmailPost(BaseModel):
|
|
1027
|
+
email: EmailStr = Field(..., title='Email')
|
|
1028
|
+
state: Optional[str] = Field(None, title='State')
|
|
1029
|
+
user_flow: Optional[UserFlow] = 'session'
|
|
1030
|
+
|
|
1031
|
+
|
|
896
1032
|
class BodyGenerateApiKeyPartialsGenerateApiKeyPost(BaseModel):
|
|
897
1033
|
scopes: List[Scope] = Field(..., title='Scopes')
|
|
898
1034
|
|
|
899
1035
|
|
|
1036
|
+
class ConstantValueInput(BaseModel):
|
|
1037
|
+
type: Literal['constant'] = Field('constant', title='Type')
|
|
1038
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1039
|
+
..., title='Quantity'
|
|
1040
|
+
)
|
|
1041
|
+
value: Value
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
class ConstantValueOutput(BaseModel):
|
|
1045
|
+
type: Literal['constant'] = Field('constant', title='Type')
|
|
1046
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1047
|
+
..., title='Quantity'
|
|
1048
|
+
)
|
|
1049
|
+
value: Value
|
|
1050
|
+
|
|
1051
|
+
|
|
900
1052
|
class DelegatedTokenRequest(BaseModel):
|
|
901
1053
|
sub: str = Field(..., title='Sub')
|
|
902
1054
|
scopes: Optional[List[Scope]] = Field(None, title='Scopes')
|
|
@@ -922,6 +1074,13 @@ class HTTPValidationError(BaseModel):
|
|
|
922
1074
|
detail: Optional[List[ValidationError]] = Field(None, title='Detail')
|
|
923
1075
|
|
|
924
1076
|
|
|
1077
|
+
class IntervalsIcuWebhookEvent(BaseModel):
|
|
1078
|
+
athlete_id: str = Field(..., title='Athlete Id')
|
|
1079
|
+
type: IntervalsIcuWebhookEventType
|
|
1080
|
+
timestamp: datetime = Field(..., title='Timestamp')
|
|
1081
|
+
activity: Activity
|
|
1082
|
+
|
|
1083
|
+
|
|
925
1084
|
class Lap(BaseModel):
|
|
926
1085
|
power: Optional[PowerSummary] = None
|
|
927
1086
|
speed: Optional[SpeedSummary] = None
|
|
@@ -938,6 +1097,155 @@ class Lap(BaseModel):
|
|
|
938
1097
|
end_local: datetime = Field(..., title='End Local')
|
|
939
1098
|
|
|
940
1099
|
|
|
1100
|
+
class RampValueInput(BaseModel):
|
|
1101
|
+
type: Literal['ramp'] = Field('ramp', title='Type')
|
|
1102
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1103
|
+
..., title='Quantity'
|
|
1104
|
+
)
|
|
1105
|
+
start: Value
|
|
1106
|
+
end: Value
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
class RampValueOutput(BaseModel):
|
|
1110
|
+
type: Literal['ramp'] = Field('ramp', title='Type')
|
|
1111
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1112
|
+
..., title='Quantity'
|
|
1113
|
+
)
|
|
1114
|
+
start: Value
|
|
1115
|
+
end: Value
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
class RangeValueInput(BaseModel):
|
|
1119
|
+
type: Literal['range'] = Field('range', title='Type')
|
|
1120
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1121
|
+
..., title='Quantity'
|
|
1122
|
+
)
|
|
1123
|
+
min: Optional[Value] = None
|
|
1124
|
+
max: Optional[Value] = None
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
class RangeValueOutput(BaseModel):
|
|
1128
|
+
type: Literal['range'] = Field('range', title='Type')
|
|
1129
|
+
quantity: Union[VolumeQuantity, IntensityQuantity, RepeatQuantity] = Field(
|
|
1130
|
+
..., title='Quantity'
|
|
1131
|
+
)
|
|
1132
|
+
min: Optional[Value] = None
|
|
1133
|
+
max: Optional[Value] = None
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
class IntervalInput(BaseModel):
|
|
1137
|
+
type: Literal['interval'] = Field('interval', title='Type')
|
|
1138
|
+
volume: Union[ConstantValueInput, RangeValueInput, RampValueInput] = Field(
|
|
1139
|
+
..., discriminator='type', title='Volume'
|
|
1140
|
+
)
|
|
1141
|
+
intensity: Union[ConstantValueInput, RangeValueInput, RampValueInput] = Field(
|
|
1142
|
+
..., discriminator='type', title='Intensity'
|
|
1143
|
+
)
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
class IntervalOutput(BaseModel):
|
|
1147
|
+
type: Literal['interval'] = Field('interval', title='Type')
|
|
1148
|
+
volume: Union[ConstantValueOutput, RangeValueOutput, RampValueOutput] = Field(
|
|
1149
|
+
..., discriminator='type', title='Volume'
|
|
1150
|
+
)
|
|
1151
|
+
intensity: Union[ConstantValueOutput, RangeValueOutput, RampValueOutput] = Field(
|
|
1152
|
+
..., discriminator='type', title='Intensity'
|
|
1153
|
+
)
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
class IntervalsIcuWebhookBody(BaseModel):
|
|
1157
|
+
secret: str = Field(..., title='Secret')
|
|
1158
|
+
events: List[IntervalsIcuWebhookEvent] = Field(..., title='Events')
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
class RepeatInput(BaseModel):
|
|
1162
|
+
type: Literal['repeat'] = Field(..., title='Type')
|
|
1163
|
+
count: Union[ConstantValueInput, RangeValueInput] = Field(
|
|
1164
|
+
..., discriminator='type', title='Count'
|
|
1165
|
+
)
|
|
1166
|
+
content: List[Union[IntervalInput, RepeatInput, Instruction]] = Field(
|
|
1167
|
+
..., title='Content'
|
|
1168
|
+
)
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
class RepeatOutput(BaseModel):
|
|
1172
|
+
type: Literal['repeat'] = Field(..., title='Type')
|
|
1173
|
+
count: Union[ConstantValueOutput, RangeValueOutput] = Field(
|
|
1174
|
+
..., discriminator='type', title='Count'
|
|
1175
|
+
)
|
|
1176
|
+
content: List[Union[IntervalOutput, RepeatOutput, Instruction]] = Field(
|
|
1177
|
+
..., title='Content'
|
|
1178
|
+
)
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
class SectionInput(BaseModel):
|
|
1182
|
+
type: Literal['section'] = Field('section', title='Type')
|
|
1183
|
+
name: Optional[str] = Field(..., title='Name')
|
|
1184
|
+
content: List[Union[IntervalInput, RepeatInput, Instruction]] = Field(
|
|
1185
|
+
..., title='Content'
|
|
1186
|
+
)
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
class SectionOutput(BaseModel):
|
|
1190
|
+
type: Literal['section'] = Field('section', title='Type')
|
|
1191
|
+
name: Optional[str] = Field(..., title='Name')
|
|
1192
|
+
content: List[Union[IntervalOutput, RepeatOutput, Instruction]] = Field(
|
|
1193
|
+
..., title='Content'
|
|
1194
|
+
)
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
class Content(RootModel[Union[IntervalInput, RepeatInput, SectionInput, Instruction]]):
|
|
1198
|
+
root: Union[IntervalInput, RepeatInput, SectionInput, Instruction] = Field(
|
|
1199
|
+
..., discriminator='type'
|
|
1200
|
+
)
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
class WorkoutInput(BaseModel):
|
|
1204
|
+
version: Optional[str] = Field('0.1.0', title='Version')
|
|
1205
|
+
title: Optional[str] = Field(None, title='Title')
|
|
1206
|
+
description: Optional[str] = Field(None, title='Description')
|
|
1207
|
+
content: List[Content] = Field(..., title='Content')
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
class Content1(
|
|
1211
|
+
RootModel[Union[IntervalOutput, RepeatOutput, SectionOutput, Instruction]]
|
|
1212
|
+
):
|
|
1213
|
+
root: Union[IntervalOutput, RepeatOutput, SectionOutput, Instruction] = Field(
|
|
1214
|
+
..., discriminator='type'
|
|
1215
|
+
)
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
class WorkoutOutput(BaseModel):
|
|
1219
|
+
version: Optional[str] = Field('0.1.0', title='Version')
|
|
1220
|
+
title: Optional[str] = Field(None, title='Title')
|
|
1221
|
+
description: Optional[str] = Field(None, title='Description')
|
|
1222
|
+
content: List[Content1] = Field(..., title='Content')
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
class LibraryWorkoutCreate(BaseModel):
|
|
1226
|
+
swf: WorkoutInput
|
|
1227
|
+
sport: Sport
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
class LibraryWorkoutResponse(BaseModel):
|
|
1231
|
+
id: str = Field(..., title='Id')
|
|
1232
|
+
swf: WorkoutOutput
|
|
1233
|
+
sport: Sport
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
class ScheduledWorkoutCreate(BaseModel):
|
|
1237
|
+
swf: WorkoutInput
|
|
1238
|
+
sport: Sport
|
|
1239
|
+
start: datetime = Field(..., title='Start')
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
class ScheduledWorkoutResponse(BaseModel):
|
|
1243
|
+
id: str = Field(..., title='Id')
|
|
1244
|
+
swf: WorkoutOutput
|
|
1245
|
+
sport: Sport
|
|
1246
|
+
start: Optional[datetime] = Field(..., title='Start')
|
|
1247
|
+
|
|
1248
|
+
|
|
941
1249
|
class ActivityDetails(BaseModel):
|
|
942
1250
|
tags: Optional[List[str]] = Field(None, title='Tags')
|
|
943
1251
|
id: str = Field(..., title='Id')
|
|
@@ -987,5 +1295,7 @@ class TraceDetails(BaseModel):
|
|
|
987
1295
|
timestamp_local: datetime = Field(..., title='Timestamp Local')
|
|
988
1296
|
|
|
989
1297
|
|
|
1298
|
+
RepeatInput.model_rebuild()
|
|
1299
|
+
RepeatOutput.model_rebuild()
|
|
990
1300
|
ActivityDetails.model_rebuild()
|
|
991
1301
|
ActivitySummary.model_rebuild()
|
|
@@ -2,7 +2,7 @@ from enum import Enum
|
|
|
2
2
|
from typing import List, Union
|
|
3
3
|
|
|
4
4
|
from .openapi_schemas import (
|
|
5
|
-
ActivityDetails, ActivitySummary, Metric, Scope, Sport,
|
|
5
|
+
ActivityDetails, ActivitySummary, BackfillStatus, Metric, Scope, Sport,
|
|
6
6
|
TraceDetails, UserInfoResponse, UserSummary
|
|
7
7
|
)
|
|
8
8
|
|