arize-phoenix 5.5.2__py3-none-any.whl → 5.7.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 (186) hide show
  1. {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/METADATA +4 -7
  2. arize_phoenix-5.7.0.dist-info/RECORD +330 -0
  3. phoenix/config.py +50 -8
  4. phoenix/core/model.py +3 -3
  5. phoenix/core/model_schema.py +41 -50
  6. phoenix/core/model_schema_adapter.py +17 -16
  7. phoenix/datetime_utils.py +2 -2
  8. phoenix/db/bulk_inserter.py +10 -20
  9. phoenix/db/engines.py +2 -1
  10. phoenix/db/enums.py +2 -2
  11. phoenix/db/helpers.py +8 -7
  12. phoenix/db/insertion/dataset.py +9 -19
  13. phoenix/db/insertion/document_annotation.py +14 -13
  14. phoenix/db/insertion/helpers.py +6 -16
  15. phoenix/db/insertion/span_annotation.py +14 -13
  16. phoenix/db/insertion/trace_annotation.py +14 -13
  17. phoenix/db/insertion/types.py +19 -30
  18. phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +8 -8
  19. phoenix/db/models.py +28 -28
  20. phoenix/experiments/evaluators/base.py +2 -1
  21. phoenix/experiments/evaluators/code_evaluators.py +4 -5
  22. phoenix/experiments/evaluators/llm_evaluators.py +157 -4
  23. phoenix/experiments/evaluators/utils.py +3 -2
  24. phoenix/experiments/functions.py +10 -21
  25. phoenix/experiments/tracing.py +2 -1
  26. phoenix/experiments/types.py +20 -29
  27. phoenix/experiments/utils.py +2 -1
  28. phoenix/inferences/errors.py +6 -5
  29. phoenix/inferences/fixtures.py +6 -5
  30. phoenix/inferences/inferences.py +37 -37
  31. phoenix/inferences/schema.py +11 -10
  32. phoenix/inferences/validation.py +13 -14
  33. phoenix/logging/_formatter.py +3 -3
  34. phoenix/metrics/__init__.py +5 -4
  35. phoenix/metrics/binning.py +2 -1
  36. phoenix/metrics/metrics.py +2 -1
  37. phoenix/metrics/mixins.py +7 -6
  38. phoenix/metrics/retrieval_metrics.py +2 -1
  39. phoenix/metrics/timeseries.py +5 -4
  40. phoenix/metrics/wrappers.py +2 -2
  41. phoenix/pointcloud/clustering.py +3 -4
  42. phoenix/pointcloud/pointcloud.py +7 -5
  43. phoenix/pointcloud/umap_parameters.py +2 -1
  44. phoenix/server/api/dataloaders/annotation_summaries.py +12 -19
  45. phoenix/server/api/dataloaders/average_experiment_run_latency.py +2 -2
  46. phoenix/server/api/dataloaders/cache/two_tier_cache.py +3 -2
  47. phoenix/server/api/dataloaders/dataset_example_revisions.py +3 -8
  48. phoenix/server/api/dataloaders/dataset_example_spans.py +2 -5
  49. phoenix/server/api/dataloaders/document_evaluation_summaries.py +12 -18
  50. phoenix/server/api/dataloaders/document_evaluations.py +3 -7
  51. phoenix/server/api/dataloaders/document_retrieval_metrics.py +6 -13
  52. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +4 -8
  53. phoenix/server/api/dataloaders/experiment_error_rates.py +2 -5
  54. phoenix/server/api/dataloaders/experiment_run_annotations.py +3 -7
  55. phoenix/server/api/dataloaders/experiment_run_counts.py +1 -5
  56. phoenix/server/api/dataloaders/experiment_sequence_number.py +2 -5
  57. phoenix/server/api/dataloaders/latency_ms_quantile.py +21 -30
  58. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +7 -13
  59. phoenix/server/api/dataloaders/project_by_name.py +3 -3
  60. phoenix/server/api/dataloaders/record_counts.py +11 -18
  61. phoenix/server/api/dataloaders/span_annotations.py +3 -7
  62. phoenix/server/api/dataloaders/span_dataset_examples.py +3 -8
  63. phoenix/server/api/dataloaders/span_descendants.py +3 -7
  64. phoenix/server/api/dataloaders/span_projects.py +2 -2
  65. phoenix/server/api/dataloaders/token_counts.py +12 -19
  66. phoenix/server/api/dataloaders/trace_row_ids.py +3 -7
  67. phoenix/server/api/dataloaders/user_roles.py +3 -3
  68. phoenix/server/api/dataloaders/users.py +3 -3
  69. phoenix/server/api/helpers/__init__.py +4 -3
  70. phoenix/server/api/helpers/dataset_helpers.py +10 -9
  71. phoenix/server/api/helpers/playground_clients.py +671 -0
  72. phoenix/server/api/helpers/playground_registry.py +70 -0
  73. phoenix/server/api/helpers/playground_spans.py +325 -0
  74. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +2 -2
  75. phoenix/server/api/input_types/AddSpansToDatasetInput.py +2 -2
  76. phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
  77. phoenix/server/api/input_types/ChatCompletionMessageInput.py +13 -1
  78. phoenix/server/api/input_types/ClusterInput.py +2 -2
  79. phoenix/server/api/input_types/DeleteAnnotationsInput.py +1 -3
  80. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +2 -2
  81. phoenix/server/api/input_types/DeleteExperimentsInput.py +1 -3
  82. phoenix/server/api/input_types/DimensionFilter.py +4 -4
  83. phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
  84. phoenix/server/api/input_types/Granularity.py +1 -1
  85. phoenix/server/api/input_types/InvocationParameters.py +156 -13
  86. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +2 -2
  87. phoenix/server/api/input_types/TemplateOptions.py +10 -0
  88. phoenix/server/api/mutations/__init__.py +4 -0
  89. phoenix/server/api/mutations/chat_mutations.py +374 -0
  90. phoenix/server/api/mutations/dataset_mutations.py +4 -4
  91. phoenix/server/api/mutations/experiment_mutations.py +1 -2
  92. phoenix/server/api/mutations/export_events_mutations.py +7 -7
  93. phoenix/server/api/mutations/span_annotations_mutations.py +4 -4
  94. phoenix/server/api/mutations/trace_annotations_mutations.py +4 -4
  95. phoenix/server/api/mutations/user_mutations.py +4 -4
  96. phoenix/server/api/openapi/schema.py +2 -2
  97. phoenix/server/api/queries.py +61 -72
  98. phoenix/server/api/routers/oauth2.py +4 -4
  99. phoenix/server/api/routers/v1/datasets.py +22 -36
  100. phoenix/server/api/routers/v1/evaluations.py +6 -5
  101. phoenix/server/api/routers/v1/experiment_evaluations.py +2 -2
  102. phoenix/server/api/routers/v1/experiment_runs.py +2 -2
  103. phoenix/server/api/routers/v1/experiments.py +4 -4
  104. phoenix/server/api/routers/v1/spans.py +13 -12
  105. phoenix/server/api/routers/v1/traces.py +5 -5
  106. phoenix/server/api/routers/v1/utils.py +5 -5
  107. phoenix/server/api/schema.py +42 -10
  108. phoenix/server/api/subscriptions.py +347 -494
  109. phoenix/server/api/types/AnnotationSummary.py +3 -3
  110. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +44 -0
  111. phoenix/server/api/types/Cluster.py +8 -7
  112. phoenix/server/api/types/Dataset.py +5 -4
  113. phoenix/server/api/types/Dimension.py +3 -3
  114. phoenix/server/api/types/DocumentEvaluationSummary.py +8 -7
  115. phoenix/server/api/types/EmbeddingDimension.py +6 -5
  116. phoenix/server/api/types/EvaluationSummary.py +3 -3
  117. phoenix/server/api/types/Event.py +7 -7
  118. phoenix/server/api/types/Experiment.py +3 -3
  119. phoenix/server/api/types/ExperimentComparison.py +2 -4
  120. phoenix/server/api/types/GenerativeProvider.py +27 -3
  121. phoenix/server/api/types/Inferences.py +9 -8
  122. phoenix/server/api/types/InferencesRole.py +2 -2
  123. phoenix/server/api/types/Model.py +2 -2
  124. phoenix/server/api/types/Project.py +11 -18
  125. phoenix/server/api/types/Segments.py +3 -3
  126. phoenix/server/api/types/Span.py +45 -7
  127. phoenix/server/api/types/TemplateLanguage.py +9 -0
  128. phoenix/server/api/types/TimeSeries.py +8 -7
  129. phoenix/server/api/types/Trace.py +2 -2
  130. phoenix/server/api/types/UMAPPoints.py +6 -6
  131. phoenix/server/api/types/User.py +3 -3
  132. phoenix/server/api/types/node.py +1 -3
  133. phoenix/server/api/types/pagination.py +4 -4
  134. phoenix/server/api/utils.py +2 -4
  135. phoenix/server/app.py +76 -37
  136. phoenix/server/bearer_auth.py +4 -10
  137. phoenix/server/dml_event.py +3 -3
  138. phoenix/server/dml_event_handler.py +10 -24
  139. phoenix/server/grpc_server.py +3 -2
  140. phoenix/server/jwt_store.py +22 -21
  141. phoenix/server/main.py +17 -4
  142. phoenix/server/oauth2.py +3 -2
  143. phoenix/server/rate_limiters.py +5 -8
  144. phoenix/server/static/.vite/manifest.json +31 -31
  145. phoenix/server/static/assets/components-Csu8UKOs.js +1612 -0
  146. phoenix/server/static/assets/{index-DCzakdJq.js → index-Bk5C9EA7.js} +2 -2
  147. phoenix/server/static/assets/{pages-CAL1FDMt.js → pages-UeWaKXNs.js} +337 -442
  148. phoenix/server/static/assets/{vendor-6IcPAw_j.js → vendor-CtqfhlbC.js} +6 -6
  149. phoenix/server/static/assets/{vendor-arizeai-DRZuoyuF.js → vendor-arizeai-C_3SBz56.js} +2 -2
  150. phoenix/server/static/assets/{vendor-codemirror-DVE2_WBr.js → vendor-codemirror-wfdk9cjp.js} +1 -1
  151. phoenix/server/static/assets/{vendor-recharts-DwrexFA4.js → vendor-recharts-BiVnSv90.js} +1 -1
  152. phoenix/server/templates/index.html +1 -0
  153. phoenix/server/thread_server.py +1 -1
  154. phoenix/server/types.py +17 -29
  155. phoenix/services.py +8 -3
  156. phoenix/session/client.py +12 -24
  157. phoenix/session/data_extractor.py +3 -3
  158. phoenix/session/evaluation.py +1 -2
  159. phoenix/session/session.py +26 -21
  160. phoenix/trace/attributes.py +16 -28
  161. phoenix/trace/dsl/filter.py +17 -21
  162. phoenix/trace/dsl/helpers.py +3 -3
  163. phoenix/trace/dsl/query.py +13 -22
  164. phoenix/trace/fixtures.py +11 -17
  165. phoenix/trace/otel.py +5 -15
  166. phoenix/trace/projects.py +3 -2
  167. phoenix/trace/schemas.py +2 -2
  168. phoenix/trace/span_evaluations.py +9 -8
  169. phoenix/trace/span_json_decoder.py +3 -3
  170. phoenix/trace/span_json_encoder.py +2 -2
  171. phoenix/trace/trace_dataset.py +6 -5
  172. phoenix/trace/utils.py +6 -6
  173. phoenix/utilities/deprecation.py +3 -2
  174. phoenix/utilities/error_handling.py +3 -2
  175. phoenix/utilities/json.py +2 -1
  176. phoenix/utilities/logging.py +2 -2
  177. phoenix/utilities/project.py +1 -1
  178. phoenix/utilities/re.py +3 -4
  179. phoenix/utilities/template_formatters.py +16 -5
  180. phoenix/version.py +1 -1
  181. arize_phoenix-5.5.2.dist-info/RECORD +0 -321
  182. phoenix/server/static/assets/components-hX0LgYz3.js +0 -1428
  183. {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/WHEEL +0 -0
  184. {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/entry_points.txt +0 -0
  185. {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/licenses/IP_NOTICE +0 -0
  186. {arize_phoenix-5.5.2.dist-info → arize_phoenix-5.7.0.dist-info}/licenses/LICENSE +0 -0
phoenix/trace/fixtures.py CHANGED
@@ -2,6 +2,7 @@ import logging
2
2
  import shutil
3
3
  from binascii import hexlify
4
4
  from collections import defaultdict
5
+ from collections.abc import Iterable, Iterator, Sequence
5
6
  from dataclasses import dataclass, field, replace
6
7
  from datetime import datetime, timezone
7
8
  from io import StringIO
@@ -9,15 +10,8 @@ from random import getrandbits
9
10
  from tempfile import NamedTemporaryFile
10
11
  from time import sleep, time
11
12
  from typing import (
12
- DefaultDict,
13
- Dict,
14
- Iterable,
15
- Iterator,
16
- List,
17
13
  NamedTuple,
18
14
  Optional,
19
- Sequence,
20
- Tuple,
21
15
  cast,
22
16
  )
23
17
  from urllib.parse import urljoin
@@ -280,7 +274,7 @@ random_fixture = TracesFixture(
280
274
  file_name="random.jsonl",
281
275
  )
282
276
 
283
- TRACES_FIXTURES: List[TracesFixture] = [
277
+ TRACES_FIXTURES: list[TracesFixture] = [
284
278
  demo_llama_index_rag_fixture,
285
279
  demo_llama_index_rag_llm_fixture,
286
280
  demo_langgraph_agent_fixture,
@@ -298,10 +292,10 @@ TRACES_FIXTURES: List[TracesFixture] = [
298
292
  anthropic_tools_fixture,
299
293
  ]
300
294
 
301
- NAME_TO_TRACES_FIXTURE: Dict[str, TracesFixture] = {
295
+ NAME_TO_TRACES_FIXTURE: dict[str, TracesFixture] = {
302
296
  fixture.name: fixture for fixture in TRACES_FIXTURES
303
297
  }
304
- PROJ_NAME_TO_TRACES_FIXTURE: DefaultDict[str, List[TracesFixture]] = defaultdict(list)
298
+ PROJ_NAME_TO_TRACES_FIXTURE: defaultdict[str, list[TracesFixture]] = defaultdict(list)
305
299
  for fixture in TRACES_FIXTURES:
306
300
  if fixture.project_name:
307
301
  PROJ_NAME_TO_TRACES_FIXTURE[fixture.project_name].append(fixture)
@@ -322,7 +316,7 @@ def get_trace_fixture_by_name(fixture_name: str) -> TracesFixture:
322
316
  return NAME_TO_TRACES_FIXTURE[fixture_name]
323
317
 
324
318
 
325
- def get_trace_fixtures_by_project_name(proj_name: str) -> List[TracesFixture]:
319
+ def get_trace_fixtures_by_project_name(proj_name: str) -> list[TracesFixture]:
326
320
  """
327
321
  Returns a dictionary of project name (key) and set of TracesFixtures (value)
328
322
  whose project name matches the input name.
@@ -437,7 +431,7 @@ def _read_eval_fixture(eval_fixture: EvaluationFixture) -> Iterator[pb.Evaluatio
437
431
  explanation=StringValue(value=cast(str, explanation)) if explanation else None,
438
432
  )
439
433
  if isinstance(eval_fixture, DocumentEvaluationFixture):
440
- span_id, document_position = cast(Tuple[str, int], index)
434
+ span_id, document_position = cast(tuple[str, int], index)
441
435
  # Legacy fixture files contain UUID strings for span_ids. The hyphens in these
442
436
  # strings need to be removed because we are also removing the hyphens from the
443
437
  # span_ids of their corresponding traces. In general, hyphen is not an allowed
@@ -476,10 +470,10 @@ def _url(
476
470
  def reset_fixture_span_ids_and_timestamps(
477
471
  spans: Iterable[Span],
478
472
  evals: Iterable[pb.Evaluation] = (),
479
- ) -> Tuple[List[Span], List[pb.Evaluation]]:
473
+ ) -> tuple[list[Span], list[pb.Evaluation]]:
480
474
  old_spans, old_evals = list(spans), list(evals)
481
- new_trace_ids: Dict[str, str] = {}
482
- new_span_ids: Dict[str, str] = {}
475
+ new_trace_ids: dict[str, str] = {}
476
+ new_span_ids: dict[str, str] = {}
483
477
  for old_span in old_spans:
484
478
  new_trace_ids[old_span.context.trace_id] = _new_trace_id()
485
479
  new_span_ids[old_span.context.span_id] = _new_span_id()
@@ -495,8 +489,8 @@ def reset_fixture_span_ids_and_timestamps(
495
489
  new_span_ids[span_id] = _new_span_id()
496
490
  max_end_time = max(old_span.end_time for old_span in old_spans)
497
491
  time_diff = datetime.now(timezone.utc) - max_end_time
498
- new_spans: List[Span] = []
499
- new_evals: List[pb.Evaluation] = []
492
+ new_spans: list[Span] = []
493
+ new_evals: list[pb.Evaluation] = []
500
494
  for old_span in old_spans:
501
495
  new_trace_id = new_trace_ids[old_span.context.trace_id]
502
496
  new_span_id = new_span_ids[old_span.context.span_id]
phoenix/trace/otel.py CHANGED
@@ -1,19 +1,9 @@
1
1
  import json
2
2
  from binascii import hexlify, unhexlify
3
+ from collections.abc import Iterable, Iterator, Mapping, Sequence
3
4
  from datetime import datetime, timezone
4
5
  from types import MappingProxyType
5
- from typing import (
6
- Any,
7
- Dict,
8
- Iterable,
9
- Iterator,
10
- Mapping,
11
- Optional,
12
- Sequence,
13
- SupportsFloat,
14
- Tuple,
15
- cast,
16
- )
6
+ from typing import Any, Optional, SupportsFloat, cast
17
7
 
18
8
  import numpy as np
19
9
  import opentelemetry.proto.trace.v1.trace_pb2 as otlp
@@ -133,7 +123,7 @@ def _decode_unix_nano(time_unix_nano: int) -> datetime:
133
123
 
134
124
  def _decode_key_values(
135
125
  key_values: Iterable[KeyValue],
136
- ) -> Iterator[Tuple[str, Any]]:
126
+ ) -> Iterator[tuple[str, Any]]:
137
127
  return ((kv.key, _decode_value(kv.value)) for kv in key_values)
138
128
 
139
129
 
@@ -169,7 +159,7 @@ _STATUS_DECODING = MappingProxyType(
169
159
  )
170
160
 
171
161
 
172
- def _decode_status(otlp_status: otlp.Status) -> Tuple[SpanStatusCode, StatusMessage]:
162
+ def _decode_status(otlp_status: otlp.Status) -> tuple[SpanStatusCode, StatusMessage]:
173
163
  status_code = _STATUS_DECODING.get(otlp_status.code, SpanStatusCode.UNSET)
174
164
  return status_code, otlp_status.message
175
165
 
@@ -186,7 +176,7 @@ def encode_span_to_otlp(span: Span) -> otlp.Span:
186
176
  start_time_unix_nano: int = int(span.start_time.timestamp() * _BILLION)
187
177
  end_time_unix_nano: int = int(span.end_time.timestamp() * _BILLION) if span.end_time else 0
188
178
 
189
- attributes: Dict[str, Any] = dict(span.attributes)
179
+ attributes: dict[str, Any] = dict(span.attributes)
190
180
 
191
181
  for key, value in span.attributes.items():
192
182
  if value is None:
phoenix/trace/projects.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import types
2
- from typing import Any, Callable, Optional, Type
2
+ from collections.abc import Callable
3
+ from typing import Any, Optional
3
4
 
4
5
  from openinference.semconv.resource import ResourceAttributes
5
6
  from opentelemetry.sdk import trace
@@ -58,7 +59,7 @@ class using_project:
58
59
 
59
60
  def __exit__(
60
61
  self,
61
- exc_type: Optional[Type[BaseException]],
62
+ exc_type: Optional[type[BaseException]],
62
63
  exc_value: Optional[BaseException],
63
64
  traceback: Optional[types.TracebackType],
64
65
  ) -> None:
phoenix/trace/schemas.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from datetime import datetime
3
3
  from enum import Enum
4
- from typing import Any, List, Mapping, NamedTuple, Optional
4
+ from typing import Any, Mapping, NamedTuple, Optional
5
5
  from uuid import UUID
6
6
 
7
7
  EXCEPTION_TYPE = "exception.type"
@@ -169,7 +169,7 @@ class Span:
169
169
  OpenTelemetry Inspiration:
170
170
  https://opentelemetry.io/docs/concepts/signals/traces/#span-events
171
171
  """
172
- events: List[SpanEvent]
172
+ events: list[SpanEvent]
173
173
 
174
174
  """
175
175
  An extension of the OpenTelemetry Span interface to include the
@@ -1,10 +1,11 @@
1
1
  import json
2
2
  from abc import ABC
3
+ from collections.abc import Callable, Mapping, Sequence
3
4
  from dataclasses import dataclass, field
4
5
  from itertools import product
5
6
  from pathlib import Path
6
7
  from types import MappingProxyType
7
- from typing import Any, Callable, List, Mapping, Optional, Sequence, Set, Tuple, Type, Union
8
+ from typing import Any, Optional, Union
8
9
  from uuid import UUID, uuid4
9
10
 
10
11
  import pandas as pd
@@ -20,11 +21,11 @@ EVAL_PARQUET_FILE_NAME = "evaluations-{id}.parquet"
20
21
 
21
22
 
22
23
  class NeedsNamedIndex(ABC):
23
- index_names: Mapping[Tuple[str, ...], Callable[[Any], bool]]
24
- all_valid_index_name_sorted_combos: Set[Tuple[str, ...]]
24
+ index_names: Mapping[tuple[str, ...], Callable[[Any], bool]]
25
+ all_valid_index_name_sorted_combos: set[tuple[str, ...]]
25
26
 
26
27
  @classmethod
27
- def preferred_names(cls) -> List[str]:
28
+ def preferred_names(cls) -> list[str]:
28
29
  return [choices[0] for choices in cls.index_names.keys()]
29
30
 
30
31
  @classmethod
@@ -43,7 +44,7 @@ class NeedsNamedIndex(ABC):
43
44
  )
44
45
 
45
46
  @classmethod
46
- def find_valid_index_names(cls, dtypes: "pd.Series[Any]") -> Optional[List[str]]:
47
+ def find_valid_index_names(cls, dtypes: "pd.Series[Any]") -> Optional[list[str]]:
47
48
  valid_names = []
48
49
  for names, check_type in cls.index_names.items():
49
50
  for name in names:
@@ -92,7 +93,7 @@ class Evaluations(NeedsNamedIndex, NeedsResultColumns, ABC):
92
93
  f"dataframe=<rows: {len(self.dataframe)!r}>)"
93
94
  )
94
95
 
95
- def __dir__(self) -> List[str]:
96
+ def __dir__(self) -> list[str]:
96
97
  return ["get_dataframe"]
97
98
 
98
99
  def get_dataframe(self, prefix_columns_with_name: bool = True) -> pd.DataFrame:
@@ -153,7 +154,7 @@ class Evaluations(NeedsNamedIndex, NeedsResultColumns, ABC):
153
154
 
154
155
  def __init_subclass__(
155
156
  cls,
156
- index_names: Mapping[Tuple[str, ...], Callable[[Any], bool]],
157
+ index_names: Mapping[tuple[str, ...], Callable[[Any], bool]],
157
158
  **kwargs: Any,
158
159
  ) -> None:
159
160
  super().__init_subclass__(**kwargs)
@@ -327,7 +328,7 @@ class TraceEvaluations(
327
328
  ): ...
328
329
 
329
330
 
330
- def _parse_schema_metadata(schema: Schema) -> Tuple[UUID, str, Type[Evaluations]]:
331
+ def _parse_schema_metadata(schema: Schema) -> tuple[UUID, str, type[Evaluations]]:
331
332
  """
332
333
  Validates and parses the pyarrow schema metadata.
333
334
  """
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from datetime import datetime
3
- from typing import Any, Dict, Optional
3
+ from typing import Any, Optional
4
4
 
5
5
  from openinference.semconv.trace import SpanAttributes
6
6
 
@@ -22,7 +22,7 @@ INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
22
22
  OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
23
23
 
24
24
 
25
- def json_to_attributes(obj: Optional[Dict[str, Any]]) -> Dict[str, Any]:
25
+ def json_to_attributes(obj: Optional[dict[str, Any]]) -> dict[str, Any]:
26
26
  if obj is None:
27
27
  return {}
28
28
  if not isinstance(obj, dict):
@@ -34,7 +34,7 @@ def json_to_attributes(obj: Optional[Dict[str, Any]]) -> Dict[str, Any]:
34
34
  return obj
35
35
 
36
36
 
37
- def json_to_span(data: Dict[str, Any]) -> Any:
37
+ def json_to_span(data: dict[str, Any]) -> Any:
38
38
  """
39
39
  A hook for json.loads to convert a dict to a Span object.
40
40
  """
@@ -2,7 +2,7 @@ import json
2
2
  from dataclasses import asdict
3
3
  from datetime import datetime
4
4
  from enum import Enum
5
- from typing import Any, List
5
+ from typing import Any
6
6
  from uuid import UUID
7
7
 
8
8
  import numpy as np
@@ -60,5 +60,5 @@ def span_to_json(span: Span) -> str:
60
60
  return json.dumps(span, cls=SpanJSONEncoder)
61
61
 
62
62
 
63
- def spans_to_jsonl(spans: List[Span]) -> str:
63
+ def spans_to_jsonl(spans: list[Span]) -> str:
64
64
  return "\n".join(span_to_json(span) for span in spans)
@@ -1,7 +1,8 @@
1
1
  import json
2
+ from collections.abc import Iterable, Iterator
2
3
  from datetime import datetime
3
4
  from pathlib import Path
4
- from typing import Any, Iterable, Iterator, List, Optional, Tuple, Union, cast
5
+ from typing import Any, Optional, Union, cast
5
6
  from uuid import UUID, uuid4
6
7
  from warnings import warn
7
8
 
@@ -116,7 +117,7 @@ class TraceDataset:
116
117
  A human readable name for the dataset.
117
118
  """
118
119
  dataframe: pd.DataFrame
119
- evaluations: List[Evaluations] = []
120
+ evaluations: list[Evaluations] = []
120
121
  _id: UUID
121
122
  _data_file_name: str = "data.parquet"
122
123
 
@@ -152,11 +153,11 @@ class TraceDataset:
152
153
  self.evaluations = list(evaluations)
153
154
 
154
155
  @classmethod
155
- def from_spans(cls, spans: List[Span]) -> "TraceDataset":
156
+ def from_spans(cls, spans: list[Span]) -> "TraceDataset":
156
157
  """Creates a TraceDataset from a list of spans.
157
158
 
158
159
  Args:
159
- spans (List[Span]): A list of spans.
160
+ spans (list[Span]): A list of spans.
160
161
 
161
162
  Returns:
162
163
  TraceDataset: A TraceDataset containing the spans.
@@ -349,7 +350,7 @@ class TraceDataset:
349
350
  return pd.concat([df, evals_df], axis=1)
350
351
 
351
352
 
352
- def _parse_schema_metadata(schema: Schema) -> Tuple[UUID, str, List[UUID]]:
353
+ def _parse_schema_metadata(schema: Schema) -> tuple[UUID, str, list[UUID]]:
353
354
  """
354
355
  Returns parsed metadata from a parquet schema or raises an exception if the
355
356
  metadata is invalid.
phoenix/trace/utils.py CHANGED
@@ -2,7 +2,7 @@ import json
2
2
  import os
3
3
  import re
4
4
  from traceback import format_exception
5
- from typing import List, Optional, Tuple, cast
5
+ from typing import Optional, cast
6
6
  from urllib import request
7
7
 
8
8
  import pandas as pd
@@ -14,16 +14,16 @@ def parse_file_extension(file_path: str) -> str:
14
14
 
15
15
  def download_json_traces_fixture(
16
16
  url: str,
17
- ) -> List[str]:
17
+ ) -> list[str]:
18
18
  """
19
19
  Stores the traces fixture as list of jsons from the jsonl files in the phoenix bucket.
20
20
  """
21
21
 
22
22
  with request.urlopen(url) as f:
23
- return cast(List[str], f.readlines())
23
+ return cast(list[str], f.readlines())
24
24
 
25
25
 
26
- def json_lines_to_df(lines: List[str]) -> pd.DataFrame:
26
+ def json_lines_to_df(lines: list[str]) -> pd.DataFrame:
27
27
  """
28
28
  Convert a list of JSON line strings to a Pandas DataFrame.
29
29
  """
@@ -56,9 +56,9 @@ def get_stacktrace(exception: BaseException) -> str:
56
56
  _VERSION_TRIPLET_REGEX = re.compile(r"(\d+)\.(\d+)\.(\d+)")
57
57
 
58
58
 
59
- def extract_version_triplet(version: str) -> Optional[Tuple[int, int, int]]:
59
+ def extract_version_triplet(version: str) -> Optional[tuple[int, int, int]]:
60
60
  return (
61
- cast(Tuple[int, int, int], tuple(map(int, match.groups())))
61
+ cast(tuple[int, int, int], tuple(map(int, match.groups())))
62
62
  if (match := _VERSION_TRIPLET_REGEX.search(version))
63
63
  else None
64
64
  )
@@ -1,8 +1,9 @@
1
1
  import functools
2
2
  import warnings
3
- from typing import Any, Callable, Type, TypeVar
3
+ from collections.abc import Callable
4
+ from typing import Any, TypeVar
4
5
 
5
- GenericClass = TypeVar("GenericClass", bound=Type[Any])
6
+ GenericClass = TypeVar("GenericClass", bound=type[Any])
6
7
  CallableType = TypeVar("CallableType", bound=Callable[..., Any])
7
8
 
8
9
 
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import traceback
3
- from typing import Any, Callable, Iterable, Optional, Type, TypeVar, cast
3
+ from collections.abc import Callable, Iterable
4
+ from typing import Any, Optional, TypeVar, cast
4
5
 
5
6
  F = TypeVar("F", bound=Callable[..., Any])
6
7
 
7
8
 
8
9
  def graceful_fallback(
9
- fallback_method: Callable[..., Any], exceptions: Optional[Iterable[Type[BaseException]]] = None
10
+ fallback_method: Callable[..., Any], exceptions: Optional[Iterable[type[BaseException]]] = None
10
11
  ) -> Callable[[F], F]:
11
12
  """
12
13
  Decorator that reroutes failing functions to a specified fallback method.
phoenix/utilities/json.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import dataclasses
2
2
  import datetime
3
+ from collections.abc import Mapping, Sequence
3
4
  from enum import Enum
4
5
  from pathlib import Path
5
- from typing import Any, Mapping, Sequence, Union, get_args, get_origin
6
+ from typing import Any, Union, get_args, get_origin
6
7
 
7
8
  import numpy as np
8
9
  from strawberry import UNSET
@@ -1,6 +1,6 @@
1
1
  # A collection of printing and logging utilities
2
2
 
3
- from typing import Any, List
3
+ from typing import Any
4
4
 
5
5
  from tqdm.auto import tqdm
6
6
 
@@ -10,7 +10,7 @@ def printif(condition: bool, *args: Any, **kwargs: Any) -> None:
10
10
  tqdm.write(*args, **kwargs)
11
11
 
12
12
 
13
- def log_a_list(list_of_str: List[str], join_word: str) -> str:
13
+ def log_a_list(list_of_str: list[str], join_word: str) -> str:
14
14
  if list_of_str is None or len(list_of_str) == 0:
15
15
  return ""
16
16
  if len(list_of_str) == 1:
@@ -1,4 +1,4 @@
1
- from typing import Iterable
1
+ from collections.abc import Iterable
2
2
 
3
3
  from openinference.semconv.resource import ResourceAttributes
4
4
  from opentelemetry.proto.common.v1.common_pb2 import KeyValue
phoenix/utilities/re.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from re import compile, split
3
- from typing import Dict, List
4
3
  from urllib.parse import unquote
5
4
 
6
5
  logger = logging.getLogger(__name__)
@@ -19,7 +18,7 @@ _HEADER_PATTERN = compile(_KEY_VALUE_FORMAT)
19
18
  _DELIMITER_PATTERN = compile(r"[ \t]*,[ \t]*")
20
19
 
21
20
 
22
- def parse_env_headers(s: str) -> Dict[str, str]:
21
+ def parse_env_headers(s: str) -> dict[str, str]:
23
22
  """
24
23
  Parse ``s``, which is a ``str`` instance containing HTTP headers encoded
25
24
  for use in ENV variables per the W3C Baggage HTTP header format at
@@ -28,8 +27,8 @@ def parse_env_headers(s: str) -> Dict[str, str]:
28
27
 
29
28
  src: https://github.com/open-telemetry/opentelemetry-python/blob/2d5cd58f33bd8a16f45f30be620a96699bc14297/opentelemetry-api/src/opentelemetry/util/re.py#L52
30
29
  """
31
- headers: Dict[str, str] = {}
32
- headers_list: List[str] = split(_DELIMITER_PATTERN, s)
30
+ headers: dict[str, str] = {}
31
+ headers_list: list[str] = split(_DELIMITER_PATTERN, s)
33
32
  for header in headers_list:
34
33
  if not header: # empty string
35
34
  continue
@@ -1,12 +1,13 @@
1
1
  import re
2
2
  from abc import ABC, abstractmethod
3
+ from collections.abc import Iterable
3
4
  from string import Formatter
4
- from typing import Any, Iterable, Set
5
+ from typing import Any
5
6
 
6
7
 
7
8
  class TemplateFormatter(ABC):
8
9
  @abstractmethod
9
- def parse(self, template: str) -> Set[str]:
10
+ def parse(self, template: str) -> set[str]:
10
11
  """
11
12
  Parse the template and return a set of variable names.
12
13
  """
@@ -18,7 +19,9 @@ class TemplateFormatter(ABC):
18
19
  """
19
20
  template_variable_names = self.parse(template)
20
21
  if missing_template_variables := template_variable_names - set(variables.keys()):
21
- raise ValueError(f"Missing template variables: {', '.join(missing_template_variables)}")
22
+ raise TemplateFormatterError(
23
+ f"Missing template variable(s): {', '.join(missing_template_variables)}"
24
+ )
22
25
  return self._format(template, template_variable_names, **variables)
23
26
 
24
27
  @abstractmethod
@@ -37,7 +40,7 @@ class FStringTemplateFormatter(TemplateFormatter):
37
40
  'world'
38
41
  """
39
42
 
40
- def parse(self, template: str) -> Set[str]:
43
+ def parse(self, template: str) -> set[str]:
41
44
  return set(field_name for _, field_name, _, _ in Formatter().parse(template) if field_name)
42
45
 
43
46
  def _format(self, template: str, variable_names: Iterable[str], **variables: Any) -> str:
@@ -57,7 +60,7 @@ class MustacheTemplateFormatter(TemplateFormatter):
57
60
 
58
61
  PATTERN = re.compile(r"(?<!\\){{\s*(\w+)\s*}}")
59
62
 
60
- def parse(self, template: str) -> Set[str]:
63
+ def parse(self, template: str) -> set[str]:
61
64
  return set(match for match in re.findall(self.PATTERN, template))
62
65
 
63
66
  def _format(self, template: str, variable_names: Iterable[str], **variables: Any) -> str:
@@ -68,3 +71,11 @@ class MustacheTemplateFormatter(TemplateFormatter):
68
71
  string=template,
69
72
  )
70
73
  return template
74
+
75
+
76
+ class TemplateFormatterError(Exception):
77
+ """
78
+ An error raised when template formatting fails.
79
+ """
80
+
81
+ pass
phoenix/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "5.5.2"
1
+ __version__ = "5.7.0"