sweatstack 0.14.1__py3-none-any.whl → 0.14.3__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 +20 -7
- sweatstack/streamlit.py +3 -1
- sweatstack/utils.py +43 -3
- {sweatstack-0.14.1.dist-info → sweatstack-0.14.3.dist-info}/METADATA +1 -1
- {sweatstack-0.14.1.dist-info → sweatstack-0.14.3.dist-info}/RECORD +7 -7
- {sweatstack-0.14.1.dist-info → sweatstack-0.14.3.dist-info}/WHEEL +0 -0
- {sweatstack-0.14.1.dist-info → sweatstack-0.14.3.dist-info}/entry_points.txt +0 -0
sweatstack/client.py
CHANGED
|
@@ -19,7 +19,7 @@ import pandas as pd
|
|
|
19
19
|
|
|
20
20
|
from .constants import DEFAULT_URL
|
|
21
21
|
from .schemas import ActivityDetails, ActivitySummary, Sport, TraceDetails
|
|
22
|
-
from .utils import decode_jwt_body
|
|
22
|
+
from .utils import decode_jwt_body, make_dataframe_streamlit_compatible
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
AUTH_SUCCESSFUL_RESPONSE = "<!DOCTYPE html><html><body><h1>Authentication successful. You can now close this window.</h1></body></html>"
|
|
@@ -109,10 +109,12 @@ class Client(OAuth2Mixin):
|
|
|
109
109
|
api_key: str | None = None,
|
|
110
110
|
refresh_token: str | None = None,
|
|
111
111
|
url: str | None = None,
|
|
112
|
+
streamlit_compatible: bool = False,
|
|
112
113
|
):
|
|
113
114
|
self.api_key = api_key
|
|
114
115
|
self.refresh_token = refresh_token
|
|
115
116
|
self.url = url
|
|
117
|
+
self.streamlit_compatible = streamlit_compatible
|
|
116
118
|
|
|
117
119
|
def _do_token_refresh(self, tz_offset: int) -> str:
|
|
118
120
|
with self._http_client() as client:
|
|
@@ -247,6 +249,12 @@ class Client(OAuth2Mixin):
|
|
|
247
249
|
params["limit"] = min(default_limit, limit - num_returned)
|
|
248
250
|
params["offset"] += default_limit
|
|
249
251
|
|
|
252
|
+
def _postprocess_dataframe(self, df: pd.DataFrame) -> pd.DataFrame:
|
|
253
|
+
if self.streamlit_compatible:
|
|
254
|
+
return make_dataframe_streamlit_compatible(df)
|
|
255
|
+
else:
|
|
256
|
+
return df
|
|
257
|
+
|
|
250
258
|
def get_activities(
|
|
251
259
|
self,
|
|
252
260
|
*,
|
|
@@ -265,7 +273,8 @@ class Client(OAuth2Mixin):
|
|
|
265
273
|
limit=limit,
|
|
266
274
|
)
|
|
267
275
|
if as_dataframe:
|
|
268
|
-
|
|
276
|
+
df = pd.DataFrame([activity.model_dump() for activity in generator])
|
|
277
|
+
return self._postprocess_dataframe(df)
|
|
269
278
|
else:
|
|
270
279
|
return generator
|
|
271
280
|
|
|
@@ -308,7 +317,8 @@ class Client(OAuth2Mixin):
|
|
|
308
317
|
|
|
309
318
|
response.raise_for_status()
|
|
310
319
|
|
|
311
|
-
|
|
320
|
+
df = pd.read_parquet(BytesIO(response.content))
|
|
321
|
+
return self._postprocess_dataframe(df)
|
|
312
322
|
|
|
313
323
|
def get_activity_mean_max(
|
|
314
324
|
self,
|
|
@@ -325,7 +335,8 @@ class Client(OAuth2Mixin):
|
|
|
325
335
|
},
|
|
326
336
|
)
|
|
327
337
|
response.raise_for_status()
|
|
328
|
-
|
|
338
|
+
df = pd.read_parquet(BytesIO(response.content))
|
|
339
|
+
return self._postprocess_dataframe(df)
|
|
329
340
|
|
|
330
341
|
def get_latest_activity_data(
|
|
331
342
|
self,
|
|
@@ -379,7 +390,8 @@ class Client(OAuth2Mixin):
|
|
|
379
390
|
)
|
|
380
391
|
response.raise_for_status()
|
|
381
392
|
|
|
382
|
-
|
|
393
|
+
df = pd.read_parquet(BytesIO(response.content))
|
|
394
|
+
return self._postprocess_dataframe(df)
|
|
383
395
|
|
|
384
396
|
def get_longitudinal_mean_max(
|
|
385
397
|
self,
|
|
@@ -405,7 +417,8 @@ class Client(OAuth2Mixin):
|
|
|
405
417
|
)
|
|
406
418
|
response.raise_for_status()
|
|
407
419
|
|
|
408
|
-
|
|
420
|
+
df = pd.read_parquet(BytesIO(response.content))
|
|
421
|
+
return self._postprocess_dataframe(df)
|
|
409
422
|
|
|
410
423
|
def _get_traces_generator(
|
|
411
424
|
self,
|
|
@@ -488,7 +501,7 @@ class Client(OAuth2Mixin):
|
|
|
488
501
|
if "lap" in data.columns:
|
|
489
502
|
data = self._normalize_dataframe_column(data, "lap")
|
|
490
503
|
|
|
491
|
-
return data
|
|
504
|
+
return self._postprocess_dataframe(data)
|
|
492
505
|
|
|
493
506
|
def create_trace(
|
|
494
507
|
self,
|
sweatstack/streamlit.py
CHANGED
|
@@ -60,9 +60,11 @@ class StreamlitAuth:
|
|
|
60
60
|
"client_secret": self.client_secret,
|
|
61
61
|
"code": code,
|
|
62
62
|
}
|
|
63
|
+
auth = httpx.BasicAuth(username=self.client_id, password=self.client_secret)
|
|
63
64
|
response = httpx.post(
|
|
64
65
|
f"{DEFAULT_URL}/api/v1/oauth/token",
|
|
65
66
|
data=token_data,
|
|
67
|
+
auth=auth,
|
|
66
68
|
)
|
|
67
69
|
try:
|
|
68
70
|
response.raise_for_status()
|
|
@@ -73,7 +75,7 @@ class StreamlitAuth:
|
|
|
73
75
|
self.api_key = token_response.get("access_token")
|
|
74
76
|
st.session_state["sweatstack_api_key"] = self.api_key
|
|
75
77
|
|
|
76
|
-
self.client = Client(self.api_key)
|
|
78
|
+
self.client = Client(self.api_key, streamlit_compatible=True)
|
|
77
79
|
|
|
78
80
|
return
|
|
79
81
|
|
sweatstack/utils.py
CHANGED
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import json
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
def decode_jwt_body(jwt: str) -> dict:
|
|
6
9
|
payload = jwt.split(".")[1]
|
|
7
|
-
|
|
10
|
+
|
|
8
11
|
padding = len(payload) % 4
|
|
9
12
|
if padding:
|
|
10
13
|
payload += "=" * (4 - padding)
|
|
11
|
-
|
|
14
|
+
|
|
12
15
|
decoded = base64.urlsafe_b64decode(payload)
|
|
13
|
-
return json.loads(decoded)
|
|
16
|
+
return json.loads(decoded)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def make_dataframe_streamlit_compatible(df):
|
|
20
|
+
"""
|
|
21
|
+
Converts all columns containing enum values in a DataFrame to their respective string values.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
df (pd.DataFrame): The DataFrame to process
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
pd.DataFrame: A new DataFrame with enum values converted to strings
|
|
28
|
+
"""
|
|
29
|
+
df_copy = None
|
|
30
|
+
|
|
31
|
+
for column in df.columns:
|
|
32
|
+
# Check if the column contains enum values
|
|
33
|
+
if df[column].dtype == 'object':
|
|
34
|
+
# First check if it's a list column of enums
|
|
35
|
+
if df[column].notna().any():
|
|
36
|
+
first_value = df[column].dropna().iloc[0]
|
|
37
|
+
|
|
38
|
+
# Handle list of enums
|
|
39
|
+
if isinstance(first_value, list) and first_value and isinstance(first_value[0], Enum):
|
|
40
|
+
if df_copy is None:
|
|
41
|
+
df_copy = df.copy()
|
|
42
|
+
df_copy[column] = df_copy[column].apply(
|
|
43
|
+
lambda x: [item.value if isinstance(item, Enum) else item for item in x] if isinstance(x, list) else x
|
|
44
|
+
)
|
|
45
|
+
# Handle single enum values
|
|
46
|
+
elif isinstance(first_value, Enum):
|
|
47
|
+
if df_copy is None:
|
|
48
|
+
df_copy = df.copy()
|
|
49
|
+
df_copy[column] = df_copy[column].apply(
|
|
50
|
+
lambda x: x.value if isinstance(x, Enum) else x
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return df_copy if df_copy is not None else df
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
sweatstack/__init__.py,sha256=tiVfgKlswRPaDMEy0gA7u8rveqEYZTA_kyB9lJ3J6Sc,21
|
|
2
2
|
sweatstack/cli.py,sha256=N1NWOgEZR2yaJvIXxo9qvp_jFlypZYb0nujpbVNYQ6A,720
|
|
3
|
-
sweatstack/client.py,sha256=
|
|
3
|
+
sweatstack/client.py,sha256=op-pfQAAxmoz6XhTL8p2H8GXqCcN92vxwJfoAmCP7CM,19747
|
|
4
4
|
sweatstack/constants.py,sha256=fGO6ksOv5HeISv9lHRoYm4besW1GTveXS8YD3K0ljg0,41
|
|
5
5
|
sweatstack/ipython_init.py,sha256=zBGUlMFkdpLvsNpOpwrNaKRUpUZhzaICvH8ODJgMPcI,229
|
|
6
6
|
sweatstack/jupyterlab_oauth2_startup.py,sha256=eZ6xi0Sa4hO4vUanimq0SqjduHtiywCURSDNWk_I-7s,1200
|
|
7
7
|
sweatstack/openapi_schemas.py,sha256=vtYHa6A0kADFbd_jK1O7Kbn8YkbPfzaIwsRDDYjYeSA,13038
|
|
8
8
|
sweatstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
sweatstack/schemas.py,sha256=CdkeV6IRmIuvxae7C5dz-hVlb6hkzEYfqKHHgVJprmY,90
|
|
10
|
-
sweatstack/streamlit.py,sha256=
|
|
10
|
+
sweatstack/streamlit.py,sha256=xmASRIB-TfqMc3je6Qkkr0D-L9lr9oNVUWcXUzgiMME,3403
|
|
11
11
|
sweatstack/sweatshell.py,sha256=MYLNcWbOdceqKJ3S0Pe8dwHXEeYsGJNjQoYUXpMTftA,333
|
|
12
|
-
sweatstack/utils.py,sha256=
|
|
13
|
-
sweatstack-0.14.
|
|
14
|
-
sweatstack-0.14.
|
|
15
|
-
sweatstack-0.14.
|
|
16
|
-
sweatstack-0.14.
|
|
12
|
+
sweatstack/utils.py,sha256=kQZi7W5BXYn4Exmykvhf8A91YHbsCMR37Mobunt3pNE,1743
|
|
13
|
+
sweatstack-0.14.3.dist-info/METADATA,sha256=UI1v17FhKY8UrrLiP8rri3clWr8wkBtNR-pOe3rcbrc,2966
|
|
14
|
+
sweatstack-0.14.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
sweatstack-0.14.3.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
|
|
16
|
+
sweatstack-0.14.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|