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
@@ -1,18 +1,19 @@
1
1
  from fastapi import APIRouter, Depends, HTTPException, Request
2
2
  from fastapi.security import APIKeyHeader
3
- from starlette.status import HTTP_403_FORBIDDEN
4
3
 
5
- from phoenix.server.bearer_auth import is_authenticated
4
+ from phoenix.server.bearer_auth import PhoenixUser, is_authenticated
6
5
 
7
6
  from .annotation_configs import router as annotation_configs_router
8
7
  from .annotations import router as annotations_router
9
8
  from .datasets import router as datasets_router
9
+ from .documents import router as documents_router
10
10
  from .evaluations import router as evaluations_router
11
11
  from .experiment_evaluations import router as experiment_evaluations_router
12
12
  from .experiment_runs import router as experiment_runs_router
13
13
  from .experiments import router as experiments_router
14
14
  from .projects import router as projects_router
15
15
  from .prompts import router as prompts_router
16
+ from .sessions import router as sessions_router
16
17
  from .spans import router as spans_router
17
18
  from .traces import router as traces_router
18
19
  from .users import router as users_router
@@ -28,7 +29,21 @@ async def prevent_access_in_read_only_mode(request: Request) -> None:
28
29
  if request.app.state.read_only:
29
30
  raise HTTPException(
30
31
  detail="The Phoenix REST API is disabled in read-only mode.",
31
- status_code=HTTP_403_FORBIDDEN,
32
+ status_code=403,
33
+ )
34
+
35
+
36
+ async def restrict_access_by_viewers(request: Request) -> None:
37
+ """
38
+ Prevents access to the REST API for viewers, except for GET requests
39
+ and specific allowed POST routes.
40
+ """
41
+ if request.method == "GET":
42
+ return
43
+ if isinstance(request.user, PhoenixUser) and request.user.is_viewer:
44
+ raise HTTPException(
45
+ status_code=403,
46
+ detail="Viewers cannot perform this action.",
32
47
  )
33
48
 
34
49
 
@@ -49,13 +64,14 @@ def create_v1_router(authentication_enabled: bool) -> APIRouter:
49
64
  )
50
65
  )
51
66
  dependencies.append(Depends(is_authenticated))
67
+ dependencies.append(Depends(restrict_access_by_viewers))
52
68
 
53
69
  router = APIRouter(
54
70
  prefix="/v1",
55
71
  dependencies=dependencies,
56
72
  responses=add_errors_to_responses(
57
73
  [
58
- HTTP_403_FORBIDDEN # adds a 403 response to routes in the generated OpenAPI schema
74
+ 403 # adds a 403 response to routes in the generated OpenAPI schema
59
75
  ]
60
76
  ),
61
77
  )
@@ -70,5 +86,7 @@ def create_v1_router(authentication_enabled: bool) -> APIRouter:
70
86
  router.include_router(evaluations_router)
71
87
  router.include_router(prompts_router)
72
88
  router.include_router(projects_router)
89
+ router.include_router(sessions_router)
90
+ router.include_router(documents_router)
73
91
  router.include_router(users_router)
74
92
  return router
@@ -7,11 +7,6 @@ from sqlalchemy import delete, select
7
7
  from sqlalchemy.exc import IntegrityError as PostgreSQLIntegrityError
8
8
  from sqlean.dbapi2 import IntegrityError as SQLiteIntegrityError # type: ignore[import-untyped]
9
9
  from starlette.requests import Request
10
- from starlette.status import (
11
- HTTP_400_BAD_REQUEST,
12
- HTTP_404_NOT_FOUND,
13
- HTTP_409_CONFLICT,
14
- )
15
10
  from strawberry.relay import GlobalID
16
11
  from typing_extensions import TypeAlias, assert_never
17
12
 
@@ -206,7 +201,7 @@ async def list_annotation_configs(
206
201
  except ValueError:
207
202
  raise HTTPException(
208
203
  detail=f"Invalid cursor: {cursor}",
209
- status_code=HTTP_400_BAD_REQUEST,
204
+ status_code=400,
210
205
  )
211
206
  if cursor_gid.type_name not in (
212
207
  CategoricalAnnotationConfigType.__name__,
@@ -215,7 +210,7 @@ async def list_annotation_configs(
215
210
  ):
216
211
  raise HTTPException(
217
212
  detail=f"Invalid cursor: {cursor}",
218
- status_code=HTTP_400_BAD_REQUEST,
213
+ status_code=400,
219
214
  )
220
215
  cursor_id = int(cursor_gid.node_id)
221
216
 
@@ -261,9 +256,7 @@ async def get_annotation_config_by_name_or_id(
261
256
  query = query.where(models.AnnotationConfig.name == config_identifier)
262
257
  config = await session.scalar(query)
263
258
  if not config:
264
- raise HTTPException(
265
- status_code=HTTP_404_NOT_FOUND, detail="Annotation configuration not found"
266
- )
259
+ raise HTTPException(status_code=404, detail="Annotation configuration not found")
267
260
  return GetAnnotationConfigResponseBody(data=db_to_api_annotation_config(config))
268
261
 
269
262
 
@@ -282,7 +275,7 @@ async def create_annotation_config(
282
275
  try:
283
276
  db_config = _to_db_annotation_config(input_config)
284
277
  except ValueError as error:
285
- raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail=str(error))
278
+ raise HTTPException(status_code=400, detail=str(error))
286
279
 
287
280
  async with request.app.state.db() as session:
288
281
  annotation_config = models.AnnotationConfig(
@@ -294,7 +287,7 @@ async def create_annotation_config(
294
287
  await session.commit()
295
288
  except (PostgreSQLIntegrityError, SQLiteIntegrityError):
296
289
  raise HTTPException(
297
- status_code=HTTP_409_CONFLICT,
290
+ status_code=409,
298
291
  detail="The name of the annotation configuration is already taken",
299
292
  )
300
293
  return CreateAnnotationConfigResponseBody(
@@ -321,22 +314,18 @@ async def update_annotation_config(
321
314
  ContinuousAnnotationConfigType.__name__,
322
315
  FreeformAnnotationConfigType.__name__,
323
316
  ):
324
- raise HTTPException(
325
- status_code=HTTP_400_BAD_REQUEST, detail="Invalid annotation configuration ID"
326
- )
317
+ raise HTTPException(status_code=400, detail="Invalid annotation configuration ID")
327
318
  config_rowid = int(config_gid.node_id)
328
319
 
329
320
  try:
330
321
  db_config = _to_db_annotation_config(input_config)
331
322
  except ValueError as error:
332
- raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail=str(error))
323
+ raise HTTPException(status_code=400, detail=str(error))
333
324
 
334
325
  async with request.app.state.db() as session:
335
326
  existing_config = await session.get(models.AnnotationConfig, config_rowid)
336
327
  if not existing_config:
337
- raise HTTPException(
338
- status_code=HTTP_404_NOT_FOUND, detail="Annotation configuration not found"
339
- )
328
+ raise HTTPException(status_code=404, detail="Annotation configuration not found")
340
329
 
341
330
  existing_config.name = input_config.name
342
331
  existing_config.config = db_config
@@ -345,7 +334,7 @@ async def update_annotation_config(
345
334
  await session.commit()
346
335
  except (PostgreSQLIntegrityError, SQLiteIntegrityError):
347
336
  raise HTTPException(
348
- status_code=HTTP_409_CONFLICT,
337
+ status_code=409,
349
338
  detail="The name of the annotation configuration is already taken",
350
339
  )
351
340
 
@@ -360,15 +349,19 @@ async def delete_annotation_config(
360
349
  request: Request,
361
350
  config_id: str = Path(..., description="ID of the annotation configuration"),
362
351
  ) -> DeleteAnnotationConfigResponseBody:
363
- config_gid = GlobalID.from_id(config_id)
352
+ try:
353
+ config_gid = GlobalID.from_id(config_id)
354
+ except Exception:
355
+ raise HTTPException(
356
+ status_code=422,
357
+ detail=f"Invalid annotation configuration ID format: {config_id}",
358
+ )
364
359
  if config_gid.type_name not in (
365
360
  CategoricalAnnotationConfigType.__name__,
366
361
  ContinuousAnnotationConfigType.__name__,
367
362
  FreeformAnnotationConfigType.__name__,
368
363
  ):
369
- raise HTTPException(
370
- status_code=HTTP_400_BAD_REQUEST, detail="Invalid annotation configuration ID"
371
- )
364
+ raise HTTPException(status_code=400, detail="Invalid annotation configuration ID")
372
365
  config_rowid = int(config_gid.node_id)
373
366
  async with request.app.state.db() as session:
374
367
  stmt = (
@@ -378,9 +371,7 @@ async def delete_annotation_config(
378
371
  )
379
372
  annotation_config = await session.scalar(stmt)
380
373
  if annotation_config is None:
381
- raise HTTPException(
382
- status_code=HTTP_404_NOT_FOUND, detail="Annotation configuration not found"
383
- )
374
+ raise HTTPException(status_code=404, detail="Annotation configuration not found")
384
375
  await session.commit()
385
376
  return DeleteAnnotationConfigResponseBody(data=db_to_api_annotation_config(annotation_config))
386
377
 
@@ -400,9 +391,7 @@ def _get_annotation_config_db_id(config_gid: str) -> int:
400
391
  def _reserve_note_annotation_name(data: AnnotationConfigData) -> str:
401
392
  name = data.name
402
393
  if name == "note":
403
- raise HTTPException(
404
- status_code=HTTP_409_CONFLICT, detail="The name 'note' is reserved for span notes"
405
- )
394
+ raise HTTPException(status_code=409, detail="The name 'note' is reserved for span notes")
406
395
  return name
407
396
 
408
397