arize-phoenix 4.28.1__py3-none-any.whl → 4.30.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

Files changed (29) hide show
  1. {arize_phoenix-4.28.1.dist-info → arize_phoenix-4.30.0.dist-info}/METADATA +2 -1
  2. {arize_phoenix-4.28.1.dist-info → arize_phoenix-4.30.0.dist-info}/RECORD +26 -22
  3. phoenix/otel/__init__.py +22 -0
  4. phoenix/otel/otel.py +284 -0
  5. phoenix/otel/settings.py +82 -0
  6. phoenix/server/api/dataloaders/dataset_example_revisions.py +3 -2
  7. phoenix/server/api/exceptions.py +41 -0
  8. phoenix/server/api/mutations/api_key_mutations.py +29 -0
  9. phoenix/server/api/mutations/auth_mutations.py +4 -2
  10. phoenix/server/api/mutations/dataset_mutations.py +9 -8
  11. phoenix/server/api/mutations/experiment_mutations.py +2 -1
  12. phoenix/server/api/queries.py +9 -8
  13. phoenix/server/api/routers/v1/experiments.py +4 -4
  14. phoenix/server/api/schema.py +2 -0
  15. phoenix/server/static/.vite/manifest.json +31 -31
  16. phoenix/server/static/assets/components-CkSg5zK4.js +1344 -0
  17. phoenix/server/static/assets/{index-fqdjNpYm.js → index-DTecsU5w.js} +1 -1
  18. phoenix/server/static/assets/{pages-DnbxgoTK.js → pages-C6emDFIO.js} +212 -210
  19. phoenix/server/static/assets/vendor-DsnEJuEV.js +641 -0
  20. phoenix/server/static/assets/{vendor-arizeai-CsdcB1NH.js → vendor-arizeai-DtynTLNi.js} +2 -2
  21. phoenix/server/static/assets/vendor-codemirror-C5to5cK4.js +27 -0
  22. phoenix/server/static/assets/{vendor-recharts-B0sannek.js → vendor-recharts-reihe2SJ.js} +1 -1
  23. phoenix/version.py +1 -1
  24. phoenix/server/static/assets/components-BYH03rjA.js +0 -1228
  25. phoenix/server/static/assets/vendor-aSQri0vz.js +0 -641
  26. phoenix/server/static/assets/vendor-codemirror-CYHkhs7D.js +0 -15
  27. {arize_phoenix-4.28.1.dist-info → arize_phoenix-4.30.0.dist-info}/WHEEL +0 -0
  28. {arize_phoenix-4.28.1.dist-info → arize_phoenix-4.30.0.dist-info}/licenses/IP_NOTICE +0 -0
  29. {arize_phoenix-4.28.1.dist-info → arize_phoenix-4.30.0.dist-info}/licenses/LICENSE +0 -0
@@ -13,6 +13,7 @@ from strawberry.types import Info
13
13
  from phoenix.db import models
14
14
  from phoenix.db.helpers import get_eval_trace_ids_for_datasets, get_project_names_for_datasets
15
15
  from phoenix.server.api.context import Context
16
+ from phoenix.server.api.exceptions import BadRequest, NotFound
16
17
  from phoenix.server.api.helpers.dataset_helpers import (
17
18
  get_dataset_example_input,
18
19
  get_dataset_example_output,
@@ -362,7 +363,7 @@ class DatasetMutationMixin:
362
363
  expected_type_name=Dataset.__name__,
363
364
  )
364
365
  except ValueError:
365
- raise ValueError(f"Unknown dataset: {input.dataset_id}")
366
+ raise NotFound(f"Unknown dataset: {input.dataset_id}")
366
367
  project_names_stmt = get_project_names_for_datasets(dataset_id)
367
368
  eval_trace_ids_stmt = get_eval_trace_ids_for_datasets(dataset_id)
368
369
  stmt = (
@@ -372,7 +373,7 @@ class DatasetMutationMixin:
372
373
  project_names = await session.scalars(project_names_stmt)
373
374
  eval_trace_ids = await session.scalars(eval_trace_ids_stmt)
374
375
  if not (dataset := await session.scalar(stmt)):
375
- raise ValueError(f"Unknown dataset: {input.dataset_id}")
376
+ raise NotFound(f"Unknown dataset: {input.dataset_id}")
376
377
  await asyncio.gather(
377
378
  delete_projects(info.context.db, *project_names),
378
379
  delete_traces(info.context.db, *eval_trace_ids),
@@ -388,7 +389,7 @@ class DatasetMutationMixin:
388
389
  input: PatchDatasetExamplesInput,
389
390
  ) -> DatasetMutationPayload:
390
391
  if not (patches := input.patches):
391
- raise ValueError("Must provide examples to patch.")
392
+ raise BadRequest("Must provide examples to patch.")
392
393
  by_numeric_id = [
393
394
  (
394
395
  from_global_id_with_expected_type(patch.example_id, DatasetExample.__name__),
@@ -399,9 +400,9 @@ class DatasetMutationMixin:
399
400
  ]
400
401
  example_ids, _, patches = map(list, zip(*sorted(by_numeric_id)))
401
402
  if len(set(example_ids)) < len(example_ids):
402
- raise ValueError("Cannot patch the same example more than once per mutation.")
403
+ raise BadRequest("Cannot patch the same example more than once per mutation.")
403
404
  if any(patch.is_empty() for patch in patches):
404
- raise ValueError("Received one or more empty patches that contain no fields to update.")
405
+ raise BadRequest("Received one or more empty patches that contain no fields to update.")
405
406
  version_description = input.version_description or None
406
407
  version_metadata = input.version_metadata
407
408
  async with info.context.db() as session:
@@ -419,9 +420,9 @@ class DatasetMutationMixin:
419
420
  )
420
421
  ).all()
421
422
  if not datasets:
422
- raise ValueError("No examples found.")
423
+ raise NotFound("No examples found.")
423
424
  if len(set(ds.id for ds in datasets)) > 1:
424
- raise ValueError("Examples must come from the same dataset.")
425
+ raise BadRequest("Examples must come from the same dataset.")
425
426
  dataset = datasets[0]
426
427
 
427
428
  revision_ids = (
@@ -445,7 +446,7 @@ class DatasetMutationMixin:
445
446
  )
446
447
  ).all()
447
448
  if (num_missing_examples := len(example_ids) - len(revisions)) > 0:
448
- raise ValueError(f"{num_missing_examples} example(s) could not be found.")
449
+ raise NotFound(f"{num_missing_examples} example(s) could not be found.")
449
450
 
450
451
  version_id = await session.scalar(
451
452
  insert(models.DatasetVersion)
@@ -9,6 +9,7 @@ from strawberry.types import Info
9
9
  from phoenix.db import models
10
10
  from phoenix.db.helpers import get_eval_trace_ids_for_experiments, get_project_names_for_experiments
11
11
  from phoenix.server.api.context import Context
12
+ from phoenix.server.api.exceptions import CustomGraphQLError
12
13
  from phoenix.server.api.input_types.DeleteExperimentsInput import DeleteExperimentsInput
13
14
  from phoenix.server.api.mutations.auth import IsAuthenticated
14
15
  from phoenix.server.api.types.Experiment import Experiment, to_gql_experiment
@@ -52,7 +53,7 @@ class ExperimentMutationMixin:
52
53
  }
53
54
  if unknown_experiment_ids := set(experiment_ids) - set(experiments.keys()):
54
55
  await savepoint.rollback()
55
- raise ValueError(
56
+ raise CustomGraphQLError(
56
57
  "Failed to delete experiment(s), "
57
58
  "probably due to invalid input experiment ID(s): "
58
59
  + str(
@@ -33,6 +33,7 @@ from phoenix.db.models import (
33
33
  )
34
34
  from phoenix.pointcloud.clustering import Hdbscan
35
35
  from phoenix.server.api.context import Context
36
+ from phoenix.server.api.exceptions import NotFound
36
37
  from phoenix.server.api.helpers import ensure_list
37
38
  from phoenix.server.api.input_types.ClusterInput import ClusterInput
38
39
  from phoenix.server.api.input_types.Coordinates import (
@@ -391,7 +392,7 @@ class Query:
391
392
  async with info.context.db() as session:
392
393
  project = (await session.execute(project_stmt)).first()
393
394
  if project is None:
394
- raise ValueError(f"Unknown project: {id}")
395
+ raise NotFound(f"Unknown project: {id}")
395
396
  return Project(
396
397
  id_attr=project.id,
397
398
  name=project.name,
@@ -406,7 +407,7 @@ class Query:
406
407
  async with info.context.db() as session:
407
408
  trace = (await session.execute(trace_stmt)).first()
408
409
  if trace is None:
409
- raise ValueError(f"Unknown trace: {id}")
410
+ raise NotFound(f"Unknown trace: {id}")
410
411
  return Trace(
411
412
  id_attr=trace.id, trace_id=trace.trace_id, project_rowid=trace.project_rowid
412
413
  )
@@ -421,13 +422,13 @@ class Query:
421
422
  async with info.context.db() as session:
422
423
  span = await session.scalar(span_stmt)
423
424
  if span is None:
424
- raise ValueError(f"Unknown span: {id}")
425
+ raise NotFound(f"Unknown span: {id}")
425
426
  return to_gql_span(span)
426
427
  elif type_name == Dataset.__name__:
427
428
  dataset_stmt = select(models.Dataset).where(models.Dataset.id == node_id)
428
429
  async with info.context.db() as session:
429
430
  if (dataset := await session.scalar(dataset_stmt)) is None:
430
- raise ValueError(f"Unknown dataset: {id}")
431
+ raise NotFound(f"Unknown dataset: {id}")
431
432
  return to_gql_dataset(dataset)
432
433
  elif type_name == DatasetExample.__name__:
433
434
  example_id = node_id
@@ -453,7 +454,7 @@ class Query:
453
454
  )
454
455
  )
455
456
  if not example:
456
- raise ValueError(f"Unknown dataset example: {id}")
457
+ raise NotFound(f"Unknown dataset example: {id}")
457
458
  return DatasetExample(
458
459
  id_attr=example.id,
459
460
  created_at=example.created_at,
@@ -464,7 +465,7 @@ class Query:
464
465
  select(models.Experiment).where(models.Experiment.id == node_id)
465
466
  )
466
467
  if not experiment:
467
- raise ValueError(f"Unknown experiment: {id}")
468
+ raise NotFound(f"Unknown experiment: {id}")
468
469
  return Experiment(
469
470
  id_attr=experiment.id,
470
471
  name=experiment.name,
@@ -485,9 +486,9 @@ class Query:
485
486
  )
486
487
  )
487
488
  ):
488
- raise ValueError(f"Unknown experiment run: {id}")
489
+ raise NotFound(f"Unknown experiment run: {id}")
489
490
  return to_gql_experiment_run(run)
490
- raise Exception(f"Unknown node type: {type_name}")
491
+ raise NotFound(f"Unknown node type: {type_name}")
491
492
 
492
493
  @strawberry.field
493
494
  def clusters(
@@ -2,7 +2,7 @@ from datetime import datetime
2
2
  from random import getrandbits
3
3
  from typing import Any, Dict, List, Optional
4
4
 
5
- from fastapi import APIRouter, HTTPException
5
+ from fastapi import APIRouter, HTTPException, Path
6
6
  from pydantic import Field
7
7
  from sqlalchemy import select
8
8
  from starlette.requests import Request
@@ -18,7 +18,7 @@ from phoenix.server.dml_event import ExperimentInsertEvent
18
18
  from .pydantic_compat import V1RoutesBaseModel
19
19
  from .utils import ResponseBody, add_errors_to_responses
20
20
 
21
- router = APIRouter(tags=["experiments"], include_in_schema=False)
21
+ router = APIRouter(tags=["experiments"], include_in_schema=True)
22
22
 
23
23
 
24
24
  def _short_uuid() -> str:
@@ -90,8 +90,8 @@ class CreateExperimentResponseBody(ResponseBody[Experiment]):
90
90
  )
91
91
  async def create_experiment(
92
92
  request: Request,
93
- dataset_id: str,
94
93
  request_body: CreateExperimentRequestBody,
94
+ dataset_id: str = Path(..., title="Dataset ID"),
95
95
  ) -> CreateExperimentResponseBody:
96
96
  dataset_globalid = GlobalID.from_id(dataset_id)
97
97
  try:
@@ -266,7 +266,7 @@ class ListExperimentsResponseBody(ResponseBody[List[Experiment]]):
266
266
  )
267
267
  async def list_experiments(
268
268
  request: Request,
269
- dataset_id: str,
269
+ dataset_id: str = Path(..., title="Dataset ID"),
270
270
  ) -> ListExperimentsResponseBody:
271
271
  dataset_gid = GlobalID.from_id(dataset_id)
272
272
  try:
@@ -1,5 +1,6 @@
1
1
  import strawberry
2
2
 
3
+ from phoenix.server.api.exceptions import get_mask_errors_extension
3
4
  from phoenix.server.api.mutations import Mutation
4
5
  from phoenix.server.api.queries import Query
5
6
 
@@ -10,4 +11,5 @@ from phoenix.server.api.queries import Query
10
11
  schema = strawberry.Schema(
11
12
  query=Query,
12
13
  mutation=Mutation,
14
+ extensions=[get_mask_errors_extension()],
13
15
  )
@@ -1,32 +1,32 @@
1
1
  {
2
- "_components-BYH03rjA.js": {
3
- "file": "assets/components-BYH03rjA.js",
2
+ "_components-CkSg5zK4.js": {
3
+ "file": "assets/components-CkSg5zK4.js",
4
4
  "name": "components",
5
5
  "imports": [
6
- "_vendor-aSQri0vz.js",
7
- "_vendor-arizeai-CsdcB1NH.js",
8
- "_pages-DnbxgoTK.js",
6
+ "_vendor-DsnEJuEV.js",
7
+ "_vendor-arizeai-DtynTLNi.js",
8
+ "_pages-C6emDFIO.js",
9
9
  "_vendor-three-DwGkEfCM.js",
10
- "_vendor-codemirror-CYHkhs7D.js"
10
+ "_vendor-codemirror-C5to5cK4.js"
11
11
  ]
12
12
  },
13
- "_pages-DnbxgoTK.js": {
14
- "file": "assets/pages-DnbxgoTK.js",
13
+ "_pages-C6emDFIO.js": {
14
+ "file": "assets/pages-C6emDFIO.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
- "_vendor-aSQri0vz.js",
18
- "_components-BYH03rjA.js",
19
- "_vendor-arizeai-CsdcB1NH.js",
20
- "_vendor-recharts-B0sannek.js",
21
- "_vendor-codemirror-CYHkhs7D.js"
17
+ "_vendor-DsnEJuEV.js",
18
+ "_components-CkSg5zK4.js",
19
+ "_vendor-arizeai-DtynTLNi.js",
20
+ "_vendor-recharts-reihe2SJ.js",
21
+ "_vendor-codemirror-C5to5cK4.js"
22
22
  ]
23
23
  },
24
24
  "_vendor-!~{003}~.js": {
25
25
  "file": "assets/vendor-DxkFTwjz.css",
26
26
  "src": "_vendor-!~{003}~.js"
27
27
  },
28
- "_vendor-aSQri0vz.js": {
29
- "file": "assets/vendor-aSQri0vz.js",
28
+ "_vendor-DsnEJuEV.js": {
29
+ "file": "assets/vendor-DsnEJuEV.js",
30
30
  "name": "vendor",
31
31
  "imports": [
32
32
  "_vendor-three-DwGkEfCM.js"
@@ -35,25 +35,25 @@
35
35
  "assets/vendor-DxkFTwjz.css"
36
36
  ]
37
37
  },
38
- "_vendor-arizeai-CsdcB1NH.js": {
39
- "file": "assets/vendor-arizeai-CsdcB1NH.js",
38
+ "_vendor-arizeai-DtynTLNi.js": {
39
+ "file": "assets/vendor-arizeai-DtynTLNi.js",
40
40
  "name": "vendor-arizeai",
41
41
  "imports": [
42
- "_vendor-aSQri0vz.js"
42
+ "_vendor-DsnEJuEV.js"
43
43
  ]
44
44
  },
45
- "_vendor-codemirror-CYHkhs7D.js": {
46
- "file": "assets/vendor-codemirror-CYHkhs7D.js",
45
+ "_vendor-codemirror-C5to5cK4.js": {
46
+ "file": "assets/vendor-codemirror-C5to5cK4.js",
47
47
  "name": "vendor-codemirror",
48
48
  "imports": [
49
- "_vendor-aSQri0vz.js"
49
+ "_vendor-DsnEJuEV.js"
50
50
  ]
51
51
  },
52
- "_vendor-recharts-B0sannek.js": {
53
- "file": "assets/vendor-recharts-B0sannek.js",
52
+ "_vendor-recharts-reihe2SJ.js": {
53
+ "file": "assets/vendor-recharts-reihe2SJ.js",
54
54
  "name": "vendor-recharts",
55
55
  "imports": [
56
- "_vendor-aSQri0vz.js"
56
+ "_vendor-DsnEJuEV.js"
57
57
  ]
58
58
  },
59
59
  "_vendor-three-DwGkEfCM.js": {
@@ -61,18 +61,18 @@
61
61
  "name": "vendor-three"
62
62
  },
63
63
  "index.tsx": {
64
- "file": "assets/index-fqdjNpYm.js",
64
+ "file": "assets/index-DTecsU5w.js",
65
65
  "name": "index",
66
66
  "src": "index.tsx",
67
67
  "isEntry": true,
68
68
  "imports": [
69
- "_vendor-aSQri0vz.js",
70
- "_vendor-arizeai-CsdcB1NH.js",
71
- "_pages-DnbxgoTK.js",
72
- "_components-BYH03rjA.js",
69
+ "_vendor-DsnEJuEV.js",
70
+ "_vendor-arizeai-DtynTLNi.js",
71
+ "_pages-C6emDFIO.js",
72
+ "_components-CkSg5zK4.js",
73
73
  "_vendor-three-DwGkEfCM.js",
74
- "_vendor-recharts-B0sannek.js",
75
- "_vendor-codemirror-CYHkhs7D.js"
74
+ "_vendor-recharts-reihe2SJ.js",
75
+ "_vendor-codemirror-C5to5cK4.js"
76
76
  ]
77
77
  }
78
78
  }