codemie-sdk-python 0.1.427__tar.gz → 0.1.429__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.
Files changed (61) hide show
  1. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/PKG-INFO +1 -1
  2. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/pyproject.toml +1 -1
  3. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/auth/credentials.py +40 -24
  4. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/client/client.py +40 -91
  5. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/exceptions.py +2 -4
  6. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/admin.py +1 -2
  7. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/analytics.py +17 -17
  8. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/assistant.py +115 -121
  9. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/categories.py +5 -7
  10. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/common.py +5 -5
  11. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/conversation.py +72 -71
  12. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/datasource.py +62 -64
  13. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/errors.py +8 -14
  14. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/file_operation.py +3 -3
  15. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/guardrails.py +3 -5
  16. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/integration.py +9 -9
  17. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/llm.py +14 -15
  18. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/project.py +22 -22
  19. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/skill.py +21 -22
  20. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/task.py +2 -3
  21. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/user.py +7 -12
  22. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/vendor_assistant.py +11 -12
  23. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/vendor_guardrail.py +11 -12
  24. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/vendor_knowledgebase.py +11 -12
  25. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/vendor_workflow.py +10 -11
  26. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/workflow.py +15 -16
  27. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/workflow_execution_payload.py +5 -6
  28. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/workflow_state.py +6 -7
  29. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/workflow_thoughts.py +2 -3
  30. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/admin.py +3 -5
  31. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/analytics.py +24 -26
  32. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/assistant.py +27 -21
  33. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/categories.py +4 -6
  34. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/codemie_guardrails.py +2 -2
  35. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/conversation.py +12 -11
  36. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/datasource.py +14 -12
  37. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/files.py +3 -4
  38. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/integration.py +7 -7
  39. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/llm.py +7 -7
  40. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/mermaid.py +2 -2
  41. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/project.py +9 -9
  42. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/skill.py +16 -14
  43. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/task.py +2 -2
  44. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/user.py +2 -2
  45. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/vendor_assistant.py +6 -6
  46. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/vendor_guardrail.py +6 -6
  47. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/vendor_knowledgebase.py +5 -5
  48. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/vendor_workflow.py +6 -6
  49. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/webhook.py +4 -4
  50. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/workflow.py +16 -14
  51. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/workflow_execution.py +14 -14
  52. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/services/workflow_execution_state.py +2 -4
  53. codemie_sdk_python-0.1.429/src/codemie_sdk/utils/__init__.py +5 -0
  54. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/utils/http.py +43 -29
  55. codemie_sdk_python-0.1.427/src/codemie_sdk/utils/__init__.py +0 -5
  56. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/README.md +0 -0
  57. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/__init__.py +0 -0
  58. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/auth/__init__.py +0 -0
  59. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/client/__init__.py +0 -0
  60. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/__init__.py +0 -0
  61. {codemie_sdk_python-0.1.427 → codemie_sdk_python-0.1.429}/src/codemie_sdk/models/mermaid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codemie-sdk-python
3
- Version: 0.1.427
3
+ Version: 0.1.429
4
4
  Summary: CodeMie SDK for Python
5
5
  Author: Vadym Vlasenko
6
6
  Author-email: vadym_vlasenko@epam.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "codemie-sdk-python"
3
- version = "0.1.427"
3
+ version = "0.1.429"
4
4
  description = "CodeMie SDK for Python"
5
5
  authors = [
6
6
  "Vadym Vlasenko <vadym_vlasenko@epam.com>",
@@ -1,22 +1,25 @@
1
1
  """Authentication credentials module for CodeMie SDK."""
2
2
 
3
+ import time
3
4
  import requests
4
- from typing import Optional
5
+ from typing import Callable
5
6
 
6
7
 
7
8
  class KeycloakCredentials:
8
9
  """Keycloak authentication credentials handler."""
9
10
 
11
+ _TOKEN_EXPIRY_BUFFER_SECONDS = 30
12
+
10
13
  def __init__(
11
14
  self,
12
15
  server_url: str,
13
16
  realm_name: str,
14
- client_id: Optional[str] = None,
15
- client_secret: Optional[str] = None,
16
- username: Optional[str] = None,
17
- password: Optional[str] = None,
18
- external_token: Optional[str] = None,
19
- external_idp: Optional[str] = None,
17
+ client_id: str | None = None,
18
+ client_secret: str | None = None,
19
+ username: str | None = None,
20
+ password: str | None = None,
21
+ external_token: str | Callable[[], str] | None = None,
22
+ external_idp: str | None = None,
20
23
  verify_ssl: bool = True,
21
24
  ):
22
25
  """Initialize Keycloak credentials.
@@ -41,9 +44,15 @@ class KeycloakCredentials:
41
44
  self.external_token = external_token
42
45
  self.external_idp = external_idp
43
46
  self.verify_ssl = verify_ssl
47
+ self._cached_token: str | None = None
48
+ self._token_expires_at: float = 0.0
44
49
 
45
50
  def get_token(self) -> str:
46
- """Get access token using either client credentials or password grant."""
51
+ """Get access token, returning cached value if still valid."""
52
+ now = time.monotonic()
53
+ if self._cached_token and now < self._token_expires_at:
54
+ return self._cached_token
55
+
47
56
  if not (
48
57
  (self.client_id and self.client_secret)
49
58
  or (self.username and self.password)
@@ -57,28 +66,31 @@ class KeycloakCredentials:
57
66
  f"{self.server_url}/realms/{self.realm_name}/protocol/openid-connect/token"
58
67
  )
59
68
 
60
- if self.username and self.password:
61
- # Use Resource Owner Password Credentials flow
62
- payload = {
63
- "grant_type": "password",
64
- "username": self.username,
65
- "password": self.password,
66
- "client_id": self.client_id
67
- or "codemie-sdk", # Use default client if not specified
68
- }
69
- if self.client_secret:
70
- payload["client_secret"] = self.client_secret
71
- elif self.external_token and self.external_idp:
69
+ if self.external_token and self.external_idp:
70
+ subject_token = (
71
+ self.external_token()
72
+ if callable(self.external_token)
73
+ else self.external_token
74
+ )
72
75
  payload = {
73
76
  "client_id": self.client_id,
74
77
  "client_secret": self.client_secret,
75
78
  "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
76
- "subject_token": self.external_token,
79
+ "subject_token": subject_token,
80
+ "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
77
81
  "subject_issuer": self.external_idp,
78
82
  "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
79
83
  }
84
+ elif self.username and self.password:
85
+ payload = {
86
+ "grant_type": "password",
87
+ "username": self.username,
88
+ "password": self.password,
89
+ "client_id": self.client_id or "codemie-sdk",
90
+ }
91
+ if self.client_secret:
92
+ payload["client_secret"] = self.client_secret
80
93
  else:
81
- # Use Client Credentials flow
82
94
  payload = {
83
95
  "grant_type": "client_credentials",
84
96
  "client_id": self.client_id,
@@ -87,7 +99,11 @@ class KeycloakCredentials:
87
99
 
88
100
  response = requests.post(url, data=payload, verify=self.verify_ssl)
89
101
  response.raise_for_status()
90
- return response.json()["access_token"]
102
+ data = response.json()
103
+ self._cached_token = data["access_token"]
104
+ expires_in = data.get("expires_in", 300)
105
+ self._token_expires_at = now + expires_in - self._TOKEN_EXPIRY_BUFFER_SECONDS
106
+ return self._cached_token
91
107
 
92
108
  def exchange_token_for_user(self, email: str, access_token: str) -> str:
93
109
  """Exchange service account token for user token."""
@@ -118,7 +134,7 @@ class KeycloakCredentials:
118
134
  payload = {
119
135
  "client_id": self.client_id,
120
136
  "client_secret": self.client_secret,
121
- "grant_type": "urn:ietf:params:oauth:grant-datasource_type:token-exchange",
137
+ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
122
138
  "subject_token": service_account_token,
123
139
  "requested_subject": user_id,
124
140
  }
@@ -1,6 +1,6 @@
1
1
  """Base client implementation for CodeMie SDK."""
2
2
 
3
- from typing import Optional
3
+ from typing import Callable
4
4
 
5
5
  from ..auth.credentials import KeycloakCredentials
6
6
  from ..services.admin import AdminService
@@ -34,12 +34,12 @@ class CodeMieClient:
34
34
  auth_server_url: str,
35
35
  auth_realm_name: str,
36
36
  codemie_api_domain: str,
37
- auth_client_id: Optional[str] = None,
38
- auth_client_secret: Optional[str] = None,
39
- username: Optional[str] = None,
40
- password: Optional[str] = None,
41
- external_token: Optional[str] = None,
42
- external_idp: Optional[str] = None,
37
+ auth_client_id: str | None = None,
38
+ auth_client_secret: str | None = None,
39
+ username: str | None = None,
40
+ password: str | None = None,
41
+ external_token: str | Callable[[], str] | None = None,
42
+ external_idp: str | None = None,
43
43
  verify_ssl: bool = True,
44
44
  ):
45
45
  """Initialize CodeMie client with authentication credentials.
@@ -68,7 +68,7 @@ class CodeMieClient:
68
68
  verify_ssl=verify_ssl,
69
69
  )
70
70
 
71
- self._token: Optional[str] = None
71
+ self._token: str | None = None
72
72
  self._api_domain = codemie_api_domain.rstrip("/")
73
73
  self._is_localhost = self._is_localhost_domain(self._api_domain)
74
74
  self._verify_ssl = verify_ssl
@@ -78,62 +78,68 @@ class CodeMieClient:
78
78
 
79
79
  requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
80
80
 
81
- # Initialize token
81
+ # Initialize token; keep string copy for backward-compat callers reading _token directly
82
82
  self._token = "" if self._is_localhost else self.auth.get_token()
83
+ # Services receive the bound method so each request resolves a fresh (cached) token
84
+ _token_source = "" if self._is_localhost else self.auth.get_token
83
85
 
84
86
  # Initialize services with verify_ssl parameter and token
85
- self.admin = AdminService(self._api_domain, self._token, verify_ssl=verify_ssl)
87
+ self.admin = AdminService(
88
+ self._api_domain, _token_source, verify_ssl=verify_ssl
89
+ )
86
90
  self.analytics = AnalyticsService(
87
- self._api_domain, self._token, verify_ssl=verify_ssl
91
+ self._api_domain, _token_source, verify_ssl=verify_ssl
88
92
  )
89
93
  self.assistants = AssistantService(
90
- self._api_domain, self._token, verify_ssl=verify_ssl
94
+ self._api_domain, _token_source, verify_ssl=verify_ssl
91
95
  )
92
96
  self.categories = CategoryService(
93
- self._api_domain, self._token, verify_ssl=verify_ssl
97
+ self._api_domain, _token_source, verify_ssl=verify_ssl
94
98
  )
95
- self.llms = LLMService(self._api_domain, self._token, verify_ssl=verify_ssl)
99
+ self.llms = LLMService(self._api_domain, _token_source, verify_ssl=verify_ssl)
96
100
  self.mermaid = MermaidService(
97
- self._api_domain, self._token, verify_ssl=verify_ssl
101
+ self._api_domain, _token_source, verify_ssl=verify_ssl
98
102
  )
99
103
  self.integrations = IntegrationService(
100
- self._api_domain, self._token, verify_ssl=verify_ssl
104
+ self._api_domain, _token_source, verify_ssl=verify_ssl
101
105
  )
102
106
  self.projects = ProjectService(
103
- self._api_domain, self._token, verify_ssl=verify_ssl
107
+ self._api_domain, _token_source, verify_ssl=verify_ssl
108
+ )
109
+ self.skills = SkillService(
110
+ self._api_domain, _token_source, verify_ssl=verify_ssl
104
111
  )
105
- self.skills = SkillService(self._api_domain, self._token, verify_ssl=verify_ssl)
106
- self.tasks = TaskService(self._api_domain, self._token, verify_ssl=verify_ssl)
107
- self.users = UserService(self._api_domain, self._token, verify_ssl=verify_ssl)
112
+ self.tasks = TaskService(self._api_domain, _token_source, verify_ssl=verify_ssl)
113
+ self.users = UserService(self._api_domain, _token_source, verify_ssl=verify_ssl)
108
114
  self.datasources = DatasourceService(
109
- self._api_domain, self._token, verify_ssl=verify_ssl
115
+ self._api_domain, _token_source, verify_ssl=verify_ssl
110
116
  )
111
117
  self.workflows = WorkflowService(
112
- self._api_domain, self._token, verify_ssl=self._verify_ssl
118
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
113
119
  )
114
120
  self.conversations = ConversationService(
115
- self._api_domain, self._token, verify_ssl=self._verify_ssl
121
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
116
122
  )
117
123
  self.files = FileOperationService(
118
- self._api_domain, self._token, verify_ssl=self._verify_ssl
124
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
119
125
  )
120
126
  self.webhook = WebhookService(
121
- self._api_domain, self._token, verify_ssl=self._verify_ssl
127
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
122
128
  )
123
129
  self.vendor_assistants = VendorAssistantService(
124
- self._api_domain, self._token, verify_ssl=self._verify_ssl
130
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
125
131
  )
126
132
  self.vendor_workflows = VendorWorkflowService(
127
- self._api_domain, self._token, verify_ssl=self._verify_ssl
133
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
128
134
  )
129
135
  self.vendor_knowledgebases = VendorKnowledgeBaseService(
130
- self._api_domain, self._token, verify_ssl=self._verify_ssl
136
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
131
137
  )
132
138
  self.vendor_guardrails = VendorGuardrailService(
133
- self._api_domain, self._token, verify_ssl=self._verify_ssl
139
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
134
140
  )
135
141
  self.codemie_guardrails = CodemieGuardrailService(
136
- self._api_domain, self._token, verify_ssl=self._verify_ssl
142
+ self._api_domain, _token_source, verify_ssl=self._verify_ssl
137
143
  )
138
144
 
139
145
  @property
@@ -156,66 +162,9 @@ class CodeMieClient:
156
162
 
157
163
  def refresh_token(self) -> str:
158
164
  """Force token refresh."""
165
+ # Invalidate cache so next get_token() call re-fetches from Keycloak
166
+ self.auth._cached_token = None
167
+ self.auth._token_expires_at = 0.0
159
168
  self._token = "" if self._is_localhost else self.auth.get_token()
160
- # Update token in services
161
- self.admin = AdminService(
162
- self._api_domain, self._token, verify_ssl=self._verify_ssl
163
- )
164
- self.analytics = AnalyticsService(
165
- self._api_domain, self._token, verify_ssl=self._verify_ssl
166
- )
167
- self.assistants = AssistantService(
168
- self._api_domain, self._token, verify_ssl=self._verify_ssl
169
- )
170
- self.categories = CategoryService(
171
- self._api_domain, self._token, verify_ssl=self._verify_ssl
172
- )
173
- self.llms = LLMService(
174
- self._api_domain, self._token, verify_ssl=self._verify_ssl
175
- )
176
- self.mermaid = MermaidService(
177
- self._api_domain, self._token, verify_ssl=self._verify_ssl
178
- )
179
- self.integrations = IntegrationService(
180
- self._api_domain, self._token, verify_ssl=self._verify_ssl
181
- )
182
- self.skills = SkillService(
183
- self._api_domain, self._token, verify_ssl=self._verify_ssl
184
- )
185
- self.tasks = TaskService(
186
- self._api_domain, self._token, verify_ssl=self._verify_ssl
187
- )
188
- self.users = UserService(
189
- self._api_domain, self._token, verify_ssl=self._verify_ssl
190
- )
191
- self.datasources = DatasourceService(
192
- self._api_domain, self._token, verify_ssl=self._verify_ssl
193
- )
194
- self.workflows = WorkflowService(
195
- self._api_domain, self._token, verify_ssl=self._verify_ssl
196
- )
197
- self.conversations = ConversationService(
198
- self._api_domain, self._token, verify_ssl=self._verify_ssl
199
- )
200
- self.files = FileOperationService(
201
- self._api_domain, self._token, verify_ssl=self._verify_ssl
202
- )
203
- self.webhook = WebhookService(
204
- self._api_domain, self._token, verify_ssl=self._verify_ssl
205
- )
206
- self.vendor_assistants = VendorAssistantService(
207
- self._api_domain, self._token, verify_ssl=self._verify_ssl
208
- )
209
- self.vendor_workflows = VendorWorkflowService(
210
- self._api_domain, self._token, verify_ssl=self._verify_ssl
211
- )
212
- self.vendor_knowledgebases = VendorKnowledgeBaseService(
213
- self._api_domain, self._token, verify_ssl=self._verify_ssl
214
- )
215
- self.vendor_guardrails = VendorGuardrailService(
216
- self._api_domain, self._token, verify_ssl=self._verify_ssl
217
- )
218
- self.codemie_guardrails = CodemieGuardrailService(
219
- self._api_domain, self._token, verify_ssl=self._verify_ssl
220
- )
169
+ # Services already hold self.auth.get_token callable, so no reconstruction needed
221
170
  return self._token
@@ -1,7 +1,5 @@
1
1
  """Custom exceptions for the CodeMie SDK."""
2
2
 
3
- from typing import Optional
4
-
5
3
 
6
4
  class CodeMieError(Exception):
7
5
  """Base exception for all CodeMie SDK errors."""
@@ -15,8 +13,8 @@ class ApiError(CodeMieError):
15
13
  def __init__(
16
14
  self,
17
15
  message: str,
18
- status_code: Optional[int] = None,
19
- response: Optional[dict] = None,
16
+ status_code: int | None = None,
17
+ response: dict | None = None,
20
18
  ):
21
19
  """Initialize API error.
22
20
 
@@ -1,6 +1,5 @@
1
1
  """Admin models for managing applications/projects."""
2
2
 
3
- from typing import List
4
3
  from pydantic import BaseModel, ConfigDict, Field
5
4
 
6
5
 
@@ -9,7 +8,7 @@ class ApplicationsListResponse(BaseModel):
9
8
 
10
9
  model_config = ConfigDict(extra="ignore")
11
10
 
12
- applications: List[str] = Field(..., description="List of application names")
11
+ applications: list[str] = Field(..., description="List of application names")
13
12
 
14
13
 
15
14
  class ApplicationCreateRequest(BaseModel):
@@ -1,6 +1,6 @@
1
1
  """Models for analytics-related data structures."""
2
2
 
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any
4
4
 
5
5
  from pydantic import BaseModel, ConfigDict, Field
6
6
 
@@ -12,7 +12,7 @@ class ResponseMetadata(BaseModel):
12
12
 
13
13
  timestamp: str = Field(description="ISO 8601 timestamp when response generated")
14
14
  data_as_of: str = Field(description="ISO 8601 timestamp of data freshness")
15
- filters_applied: Dict[str, Any] = Field(description="Applied filters")
15
+ filters_applied: dict[str, Any] = Field(description="Applied filters")
16
16
  execution_time_ms: float = Field(description="Query execution time in milliseconds")
17
17
 
18
18
 
@@ -35,10 +35,10 @@ class ColumnDefinition(BaseModel):
35
35
  id: str = Field(description="Column identifier")
36
36
  label: str = Field(description="Human-readable label")
37
37
  type: str = Field(description='Data type: "string", "number", "date"')
38
- format: Optional[str] = Field(
38
+ format: str | None = Field(
39
39
  None, description='Format hint: "currency", "percentage", "timestamp"'
40
40
  )
41
- description: Optional[str] = Field(None, description="Column description")
41
+ description: str | None = Field(None, description="Column description")
42
42
 
43
43
 
44
44
  class Metric(BaseModel):
@@ -50,10 +50,10 @@ class Metric(BaseModel):
50
50
  label: str = Field(description="Human-readable label")
51
51
  type: str = Field(description="Data type")
52
52
  value: Any = Field(description="Metric value (int, float, str, etc.)")
53
- format: Optional[str] = Field(
53
+ format: str | None = Field(
54
54
  None, description='Format hint: "currency", "percentage", "number"'
55
55
  )
56
- description: Optional[str] = Field(None, description="Metric description")
56
+ description: str | None = Field(None, description="Metric description")
57
57
 
58
58
 
59
59
  class SummariesData(BaseModel):
@@ -61,7 +61,7 @@ class SummariesData(BaseModel):
61
61
 
62
62
  model_config = ConfigDict(extra="ignore")
63
63
 
64
- metrics: List[Metric] = Field(description="Array of metrics")
64
+ metrics: list[Metric] = Field(description="Array of metrics")
65
65
 
66
66
 
67
67
  class TabularData(BaseModel):
@@ -69,9 +69,9 @@ class TabularData(BaseModel):
69
69
 
70
70
  model_config = ConfigDict(extra="ignore")
71
71
 
72
- columns: List[ColumnDefinition] = Field(description="Column definitions")
73
- rows: List[Dict[str, Any]] = Field(description="Data rows (dict per row)")
74
- totals: Optional[Dict[str, Any]] = Field(None, description="Optional totals row")
72
+ columns: list[ColumnDefinition] = Field(description="Column definitions")
73
+ rows: list[dict[str, Any]] = Field(description="Data rows (dict per row)")
74
+ totals: dict[str, Any] | None = Field(None, description="Optional totals row")
75
75
 
76
76
 
77
77
  class UserListItem(BaseModel):
@@ -88,7 +88,7 @@ class UsersListData(BaseModel):
88
88
 
89
89
  model_config = ConfigDict(extra="ignore")
90
90
 
91
- users: List[UserListItem] = Field(description="List of users")
91
+ users: list[UserListItem] = Field(description="List of users")
92
92
  total_count: int = Field(description="Total number of users")
93
93
 
94
94
 
@@ -108,7 +108,7 @@ class TabularResponse(BaseModel):
108
108
 
109
109
  data: TabularData = Field(description="Tabular data")
110
110
  metadata: ResponseMetadata = Field(description="Response metadata")
111
- pagination: Optional[PaginationMetadata] = Field(
111
+ pagination: PaginationMetadata | None = Field(
112
112
  None, description="Optional pagination metadata"
113
113
  )
114
114
 
@@ -127,18 +127,18 @@ class AnalyticsQueryParams(BaseModel):
127
127
 
128
128
  model_config = ConfigDict(extra="ignore")
129
129
 
130
- time_period: Optional[str] = Field(
130
+ time_period: str | None = Field(
131
131
  None,
132
132
  description='Time period: "last_hour", "last_6_hours", "last_24_hours", "last_7_days", "last_30_days", "last_90_days", "last_year"',
133
133
  )
134
- start_date: Optional[str] = Field(
134
+ start_date: str | None = Field(
135
135
  None, description="ISO 8601 format start date (use with end_date)"
136
136
  )
137
- end_date: Optional[str] = Field(
137
+ end_date: str | None = Field(
138
138
  None, description="ISO 8601 format end date (use with start_date)"
139
139
  )
140
- users: Optional[str] = Field(None, description="Comma-separated user IDs")
141
- projects: Optional[str] = Field(None, description="Comma-separated project names")
140
+ users: str | None = Field(None, description="Comma-separated user IDs")
141
+ projects: str | None = Field(None, description="Comma-separated project names")
142
142
 
143
143
 
144
144
  class PaginatedAnalyticsQueryParams(AnalyticsQueryParams):