sweatstack 0.45.0__py3-none-any.whl → 0.47.0__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.
sweatstack/client.py CHANGED
@@ -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, TraceDetails, UserInfoResponse, UserSummary
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-04-15T12:24:50+00:00
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 AnyUrl, BaseModel, Field, SecretStr, confloat, conint
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[AnyUrl] = Field(..., title='Redirect Uris')
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: str = Field(..., title='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: str = Field(..., title='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[AnyUrl] = Field(..., title='Redirect Uris')
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()
sweatstack/schemas.py CHANGED
@@ -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
 
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sweatstack
3
- Version: 0.45.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,17 +1,17 @@
1
1
  sweatstack/__init__.py,sha256=tiVfgKlswRPaDMEy0gA7u8rveqEYZTA_kyB9lJ3J6Sc,21
2
2
  sweatstack/cli.py,sha256=N1NWOgEZR2yaJvIXxo9qvp_jFlypZYb0nujpbVNYQ6A,720
3
- sweatstack/client.py,sha256=bea8IY72fH93PES-dKMbNaB02k_GepRDzVMxEQuBI4g,46966
3
+ sweatstack/client.py,sha256=31iiErq1nWk-zFgApTN_iCWn7an7bB3VOBygGZgAOJ8,49517
4
4
  sweatstack/constants.py,sha256=fGO6ksOv5HeISv9lHRoYm4besW1GTveXS8YD3K0ljg0,41
5
5
  sweatstack/ipython_init.py,sha256=OtBB9dQvyLXklD4kA2x1swaVtU9u73fG4V4-zz4YRAg,139
6
6
  sweatstack/jupyterlab_oauth2_startup.py,sha256=YcjXvzeZ459vL_dCkFi1IxX_RNAu80ZX9rwa0OXJfTM,1023
7
- sweatstack/openapi_schemas.py,sha256=uS5p_ksdF605FNTOhJ_VPPUCxJHOVJwyIOwVfXS-wEI,37019
7
+ sweatstack/openapi_schemas.py,sha256=VvquBdbssdB9D1KeJYQCx51hy1Df4SS0PjzGWXcUaew,46221
8
8
  sweatstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- sweatstack/schemas.py,sha256=cYefSktNv9VJoq4PQ5SrUvZRRwB637xNOaj7kjzjocM,3667
9
+ sweatstack/schemas.py,sha256=44sXrNCYR0qtDsH8sUKR8df9zpcVA-TimkinXJBesOg,3683
10
10
  sweatstack/streamlit.py,sha256=_PER03s0dYu5eF1MZdewPDqSvYHqMr0lZLu_EnGit3Y,13257
11
11
  sweatstack/sweatshell.py,sha256=MYLNcWbOdceqKJ3S0Pe8dwHXEeYsGJNjQoYUXpMTftA,333
12
12
  sweatstack/utils.py,sha256=AwHRdC1ziOZ5o9RBIB21Uxm-DoClVRAJSVvgsmSmvps,1801
13
13
  sweatstack/Sweat Stack examples/Getting started.ipynb,sha256=k2hiSffWecoQ0VxjdpDcgFzBXDQiYEebhnAYlu8cgX8,6335204
14
- sweatstack-0.45.0.dist-info/METADATA,sha256=cos9ZNDCxVPlXUjrcqEiozVN5js56jh0qy_Gx3zElos,814
15
- sweatstack-0.45.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- sweatstack-0.45.0.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
17
- sweatstack-0.45.0.dist-info/RECORD,,
14
+ sweatstack-0.47.0.dist-info/METADATA,sha256=UuRlROP5y90JVM6eopj0PklP0WvdkB1TWxy6RwALrS0,852
15
+ sweatstack-0.47.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ sweatstack-0.47.0.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
17
+ sweatstack-0.47.0.dist-info/RECORD,,