arize-phoenix 3.16.1__py3-none-any.whl → 7.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.
- arize_phoenix-7.7.0.dist-info/METADATA +261 -0
- arize_phoenix-7.7.0.dist-info/RECORD +345 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
- arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
- phoenix/__init__.py +86 -14
- phoenix/auth.py +309 -0
- phoenix/config.py +675 -45
- phoenix/core/model.py +32 -30
- phoenix/core/model_schema.py +102 -109
- phoenix/core/model_schema_adapter.py +48 -45
- phoenix/datetime_utils.py +24 -3
- phoenix/db/README.md +54 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +85 -0
- phoenix/db/bulk_inserter.py +294 -0
- phoenix/db/engines.py +208 -0
- phoenix/db/enums.py +20 -0
- phoenix/db/facilitator.py +113 -0
- phoenix/db/helpers.py +159 -0
- phoenix/db/insertion/constants.py +2 -0
- phoenix/db/insertion/dataset.py +227 -0
- phoenix/db/insertion/document_annotation.py +171 -0
- phoenix/db/insertion/evaluation.py +191 -0
- phoenix/db/insertion/helpers.py +98 -0
- phoenix/db/insertion/span.py +193 -0
- phoenix/db/insertion/span_annotation.py +158 -0
- phoenix/db/insertion/trace_annotation.py +158 -0
- phoenix/db/insertion/types.py +256 -0
- phoenix/db/migrate.py +86 -0
- phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
- phoenix/db/migrations/env.py +114 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
- phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
- phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
- phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +807 -0
- phoenix/exceptions.py +5 -1
- phoenix/experiments/__init__.py +6 -0
- phoenix/experiments/evaluators/__init__.py +29 -0
- phoenix/experiments/evaluators/base.py +158 -0
- phoenix/experiments/evaluators/code_evaluators.py +184 -0
- phoenix/experiments/evaluators/llm_evaluators.py +473 -0
- phoenix/experiments/evaluators/utils.py +236 -0
- phoenix/experiments/functions.py +772 -0
- phoenix/experiments/tracing.py +86 -0
- phoenix/experiments/types.py +726 -0
- phoenix/experiments/utils.py +25 -0
- phoenix/inferences/__init__.py +0 -0
- phoenix/{datasets → inferences}/errors.py +6 -5
- phoenix/{datasets → inferences}/fixtures.py +49 -42
- phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
- phoenix/{datasets → inferences}/schema.py +11 -11
- phoenix/{datasets → inferences}/validation.py +13 -14
- phoenix/logging/__init__.py +3 -0
- phoenix/logging/_config.py +90 -0
- phoenix/logging/_filter.py +6 -0
- phoenix/logging/_formatter.py +69 -0
- phoenix/metrics/__init__.py +5 -4
- phoenix/metrics/binning.py +4 -3
- phoenix/metrics/metrics.py +2 -1
- phoenix/metrics/mixins.py +7 -6
- phoenix/metrics/retrieval_metrics.py +2 -1
- phoenix/metrics/timeseries.py +5 -4
- phoenix/metrics/wrappers.py +9 -3
- phoenix/pointcloud/clustering.py +5 -5
- phoenix/pointcloud/pointcloud.py +7 -5
- phoenix/pointcloud/projectors.py +5 -6
- phoenix/pointcloud/umap_parameters.py +53 -52
- phoenix/server/api/README.md +28 -0
- phoenix/server/api/auth.py +44 -0
- phoenix/server/api/context.py +152 -9
- phoenix/server/api/dataloaders/__init__.py +91 -0
- phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
- phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
- phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
- phoenix/server/api/dataloaders/document_evaluations.py +31 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
- phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
- phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
- phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
- phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
- phoenix/server/api/dataloaders/project_by_name.py +31 -0
- phoenix/server/api/dataloaders/record_counts.py +116 -0
- phoenix/server/api/dataloaders/session_io.py +79 -0
- phoenix/server/api/dataloaders/session_num_traces.py +30 -0
- phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
- phoenix/server/api/dataloaders/session_token_usages.py +41 -0
- phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
- phoenix/server/api/dataloaders/span_annotations.py +26 -0
- phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
- phoenix/server/api/dataloaders/span_descendants.py +57 -0
- phoenix/server/api/dataloaders/span_projects.py +33 -0
- phoenix/server/api/dataloaders/token_counts.py +124 -0
- phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
- phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
- phoenix/server/api/dataloaders/user_roles.py +30 -0
- phoenix/server/api/dataloaders/users.py +33 -0
- phoenix/server/api/exceptions.py +48 -0
- phoenix/server/api/helpers/__init__.py +12 -0
- phoenix/server/api/helpers/dataset_helpers.py +217 -0
- phoenix/server/api/helpers/experiment_run_filters.py +763 -0
- phoenix/server/api/helpers/playground_clients.py +948 -0
- phoenix/server/api/helpers/playground_registry.py +70 -0
- phoenix/server/api/helpers/playground_spans.py +455 -0
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
- phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
- phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
- phoenix/server/api/input_types/ClearProjectInput.py +15 -0
- phoenix/server/api/input_types/ClusterInput.py +2 -2
- phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
- phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
- phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
- phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
- phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
- phoenix/server/api/input_types/DatasetSort.py +17 -0
- phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
- phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
- phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
- phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
- phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
- phoenix/server/api/input_types/DimensionFilter.py +4 -4
- phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
- phoenix/server/api/input_types/Granularity.py +1 -1
- phoenix/server/api/input_types/InvocationParameters.py +162 -0
- phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
- phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
- phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
- phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
- phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
- phoenix/server/api/input_types/SpanSort.py +134 -69
- phoenix/server/api/input_types/TemplateOptions.py +10 -0
- phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
- phoenix/server/api/input_types/UserRoleInput.py +9 -0
- phoenix/server/api/mutations/__init__.py +28 -0
- phoenix/server/api/mutations/api_key_mutations.py +167 -0
- phoenix/server/api/mutations/chat_mutations.py +593 -0
- phoenix/server/api/mutations/dataset_mutations.py +591 -0
- phoenix/server/api/mutations/experiment_mutations.py +75 -0
- phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
- phoenix/server/api/mutations/project_mutations.py +57 -0
- phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
- phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
- phoenix/server/api/mutations/user_mutations.py +329 -0
- phoenix/server/api/openapi/__init__.py +0 -0
- phoenix/server/api/openapi/main.py +17 -0
- phoenix/server/api/openapi/schema.py +16 -0
- phoenix/server/api/queries.py +738 -0
- phoenix/server/api/routers/__init__.py +11 -0
- phoenix/server/api/routers/auth.py +284 -0
- phoenix/server/api/routers/embeddings.py +26 -0
- phoenix/server/api/routers/oauth2.py +488 -0
- phoenix/server/api/routers/v1/__init__.py +64 -0
- phoenix/server/api/routers/v1/datasets.py +1017 -0
- phoenix/server/api/routers/v1/evaluations.py +362 -0
- phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
- phoenix/server/api/routers/v1/experiment_runs.py +167 -0
- phoenix/server/api/routers/v1/experiments.py +308 -0
- phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
- phoenix/server/api/routers/v1/spans.py +267 -0
- phoenix/server/api/routers/v1/traces.py +208 -0
- phoenix/server/api/routers/v1/utils.py +95 -0
- phoenix/server/api/schema.py +44 -241
- phoenix/server/api/subscriptions.py +597 -0
- phoenix/server/api/types/Annotation.py +21 -0
- phoenix/server/api/types/AnnotationSummary.py +55 -0
- phoenix/server/api/types/AnnotatorKind.py +16 -0
- phoenix/server/api/types/ApiKey.py +27 -0
- phoenix/server/api/types/AuthMethod.py +9 -0
- phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
- phoenix/server/api/types/Cluster.py +25 -24
- phoenix/server/api/types/CreateDatasetPayload.py +8 -0
- phoenix/server/api/types/DataQualityMetric.py +31 -13
- phoenix/server/api/types/Dataset.py +288 -63
- phoenix/server/api/types/DatasetExample.py +85 -0
- phoenix/server/api/types/DatasetExampleRevision.py +34 -0
- phoenix/server/api/types/DatasetVersion.py +14 -0
- phoenix/server/api/types/Dimension.py +32 -31
- phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
- phoenix/server/api/types/EmbeddingDimension.py +56 -49
- phoenix/server/api/types/Evaluation.py +25 -31
- phoenix/server/api/types/EvaluationSummary.py +30 -50
- phoenix/server/api/types/Event.py +20 -20
- phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
- phoenix/server/api/types/Experiment.py +152 -0
- phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
- phoenix/server/api/types/ExperimentComparison.py +17 -0
- phoenix/server/api/types/ExperimentRun.py +119 -0
- phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
- phoenix/server/api/types/GenerativeModel.py +9 -0
- phoenix/server/api/types/GenerativeProvider.py +85 -0
- phoenix/server/api/types/Inferences.py +80 -0
- phoenix/server/api/types/InferencesRole.py +23 -0
- phoenix/server/api/types/LabelFraction.py +7 -0
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +54 -54
- phoenix/server/api/types/PerformanceMetric.py +8 -5
- phoenix/server/api/types/Project.py +407 -142
- phoenix/server/api/types/ProjectSession.py +139 -0
- phoenix/server/api/types/Segments.py +4 -4
- phoenix/server/api/types/Span.py +221 -176
- phoenix/server/api/types/SpanAnnotation.py +43 -0
- phoenix/server/api/types/SpanIOValue.py +15 -0
- phoenix/server/api/types/SystemApiKey.py +9 -0
- phoenix/server/api/types/TemplateLanguage.py +10 -0
- phoenix/server/api/types/TimeSeries.py +19 -15
- phoenix/server/api/types/TokenUsage.py +11 -0
- phoenix/server/api/types/Trace.py +154 -0
- phoenix/server/api/types/TraceAnnotation.py +45 -0
- phoenix/server/api/types/UMAPPoints.py +7 -7
- phoenix/server/api/types/User.py +60 -0
- phoenix/server/api/types/UserApiKey.py +45 -0
- phoenix/server/api/types/UserRole.py +15 -0
- phoenix/server/api/types/node.py +4 -112
- phoenix/server/api/types/pagination.py +156 -57
- phoenix/server/api/utils.py +34 -0
- phoenix/server/app.py +864 -115
- phoenix/server/bearer_auth.py +163 -0
- phoenix/server/dml_event.py +136 -0
- phoenix/server/dml_event_handler.py +256 -0
- phoenix/server/email/__init__.py +0 -0
- phoenix/server/email/sender.py +97 -0
- phoenix/server/email/templates/__init__.py +0 -0
- phoenix/server/email/templates/password_reset.html +19 -0
- phoenix/server/email/types.py +11 -0
- phoenix/server/grpc_server.py +102 -0
- phoenix/server/jwt_store.py +505 -0
- phoenix/server/main.py +305 -116
- phoenix/server/oauth2.py +52 -0
- phoenix/server/openapi/__init__.py +0 -0
- phoenix/server/prometheus.py +111 -0
- phoenix/server/rate_limiters.py +188 -0
- phoenix/server/static/.vite/manifest.json +87 -0
- phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
- phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
- phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
- phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
- phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
- phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
- phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
- phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
- phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
- phoenix/server/telemetry.py +68 -0
- phoenix/server/templates/index.html +82 -23
- phoenix/server/thread_server.py +3 -3
- phoenix/server/types.py +275 -0
- phoenix/services.py +27 -18
- phoenix/session/client.py +743 -68
- phoenix/session/data_extractor.py +31 -7
- phoenix/session/evaluation.py +3 -9
- phoenix/session/session.py +263 -219
- phoenix/settings.py +22 -0
- phoenix/trace/__init__.py +2 -22
- phoenix/trace/attributes.py +338 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +663 -213
- phoenix/trace/dsl/helpers.py +73 -21
- phoenix/trace/dsl/query.py +574 -201
- phoenix/trace/exporter.py +24 -19
- phoenix/trace/fixtures.py +368 -32
- phoenix/trace/otel.py +71 -219
- phoenix/trace/projects.py +3 -2
- phoenix/trace/schemas.py +33 -11
- phoenix/trace/span_evaluations.py +21 -16
- phoenix/trace/span_json_decoder.py +6 -4
- phoenix/trace/span_json_encoder.py +2 -2
- phoenix/trace/trace_dataset.py +47 -32
- phoenix/trace/utils.py +21 -4
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/client.py +132 -0
- phoenix/utilities/deprecation.py +31 -0
- phoenix/utilities/error_handling.py +3 -2
- phoenix/utilities/json.py +109 -0
- phoenix/utilities/logging.py +8 -0
- phoenix/utilities/project.py +2 -2
- phoenix/utilities/re.py +49 -0
- phoenix/utilities/span_store.py +0 -23
- phoenix/utilities/template_formatters.py +99 -0
- phoenix/version.py +1 -1
- arize_phoenix-3.16.1.dist-info/METADATA +0 -495
- arize_phoenix-3.16.1.dist-info/RECORD +0 -178
- phoenix/core/project.py +0 -619
- phoenix/core/traces.py +0 -96
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -448
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/helpers.py +0 -11
- phoenix/server/api/routers/evaluation_handler.py +0 -109
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/server/api/types/DatasetRole.py +0 -23
- phoenix/server/static/index.css +0 -6
- phoenix/server/static/index.js +0 -7447
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- phoenix/trace/langchain/__init__.py +0 -3
- phoenix/trace/langchain/instrumentor.py +0 -35
- phoenix/trace/llama_index/__init__.py +0 -3
- phoenix/trace/llama_index/callback.py +0 -102
- phoenix/trace/openai/__init__.py +0 -3
- phoenix/trace/openai/instrumentor.py +0 -30
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
|
@@ -1,69 +1,149 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from enum import Enum, auto
|
|
5
|
+
from typing import Any, ClassVar, Optional, Union
|
|
4
6
|
|
|
5
|
-
import strawberry
|
|
6
7
|
from strawberry import UNSET
|
|
8
|
+
from strawberry.relay.types import Connection, Edge, NodeType, PageInfo
|
|
9
|
+
from typing_extensions import TypeAlias, assert_never
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@strawberry.type
|
|
12
|
-
class Connection(Generic[GenericType]):
|
|
13
|
-
"""Represents a paginated relationship between two entities
|
|
14
|
-
|
|
15
|
-
This pattern is used when the relationship itself has attributes.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
page_info: "PageInfo"
|
|
19
|
-
edges: List["Edge[GenericType]"]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@strawberry.type
|
|
23
|
-
class PageInfo:
|
|
24
|
-
"""Pagination context to navigate objects with cursor-based pagination
|
|
25
|
-
|
|
26
|
-
Instead of classic offset pagination via `page` and `limit` parameters,
|
|
27
|
-
here we have a cursor of the last object and we fetch items starting from that one
|
|
28
|
-
|
|
29
|
-
Read more at:
|
|
30
|
-
- https://graphql.org/learn/pagination/#pagination-and-edges
|
|
31
|
-
- https://relay.dev/graphql/connections.htm
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
has_next_page: bool
|
|
35
|
-
has_previous_page: bool
|
|
36
|
-
start_cursor: Optional[str]
|
|
37
|
-
end_cursor: Optional[str]
|
|
38
|
-
total_count: int
|
|
39
|
-
|
|
11
|
+
ID: TypeAlias = int
|
|
12
|
+
CursorSortColumnValue: TypeAlias = Union[str, int, float, datetime]
|
|
40
13
|
|
|
41
14
|
# A type alias for the connection cursor implementation
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@strawberry.type
|
|
46
|
-
class Edge(Generic[GenericType]):
|
|
47
|
-
"""
|
|
48
|
-
An edge may contain additional information of the relationship. This is the trivial case
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
node: GenericType
|
|
52
|
-
cursor: str
|
|
53
|
-
|
|
15
|
+
CursorString = str
|
|
54
16
|
|
|
55
17
|
# The hashing prefix for a connection cursor
|
|
56
18
|
CURSOR_PREFIX = "connection:"
|
|
57
19
|
|
|
58
20
|
|
|
59
|
-
|
|
21
|
+
class CursorSortColumnDataType(Enum):
|
|
22
|
+
STRING = auto()
|
|
23
|
+
INT = auto()
|
|
24
|
+
FLOAT = auto()
|
|
25
|
+
DATETIME = auto()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class CursorSortColumn:
|
|
30
|
+
type: CursorSortColumnDataType
|
|
31
|
+
value: CursorSortColumnValue
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
if isinstance(self.value, str):
|
|
35
|
+
return self.value
|
|
36
|
+
if isinstance(self.value, (int, float)):
|
|
37
|
+
return str(self.value)
|
|
38
|
+
if isinstance(self.value, datetime):
|
|
39
|
+
return self.value.isoformat()
|
|
40
|
+
assert_never(self.type)
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_string(cls, type: CursorSortColumnDataType, cursor_string: str) -> "CursorSortColumn":
|
|
44
|
+
value: CursorSortColumnValue
|
|
45
|
+
if type is CursorSortColumnDataType.STRING:
|
|
46
|
+
value = cursor_string
|
|
47
|
+
elif type is CursorSortColumnDataType.INT:
|
|
48
|
+
value = int(cursor_string)
|
|
49
|
+
elif type is CursorSortColumnDataType.FLOAT:
|
|
50
|
+
value = float(cursor_string)
|
|
51
|
+
elif type is CursorSortColumnDataType.DATETIME:
|
|
52
|
+
value = datetime.fromisoformat(cursor_string)
|
|
53
|
+
else:
|
|
54
|
+
assert_never(type)
|
|
55
|
+
return cls(type=type, value=value)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class Cursor:
|
|
60
|
+
"""
|
|
61
|
+
Serializes and deserializes cursor strings for ID-based pagination.
|
|
62
|
+
|
|
63
|
+
In the simplest case, a cursor encodes the rowid of a record. In the case
|
|
64
|
+
that a sort has been applied, the cursor additionally encodes the data type
|
|
65
|
+
and value of the column indexed for sorting so that the sort position can be
|
|
66
|
+
efficiently found. The encoding ensures that the cursor string is opaque to
|
|
67
|
+
the client and discourages the client from making use of the encoded
|
|
68
|
+
content.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
# encodes "10"
|
|
72
|
+
Cursor(rowid=10)
|
|
73
|
+
|
|
74
|
+
# encodes "11:STRING:abc"
|
|
75
|
+
Cursor(
|
|
76
|
+
rowid=11,
|
|
77
|
+
sort_column=CursorSortColumn(
|
|
78
|
+
type=CursorSortColumnDataType.STRING,
|
|
79
|
+
value="abc"
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# encodes "10:INT:5"
|
|
84
|
+
Cursor(
|
|
85
|
+
rowid=10,
|
|
86
|
+
sort_column=CursorSortColumn(
|
|
87
|
+
type=CursorSortColumnDataType.INT,
|
|
88
|
+
value=5
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# encodes "17:FLOAT:5.7"
|
|
93
|
+
Cursor(
|
|
94
|
+
rowid=17,
|
|
95
|
+
sort_column=CursorSortColumn(
|
|
96
|
+
type=CursorSortColumnDataType.FLOAT,
|
|
97
|
+
value=5.7
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# encodes "20:DATETIME:2024-05-05T04:25:29.911245+00:00"
|
|
102
|
+
Cursor(
|
|
103
|
+
rowid=20,
|
|
104
|
+
sort_column=CursorSortColumn(
|
|
105
|
+
type=CursorSortColumnDataType.DATETIME,
|
|
106
|
+
value=datetime.fromisoformat("2024-05-05T04:25:29.911245+00:00")
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
rowid: int
|
|
112
|
+
sort_column: Optional[CursorSortColumn] = None
|
|
113
|
+
|
|
114
|
+
_DELIMITER: ClassVar[str] = ":"
|
|
115
|
+
|
|
116
|
+
def __str__(self) -> str:
|
|
117
|
+
cursor_parts = [str(self.rowid)]
|
|
118
|
+
if (sort_column := self.sort_column) is not None:
|
|
119
|
+
cursor_parts.extend([sort_column.type.name, str(sort_column)])
|
|
120
|
+
return base64.b64encode(self._DELIMITER.join(cursor_parts).encode()).decode()
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def from_string(cls, cursor: str) -> "Cursor":
|
|
124
|
+
decoded = base64.b64decode(cursor).decode()
|
|
125
|
+
rowid_string = decoded
|
|
126
|
+
sort_column = None
|
|
127
|
+
if (first_delimiter_index := decoded.find(cls._DELIMITER)) > -1:
|
|
128
|
+
rowid_string = decoded[:first_delimiter_index]
|
|
129
|
+
second_delimiter_index = decoded.index(cls._DELIMITER, first_delimiter_index + 1)
|
|
130
|
+
sort_column = CursorSortColumn.from_string(
|
|
131
|
+
type=CursorSortColumnDataType[
|
|
132
|
+
decoded[first_delimiter_index + 1 : second_delimiter_index]
|
|
133
|
+
],
|
|
134
|
+
cursor_string=decoded[second_delimiter_index + 1 :],
|
|
135
|
+
)
|
|
136
|
+
return cls(rowid=int(rowid_string), sort_column=sort_column)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def offset_to_cursor(offset: int) -> CursorString:
|
|
60
140
|
"""
|
|
61
141
|
Creates the cursor string from an offset.
|
|
62
142
|
"""
|
|
63
143
|
return base64.b64encode(f"{CURSOR_PREFIX}{offset}".encode("utf-8")).decode()
|
|
64
144
|
|
|
65
145
|
|
|
66
|
-
def cursor_to_offset(cursor:
|
|
146
|
+
def cursor_to_offset(cursor: CursorString) -> int:
|
|
67
147
|
"""
|
|
68
148
|
Extracts the offset from the cursor string.
|
|
69
149
|
"""
|
|
@@ -71,13 +151,13 @@ def cursor_to_offset(cursor: Cursor) -> int:
|
|
|
71
151
|
return int(offset)
|
|
72
152
|
|
|
73
153
|
|
|
74
|
-
def get_offset_with_default(cursor: Optional[
|
|
154
|
+
def get_offset_with_default(cursor: Optional[CursorString], default_offset: int) -> int:
|
|
75
155
|
"""
|
|
76
156
|
Given an optional cursor and a default offset, returns the offset
|
|
77
157
|
to use; if the cursor contains a valid offset, that will be used,
|
|
78
158
|
otherwise it will be the default.
|
|
79
159
|
"""
|
|
80
|
-
if not isinstance(cursor,
|
|
160
|
+
if not isinstance(cursor, CursorString):
|
|
81
161
|
return default_offset
|
|
82
162
|
offset = cursor_to_offset(cursor)
|
|
83
163
|
return offset if isinstance(offset, int) else default_offset
|
|
@@ -90,15 +170,15 @@ class ConnectionArgs:
|
|
|
90
170
|
"""
|
|
91
171
|
|
|
92
172
|
first: Optional[int] = UNSET
|
|
93
|
-
after: Optional[
|
|
173
|
+
after: Optional[CursorString] = UNSET
|
|
94
174
|
last: Optional[int] = UNSET
|
|
95
|
-
before: Optional[
|
|
175
|
+
before: Optional[CursorString] = UNSET
|
|
96
176
|
|
|
97
177
|
|
|
98
178
|
def connection_from_list(
|
|
99
|
-
data:
|
|
179
|
+
data: list[NodeType],
|
|
100
180
|
args: ConnectionArgs,
|
|
101
|
-
) -> Connection[
|
|
181
|
+
) -> Connection[NodeType]:
|
|
102
182
|
"""
|
|
103
183
|
A simple function that accepts a list and connection arguments, and returns
|
|
104
184
|
a connection object for use in GraphQL. It uses list offsets as pagination,
|
|
@@ -108,11 +188,11 @@ def connection_from_list(
|
|
|
108
188
|
|
|
109
189
|
|
|
110
190
|
def connection_from_list_slice(
|
|
111
|
-
list_slice:
|
|
191
|
+
list_slice: list[NodeType],
|
|
112
192
|
args: ConnectionArgs,
|
|
113
193
|
slice_start: int,
|
|
114
194
|
list_length: int,
|
|
115
|
-
) -> Connection[
|
|
195
|
+
) -> Connection[NodeType]:
|
|
116
196
|
"""
|
|
117
197
|
Given a slice (subset) of a list, returns a connection object for use in
|
|
118
198
|
GraphQL.
|
|
@@ -169,6 +249,25 @@ def connection_from_list_slice(
|
|
|
169
249
|
end_cursor=last_edge.cursor if last_edge else None,
|
|
170
250
|
has_previous_page=start_offset > lower_bound if isinstance(args.last, int) else False,
|
|
171
251
|
has_next_page=end_offset < upper_bound if isinstance(args.first, int) else False,
|
|
172
|
-
|
|
252
|
+
),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def connection_from_cursors_and_nodes(
|
|
257
|
+
cursors_and_nodes: list[tuple[Any, NodeType]],
|
|
258
|
+
has_previous_page: bool,
|
|
259
|
+
has_next_page: bool,
|
|
260
|
+
) -> Connection[NodeType]:
|
|
261
|
+
edges = [Edge(node=node, cursor=str(cursor)) for cursor, node in cursors_and_nodes]
|
|
262
|
+
has_edges = len(edges) > 0
|
|
263
|
+
first_edge = edges[0] if has_edges else None
|
|
264
|
+
last_edge = edges[-1] if has_edges else None
|
|
265
|
+
return Connection(
|
|
266
|
+
edges=edges,
|
|
267
|
+
page_info=PageInfo(
|
|
268
|
+
start_cursor=first_edge.cursor if first_edge else None,
|
|
269
|
+
end_cursor=last_edge.cursor if last_edge else None,
|
|
270
|
+
has_previous_page=has_previous_page,
|
|
271
|
+
has_next_page=has_next_page,
|
|
173
272
|
),
|
|
174
273
|
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from sqlalchemy import delete
|
|
2
|
+
|
|
3
|
+
from phoenix.db import models
|
|
4
|
+
from phoenix.server.types import DbSessionFactory
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def delete_projects(
|
|
8
|
+
db: DbSessionFactory,
|
|
9
|
+
*project_names: str,
|
|
10
|
+
) -> list[int]:
|
|
11
|
+
if not project_names:
|
|
12
|
+
return []
|
|
13
|
+
stmt = (
|
|
14
|
+
delete(models.Project)
|
|
15
|
+
.where(models.Project.name.in_(set(project_names)))
|
|
16
|
+
.returning(models.Project.id)
|
|
17
|
+
)
|
|
18
|
+
async with db() as session:
|
|
19
|
+
return list(await session.scalars(stmt))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def delete_traces(
|
|
23
|
+
db: DbSessionFactory,
|
|
24
|
+
*trace_ids: str,
|
|
25
|
+
) -> list[int]:
|
|
26
|
+
if not trace_ids:
|
|
27
|
+
return []
|
|
28
|
+
stmt = (
|
|
29
|
+
delete(models.Trace)
|
|
30
|
+
.where(models.Trace.trace_id.in_(set(trace_ids)))
|
|
31
|
+
.returning(models.Trace.id)
|
|
32
|
+
)
|
|
33
|
+
async with db() as session:
|
|
34
|
+
return list(await session.scalars(stmt))
|