beamlit 0.0.19__py3-none-any.whl → 0.0.20rc2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. beamlit/api/agents/create_agent.py +14 -9
  2. beamlit/api/agents/get_agent_deployment.py +22 -1
  3. beamlit/api/agents/update_agent.py +14 -9
  4. beamlit/api/functions/create_function.py +14 -9
  5. beamlit/api/functions/update_function.py +14 -9
  6. beamlit/api/{authentication_providers/list_organizations_for_authentication_provider.py → integrations/create_integration_connection.py} +45 -41
  7. beamlit/api/integrations/delete_integration_connection.py +158 -0
  8. beamlit/api/integrations/get_integration.py +97 -0
  9. beamlit/api/integrations/get_integration_connection.py +154 -0
  10. beamlit/api/integrations/get_integration_connection_model.py +97 -0
  11. beamlit/api/integrations/get_integration_model.py +97 -0
  12. beamlit/api/integrations/list_integration_connection_models.py +97 -0
  13. beamlit/api/{authentication_providers/list_models_for_authentication_provider.py → integrations/list_integration_connections.py} +24 -48
  14. beamlit/api/integrations/list_integration_models.py +97 -0
  15. beamlit/api/integrations/update_integration_connection.py +180 -0
  16. beamlit/authentication/__init__.py +2 -1
  17. beamlit/authentication/authentication.py +3 -0
  18. beamlit/authentication/clientcredentials.py +99 -0
  19. beamlit/authentication/credentials.py +7 -1
  20. beamlit/authentication/device_mode.py +0 -2
  21. beamlit/common/generate.py +166 -0
  22. beamlit/common/logger.py +30 -0
  23. beamlit/common/settings.py +112 -0
  24. beamlit/common/utils.py +13 -0
  25. beamlit/models/__init__.py +50 -24
  26. beamlit/models/agent_deployment.py +117 -49
  27. beamlit/models/{agent_deployment_configuration.py → agent_deployment_configuration_type_0.py} +5 -5
  28. beamlit/models/agent_deployment_history.py +46 -13
  29. beamlit/models/agent_deployment_history_event.py +78 -22
  30. beamlit/models/{function_deployment_pod_template.py → agent_deployment_pod_template_type_0.py} +5 -5
  31. beamlit/models/agent_with_deployments.py +174 -0
  32. beamlit/models/deployment_configurations.py +19 -6
  33. beamlit/models/deployment_serverless_config_type_0.py +218 -0
  34. beamlit/models/environment_metrics.py +19 -0
  35. beamlit/models/function_deployment.py +110 -42
  36. beamlit/models/{function_deployment_configuration.py → function_deployment_configuration_type_0.py} +5 -5
  37. beamlit/models/{agent_deployment_pod_template.py → function_deployment_pod_template_type_0.py} +5 -5
  38. beamlit/models/function_with_deployments.py +174 -0
  39. beamlit/models/increase_and_rate_metric.py +102 -0
  40. beamlit/models/integration.py +196 -0
  41. beamlit/models/integration_config.py +43 -0
  42. beamlit/models/integration_connection.py +196 -0
  43. beamlit/models/integration_connection_config.py +43 -0
  44. beamlit/models/integration_connection_secret.py +59 -0
  45. beamlit/models/integration_model.py +142 -0
  46. beamlit/models/integration_secret.py +59 -0
  47. beamlit/models/metrics.py +61 -20
  48. beamlit/models/model_deployment.py +96 -64
  49. beamlit/models/{model_deployment_pod_template.py → model_deployment_pod_template_type_0.py} +5 -5
  50. beamlit/models/policy.py +8 -34
  51. beamlit/models/provider_config.py +0 -9
  52. beamlit/models/resource_deployment_metrics.py +231 -36
  53. beamlit/models/resource_deployment_metrics_inference_per_region_type_0.py +75 -0
  54. beamlit/models/{resource_deployment_metrics_inference_per_second_per_region.py → resource_deployment_metrics_inference_per_second_per_region_type_0.py} +5 -5
  55. beamlit/models/resource_deployment_metrics_query_per_region_per_code_type_0.py +73 -0
  56. beamlit/models/{resource_deployment_metrics_query_per_second_per_region_per_code.py → resource_deployment_metrics_query_per_second_per_region_per_code_type_0.py} +5 -5
  57. beamlit/models/resource_metrics.py +36 -0
  58. beamlit/models/runtime.py +29 -12
  59. beamlit/models/{runtime_readiness_probe.py → runtime_readiness_probe_type_0.py} +5 -5
  60. beamlit/models/store_agent.py +29 -13
  61. beamlit/models/{store_agent_labels.py → store_agent_labels_type_0.py} +5 -5
  62. beamlit/models/store_configuration.py +15 -4
  63. beamlit/models/store_configuration_option.py +18 -5
  64. beamlit/models/store_function.py +29 -13
  65. beamlit/models/{store_function_labels.py → store_function_labels_type_0.py} +5 -5
  66. beamlit/run.py +49 -0
  67. {beamlit-0.0.19.dist-info → beamlit-0.0.20rc2.dist-info}/METADATA +5 -2
  68. {beamlit-0.0.19.dist-info → beamlit-0.0.20rc2.dist-info}/RECORD +70 -46
  69. beamlit/api/authentication_providers/get_model_with_repo_for_authentication_provider.py +0 -184
  70. beamlit/models/deployment_serverless_config.py +0 -129
  71. beamlit/models/labels.py +0 -43
  72. /beamlit/api/{authentication_providers → integrations}/__init__.py +0 -0
  73. {beamlit-0.0.19.dist-info → beamlit-0.0.20rc2.dist-info}/WHEEL +0 -0
@@ -5,16 +5,14 @@ import httpx
5
5
 
6
6
  from ... import errors
7
7
  from ...client import AuthenticatedClient, Client
8
- from ...models.authentication_provider_model import AuthenticationProviderModel
8
+ from ...models.integration_connection import IntegrationConnection
9
9
  from ...types import Response
10
10
 
11
11
 
12
- def _get_kwargs(
13
- authentication_provider_name: str,
14
- ) -> dict[str, Any]:
12
+ def _get_kwargs() -> dict[str, Any]:
15
13
  _kwargs: dict[str, Any] = {
16
14
  "method": "get",
17
- "url": f"/authentication_providers/{authentication_provider_name}/models",
15
+ "url": "/integrations/connections",
18
16
  }
19
17
 
20
18
  return _kwargs
@@ -22,12 +20,12 @@ def _get_kwargs(
22
20
 
23
21
  def _parse_response(
24
22
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
25
- ) -> Optional[List["AuthenticationProviderModel"]]:
23
+ ) -> Optional[List["IntegrationConnection"]]:
26
24
  if response.status_code == 200:
27
25
  response_200 = []
28
26
  _response_200 = response.json()
29
27
  for response_200_item_data in _response_200:
30
- response_200_item = AuthenticationProviderModel.from_dict(response_200_item_data)
28
+ response_200_item = IntegrationConnection.from_dict(response_200_item_data)
31
29
 
32
30
  response_200.append(response_200_item)
33
31
 
@@ -40,7 +38,7 @@ def _parse_response(
40
38
 
41
39
  def _build_response(
42
40
  *, client: Union[AuthenticatedClient, Client], response: httpx.Response
43
- ) -> Response[List["AuthenticationProviderModel"]]:
41
+ ) -> Response[List["IntegrationConnection"]]:
44
42
  return Response(
45
43
  status_code=HTTPStatus(response.status_code),
46
44
  content=response.content,
@@ -50,28 +48,22 @@ def _build_response(
50
48
 
51
49
 
52
50
  def sync_detailed(
53
- authentication_provider_name: str,
54
51
  *,
55
52
  client: AuthenticatedClient,
56
- ) -> Response[List["AuthenticationProviderModel"]]:
57
- """List models for a authentication provider
53
+ ) -> Response[List["IntegrationConnection"]]:
54
+ """List integrations connections
58
55
 
59
- Returns a list of all models for an integration by ID.
60
-
61
- Args:
62
- authentication_provider_name (str):
56
+ Returns a list of all connections integrations in the workspace.
63
57
 
64
58
  Raises:
65
59
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
66
60
  httpx.TimeoutException: If the request takes longer than Client.timeout.
67
61
 
68
62
  Returns:
69
- Response[List['AuthenticationProviderModel']]
63
+ Response[List['IntegrationConnection']]
70
64
  """
71
65
 
72
- kwargs = _get_kwargs(
73
- authentication_provider_name=authentication_provider_name,
74
- )
66
+ kwargs = _get_kwargs()
75
67
 
76
68
  response = client.get_httpx_client().request(
77
69
  **kwargs,
@@ -81,54 +73,43 @@ def sync_detailed(
81
73
 
82
74
 
83
75
  def sync(
84
- authentication_provider_name: str,
85
76
  *,
86
77
  client: AuthenticatedClient,
87
- ) -> Optional[List["AuthenticationProviderModel"]]:
88
- """List models for a authentication provider
89
-
90
- Returns a list of all models for an integration by ID.
78
+ ) -> Optional[List["IntegrationConnection"]]:
79
+ """List integrations connections
91
80
 
92
- Args:
93
- authentication_provider_name (str):
81
+ Returns a list of all connections integrations in the workspace.
94
82
 
95
83
  Raises:
96
84
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
97
85
  httpx.TimeoutException: If the request takes longer than Client.timeout.
98
86
 
99
87
  Returns:
100
- List['AuthenticationProviderModel']
88
+ List['IntegrationConnection']
101
89
  """
102
90
 
103
91
  return sync_detailed(
104
- authentication_provider_name=authentication_provider_name,
105
92
  client=client,
106
93
  ).parsed
107
94
 
108
95
 
109
96
  async def asyncio_detailed(
110
- authentication_provider_name: str,
111
97
  *,
112
98
  client: AuthenticatedClient,
113
- ) -> Response[List["AuthenticationProviderModel"]]:
114
- """List models for a authentication provider
99
+ ) -> Response[List["IntegrationConnection"]]:
100
+ """List integrations connections
115
101
 
116
- Returns a list of all models for an integration by ID.
117
-
118
- Args:
119
- authentication_provider_name (str):
102
+ Returns a list of all connections integrations in the workspace.
120
103
 
121
104
  Raises:
122
105
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
123
106
  httpx.TimeoutException: If the request takes longer than Client.timeout.
124
107
 
125
108
  Returns:
126
- Response[List['AuthenticationProviderModel']]
109
+ Response[List['IntegrationConnection']]
127
110
  """
128
111
 
129
- kwargs = _get_kwargs(
130
- authentication_provider_name=authentication_provider_name,
131
- )
112
+ kwargs = _get_kwargs()
132
113
 
133
114
  response = await client.get_async_httpx_client().request(**kwargs)
134
115
 
@@ -136,28 +117,23 @@ async def asyncio_detailed(
136
117
 
137
118
 
138
119
  async def asyncio(
139
- authentication_provider_name: str,
140
120
  *,
141
121
  client: AuthenticatedClient,
142
- ) -> Optional[List["AuthenticationProviderModel"]]:
143
- """List models for a authentication provider
144
-
145
- Returns a list of all models for an integration by ID.
122
+ ) -> Optional[List["IntegrationConnection"]]:
123
+ """List integrations connections
146
124
 
147
- Args:
148
- authentication_provider_name (str):
125
+ Returns a list of all connections integrations in the workspace.
149
126
 
150
127
  Raises:
151
128
  errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
152
129
  httpx.TimeoutException: If the request takes longer than Client.timeout.
153
130
 
154
131
  Returns:
155
- List['AuthenticationProviderModel']
132
+ List['IntegrationConnection']
156
133
  """
157
134
 
158
135
  return (
159
136
  await asyncio_detailed(
160
- authentication_provider_name=authentication_provider_name,
161
137
  client=client,
162
138
  )
163
139
  ).parsed
@@ -0,0 +1,97 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, Optional, Union
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...types import Response
9
+
10
+
11
+ def _get_kwargs(
12
+ integration_name: str,
13
+ ) -> dict[str, Any]:
14
+ _kwargs: dict[str, Any] = {
15
+ "method": "get",
16
+ "url": f"/integrations/{integration_name}/models",
17
+ }
18
+
19
+ return _kwargs
20
+
21
+
22
+ def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]:
23
+ if response.status_code == 200:
24
+ return None
25
+ if client.raise_on_unexpected_status:
26
+ raise errors.UnexpectedStatus(response.status_code, response.content)
27
+ else:
28
+ return None
29
+
30
+
31
+ def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]:
32
+ return Response(
33
+ status_code=HTTPStatus(response.status_code),
34
+ content=response.content,
35
+ headers=response.headers,
36
+ parsed=_parse_response(client=client, response=response),
37
+ )
38
+
39
+
40
+ def sync_detailed(
41
+ integration_name: str,
42
+ *,
43
+ client: AuthenticatedClient,
44
+ ) -> Response[Any]:
45
+ """List integration models
46
+
47
+ Returns a list of all models for an integration.
48
+
49
+ Args:
50
+ integration_name (str):
51
+
52
+ Raises:
53
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
54
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
55
+
56
+ Returns:
57
+ Response[Any]
58
+ """
59
+
60
+ kwargs = _get_kwargs(
61
+ integration_name=integration_name,
62
+ )
63
+
64
+ response = client.get_httpx_client().request(
65
+ **kwargs,
66
+ )
67
+
68
+ return _build_response(client=client, response=response)
69
+
70
+
71
+ async def asyncio_detailed(
72
+ integration_name: str,
73
+ *,
74
+ client: AuthenticatedClient,
75
+ ) -> Response[Any]:
76
+ """List integration models
77
+
78
+ Returns a list of all models for an integration.
79
+
80
+ Args:
81
+ integration_name (str):
82
+
83
+ Raises:
84
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
85
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
86
+
87
+ Returns:
88
+ Response[Any]
89
+ """
90
+
91
+ kwargs = _get_kwargs(
92
+ integration_name=integration_name,
93
+ )
94
+
95
+ response = await client.get_async_httpx_client().request(**kwargs)
96
+
97
+ return _build_response(client=client, response=response)
@@ -0,0 +1,180 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, Optional, Union
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.integration_connection import IntegrationConnection
9
+ from ...types import Response
10
+
11
+
12
+ def _get_kwargs(
13
+ connection_name: str,
14
+ *,
15
+ body: IntegrationConnection,
16
+ ) -> dict[str, Any]:
17
+ headers: dict[str, Any] = {}
18
+
19
+ _kwargs: dict[str, Any] = {
20
+ "method": "put",
21
+ "url": f"/integrations/connections/{connection_name}",
22
+ }
23
+
24
+ _body = body.to_dict()
25
+
26
+ _kwargs["json"] = _body
27
+ headers["Content-Type"] = "application/json"
28
+
29
+ _kwargs["headers"] = headers
30
+ return _kwargs
31
+
32
+
33
+ def _parse_response(
34
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
35
+ ) -> Optional[IntegrationConnection]:
36
+ if response.status_code == 200:
37
+ response_200 = IntegrationConnection.from_dict(response.json())
38
+
39
+ return response_200
40
+ if client.raise_on_unexpected_status:
41
+ raise errors.UnexpectedStatus(response.status_code, response.content)
42
+ else:
43
+ return None
44
+
45
+
46
+ def _build_response(
47
+ *, client: Union[AuthenticatedClient, Client], response: httpx.Response
48
+ ) -> Response[IntegrationConnection]:
49
+ return Response(
50
+ status_code=HTTPStatus(response.status_code),
51
+ content=response.content,
52
+ headers=response.headers,
53
+ parsed=_parse_response(client=client, response=response),
54
+ )
55
+
56
+
57
+ def sync_detailed(
58
+ connection_name: str,
59
+ *,
60
+ client: Union[AuthenticatedClient, Client],
61
+ body: IntegrationConnection,
62
+ ) -> Response[IntegrationConnection]:
63
+ """Update integration connection
64
+
65
+ Update an integration connection by integration name and connection name.
66
+
67
+ Args:
68
+ connection_name (str):
69
+ body (IntegrationConnection): Integration Connection
70
+
71
+ Raises:
72
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
73
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
74
+
75
+ Returns:
76
+ Response[IntegrationConnection]
77
+ """
78
+
79
+ kwargs = _get_kwargs(
80
+ connection_name=connection_name,
81
+ body=body,
82
+ )
83
+
84
+ response = client.get_httpx_client().request(
85
+ **kwargs,
86
+ )
87
+
88
+ return _build_response(client=client, response=response)
89
+
90
+
91
+ def sync(
92
+ connection_name: str,
93
+ *,
94
+ client: Union[AuthenticatedClient, Client],
95
+ body: IntegrationConnection,
96
+ ) -> Optional[IntegrationConnection]:
97
+ """Update integration connection
98
+
99
+ Update an integration connection by integration name and connection name.
100
+
101
+ Args:
102
+ connection_name (str):
103
+ body (IntegrationConnection): Integration Connection
104
+
105
+ Raises:
106
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
107
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
108
+
109
+ Returns:
110
+ IntegrationConnection
111
+ """
112
+
113
+ return sync_detailed(
114
+ connection_name=connection_name,
115
+ client=client,
116
+ body=body,
117
+ ).parsed
118
+
119
+
120
+ async def asyncio_detailed(
121
+ connection_name: str,
122
+ *,
123
+ client: Union[AuthenticatedClient, Client],
124
+ body: IntegrationConnection,
125
+ ) -> Response[IntegrationConnection]:
126
+ """Update integration connection
127
+
128
+ Update an integration connection by integration name and connection name.
129
+
130
+ Args:
131
+ connection_name (str):
132
+ body (IntegrationConnection): Integration Connection
133
+
134
+ Raises:
135
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
136
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
137
+
138
+ Returns:
139
+ Response[IntegrationConnection]
140
+ """
141
+
142
+ kwargs = _get_kwargs(
143
+ connection_name=connection_name,
144
+ body=body,
145
+ )
146
+
147
+ response = await client.get_async_httpx_client().request(**kwargs)
148
+
149
+ return _build_response(client=client, response=response)
150
+
151
+
152
+ async def asyncio(
153
+ connection_name: str,
154
+ *,
155
+ client: Union[AuthenticatedClient, Client],
156
+ body: IntegrationConnection,
157
+ ) -> Optional[IntegrationConnection]:
158
+ """Update integration connection
159
+
160
+ Update an integration connection by integration name and connection name.
161
+
162
+ Args:
163
+ connection_name (str):
164
+ body (IntegrationConnection): Integration Connection
165
+
166
+ Raises:
167
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
168
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
169
+
170
+ Returns:
171
+ IntegrationConnection
172
+ """
173
+
174
+ return (
175
+ await asyncio_detailed(
176
+ connection_name=connection_name,
177
+ client=client,
178
+ body=body,
179
+ )
180
+ ).parsed
@@ -2,7 +2,7 @@ from .apikey import ApiKeyProvider
2
2
  from .authentication import (PublicProvider, RunClientWithCredentials,
3
3
  new_client_with_credentials)
4
4
  from .credentials import (Config, ContextConfig, Credentials, WorkspaceConfig,
5
- load_credentials)
5
+ load_credentials, load_credentials_from_settings)
6
6
  from .device_mode import (BearerToken, DeviceLogin, DeviceLoginFinalizeRequest,
7
7
  DeviceLoginFinalizeResponse, DeviceLoginResponse)
8
8
 
@@ -16,6 +16,7 @@ __all__ = (
16
16
  "Credentials",
17
17
  "WorkspaceConfig",
18
18
  "load_credentials",
19
+ "load_credentials_from_settings",
19
20
  "BearerToken",
20
21
  "DeviceLogin",
21
22
  "DeviceLoginFinalizeRequest",
@@ -5,6 +5,7 @@ from httpx import Auth, Request, Response
5
5
 
6
6
  from ..client import AuthenticatedClient
7
7
  from .apikey import ApiKeyProvider
8
+ from .clientcredentials import ClientCredentials
8
9
  from .credentials import Credentials
9
10
  from .device_mode import BearerToken
10
11
 
@@ -29,6 +30,8 @@ def new_client_with_credentials(config: RunClientWithCredentials):
29
30
  provider = ApiKeyProvider(config.credentials, config.workspace)
30
31
  elif config.credentials.access_token:
31
32
  provider = BearerToken(config.credentials, config.workspace, config.api_url)
33
+ elif config.credentials.client_credentials:
34
+ provider = ClientCredentials(config.credentials, config.workspace, config.api_url)
32
35
  else:
33
36
  provider = PublicProvider()
34
37
 
@@ -0,0 +1,99 @@
1
+ import base64
2
+ import json
3
+ import time
4
+ from dataclasses import dataclass
5
+ from typing import Generator, Optional
6
+
7
+ import requests
8
+ from beamlit.common.settings import get_settings
9
+ from httpx import Auth, Request, Response, post
10
+
11
+
12
+ @dataclass
13
+ class DeviceLoginFinalizeResponse:
14
+ access_token: str
15
+ expires_in: int
16
+ refresh_token: str
17
+ token_type: str
18
+
19
+
20
+ class ClientCredentials(Auth):
21
+ def __init__(self, credentials, workspace_name: str, base_url: str):
22
+ self.credentials = credentials
23
+ self.workspace_name = workspace_name
24
+ self.base_url = base_url
25
+
26
+ def refresh_if_needed(self) -> Optional[Exception]:
27
+ # Need to refresh token if expires in less than 10 minutes
28
+ parts = self.credentials.access_token.split('.')
29
+ if len(parts) != 3:
30
+ return Exception("Invalid JWT token format")
31
+ try:
32
+ claims_bytes = base64.urlsafe_b64decode(parts[1] + '=' * (-len(parts[1]) % 4))
33
+ claims = json.loads(claims_bytes)
34
+ except Exception as e:
35
+ return Exception(f"Failed to decode/parse JWT claims: {str(e)}")
36
+
37
+ exp_time = time.gmtime(claims['exp'])
38
+ # Refresh if token expires in less than 10 minutes
39
+ if time.time() + (10 * 60) > time.mktime(exp_time):
40
+ return self.do_refresh()
41
+
42
+ return None
43
+
44
+ def auth_flow(self, request: Request) -> Generator[Request, Response, None]:
45
+ settings = get_settings()
46
+ if self.credentials.client_credentials and not self.credentials.refresh_token:
47
+ headers = { "Authorization": f"Basic {self.credentials.client_credentials}" }
48
+ body = { "grant_type": "client_credentials" }
49
+ response = requests.post(f"{settings.base_url}/oauth/token", headers=headers, json=body)
50
+ response.raise_for_status()
51
+ self.credentials.access_token = response.json()['access_token']
52
+ self.credentials.refresh_token = response.json()['refresh_token']
53
+ self.credentials.expires_in = response.json()['expires_in']
54
+ err = self.refresh_if_needed()
55
+ if err:
56
+ return err
57
+
58
+ request.headers['X-Beamlit-Authorization'] = f'Bearer {self.credentials.access_token}'
59
+ request.headers['X-Beamlit-Workspace'] = self.workspace_name
60
+ yield request
61
+
62
+ def do_refresh(self) -> Optional[Exception]:
63
+ if not self.credentials.refresh_token:
64
+ return Exception("No refresh token to refresh")
65
+
66
+ url = f"{self.base_url}/oauth/token"
67
+ refresh_data = {
68
+ "grant_type": "refresh_token",
69
+ "refresh_token": self.credentials.refresh_token,
70
+ "device_code": self.credentials.device_code,
71
+ "client_id": "beamlit"
72
+ }
73
+
74
+ try:
75
+ response = post(
76
+ url,
77
+ json=refresh_data,
78
+ headers={"Content-Type": "application/json"}
79
+ )
80
+ response.raise_for_status()
81
+ finalize_response = DeviceLoginFinalizeResponse(**response.json())
82
+
83
+ if not finalize_response.refresh_token:
84
+ finalize_response.refresh_token = self.credentials.refresh_token
85
+
86
+ from .credentials import Credentials, save_credentials
87
+ creds = Credentials(
88
+ access_token=finalize_response.access_token,
89
+ refresh_token=finalize_response.refresh_token,
90
+ expires_in=finalize_response.expires_in,
91
+ device_code=self.credentials.device_code
92
+ )
93
+
94
+ self.credentials = creds
95
+ save_credentials(self.workspace_name, creds)
96
+ return None
97
+
98
+ except Exception as e:
99
+ return Exception(f"Failed to refresh token: {str(e)}")
@@ -3,6 +3,7 @@ from pathlib import Path
3
3
  from typing import List
4
4
 
5
5
  import yaml
6
+ from beamlit.common.settings import Settings
6
7
 
7
8
 
8
9
  @dataclass
@@ -12,7 +13,7 @@ class Credentials:
12
13
  refresh_token: str = ""
13
14
  expires_in: int = 0
14
15
  device_code: str = ""
15
-
16
+ client_credentials: str = ""
16
17
  @dataclass
17
18
  class WorkspaceConfig:
18
19
  name: str
@@ -115,6 +116,11 @@ def load_credentials(workspace_name: str) -> Credentials:
115
116
  return workspace.credentials
116
117
  return Credentials()
117
118
 
119
+ def load_credentials_from_settings(config: Settings) -> Credentials:
120
+ return Credentials(
121
+ api_key=config.api_key,
122
+ client_credentials=config.client_credentials
123
+ )
118
124
 
119
125
  def create_home_dir_if_missing():
120
126
  home_dir = Path.home()
@@ -86,13 +86,11 @@ class BearerToken(Auth):
86
86
  }
87
87
 
88
88
  try:
89
- print(refresh_data)
90
89
  response = post(
91
90
  url,
92
91
  json=refresh_data,
93
92
  headers={"Content-Type": "application/json"}
94
93
  )
95
- print(response.text)
96
94
  response.raise_for_status()
97
95
  finalize_response = DeviceLoginFinalizeResponse(**response.json())
98
96