arize-phoenix 11.23.1__py3-none-any.whl → 12.28.1__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.
Files changed (221) hide show
  1. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +61 -36
  2. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/RECORD +212 -162
  3. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
  4. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/IP_NOTICE +1 -1
  5. phoenix/__generated__/__init__.py +0 -0
  6. phoenix/__generated__/classification_evaluator_configs/__init__.py +20 -0
  7. phoenix/__generated__/classification_evaluator_configs/_document_relevance_classification_evaluator_config.py +17 -0
  8. phoenix/__generated__/classification_evaluator_configs/_hallucination_classification_evaluator_config.py +17 -0
  9. phoenix/__generated__/classification_evaluator_configs/_models.py +18 -0
  10. phoenix/__generated__/classification_evaluator_configs/_tool_selection_classification_evaluator_config.py +17 -0
  11. phoenix/__init__.py +2 -1
  12. phoenix/auth.py +27 -2
  13. phoenix/config.py +1594 -81
  14. phoenix/db/README.md +546 -28
  15. phoenix/db/bulk_inserter.py +119 -116
  16. phoenix/db/engines.py +140 -33
  17. phoenix/db/facilitator.py +22 -1
  18. phoenix/db/helpers.py +818 -65
  19. phoenix/db/iam_auth.py +64 -0
  20. phoenix/db/insertion/dataset.py +133 -1
  21. phoenix/db/insertion/document_annotation.py +9 -6
  22. phoenix/db/insertion/evaluation.py +2 -3
  23. phoenix/db/insertion/helpers.py +2 -2
  24. phoenix/db/insertion/session_annotation.py +176 -0
  25. phoenix/db/insertion/span_annotation.py +3 -4
  26. phoenix/db/insertion/trace_annotation.py +3 -4
  27. phoenix/db/insertion/types.py +41 -18
  28. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  29. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  30. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  31. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  32. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  33. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  34. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  35. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  36. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  37. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  38. phoenix/db/models.py +364 -56
  39. phoenix/db/pg_config.py +10 -0
  40. phoenix/db/types/trace_retention.py +7 -6
  41. phoenix/experiments/functions.py +69 -19
  42. phoenix/inferences/inferences.py +1 -2
  43. phoenix/server/api/auth.py +9 -0
  44. phoenix/server/api/auth_messages.py +46 -0
  45. phoenix/server/api/context.py +60 -0
  46. phoenix/server/api/dataloaders/__init__.py +36 -0
  47. phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
  48. phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
  49. phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
  50. phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
  51. phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
  52. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
  53. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  54. phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
  55. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  56. phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
  57. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  58. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
  59. phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
  60. phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
  61. phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
  62. phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
  63. phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
  64. phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
  65. phoenix/server/api/dataloaders/record_counts.py +37 -10
  66. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  67. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
  68. phoenix/server/api/dataloaders/span_cost_summary_by_project.py +28 -14
  69. phoenix/server/api/dataloaders/span_costs.py +3 -9
  70. phoenix/server/api/dataloaders/table_fields.py +2 -2
  71. phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
  72. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  73. phoenix/server/api/exceptions.py +5 -1
  74. phoenix/server/api/helpers/playground_clients.py +263 -83
  75. phoenix/server/api/helpers/playground_spans.py +2 -1
  76. phoenix/server/api/helpers/playground_users.py +26 -0
  77. phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
  78. phoenix/server/api/helpers/prompts/models.py +61 -19
  79. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  80. phoenix/server/api/input_types/ChatCompletionInput.py +3 -0
  81. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  82. phoenix/server/api/input_types/DatasetFilter.py +5 -2
  83. phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
  84. phoenix/server/api/input_types/GenerativeModelInput.py +3 -0
  85. phoenix/server/api/input_types/ProjectSessionSort.py +158 -1
  86. phoenix/server/api/input_types/PromptVersionInput.py +47 -1
  87. phoenix/server/api/input_types/SpanSort.py +3 -2
  88. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  89. phoenix/server/api/input_types/UserRoleInput.py +1 -0
  90. phoenix/server/api/mutations/__init__.py +8 -0
  91. phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
  92. phoenix/server/api/mutations/api_key_mutations.py +15 -20
  93. phoenix/server/api/mutations/chat_mutations.py +106 -37
  94. phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
  95. phoenix/server/api/mutations/dataset_mutations.py +21 -16
  96. phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
  97. phoenix/server/api/mutations/experiment_mutations.py +2 -2
  98. phoenix/server/api/mutations/export_events_mutations.py +3 -3
  99. phoenix/server/api/mutations/model_mutations.py +11 -9
  100. phoenix/server/api/mutations/project_mutations.py +4 -4
  101. phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
  102. phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
  103. phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
  104. phoenix/server/api/mutations/prompt_mutations.py +65 -129
  105. phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
  106. phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
  107. phoenix/server/api/mutations/trace_annotations_mutations.py +13 -8
  108. phoenix/server/api/mutations/trace_mutations.py +3 -3
  109. phoenix/server/api/mutations/user_mutations.py +55 -26
  110. phoenix/server/api/queries.py +501 -617
  111. phoenix/server/api/routers/__init__.py +2 -2
  112. phoenix/server/api/routers/auth.py +141 -87
  113. phoenix/server/api/routers/ldap.py +229 -0
  114. phoenix/server/api/routers/oauth2.py +349 -101
  115. phoenix/server/api/routers/v1/__init__.py +22 -4
  116. phoenix/server/api/routers/v1/annotation_configs.py +19 -30
  117. phoenix/server/api/routers/v1/annotations.py +455 -13
  118. phoenix/server/api/routers/v1/datasets.py +355 -68
  119. phoenix/server/api/routers/v1/documents.py +142 -0
  120. phoenix/server/api/routers/v1/evaluations.py +20 -28
  121. phoenix/server/api/routers/v1/experiment_evaluations.py +16 -6
  122. phoenix/server/api/routers/v1/experiment_runs.py +335 -59
  123. phoenix/server/api/routers/v1/experiments.py +475 -47
  124. phoenix/server/api/routers/v1/projects.py +16 -50
  125. phoenix/server/api/routers/v1/prompts.py +50 -39
  126. phoenix/server/api/routers/v1/sessions.py +108 -0
  127. phoenix/server/api/routers/v1/spans.py +156 -96
  128. phoenix/server/api/routers/v1/traces.py +51 -77
  129. phoenix/server/api/routers/v1/users.py +64 -24
  130. phoenix/server/api/routers/v1/utils.py +3 -7
  131. phoenix/server/api/subscriptions.py +257 -93
  132. phoenix/server/api/types/Annotation.py +90 -23
  133. phoenix/server/api/types/ApiKey.py +13 -17
  134. phoenix/server/api/types/AuthMethod.py +1 -0
  135. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
  136. phoenix/server/api/types/Dataset.py +199 -72
  137. phoenix/server/api/types/DatasetExample.py +88 -18
  138. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  139. phoenix/server/api/types/DatasetLabel.py +57 -0
  140. phoenix/server/api/types/DatasetSplit.py +98 -0
  141. phoenix/server/api/types/DatasetVersion.py +49 -4
  142. phoenix/server/api/types/DocumentAnnotation.py +212 -0
  143. phoenix/server/api/types/Experiment.py +215 -68
  144. phoenix/server/api/types/ExperimentComparison.py +3 -9
  145. phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
  146. phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
  147. phoenix/server/api/types/ExperimentRun.py +120 -70
  148. phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
  149. phoenix/server/api/types/GenerativeModel.py +95 -42
  150. phoenix/server/api/types/GenerativeProvider.py +1 -1
  151. phoenix/server/api/types/ModelInterface.py +7 -2
  152. phoenix/server/api/types/PlaygroundModel.py +12 -2
  153. phoenix/server/api/types/Project.py +218 -185
  154. phoenix/server/api/types/ProjectSession.py +146 -29
  155. phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
  156. phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
  157. phoenix/server/api/types/Prompt.py +119 -39
  158. phoenix/server/api/types/PromptLabel.py +42 -25
  159. phoenix/server/api/types/PromptVersion.py +11 -8
  160. phoenix/server/api/types/PromptVersionTag.py +65 -25
  161. phoenix/server/api/types/Span.py +130 -123
  162. phoenix/server/api/types/SpanAnnotation.py +189 -42
  163. phoenix/server/api/types/SystemApiKey.py +65 -1
  164. phoenix/server/api/types/Trace.py +184 -53
  165. phoenix/server/api/types/TraceAnnotation.py +149 -50
  166. phoenix/server/api/types/User.py +128 -33
  167. phoenix/server/api/types/UserApiKey.py +73 -26
  168. phoenix/server/api/types/node.py +10 -0
  169. phoenix/server/api/types/pagination.py +11 -2
  170. phoenix/server/app.py +154 -36
  171. phoenix/server/authorization.py +5 -4
  172. phoenix/server/bearer_auth.py +13 -5
  173. phoenix/server/cost_tracking/cost_model_lookup.py +42 -14
  174. phoenix/server/cost_tracking/model_cost_manifest.json +1085 -194
  175. phoenix/server/daemons/generative_model_store.py +61 -9
  176. phoenix/server/daemons/span_cost_calculator.py +10 -8
  177. phoenix/server/dml_event.py +13 -0
  178. phoenix/server/email/sender.py +29 -2
  179. phoenix/server/grpc_server.py +9 -9
  180. phoenix/server/jwt_store.py +8 -6
  181. phoenix/server/ldap.py +1449 -0
  182. phoenix/server/main.py +9 -3
  183. phoenix/server/oauth2.py +330 -12
  184. phoenix/server/prometheus.py +43 -6
  185. phoenix/server/rate_limiters.py +4 -9
  186. phoenix/server/retention.py +33 -20
  187. phoenix/server/session_filters.py +49 -0
  188. phoenix/server/static/.vite/manifest.json +51 -53
  189. phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
  190. phoenix/server/static/assets/{index-BPCwGQr8.js → index-CTQoemZv.js} +42 -35
  191. phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
  192. phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
  193. phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
  194. phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
  195. phoenix/server/static/assets/{vendor-recharts-Bw30oz1A.js → vendor-recharts-V9cwpXsm.js} +7 -7
  196. phoenix/server/static/assets/{vendor-shiki-DZajAPeq.js → vendor-shiki-Do--csgv.js} +1 -1
  197. phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
  198. phoenix/server/templates/index.html +7 -1
  199. phoenix/server/thread_server.py +1 -2
  200. phoenix/server/utils.py +74 -0
  201. phoenix/session/client.py +55 -1
  202. phoenix/session/data_extractor.py +5 -0
  203. phoenix/session/evaluation.py +8 -4
  204. phoenix/session/session.py +44 -8
  205. phoenix/settings.py +2 -0
  206. phoenix/trace/attributes.py +80 -13
  207. phoenix/trace/dsl/query.py +2 -0
  208. phoenix/trace/projects.py +5 -0
  209. phoenix/utilities/template_formatters.py +1 -1
  210. phoenix/version.py +1 -1
  211. phoenix/server/api/types/Evaluation.py +0 -39
  212. phoenix/server/static/assets/components-D0DWAf0l.js +0 -5650
  213. phoenix/server/static/assets/pages-Creyamao.js +0 -8612
  214. phoenix/server/static/assets/vendor-CU36oj8y.js +0 -905
  215. phoenix/server/static/assets/vendor-CqDb5u4o.css +0 -1
  216. phoenix/server/static/assets/vendor-arizeai-Ctgw0e1G.js +0 -168
  217. phoenix/server/static/assets/vendor-codemirror-Cojjzqb9.js +0 -25
  218. phoenix/server/static/assets/vendor-three-BLWp5bic.js +0 -2998
  219. phoenix/utilities/deprecation.py +0 -31
  220. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
  221. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
@@ -12,15 +12,6 @@ from sqlalchemy.exc import IntegrityError as PostgreSQLIntegrityError
12
12
  from sqlalchemy.orm import joinedload
13
13
  from sqlean.dbapi2 import IntegrityError as SQLiteIntegrityError # type: ignore[import-untyped]
14
14
  from starlette.datastructures import Secret
15
- from starlette.status import (
16
- HTTP_201_CREATED,
17
- HTTP_204_NO_CONTENT,
18
- HTTP_400_BAD_REQUEST,
19
- HTTP_403_FORBIDDEN,
20
- HTTP_404_NOT_FOUND,
21
- HTTP_409_CONFLICT,
22
- HTTP_422_UNPROCESSABLE_ENTITY,
23
- )
24
15
  from strawberry.relay import GlobalID
25
16
  from typing_extensions import TypeAlias, assert_never
26
17
 
@@ -45,6 +36,7 @@ from phoenix.server.api.routers.v1.utils import (
45
36
  )
46
37
  from phoenix.server.api.types.node import from_global_id_with_expected_type
47
38
  from phoenix.server.authorization import is_not_locked, require_admin
39
+ from phoenix.server.ldap import is_ldap_user, is_null_email_marker
48
40
 
49
41
  logger = logging.getLogger(__name__)
50
42
 
@@ -68,6 +60,10 @@ class OAuth2UserData(UserData):
68
60
  oauth2_user_id: str = UNDEFINED
69
61
 
70
62
 
63
+ class LDAPUserData(UserData):
64
+ auth_method: Literal["LDAP"]
65
+
66
+
71
67
  class DbUser(V1RoutesBaseModel):
72
68
  id: str
73
69
  created_at: datetime
@@ -82,7 +78,13 @@ class OAuth2User(OAuth2UserData, DbUser):
82
78
  profile_picture_url: str = UNDEFINED
83
79
 
84
80
 
85
- User: TypeAlias = Annotated[Union[LocalUser, OAuth2User], Field(..., discriminator="auth_method")]
81
+ class LDAPUser(LDAPUserData, DbUser):
82
+ pass
83
+
84
+
85
+ User: TypeAlias = Annotated[
86
+ Union[LocalUser, OAuth2User, LDAPUser], Field(..., discriminator="auth_method")
87
+ ]
86
88
 
87
89
 
88
90
  class GetUsersResponseBody(PaginatedResponseBody[User]):
@@ -94,7 +96,9 @@ class GetUserResponseBody(ResponseBody[User]):
94
96
 
95
97
 
96
98
  class CreateUserRequestBody(V1RoutesBaseModel):
97
- user: Annotated[Union[LocalUserData, OAuth2UserData], Field(..., discriminator="auth_method")]
99
+ user: Annotated[
100
+ Union[LocalUserData, OAuth2UserData, LDAPUserData], Field(..., discriminator="auth_method")
101
+ ]
98
102
  send_welcome_email: bool = True
99
103
 
100
104
 
@@ -113,7 +117,7 @@ DEFAULT_PAGINATION_PAGE_LIMIT = 100
113
117
  response_description="A list of users.",
114
118
  responses=add_errors_to_responses(
115
119
  [
116
- HTTP_422_UNPROCESSABLE_ENTITY,
120
+ 422,
117
121
  ],
118
122
  ),
119
123
  dependencies=[Depends(require_admin)],
@@ -161,6 +165,19 @@ async def list_users(
161
165
  password_needs_reset=user.reset_password,
162
166
  )
163
167
  )
168
+ elif isinstance(user, models.OAuth2User) and is_ldap_user(user.oauth2_client_id):
169
+ # Check if this is an LDAP user (identified by special marker)
170
+ data.append(
171
+ LDAPUser(
172
+ id=str(GlobalID("User", str(user.id))),
173
+ username=user.username,
174
+ email="" if is_null_email_marker(user.email) else user.email,
175
+ role=user.role.name,
176
+ created_at=user.created_at,
177
+ updated_at=user.updated_at,
178
+ auth_method="LDAP",
179
+ )
180
+ )
164
181
  elif isinstance(user, models.OAuth2User):
165
182
  oauth2_user = OAuth2User(
166
183
  id=str(GlobalID("User", str(user.id))),
@@ -187,12 +204,12 @@ async def list_users(
187
204
  summary="Create a new user",
188
205
  description="Create a new user with the specified configuration.",
189
206
  response_description="The newly created user.",
190
- status_code=HTTP_201_CREATED,
207
+ status_code=201,
191
208
  responses=add_errors_to_responses(
192
209
  [
193
- {"status_code": HTTP_400_BAD_REQUEST, "description": "Role not found."},
194
- {"status_code": HTTP_409_CONFLICT, "description": "Username or email already exists."},
195
- HTTP_422_UNPROCESSABLE_ENTITY,
210
+ {"status_code": 400, "description": "Role not found."},
211
+ {"status_code": 409, "description": "Username or email already exists."},
212
+ 422,
196
213
  ]
197
214
  ),
198
215
  dependencies=[Depends(require_admin), Depends(is_not_locked)],
@@ -213,10 +230,18 @@ async def create_user(
213
230
  # Prevent creation of SYSTEM users
214
231
  if role == "SYSTEM":
215
232
  raise HTTPException(
216
- status_code=HTTP_400_BAD_REQUEST,
233
+ status_code=400,
217
234
  detail="Cannot create users with SYSTEM role",
218
235
  )
219
236
 
237
+ # Prevent OAuth2 users from using the LDAP marker or any variation
238
+ if isinstance(user_data, OAuth2UserData):
239
+ if is_ldap_user(user_data.oauth2_client_id):
240
+ raise HTTPException(
241
+ status_code=400,
242
+ detail="Cannot create OAuth2 users with reserved LDAP identifier",
243
+ )
244
+
220
245
  user: models.User
221
246
  if isinstance(user_data, LocalUserData):
222
247
  password = (user_data.password or secrets.token_hex()).strip()
@@ -241,6 +266,11 @@ async def create_user(
241
266
  oauth2_client_id=user_data.oauth2_client_id or None,
242
267
  oauth2_user_id=user_data.oauth2_user_id or None,
243
268
  )
269
+ elif isinstance(user_data, LDAPUserData):
270
+ user = models.LDAPUser(
271
+ email=email,
272
+ username=username,
273
+ )
244
274
  else:
245
275
  assert_never(user_data)
246
276
  try:
@@ -252,12 +282,12 @@ async def create_user(
252
282
  session.add(user)
253
283
  except (PostgreSQLIntegrityError, SQLiteIntegrityError) as e:
254
284
  if "users.username" in str(e):
255
- raise HTTPException(status_code=HTTP_409_CONFLICT, detail="Username already exists")
285
+ raise HTTPException(status_code=409, detail="Username already exists")
256
286
  elif "users.email" in str(e):
257
- raise HTTPException(status_code=HTTP_409_CONFLICT, detail="Email already exists")
287
+ raise HTTPException(status_code=409, detail="Email already exists")
258
288
  else:
259
289
  raise HTTPException(
260
- status_code=HTTP_409_CONFLICT,
290
+ status_code=409,
261
291
  detail="Failed to create user due to a conflict with existing data",
262
292
  )
263
293
  id_ = str(GlobalID("User", str(user.id)))
@@ -289,6 +319,16 @@ async def create_user(
289
319
  data.oauth2_user_id = user.oauth2_user_id
290
320
  if user.profile_picture_url:
291
321
  data.profile_picture_url = user.profile_picture_url
322
+ elif isinstance(user_data, LDAPUserData):
323
+ data = LDAPUser(
324
+ id=id_,
325
+ email=email,
326
+ username=username,
327
+ auth_method="LDAP",
328
+ role=user_data.role,
329
+ created_at=user.created_at,
330
+ updated_at=user.updated_at,
331
+ )
292
332
  else:
293
333
  assert_never(user_data)
294
334
  # Send welcome email if requested
@@ -307,13 +347,13 @@ async def create_user(
307
347
  summary="Delete a user by ID",
308
348
  description="Delete an existing user by their unique GlobalID.",
309
349
  response_description="No content returned on successful deletion.",
310
- status_code=HTTP_204_NO_CONTENT,
350
+ status_code=204,
311
351
  responses=add_errors_to_responses(
312
352
  [
313
- {"status_code": HTTP_404_NOT_FOUND, "description": "User not found."},
314
- HTTP_422_UNPROCESSABLE_ENTITY,
353
+ {"status_code": 404, "description": "User not found."},
354
+ 422,
315
355
  {
316
- "status_code": HTTP_403_FORBIDDEN,
356
+ "status_code": 403,
317
357
  "description": "Cannot delete the default admin or system user",
318
358
  },
319
359
  ]
@@ -3,10 +3,6 @@ from typing import Any, Generic, Optional, TypedDict, TypeVar, Union
3
3
  from fastapi import HTTPException
4
4
  from sqlalchemy import select
5
5
  from sqlalchemy.ext.asyncio import AsyncSession
6
- from starlette.status import (
7
- HTTP_404_NOT_FOUND,
8
- HTTP_422_UNPROCESSABLE_ENTITY,
9
- )
10
6
  from strawberry.relay import GlobalID
11
7
  from typing_extensions import TypeAlias, assert_never
12
8
 
@@ -135,21 +131,21 @@ async def _get_project_by_identifier(
135
131
  name = project_identifier
136
132
  except HTTPException:
137
133
  raise HTTPException(
138
- status_code=HTTP_422_UNPROCESSABLE_ENTITY,
134
+ status_code=422,
139
135
  detail=f"Invalid project identifier format: {project_identifier}",
140
136
  )
141
137
  stmt = select(models.Project).filter_by(name=name)
142
138
  project = await session.scalar(stmt)
143
139
  if project is None:
144
140
  raise HTTPException(
145
- status_code=HTTP_404_NOT_FOUND,
141
+ status_code=404,
146
142
  detail=f"Project with name {name} not found",
147
143
  )
148
144
  else:
149
145
  project = await session.get(models.Project, id_)
150
146
  if project is None:
151
147
  raise HTTPException(
152
- status_code=HTTP_404_NOT_FOUND,
148
+ status_code=404,
153
149
  detail=f"Project with ID {project_identifier} not found",
154
150
  )
155
151
  return project