sweatstack 0.11.1__py3-none-any.whl → 0.12.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.
@@ -1,9 +1,11 @@
1
1
  import argparse
2
+ import os
2
3
  import shutil
3
4
  from pathlib import Path
4
5
 
5
6
  import sweatstack as ss
6
7
  from jupyterlab.labapp import LabApp
8
+ from sweatstack.client import _default_client
7
9
 
8
10
 
9
11
  def start_jupyterlab_with_oauth():
@@ -23,5 +25,8 @@ def start_jupyterlab_with_oauth():
23
25
  shutil.copytree(examples_dir, target_dir)
24
26
 
25
27
  ss.login()
28
+ os.environ["SWEATSTACK_API_KEY"] = _default_client.api_key
29
+ os.environ["SWEATSTACK_REFRESH_TOKEN"] = _default_client.refresh_token
30
+
26
31
 
27
32
  return LabApp.launch_instance(argv=remaining_args)
@@ -0,0 +1,368 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: openapi.json
3
+ # timestamp: 2025-02-13T12:03:28+00:00
4
+
5
+ from __future__ import annotations
6
+
7
+ from datetime import datetime, timedelta
8
+ from enum import Enum
9
+ from typing import List, Literal, Optional, Union
10
+
11
+ from pydantic import AnyUrl, BaseModel, Field, SecretStr, confloat, conint
12
+
13
+
14
+ class ActivityUpdate(BaseModel):
15
+ tags: Optional[List[str]] = Field(None, title='Tags')
16
+
17
+
18
+ class BodyAddEmailToWhitelistAdminEmailWhitelistPost(BaseModel):
19
+ email: str = Field(..., title='Email')
20
+
21
+
22
+ class BodyCreateApplicationApplicationsPost(BaseModel):
23
+ name: str = Field(..., title='Name')
24
+ description: str = Field(..., title='Description')
25
+ url: AnyUrl = Field(..., title='Url')
26
+ image: AnyUrl = Field(..., title='Image')
27
+ redirect_uris: List[AnyUrl] = Field(..., title='Redirect Uris')
28
+ privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
29
+
30
+
31
+ class BodyCreateApplicationSecretApplicationsApplicationIdSecretsPost(BaseModel):
32
+ label: str = Field(..., title='Label')
33
+
34
+
35
+ class BodyCreateTagTagsPost(BaseModel):
36
+ tag: str = Field(..., title='Tag')
37
+
38
+
39
+ class BodyDeleteEmailFromWhitelistAdminEmailWhitelistDelete(BaseModel):
40
+ email: str = Field(..., title='Email')
41
+
42
+
43
+ class BodyLoginPostLoginPost(BaseModel):
44
+ email: str = Field(..., title='Email')
45
+ password: SecretStr = Field(..., title='Password')
46
+ tz_offset: int = Field(..., title='Tz Offset')
47
+
48
+
49
+ class BodyRegisterPostRegisterPost(BaseModel):
50
+ email: str = Field(..., title='Email')
51
+ password: SecretStr = Field(..., title='Password')
52
+
53
+
54
+ class BodySaveOrUpdateIntegrationProviderTenantsTenantIdIntegrationProvidersIntegrationNamePost(
55
+ BaseModel
56
+ ):
57
+ client_id: str = Field(..., title='Client Id')
58
+ client_secret: SecretStr = Field(..., title='Client Secret')
59
+ redirect_url: str = Field(..., title='Redirect Url')
60
+
61
+
62
+ class BodyTokenOauthTokenPost(BaseModel):
63
+ grant_type: Literal['authorization_code'] = Field(..., title='Grant Type')
64
+ code: str = Field(..., title='Code')
65
+ client_id: str = Field(..., title='Client Id')
66
+ client_secret: Optional[str] = Field(None, title='Client Secret')
67
+ code_verifier: Optional[str] = Field(None, title='Code Verifier')
68
+ refresh_token: Optional[str] = Field(None, title='Refresh Token')
69
+ tz_offset: Optional[int] = Field(0, title='Tz Offset')
70
+
71
+
72
+ class BodyUpdateApplicationApplicationsApplicationIdPut(BaseModel):
73
+ name: str = Field(..., title='Name')
74
+ description: str = Field(..., title='Description')
75
+ url: AnyUrl = Field(..., title='Url')
76
+ image: AnyUrl = Field(..., title='Image')
77
+ redirect_uris: List[AnyUrl] = Field(..., title='Redirect Uris')
78
+ privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
79
+
80
+
81
+ class BodyUpdateUserUsersUserIdPut(BaseModel):
82
+ first_name: str = Field(..., title='First Name')
83
+ last_name: str = Field(..., title='Last Name')
84
+
85
+
86
+ class BodyUploadActivityFileDataUploadPost(BaseModel):
87
+ files: List[bytes] = Field(..., title='Files')
88
+
89
+
90
+ class CoreTemperatureSummary(BaseModel):
91
+ mean: Optional[float] = Field(None, title='Mean')
92
+ min: Optional[float] = Field(None, title='Min')
93
+ max: Optional[float] = Field(None, title='Max')
94
+ start: Optional[float] = Field(None, title='Start')
95
+ end: Optional[float] = Field(None, title='End')
96
+
97
+
98
+ class DistanceSummary(BaseModel):
99
+ sum: Optional[int] = Field(None, title='Sum')
100
+
101
+
102
+ class ElevationSummary(BaseModel):
103
+ min: Optional[int] = Field(None, title='Min')
104
+ max: Optional[int] = Field(None, title='Max')
105
+
106
+
107
+ class GarminDeregistration(BaseModel):
108
+ userId: str = Field(..., title='Userid')
109
+ userAccessToken: str = Field(..., title='Useraccesstoken')
110
+
111
+
112
+ class GarminDeregistrationBody(BaseModel):
113
+ deregistrations: List[GarminDeregistration] = Field(..., title='Deregistrations')
114
+
115
+
116
+ class GarminFileTypes(Enum):
117
+ FIT = 'FIT'
118
+ GPX = 'GPX'
119
+ TCX = 'TCX'
120
+
121
+
122
+ class GrantType(Enum):
123
+ authorization_code = 'authorization_code'
124
+ refresh_token = 'refresh_token'
125
+ implicit = 'implicit'
126
+
127
+
128
+ class HeartRateSummary(BaseModel):
129
+ mean: Optional[float] = Field(None, title='Mean')
130
+ min: Optional[float] = Field(None, title='Min')
131
+ max: Optional[float] = Field(None, title='Max')
132
+ start: Optional[float] = Field(None, title='Start')
133
+ end: Optional[float] = Field(None, title='End')
134
+
135
+
136
+ class IntegrationName(Enum):
137
+ garmin_connect = 'garmin_connect'
138
+
139
+
140
+ class Metric(Enum):
141
+ duration = 'duration'
142
+ lap = 'lap'
143
+ power = 'power'
144
+ speed = 'speed'
145
+ heart_rate = 'heart_rate'
146
+ smo2 = 'smo2'
147
+ core_temperature = 'core_temperature'
148
+ elevation = 'elevation'
149
+ cadence = 'cadence'
150
+ temperature = 'temperature'
151
+ distance = 'distance'
152
+ longitude = 'longitude'
153
+ latitude = 'latitude'
154
+ lactate = 'lactate'
155
+ rpe = 'rpe'
156
+ notes = 'notes'
157
+
158
+
159
+ class PowerSummary(BaseModel):
160
+ mean: Optional[float] = Field(None, title='Mean')
161
+ min: Optional[float] = Field(None, title='Min')
162
+ max: Optional[float] = Field(None, title='Max')
163
+
164
+
165
+ class Scope(Enum):
166
+ data_read = 'data:read'
167
+ data_write = 'data:write'
168
+ admin = 'admin'
169
+
170
+
171
+ class Smo2Summary(BaseModel):
172
+ mean: Optional[float] = Field(None, title='Mean')
173
+ min: Optional[float] = Field(None, title='Min')
174
+ max: Optional[float] = Field(None, title='Max')
175
+ start: Optional[float] = Field(None, title='Start')
176
+ end: Optional[float] = Field(None, title='End')
177
+
178
+
179
+ class SpeedSummary(BaseModel):
180
+ mean: Optional[float] = Field(None, title='Mean')
181
+ min: Optional[float] = Field(None, title='Min')
182
+ max: Optional[float] = Field(None, title='Max')
183
+
184
+
185
+ class Sport(Enum):
186
+ cycling = 'cycling'
187
+ cycling_road = 'cycling.road'
188
+ cycling_tt = 'cycling.tt'
189
+ cycling_cyclocross = 'cycling.cyclocross'
190
+ cycling_gravel = 'cycling.gravel'
191
+ cycling_mountainbike = 'cycling.mountainbike'
192
+ cycling_track = 'cycling.track'
193
+ cycling_track_250m = 'cycling.track.250m'
194
+ cycling_track_333m = 'cycling.track.333m'
195
+ cycling_trainer = 'cycling.trainer'
196
+ running = 'running'
197
+ running_road = 'running.road'
198
+ running_track = 'running.track'
199
+ running_track_200m = 'running.track.200m'
200
+ running_track_400m = 'running.track.400m'
201
+ running_trail = 'running.trail'
202
+ running_treadmill = 'running.treadmill'
203
+ walking = 'walking'
204
+ walking_hiking = 'walking.hiking'
205
+ cross_country_skiing = 'cross_country_skiing'
206
+ cross_country_skiing_classic = 'cross_country_skiing.classic'
207
+ cross_country_skiing_skate = 'cross_country_skiing.skate'
208
+ cross_country_skiing_backcountry = 'cross_country_skiing.backcountry'
209
+ cross_country_skiing_ergometer = 'cross_country_skiing.ergometer'
210
+ rowing = 'rowing'
211
+ rowing_ergometer = 'rowing.ergometer'
212
+ rowing_indoor = 'rowing.indoor'
213
+ rowing_regatta = 'rowing.regatta'
214
+ rowing_fixed_seat = 'rowing.fixed-seat'
215
+ rowing_coastal = 'rowing.coastal'
216
+ swimming = 'swimming'
217
+ swimming_pool = 'swimming.pool'
218
+ swimming_pool_50m = 'swimming.pool.50m'
219
+ swimming_pool_25m = 'swimming.pool.25m'
220
+ swimming_pool_25y = 'swimming.pool.25y'
221
+ swimming_pool_33m = 'swimming.pool.33m'
222
+ swimming_open_water = 'swimming.open_water'
223
+ swimming_flume = 'swimming.flume'
224
+ generic = 'generic'
225
+ unknown = 'unknown'
226
+
227
+
228
+ class TemperatureSummary(BaseModel):
229
+ mean: Optional[float] = Field(None, title='Mean')
230
+ min: Optional[float] = Field(None, title='Min')
231
+ max: Optional[float] = Field(None, title='Max')
232
+
233
+
234
+ class TokenRequest(BaseModel):
235
+ grant_type: GrantType
236
+ code: Optional[str] = Field(None, title='Code')
237
+ refresh_token: Optional[str] = Field(None, title='Refresh Token')
238
+ client_id: Optional[str] = Field(None, title='Client Id')
239
+ client_secret: Optional[SecretStr] = Field(None, title='Client Secret')
240
+ tz_offset: Optional[int] = Field(
241
+ 3600, description='Timezone DST offset in seconds', title='Tz Offset'
242
+ )
243
+
244
+
245
+ class TokenResponse(BaseModel):
246
+ access_token: str = Field(..., title='Access Token')
247
+ token_type: Literal['Bearer'] = Field('Bearer', title='Token Type')
248
+ expires_in: int = Field(..., title='Expires In')
249
+ refresh_token: str = Field(..., title='Refresh Token')
250
+ scope: Optional[str] = Field(None, title='Scope')
251
+
252
+
253
+ class TraceCreateOrUpdate(BaseModel):
254
+ timestamp: datetime = Field(..., title='Timestamp')
255
+ lactate: Optional[float] = Field(None, title='Lactate')
256
+ rpe: Optional[int] = Field(None, title='Rpe')
257
+ notes: Optional[str] = Field(None, title='Notes')
258
+ power: Optional[conint(ge=0)] = Field(None, title='Power')
259
+ speed: Optional[confloat(ge=0.0)] = Field(None, title='Speed')
260
+ heart_rate: Optional[conint(ge=0)] = Field(None, title='Heart Rate')
261
+ tags: Optional[List[str]] = Field(None, title='Tags')
262
+
263
+
264
+ class ValidationError(BaseModel):
265
+ loc: List[Union[str, int]] = Field(..., title='Location')
266
+ msg: str = Field(..., title='Message')
267
+ type: str = Field(..., title='Error Type')
268
+
269
+
270
+ class ActivitySummarySummary(BaseModel):
271
+ power: Optional[PowerSummary] = None
272
+ speed: Optional[SpeedSummary] = None
273
+ distance: Optional[DistanceSummary] = None
274
+ elevation: Optional[ElevationSummary] = None
275
+ heart_rate: Optional[HeartRateSummary] = None
276
+ temperature: Optional[TemperatureSummary] = None
277
+ core_temperature: Optional[CoreTemperatureSummary] = None
278
+ smo2: Optional[Smo2Summary] = None
279
+
280
+
281
+ class BodyAuthorizeOauthAuthorizePost(BaseModel):
282
+ client_id: str = Field(..., title='Client Id')
283
+ redirect_uri: Optional[str] = Field(None, title='Redirect Uri')
284
+ scopes: List[Scope] = Field(..., min_length=1, title='Scopes')
285
+ state: Optional[str] = Field(None, title='State')
286
+ code_challenge: Optional[str] = Field(None, title='Code Challenge')
287
+ code_challenge_method: Optional[str] = Field(None, title='Code Challenge Method')
288
+
289
+
290
+ class GarminActivityFileData(BaseModel):
291
+ userId: str = Field(..., title='Userid')
292
+ userAccessToken: str = Field(..., title='Useraccesstoken')
293
+ summaryId: str = Field(..., title='Summaryid')
294
+ fileType: GarminFileTypes
295
+ callbackURL: str = Field(..., title='Callbackurl')
296
+ startTimeInSeconds: datetime = Field(..., title='Starttimeinseconds')
297
+ activityId: str = Field(..., title='Activityid')
298
+ activityName: str = Field(..., title='Activityname')
299
+ manual: Optional[bool] = Field(False, title='Manual')
300
+
301
+
302
+ class GarminPingBody(BaseModel):
303
+ activityFiles: List[GarminActivityFileData] = Field(..., title='Activityfiles')
304
+
305
+
306
+ class HTTPValidationError(BaseModel):
307
+ detail: Optional[List[ValidationError]] = Field(None, title='Detail')
308
+
309
+
310
+ class Lap(BaseModel):
311
+ power: Optional[PowerSummary] = None
312
+ speed: Optional[SpeedSummary] = None
313
+ distance: Optional[DistanceSummary] = None
314
+ elevation: Optional[ElevationSummary] = None
315
+ heart_rate: Optional[HeartRateSummary] = None
316
+ temperature: Optional[TemperatureSummary] = None
317
+ core_temperature: Optional[CoreTemperatureSummary] = None
318
+ smo2: Optional[Smo2Summary] = None
319
+ start: datetime = Field(..., title='Start')
320
+ end: datetime = Field(..., title='End')
321
+ duration: timedelta = Field(..., title='Duration')
322
+
323
+
324
+ class ActivityDetails(BaseModel):
325
+ tags: Optional[List[str]] = Field(None, title='Tags')
326
+ id: str = Field(..., title='Id')
327
+ sport: Sport
328
+ start: datetime = Field(..., title='Start')
329
+ end: datetime = Field(..., title='End')
330
+ metrics: List[Metric] = Field(..., title='Metrics')
331
+ source_id: str = Field(..., title='Source Id')
332
+ summary: Optional[ActivitySummarySummary] = None
333
+ laps: Optional[List[Lap]] = Field(None, title='Laps')
334
+ traces: Optional[List[TraceDetails]] = Field(None, title='Traces')
335
+ distance: Optional[float] = Field(None, title='Distance')
336
+ duration: timedelta = Field(..., title='Duration')
337
+
338
+
339
+ class ActivitySummary(BaseModel):
340
+ tags: Optional[List[str]] = Field(None, title='Tags')
341
+ id: str = Field(..., title='Id')
342
+ sport: Sport
343
+ start: datetime = Field(..., title='Start')
344
+ end: datetime = Field(..., title='End')
345
+ metrics: List[Metric] = Field(..., title='Metrics')
346
+ source_id: str = Field(..., title='Source Id')
347
+ summary: Optional[ActivitySummarySummary] = None
348
+ laps: Optional[List[Lap]] = Field(None, title='Laps')
349
+ traces: Optional[List[TraceDetails]] = Field(None, title='Traces')
350
+ duration: timedelta = Field(..., title='Duration')
351
+
352
+
353
+ class TraceDetails(BaseModel):
354
+ tags: Optional[List[str]] = Field(None, title='Tags')
355
+ id: str = Field(..., title='Id')
356
+ timestamp: datetime = Field(..., title='Timestamp')
357
+ lactate: Optional[float] = Field(None, title='Lactate')
358
+ rpe: Optional[int] = Field(None, title='Rpe')
359
+ notes: Optional[str] = Field(None, title='Notes')
360
+ power: Optional[conint(ge=0)] = Field(None, title='Power')
361
+ speed: Optional[confloat(ge=0.0)] = Field(None, title='Speed')
362
+ heart_rate: Optional[conint(ge=0)] = Field(None, title='Heart Rate')
363
+ lap: Optional[Lap] = None
364
+ activity: Optional[ActivitySummary] = None
365
+
366
+
367
+ ActivityDetails.model_rebuild()
368
+ ActivitySummary.model_rebuild()
sweatstack/py.typed ADDED
File without changes
sweatstack/schemas.py CHANGED
@@ -1,229 +1,3 @@
1
- # generated by datamodel-codegen:
2
- # filename: openapi.json
3
- # timestamp: 2024-09-17T08:24:03+00:00
4
-
5
- from __future__ import annotations
6
-
7
- from enum import Enum
8
- from typing import Dict, List, Optional, Union
9
-
10
- from pydantic import AwareDatetime, BaseModel, Field, conint
11
- from typing_extensions import Literal
12
-
13
-
14
- class ActivityLap(BaseModel):
15
- start: AwareDatetime = Field(..., title='Start')
16
- end: AwareDatetime = Field(..., title='End')
17
- power: Optional[float] = Field(None, title='Power')
18
- speed: Optional[float] = Field(None, title='Speed')
19
- distance: Optional[float] = Field(None, title='Distance')
20
- altitude: Optional[float] = Field(None, title='Altitude')
21
- heart_rate: Optional[float] = Field(None, title='Heart Rate')
22
- heart_rate_start: Optional[float] = Field(None, title='Heart Rate Start')
23
- heart_rate_end: Optional[float] = Field(None, title='Heart Rate End')
24
- cadence: Optional[float] = Field(None, title='Cadence')
25
- temperature: Optional[float] = Field(None, title='Temperature')
26
- core_temperature: Optional[float] = Field(None, title='Core Temperature')
27
- smo2: Optional[float] = Field(None, title='Smo2')
28
- duration: str = Field(..., title='Duration')
29
-
30
-
31
- class BodyAuthorizeOauthAuthorizePost(BaseModel):
32
- client_id: str = Field(..., title='Client Id')
33
- redirect_uri: str = Field(..., title='Redirect Uri')
34
- scope: Optional[str] = Field(None, title='Scope')
35
- state: Optional[str] = Field(None, title='State')
36
- code_challenge: Optional[str] = Field(None, title='Code Challenge')
37
- code_challenge_method: Optional[str] = Field(None, title='Code Challenge Method')
38
-
39
-
40
- class GrantType(Enum):
41
- authorization_code = 'authorization_code'
42
-
43
-
44
- class BodyTokenOauthTokenPost(BaseModel):
45
- grant_type: Literal['authorization_code'] = Field(..., title='Grant Type')
46
- code: str = Field(..., title='Code')
47
- client_id: str = Field(..., title='Client Id')
48
- client_secret: Optional[str] = Field(None, title='Client Secret')
49
- code_verifier: Optional[str] = Field(None, title='Code Verifier')
50
- refresh_token: Optional[str] = Field(None, title='Refresh Token')
51
-
52
-
53
- class BodyUploadActivityFileApiActivitiesUploadPost(BaseModel):
54
- files: List[bytes] = Field(..., title='Files')
55
-
56
-
57
- class IntegrationNames(Enum):
58
- garmin_connect = 'garmin_connect'
59
- manual_upload = 'manual_upload'
60
-
61
-
62
- class JWTResponse(BaseModel):
63
- jwt: str = Field(..., title='Jwt')
64
- refresh_token: str = Field(..., title='Refresh Token')
65
-
66
-
67
- class LapSyncData(BaseModel):
68
- power: Optional[float] = Field(None, title='Power')
69
- speed: Optional[float] = Field(None, title='Speed')
70
- sport: str = Field(..., title='Sport')
71
- activity: str = Field(..., title='Activity')
72
-
73
-
74
- class LapSyncedTrace(BaseModel):
75
- timestamp: AwareDatetime = Field(..., title='Timestamp')
76
- lactate: Optional[float] = Field(None, title='Lactate')
77
- rpe: Optional[conint(ge=0, le=10)] = Field(
78
- None,
79
- description='Rating of Perceived Exertion (RPE) on the CR10 scale, ranging from 0 to 10:\n0 - No exertion at all\n1 - Very light\n2 - Light\n3 - Moderate\n4 - Somewhat hard\n5 - Hard\n6 - \n7 - Very hard\n8 - \n9 - Very, very hard\n10 - Maximum effort',
80
- title='Rpe',
81
- )
82
- notes: Optional[str] = Field(None, title='Notes')
83
- lap_sync: Optional[LapSyncData] = None
84
-
85
-
86
- class Metric(Enum):
87
- power = 'power'
88
- speed = 'speed'
89
- heart_rate = 'heart_rate'
90
- smo2 = 'smo2'
91
- core_temperature = 'core_temperature'
92
- altitude = 'altitude'
93
- cadence = 'cadence'
94
- temperature = 'temperature'
95
- distance = 'distance'
96
- longitude = 'longitude'
97
- latitude = 'latitude'
98
- lactate = 'lactate'
99
- rpe = 'rpe'
100
- notes = 'notes'
101
-
102
-
103
- class PermissionType(Enum):
104
- granted = 'granted'
105
- received = 'received'
106
-
107
-
108
- class Sport(Enum):
109
- cycling = 'cycling'
110
- cycling_road = 'cycling.road'
111
- cycling_tt = 'cycling.tt'
112
- cycling_cyclocross = 'cycling.cyclocross'
113
- cycling_gravel = 'cycling.gravel'
114
- cycling_mountainbike = 'cycling.mountainbike'
115
- cycling_track = 'cycling.track'
116
- cycling_track_250m = 'cycling.track.250m'
117
- cycling_track_333m = 'cycling.track.333m'
118
- running = 'running'
119
- running_road = 'running.road'
120
- running_track = 'running.track'
121
- running_track_200m = 'running.track.200m'
122
- running_track_400m = 'running.track.400m'
123
- running_trail = 'running.trail'
124
- walking = 'walking'
125
- hiking = 'hiking'
126
- cross_country_skiing = 'cross_country_skiing'
127
- cross_country_skiing_classic = 'cross_country_skiing.classic'
128
- cross_country_skiing_skate = 'cross_country_skiing.skate'
129
- cross_country_skiing_backcountry = 'cross_country_skiing.backcountry'
130
- rowing = 'rowing'
131
- swimming = 'swimming'
132
- swimming_pool = 'swimming.pool'
133
- swimming_pool_50m = 'swimming.pool.50m'
134
- swimming_pool_25m = 'swimming.pool.25m'
135
- swimming_pool_25y = 'swimming.pool.25y'
136
- swimming_pool_33m = 'swimming.pool.33m'
137
- swimming_open_water = 'swimming.open_water'
138
- swimming_flume = 'swimming.flume'
139
- generic = 'generic'
140
-
141
-
142
- class Trace(BaseModel):
143
- timestamp: AwareDatetime = Field(..., title='Timestamp')
144
- lactate: Optional[float] = Field(None, title='Lactate')
145
- rpe: Optional[conint(ge=0, le=10)] = Field(
146
- None,
147
- description='Rating of Perceived Exertion (RPE) on the CR10 scale, ranging from 0 to 10:\n0 - No exertion at all\n1 - Very light\n2 - Light\n3 - Moderate\n4 - Somewhat hard\n5 - Hard\n6 - \n7 - Very hard\n8 - \n9 - Very, very hard\n10 - Maximum effort',
148
- title='Rpe',
149
- )
150
- notes: Optional[str] = Field(None, title='Notes')
151
-
152
-
153
- class User(BaseModel):
154
- id: str = Field(..., title='Id')
155
- first_name: Optional[str] = Field(None, title='First Name')
156
- last_name: Optional[str] = Field(None, title='Last Name')
157
- display_name: Optional[str] = Field(None, title='Display Name')
158
- permission_types: Optional[List[PermissionType]] = Field(
159
- None, title='Permission Types'
160
- )
161
-
162
-
163
- class ValidationError(BaseModel):
164
- loc: List[Union[str, int]] = Field(..., title='Location')
165
- msg: str = Field(..., title='Message')
166
- type: str = Field(..., title='Error Type')
167
-
168
-
169
- class BaseActivitySummary(BaseModel):
170
- id: str = Field(..., title='Id')
171
- title: Optional[str] = Field(None, title='Title')
172
- start: AwareDatetime = Field(..., title='Start')
173
- end: Optional[AwareDatetime] = Field(..., title='End')
174
- sport: Sport
175
- stationary: Optional[bool] = Field(None, title='Stationary')
176
- metrics: Optional[List[Metric]] = Field([], title='Metrics')
177
- integration: Optional[IntegrationNames] = None
178
- device: Optional[str] = Field(None, title='Device')
179
- duration: Optional[str] = Field(..., title='Duration')
180
- display_sport: Optional[str] = Field(..., title='Display Sport')
181
-
182
-
183
- class HTTPValidationError(BaseModel):
184
- detail: Optional[List[ValidationError]] = Field(None, title='Detail')
185
-
186
-
187
- class ActivityDetail(BaseModel):
188
- id: str = Field(..., title='Id')
189
- title: Optional[str] = Field(None, title='Title')
190
- start: AwareDatetime = Field(..., title='Start')
191
- end: Optional[AwareDatetime] = Field(..., title='End')
192
- sport: Sport
193
- stationary: Optional[bool] = Field(None, title='Stationary')
194
- metrics: Optional[List[Metric]] = Field([], title='Metrics')
195
- integration: Optional[IntegrationNames] = None
196
- device: Optional[str] = Field(None, title='Device')
197
- fusion_activities: Optional[List[BaseActivitySummary]] = Field(
198
- [], title='Fusion Activities'
199
- )
200
- laps: Optional[List[ActivityLap]] = Field([], title='Laps')
201
- duration: Optional[str] = Field(..., title='Duration')
202
- display_sport: Optional[str] = Field(..., title='Display Sport')
203
-
204
-
205
- class ActivitySummary(BaseModel):
206
- id: str = Field(..., title='Id')
207
- title: Optional[str] = Field(None, title='Title')
208
- start: AwareDatetime = Field(..., title='Start')
209
- end: Optional[AwareDatetime] = Field(..., title='End')
210
- sport: Sport
211
- stationary: Optional[bool] = Field(None, title='Stationary')
212
- metrics: Optional[List[Metric]] = Field([], title='Metrics')
213
- integration: Optional[IntegrationNames] = None
214
- device: Optional[str] = Field(None, title='Device')
215
- fusion_activities: Optional[List[BaseActivitySummary]] = Field(
216
- [], title='Fusion Activities'
217
- )
218
- duration: Optional[str] = Field(..., title='Duration')
219
- display_sport: Optional[str] = Field(..., title='Display Sport')
220
-
221
-
222
- class ActivityData(BaseModel):
223
- data: Optional[str] = Field(
224
- None,
225
- description="A JSON encoded pandas DataFrame, generated with read_json(orient='split'). See pandas documentation for more information on the schema.",
226
- title='DataFrame (optional)',
227
- )
228
- activity: ActivityDetail
229
- column_mapping: Dict[str, Dict[str, str]] = Field(..., title='Column Mapping')
1
+ from .openapi_schemas import (
2
+ ActivityDetails, ActivitySummary, Sport, TraceDetails
3
+ )
sweatstack/utils.py ADDED
@@ -0,0 +1,13 @@
1
+ import base64
2
+ import json
3
+
4
+
5
+ def decode_jwt_body(jwt: str) -> dict:
6
+ payload = jwt.split(".")[1]
7
+
8
+ padding = len(payload) % 4
9
+ if padding:
10
+ payload += "=" * (4 - padding)
11
+
12
+ decoded = base64.urlsafe_b64decode(payload)
13
+ return json.loads(decoded)