sweatstack 0.35.1__py3-none-any.whl → 0.37.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
@@ -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-03-03T13:21:38+00:00
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(..., title='Scopes')
300
+ scopes: Optional[List[Scope]] = Field(None, title='Scopes')
301
301
 
302
302
 
303
303
  class GarminActivityFileData(BaseModel):
sweatstack/schemas.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from enum import Enum
2
2
 
3
3
  from .openapi_schemas import (
4
- ActivityDetails, ActivitySummary, Metric, Sport, TraceDetails, UserSummary
4
+ ActivityDetails, ActivitySummary, Metric, Scope, Sport, TraceDetails, UserInfoResponse, UserSummary
5
5
  )
sweatstack/streamlit.py CHANGED
@@ -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__(self, client_id=None, client_secret=None, scope=None, redirect_uri=None):
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
- scope: The scope to use. If not provided, the SWEATSTACK_SCOPE environment variable will be used.
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
- self.scope = scope or os.environ.get("SWEATSTACK_SCOPE")
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": "data:read",
101
+ "scope": ",".join([scope.value for scope in self.scopes]),
85
102
  "prompt": "none",
86
103
  }
87
104
  path = "/oauth/authorize"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sweatstack
3
- Version: 0.35.1
3
+ Version: 0.37.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
@@ -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=t6UeZxP8-aiZ8K35G0LDqd0vuAf59WSskccQ-lDX-RQ,38340
3
+ sweatstack/client.py,sha256=KAvrvf-NChmGh7yx7b-kG02MoGPCsEBRdKU1xBanntM,39150
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
- sweatstack/openapi_schemas.py,sha256=XlgiL7qkfcfoDHcQrIm9e5hvhY98onC0QmZWG69bl-s,13441
7
+ sweatstack/openapi_schemas.py,sha256=rB_gdkob49AISTebZXmNjOOz3it28Y42_PEKcBF24c0,13576
8
8
  sweatstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- sweatstack/schemas.py,sha256=Lkx0rH8LNIHfX8obHSa4EdJF5q4DzDursnhofzSTddQ,134
10
- sweatstack/streamlit.py,sha256=QV_lPykNgcOR1cAO9F0B4hB_sax2IAMZGHOQLwG_0Rw,12368
9
+ sweatstack/schemas.py,sha256=zRxssFvsXmCTtLr69a7n_EHUUbfAG27w6cTr730ZeUY,159
10
+ sweatstack/streamlit.py,sha256=dtli4RpBiS8cH4GAQ9lDI_ZRDMLoU7GnTc676nLV_4A,13008
11
11
  sweatstack/sweatshell.py,sha256=MYLNcWbOdceqKJ3S0Pe8dwHXEeYsGJNjQoYUXpMTftA,333
12
12
  sweatstack/utils.py,sha256=WMY0THAfktzeDNH3kuwYNtVaoS1OQMaobONtGhpLI2E,2547
13
13
  sweatstack/Sweat Stack examples/Getting started.ipynb,sha256=k2hiSffWecoQ0VxjdpDcgFzBXDQiYEebhnAYlu8cgX8,6335204
14
- sweatstack-0.35.1.dist-info/METADATA,sha256=GB_6xc2dkdb3UiDZLGKfZeiHl-wOPky349eT3CDsnfM,779
15
- sweatstack-0.35.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- sweatstack-0.35.1.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
17
- sweatstack-0.35.1.dist-info/RECORD,,
14
+ sweatstack-0.37.0.dist-info/METADATA,sha256=MQf29vXxKG9b22yMQvH9apE5uWwljU1RY0NQRVSuUng,779
15
+ sweatstack-0.37.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ sweatstack-0.37.0.dist-info/entry_points.txt,sha256=kCzOUQI3dqbTpEYqtgYDeiKFaqaA7BMlV6D24BMzCFU,208
17
+ sweatstack-0.37.0.dist-info/RECORD,,