sweatstack 0.27.0__py3-none-any.whl → 0.30.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 +1 -0
- sweatstack/schemas.py +3 -1
- sweatstack/streamlit.py +108 -8
- sweatstack/utils.py +16 -1
- {sweatstack-0.27.0.dist-info → sweatstack-0.30.0.dist-info}/METADATA +1 -1
- {sweatstack-0.27.0.dist-info → sweatstack-0.30.0.dist-info}/RECORD +8 -8
- {sweatstack-0.27.0.dist-info → sweatstack-0.30.0.dist-info}/WHEEL +0 -0
- {sweatstack-0.27.0.dist-info → sweatstack-0.30.0.dist-info}/entry_points.txt +0 -0
sweatstack/client.py
CHANGED
|
@@ -297,6 +297,7 @@ class Client(OAuth2Mixin, DelegationMixin):
|
|
|
297
297
|
if end is not None:
|
|
298
298
|
params["end"] = end.isoformat()
|
|
299
299
|
if sports is not None:
|
|
300
|
+
sports = [sport.value if isinstance(sport, Sport) else sport for sport in sports]
|
|
300
301
|
params["sports"] = sports
|
|
301
302
|
if tags is not None:
|
|
302
303
|
params["tags"] = tags
|
sweatstack/schemas.py
CHANGED
sweatstack/streamlit.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import urllib.parse
|
|
3
|
-
|
|
3
|
+
from datetime import date
|
|
4
4
|
try:
|
|
5
5
|
import streamlit as st
|
|
6
6
|
except ImportError:
|
|
@@ -10,10 +10,11 @@ except ImportError:
|
|
|
10
10
|
"pip install 'sweatstack[streamlit]'\n\n"
|
|
11
11
|
)
|
|
12
12
|
import httpx
|
|
13
|
-
from sweatstack import Client
|
|
14
13
|
|
|
14
|
+
from .client import Client
|
|
15
15
|
from .constants import DEFAULT_URL
|
|
16
|
-
|
|
16
|
+
from .schemas import Metric, Sport
|
|
17
|
+
from .utils import format_sport
|
|
17
18
|
|
|
18
19
|
class StreamlitAuth:
|
|
19
20
|
def __init__(self, client_id=None, client_secret=None, scope=None, redirect_uri=None):
|
|
@@ -88,6 +89,11 @@ class StreamlitAuth:
|
|
|
88
89
|
|
|
89
90
|
return authorization_url
|
|
90
91
|
|
|
92
|
+
def _set_api_key(self, api_key):
|
|
93
|
+
self.api_key = api_key
|
|
94
|
+
st.session_state["sweatstack_api_key"] = api_key
|
|
95
|
+
self.client = Client(self.api_key, streamlit_compatible=True)
|
|
96
|
+
|
|
91
97
|
def _exchange_token(self, code):
|
|
92
98
|
token_data = {
|
|
93
99
|
"grant_type": "authorization_code",
|
|
@@ -107,10 +113,7 @@ class StreamlitAuth:
|
|
|
107
113
|
raise Exception(f"SweatStack Python login failed. Please try again.") from e
|
|
108
114
|
token_response = response.json()
|
|
109
115
|
|
|
110
|
-
self.
|
|
111
|
-
st.session_state["sweatstack_api_key"] = self.api_key
|
|
112
|
-
|
|
113
|
-
self.client = Client(self.api_key, streamlit_compatible=True)
|
|
116
|
+
self._set_api_key(token_response.get("access_token"))
|
|
114
117
|
|
|
115
118
|
return
|
|
116
119
|
|
|
@@ -128,4 +131,101 @@ class StreamlitAuth:
|
|
|
128
131
|
st.query_params.clear()
|
|
129
132
|
st.rerun()
|
|
130
133
|
else:
|
|
131
|
-
self._show_sweatstack_login()
|
|
134
|
+
self._show_sweatstack_login()
|
|
135
|
+
|
|
136
|
+
def select_user(self):
|
|
137
|
+
self.switch_to_principal_user()
|
|
138
|
+
other_users = self.client.get_users()
|
|
139
|
+
selected_user = st.selectbox(
|
|
140
|
+
"Select a user",
|
|
141
|
+
other_users,
|
|
142
|
+
format_func=lambda user: user.display_name,
|
|
143
|
+
)
|
|
144
|
+
self.client.switch_user(selected_user)
|
|
145
|
+
self._set_api_key(self.client.api_key)
|
|
146
|
+
|
|
147
|
+
return selected_user
|
|
148
|
+
|
|
149
|
+
def switch_to_principal_user(self):
|
|
150
|
+
self.client.switch_back()
|
|
151
|
+
self._set_api_key(self.client.api_key)
|
|
152
|
+
|
|
153
|
+
def select_activity(
|
|
154
|
+
self,
|
|
155
|
+
*,
|
|
156
|
+
start: date | None = None,
|
|
157
|
+
end: date | None = None,
|
|
158
|
+
sports: list[Sport] | None = None,
|
|
159
|
+
tags: list[str] | None = None,
|
|
160
|
+
limit: int | None = 100,
|
|
161
|
+
):
|
|
162
|
+
"""
|
|
163
|
+
Select an activity from the user's activities.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
activities = self.client.get_activities(
|
|
167
|
+
start=start,
|
|
168
|
+
end=end,
|
|
169
|
+
sports=sports,
|
|
170
|
+
tags=tags,
|
|
171
|
+
limit=limit,
|
|
172
|
+
)
|
|
173
|
+
selected_activity = st.selectbox(
|
|
174
|
+
"Select an activity",
|
|
175
|
+
activities,
|
|
176
|
+
format_func=lambda activity: f"{activity.start.date().isoformat()} {format_sport(activity.sport)}",
|
|
177
|
+
)
|
|
178
|
+
return selected_activity
|
|
179
|
+
|
|
180
|
+
def select_sport(self, only_root: bool = False, allow_multiple: bool = False, only_available: bool = True):
|
|
181
|
+
if only_available:
|
|
182
|
+
sports = self.client.get_sports(only_root)
|
|
183
|
+
else:
|
|
184
|
+
if only_root:
|
|
185
|
+
sports = [sport for sport in Sport if "." not in sport.value]
|
|
186
|
+
else:
|
|
187
|
+
sports = Sport
|
|
188
|
+
|
|
189
|
+
if allow_multiple:
|
|
190
|
+
selected_sport = st.multiselect(
|
|
191
|
+
"Select sports",
|
|
192
|
+
sports,
|
|
193
|
+
format_func=format_sport,
|
|
194
|
+
)
|
|
195
|
+
else:
|
|
196
|
+
selected_sport = st.selectbox(
|
|
197
|
+
"Select a sport",
|
|
198
|
+
sports,
|
|
199
|
+
format_func=format_sport,
|
|
200
|
+
)
|
|
201
|
+
return selected_sport
|
|
202
|
+
|
|
203
|
+
def select_tag(self, allow_multiple: bool = False):
|
|
204
|
+
tags = self.client.get_tags()
|
|
205
|
+
if allow_multiple:
|
|
206
|
+
selected_tag = st.multiselect(
|
|
207
|
+
"Select tags",
|
|
208
|
+
tags,
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
selected_tag = st.selectbox(
|
|
212
|
+
"Select a tag",
|
|
213
|
+
tags,
|
|
214
|
+
format_func=lambda tag: tag or "-",
|
|
215
|
+
)
|
|
216
|
+
return selected_tag
|
|
217
|
+
|
|
218
|
+
def select_metric(self, allow_multiple: bool = False):
|
|
219
|
+
if allow_multiple:
|
|
220
|
+
selected_metric = st.multiselect(
|
|
221
|
+
"Select metrics",
|
|
222
|
+
Metric,
|
|
223
|
+
format_func=lambda metric: metric.value,
|
|
224
|
+
)
|
|
225
|
+
else:
|
|
226
|
+
selected_metric = st.selectbox(
|
|
227
|
+
"Select a metric",
|
|
228
|
+
Metric,
|
|
229
|
+
format_func=lambda metric: metric.value,
|
|
230
|
+
)
|
|
231
|
+
return selected_metric
|
sweatstack/utils.py
CHANGED
|
@@ -4,6 +4,8 @@ from enum import Enum
|
|
|
4
4
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
|
|
7
|
+
from .schemas import Sport
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
def decode_jwt_body(jwt: str) -> dict:
|
|
9
11
|
payload = jwt.split(".")[1]
|
|
@@ -50,4 +52,17 @@ def make_dataframe_streamlit_compatible(df: pd.DataFrame) -> pd.DataFrame:
|
|
|
50
52
|
lambda x: x.value if isinstance(x, Enum) else x
|
|
51
53
|
)
|
|
52
54
|
|
|
53
|
-
return df_copy if df_copy is not None else df
|
|
55
|
+
return df_copy if df_copy is not None else df
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def format_sport(sport: Sport):
|
|
59
|
+
parts = sport.value.split(".")
|
|
60
|
+
base_sport = parts[0]
|
|
61
|
+
base_sport = base_sport.replace("_", " ")
|
|
62
|
+
|
|
63
|
+
if len(parts) == 1:
|
|
64
|
+
return base_sport
|
|
65
|
+
|
|
66
|
+
remainder = " ".join(parts[1:]).replace("_", " ")
|
|
67
|
+
|
|
68
|
+
return f"{base_sport} ({remainder})"
|
|
@@ -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=
|
|
3
|
+
sweatstack/client.py,sha256=s4OwGibC31n-XPW2dc3CpwDor-2vkfq4mSAJE8svatQ,23807
|
|
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=XlgiL7qkfcfoDHcQrIm9e5hvhY98onC0QmZWG69bl-s,13441
|
|
8
8
|
sweatstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
sweatstack/schemas.py,sha256=
|
|
10
|
-
sweatstack/streamlit.py,sha256=
|
|
9
|
+
sweatstack/schemas.py,sha256=Lkx0rH8LNIHfX8obHSa4EdJF5q4DzDursnhofzSTddQ,134
|
|
10
|
+
sweatstack/streamlit.py,sha256=gsgiIDW-INGTvF24ANnX5LJ17ZxnvXx95sjSmtcTlnY,8062
|
|
11
11
|
sweatstack/sweatshell.py,sha256=MYLNcWbOdceqKJ3S0Pe8dwHXEeYsGJNjQoYUXpMTftA,333
|
|
12
|
-
sweatstack/utils.py,sha256=
|
|
12
|
+
sweatstack/utils.py,sha256=3K97OSWQy5KZ97QiBbW4Kx1wDGxwyA96ZWpwIbkcQZc,2090
|
|
13
13
|
sweatstack/Sweat Stack examples/Getting started.ipynb,sha256=k2hiSffWecoQ0VxjdpDcgFzBXDQiYEebhnAYlu8cgX8,6335204
|
|
14
|
-
sweatstack-0.
|
|
15
|
-
sweatstack-0.
|
|
16
|
-
sweatstack-0.
|
|
17
|
-
sweatstack-0.
|
|
14
|
+
sweatstack-0.30.0.dist-info/METADATA,sha256=UcL9W5y7VlvMEUkW4N2OpwwOUPqwKjcV1LPbg2sKMCs,775
|
|
15
|
+
sweatstack-0.30.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
+
sweatstack-0.30.0.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
|
|
17
|
+
sweatstack-0.30.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|