sweatstack 0.35.1__tar.gz → 0.37.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.35.1 → sweatstack-0.37.0}/PKG-INFO +1 -1
- {sweatstack-0.35.1 → sweatstack-0.37.0}/pyproject.toml +1 -1
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/client.py +24 -2
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/openapi_schemas.py +10 -10
- sweatstack-0.37.0/src/sweatstack/schemas.py +5 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/streamlit.py +22 -5
- sweatstack-0.35.1/src/sweatstack/schemas.py +0 -5
- {sweatstack-0.35.1 → sweatstack-0.37.0}/.gitignore +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/.python-version +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/DEVELOPMENT.md +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/Makefile +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/README.md +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/.ipynb_checkpoints/Untitled-checkpoint.ipynb +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/README.md +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/Sweat Stack examples/Getting started.ipynb +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/Untitled.ipynb +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/hello.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/playground/pyproject.toml +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/Sweat Stack examples/Getting started.ipynb +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/__init__.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/cli.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/constants.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/ipython_init.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/jupyterlab_oauth2_startup.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/py.typed +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/sweatshell.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/utils.py +0 -0
- {sweatstack-0.35.1 → sweatstack-0.37.0}/uv.lock +0 -0
|
@@ -22,7 +22,7 @@ import pandas as pd
|
|
|
22
22
|
|
|
23
23
|
from .constants import DEFAULT_URL
|
|
24
24
|
from .schemas import (
|
|
25
|
-
ActivityDetails, ActivitySummary, Metric, Sport, TraceDetails, UserSummary
|
|
25
|
+
ActivityDetails, ActivitySummary, Metric, Sport, TraceDetails, UserInfoResponse, UserSummary
|
|
26
26
|
)
|
|
27
27
|
from .utils import decode_jwt_body, make_dataframe_streamlit_compatible
|
|
28
28
|
|
|
@@ -106,7 +106,7 @@ class OAuth2Mixin:
|
|
|
106
106
|
"client_id": OAUTH2_CLIENT_ID,
|
|
107
107
|
"redirect_uri": redirect_uri,
|
|
108
108
|
"code_challenge": code_challenge,
|
|
109
|
-
"scope": "data:read",
|
|
109
|
+
"scope": "data:read profile",
|
|
110
110
|
"prompt": "none",
|
|
111
111
|
}
|
|
112
112
|
base_url = self.url
|
|
@@ -991,6 +991,27 @@ class Client(OAuth2Mixin, DelegationMixin):
|
|
|
991
991
|
self._raise_for_status(response)
|
|
992
992
|
return [UserSummary.model_validate(user) for user in response.json()]
|
|
993
993
|
|
|
994
|
+
def get_userinfo(self) -> UserInfoResponse:
|
|
995
|
+
"""Gets detailed information about the current user.
|
|
996
|
+
|
|
997
|
+
This method retrieves comprehensive information about the user currently
|
|
998
|
+
authenticated with the client.
|
|
999
|
+
|
|
1000
|
+
Returns:
|
|
1001
|
+
UserInfoResponse: A UserInfoResponse object containing detailed user information
|
|
1002
|
+
including profile data, permissions, and authentication details.
|
|
1003
|
+
|
|
1004
|
+
Raises:
|
|
1005
|
+
HTTPStatusError: If the API request fails.
|
|
1006
|
+
"""
|
|
1007
|
+
with self._http_client() as client:
|
|
1008
|
+
response = client.get(
|
|
1009
|
+
url="/api/v1/oauth/userinfo",
|
|
1010
|
+
)
|
|
1011
|
+
self._raise_for_status(response)
|
|
1012
|
+
return UserInfoResponse.model_validate(response.json())
|
|
1013
|
+
|
|
1014
|
+
|
|
994
1015
|
_default_client = Client()
|
|
995
1016
|
|
|
996
1017
|
|
|
@@ -1031,6 +1052,7 @@ _generate_singleton_methods(
|
|
|
1031
1052
|
"login",
|
|
1032
1053
|
|
|
1033
1054
|
"get_users",
|
|
1055
|
+
"get_userinfo",
|
|
1034
1056
|
|
|
1035
1057
|
"get_activities",
|
|
1036
1058
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: openapi.json
|
|
3
|
-
# timestamp: 2025-
|
|
3
|
+
# timestamp: 2025-04-08T11:14:52+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -15,10 +15,6 @@ class ActivityUpdate(BaseModel):
|
|
|
15
15
|
tags: Optional[List[str]] = Field(None, title='Tags')
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class BodyAddEmailToWhitelistAdminEmailWhitelistPost(BaseModel):
|
|
19
|
-
email: str = Field(..., title='Email')
|
|
20
|
-
|
|
21
|
-
|
|
22
18
|
class BodyCreateApplicationApplicationsPost(BaseModel):
|
|
23
19
|
name: str = Field(..., title='Name')
|
|
24
20
|
description: str = Field(..., title='Description')
|
|
@@ -26,6 +22,7 @@ class BodyCreateApplicationApplicationsPost(BaseModel):
|
|
|
26
22
|
image: AnyUrl = Field(..., title='Image')
|
|
27
23
|
redirect_uris: List[AnyUrl] = Field(..., title='Redirect Uris')
|
|
28
24
|
privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
|
|
25
|
+
published: Optional[bool] = Field(False, title='Published')
|
|
29
26
|
|
|
30
27
|
|
|
31
28
|
class BodyCreateApplicationSecretApplicationsApplicationIdSecretsPost(BaseModel):
|
|
@@ -36,10 +33,6 @@ class BodyCreateTagTagsPost(BaseModel):
|
|
|
36
33
|
tag: str = Field(..., title='Tag')
|
|
37
34
|
|
|
38
35
|
|
|
39
|
-
class BodyDeleteEmailFromWhitelistAdminEmailWhitelistDelete(BaseModel):
|
|
40
|
-
email: str = Field(..., title='Email')
|
|
41
|
-
|
|
42
|
-
|
|
43
36
|
class BodyLoginPostLoginPost(BaseModel):
|
|
44
37
|
email: str = Field(..., title='Email')
|
|
45
38
|
password: SecretStr = Field(..., title='Password')
|
|
@@ -49,6 +42,7 @@ class BodyLoginPostLoginPost(BaseModel):
|
|
|
49
42
|
class BodyRegisterPostRegisterPost(BaseModel):
|
|
50
43
|
email: str = Field(..., title='Email')
|
|
51
44
|
password: SecretStr = Field(..., title='Password')
|
|
45
|
+
tz_offset: int = Field(..., title='Tz Offset')
|
|
52
46
|
|
|
53
47
|
|
|
54
48
|
class BodySaveOrUpdateIntegrationProviderTenantsTenantIdIntegrationProvidersIntegrationNamePost(
|
|
@@ -66,6 +60,7 @@ class BodyUpdateApplicationApplicationsApplicationIdPut(BaseModel):
|
|
|
66
60
|
image: AnyUrl = Field(..., title='Image')
|
|
67
61
|
redirect_uris: List[AnyUrl] = Field(..., title='Redirect Uris')
|
|
68
62
|
privacy_statement: AnyUrl = Field(..., title='Privacy Statement')
|
|
63
|
+
published: Optional[bool] = Field(False, title='Published')
|
|
69
64
|
|
|
70
65
|
|
|
71
66
|
class BodyUpdateUserUsersUserIdPut(BaseModel):
|
|
@@ -257,6 +252,7 @@ class UserInfoResponse(BaseModel):
|
|
|
257
252
|
sub: str = Field(..., title='Sub')
|
|
258
253
|
given_name: Optional[str] = Field(None, title='Given Name')
|
|
259
254
|
family_name: Optional[str] = Field(None, title='Family Name')
|
|
255
|
+
email: Optional[str] = Field(None, title='Email')
|
|
260
256
|
name: str = Field(..., title='Name')
|
|
261
257
|
|
|
262
258
|
|
|
@@ -295,9 +291,13 @@ class BodyAuthorizeOauthAuthorizePost(BaseModel):
|
|
|
295
291
|
code_challenge_method: Optional[str] = Field(None, title='Code Challenge Method')
|
|
296
292
|
|
|
297
293
|
|
|
294
|
+
class BodyGenerateApiKeyPartialsGenerateApiKeyPost(BaseModel):
|
|
295
|
+
scopes: List[Scope] = Field(..., title='Scopes')
|
|
296
|
+
|
|
297
|
+
|
|
298
298
|
class DelegatedTokenRequest(BaseModel):
|
|
299
299
|
sub: str = Field(..., title='Sub')
|
|
300
|
-
scopes: List[Scope] = Field(
|
|
300
|
+
scopes: Optional[List[Scope]] = Field(None, title='Scopes')
|
|
301
301
|
|
|
302
302
|
|
|
303
303
|
class GarminActivityFileData(BaseModel):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import urllib.parse
|
|
3
3
|
from datetime import date
|
|
4
|
+
from typing import List, Union
|
|
4
5
|
try:
|
|
5
6
|
import streamlit as st
|
|
6
7
|
except ImportError:
|
|
@@ -13,21 +14,37 @@ import httpx
|
|
|
13
14
|
|
|
14
15
|
from .client import Client
|
|
15
16
|
from .constants import DEFAULT_URL
|
|
16
|
-
from .schemas import Metric, Sport
|
|
17
|
+
from .schemas import Metric, Scope, Sport
|
|
17
18
|
from .utils import format_sport
|
|
18
19
|
|
|
19
20
|
class StreamlitAuth:
|
|
20
|
-
def __init__(
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
client_id=None,
|
|
24
|
+
client_secret=None,
|
|
25
|
+
scopes: List[Union[str, Scope]]=None,
|
|
26
|
+
redirect_uri=None,
|
|
27
|
+
):
|
|
21
28
|
"""
|
|
22
29
|
Args:
|
|
23
30
|
client_id: The client ID to use. If not provided, the SWEATSTACK_CLIENT_ID environment variable will be used.
|
|
24
31
|
client_secret: The client secret to use. If not provided, the SWEATSTACK_CLIENT_SECRET environment variable will be used.
|
|
25
|
-
|
|
32
|
+
scopes: The scopes to use. If not provided, the SWEATSTACK_SCOPES environment variable will be used. Defaults to data:read, profile.
|
|
26
33
|
redirect_uri: The redirect URI to use. If not provided, the SWEATSTACK_REDIRECT_URI environment variable will be used.
|
|
27
34
|
"""
|
|
28
35
|
self.client_id = client_id or os.environ.get("SWEATSTACK_CLIENT_ID")
|
|
29
36
|
self.client_secret = client_secret or os.environ.get("SWEATSTACK_CLIENT_SECRET")
|
|
30
|
-
|
|
37
|
+
|
|
38
|
+
if scopes is not None:
|
|
39
|
+
self.scopes = [Scope(scope.strip().lower()) if isinstance(scope, str) else scope
|
|
40
|
+
for scope in scopes] if scopes else []
|
|
41
|
+
elif os.environ.get("SWEATSTACK_SCOPES"):
|
|
42
|
+
scopes = os.environ.get("SWEATSTACK_SCOPES").split(",")
|
|
43
|
+
self.scopes = [Scope(scope.strip().lower()) if isinstance(scope, str) else scope
|
|
44
|
+
for scope in scopes]
|
|
45
|
+
else:
|
|
46
|
+
self.scopes = [Scope.data_read, Scope.profile]
|
|
47
|
+
|
|
31
48
|
self.redirect_uri = redirect_uri or os.environ.get("SWEATSTACK_REDIRECT_URI")
|
|
32
49
|
|
|
33
50
|
self.api_key = st.session_state.get("sweatstack_api_key")
|
|
@@ -81,7 +98,7 @@ class StreamlitAuth:
|
|
|
81
98
|
params = {
|
|
82
99
|
"client_id": self.client_id,
|
|
83
100
|
"redirect_uri": self.redirect_uri,
|
|
84
|
-
"scope": "
|
|
101
|
+
"scope": ",".join([scope.value for scope in self.scopes]),
|
|
85
102
|
"prompt": "none",
|
|
86
103
|
}
|
|
87
104
|
path = "/oauth/authorize"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sweatstack-0.35.1 → sweatstack-0.37.0}/playground/.ipynb_checkpoints/Untitled-checkpoint.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{sweatstack-0.35.1 → sweatstack-0.37.0}/playground/Sweat Stack examples/Getting started.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sweatstack-0.35.1 → sweatstack-0.37.0}/src/sweatstack/Sweat Stack examples/Getting started.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|