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,21 +1,25 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
1
2
|
from dataclasses import replace
|
|
2
3
|
from datetime import datetime, timedelta
|
|
3
4
|
from functools import total_ordering
|
|
4
|
-
from typing import
|
|
5
|
+
from typing import Optional, Union, cast
|
|
5
6
|
|
|
6
7
|
import pandas as pd
|
|
7
8
|
import strawberry
|
|
8
9
|
from strawberry import UNSET
|
|
9
10
|
|
|
10
|
-
from phoenix.core.model_schema import CONTINUOUS, PRIMARY, REFERENCE, Column,
|
|
11
|
+
from phoenix.core.model_schema import CONTINUOUS, PRIMARY, REFERENCE, Column, Dimension, Inferences
|
|
11
12
|
from phoenix.metrics import Metric, binning
|
|
12
13
|
from phoenix.metrics.mixins import UnaryOperator
|
|
13
14
|
from phoenix.metrics.timeseries import timeseries
|
|
14
15
|
from phoenix.server.api.input_types.Granularity import Granularity, to_timestamps
|
|
15
16
|
from phoenix.server.api.input_types.TimeRange import TimeRange
|
|
16
17
|
from phoenix.server.api.interceptor import GqlValueMediator
|
|
17
|
-
from phoenix.server.api.types.DataQualityMetric import
|
|
18
|
-
|
|
18
|
+
from phoenix.server.api.types.DataQualityMetric import (
|
|
19
|
+
DATA_QUALITY_METRIC_FACTORIES,
|
|
20
|
+
DataQualityMetric,
|
|
21
|
+
)
|
|
22
|
+
from phoenix.server.api.types.InferencesRole import InferencesRole
|
|
19
23
|
from phoenix.server.api.types.ScalarDriftMetricEnum import ScalarDriftMetric
|
|
20
24
|
from phoenix.server.api.types.VectorDriftMetricEnum import VectorDriftMetric
|
|
21
25
|
|
|
@@ -39,7 +43,7 @@ def to_gql_datapoints(
|
|
|
39
43
|
df: pd.DataFrame,
|
|
40
44
|
metric: Metric,
|
|
41
45
|
timestamps: Iterable[datetime],
|
|
42
|
-
) ->
|
|
46
|
+
) -> list[TimeSeriesDataPoint]:
|
|
43
47
|
data = []
|
|
44
48
|
for timestamp in timestamps:
|
|
45
49
|
try:
|
|
@@ -59,7 +63,7 @@ def to_gql_datapoints(
|
|
|
59
63
|
class TimeSeries:
|
|
60
64
|
"""A collection of data points over time"""
|
|
61
65
|
|
|
62
|
-
data:
|
|
66
|
+
data: list[TimeSeriesDataPoint]
|
|
63
67
|
|
|
64
68
|
|
|
65
69
|
def get_timeseries_data(
|
|
@@ -67,7 +71,7 @@ def get_timeseries_data(
|
|
|
67
71
|
metric: Metric,
|
|
68
72
|
time_range: TimeRange,
|
|
69
73
|
granularity: Granularity,
|
|
70
|
-
) ->
|
|
74
|
+
) -> list[TimeSeriesDataPoint]:
|
|
71
75
|
return df.pipe(
|
|
72
76
|
timeseries(
|
|
73
77
|
start_time=time_range.start,
|
|
@@ -97,16 +101,16 @@ def get_data_quality_timeseries_data(
|
|
|
97
101
|
metric: DataQualityMetric,
|
|
98
102
|
time_range: TimeRange,
|
|
99
103
|
granularity: Granularity,
|
|
100
|
-
|
|
101
|
-
) ->
|
|
102
|
-
metric_instance = metric
|
|
104
|
+
inferences_role: InferencesRole,
|
|
105
|
+
) -> list[TimeSeriesDataPoint]:
|
|
106
|
+
metric_instance = DATA_QUALITY_METRIC_FACTORIES[metric]()
|
|
103
107
|
if isinstance(metric_instance, UnaryOperator):
|
|
104
108
|
metric_instance = replace(
|
|
105
109
|
metric_instance,
|
|
106
110
|
operand=Column(dimension.name),
|
|
107
111
|
)
|
|
108
112
|
df = pd.DataFrame(
|
|
109
|
-
{dimension.name: dimension[
|
|
113
|
+
{dimension.name: dimension[inferences_role.value]},
|
|
110
114
|
copy=False,
|
|
111
115
|
)
|
|
112
116
|
return get_timeseries_data(
|
|
@@ -128,7 +132,7 @@ def get_drift_timeseries_data(
|
|
|
128
132
|
time_range: TimeRange,
|
|
129
133
|
granularity: Granularity,
|
|
130
134
|
reference_data: pd.DataFrame,
|
|
131
|
-
) ->
|
|
135
|
+
) -> list[TimeSeriesDataPoint]:
|
|
132
136
|
metric_instance = metric.value()
|
|
133
137
|
metric_instance = replace(
|
|
134
138
|
metric_instance,
|
|
@@ -160,12 +164,12 @@ class PerformanceTimeSeries(TimeSeries):
|
|
|
160
164
|
|
|
161
165
|
|
|
162
166
|
def ensure_timeseries_parameters(
|
|
163
|
-
|
|
167
|
+
inferences: Inferences,
|
|
164
168
|
time_range: Optional[TimeRange] = UNSET,
|
|
165
169
|
granularity: Optional[Granularity] = UNSET,
|
|
166
|
-
) ->
|
|
170
|
+
) -> tuple[TimeRange, Granularity]:
|
|
167
171
|
if not isinstance(time_range, TimeRange):
|
|
168
|
-
start, stop =
|
|
172
|
+
start, stop = inferences.time_range
|
|
169
173
|
time_range = TimeRange(start=start, end=stop)
|
|
170
174
|
if not isinstance(granularity, Granularity):
|
|
171
175
|
total_minutes = int((time_range.end - time_range.start).total_seconds()) // 60
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import TYPE_CHECKING, Annotated, Optional, Union
|
|
5
|
+
|
|
6
|
+
import strawberry
|
|
7
|
+
from openinference.semconv.trace import SpanAttributes
|
|
8
|
+
from sqlalchemy import desc, select
|
|
9
|
+
from sqlalchemy.orm import contains_eager
|
|
10
|
+
from strawberry import UNSET, Private, lazy
|
|
11
|
+
from strawberry.relay import Connection, GlobalID, Node, NodeID
|
|
12
|
+
from strawberry.types import Info
|
|
13
|
+
|
|
14
|
+
from phoenix.db import models
|
|
15
|
+
from phoenix.server.api.context import Context
|
|
16
|
+
from phoenix.server.api.input_types.TraceAnnotationSort import TraceAnnotationSort
|
|
17
|
+
from phoenix.server.api.types.pagination import (
|
|
18
|
+
ConnectionArgs,
|
|
19
|
+
CursorString,
|
|
20
|
+
connection_from_list,
|
|
21
|
+
)
|
|
22
|
+
from phoenix.server.api.types.SortDir import SortDir
|
|
23
|
+
from phoenix.server.api.types.Span import Span, to_gql_span
|
|
24
|
+
from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from phoenix.server.api.types.ProjectSession import ProjectSession
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@strawberry.type
|
|
31
|
+
class Trace(Node):
|
|
32
|
+
id_attr: NodeID[int]
|
|
33
|
+
project_rowid: Private[int]
|
|
34
|
+
project_session_rowid: Private[Optional[int]]
|
|
35
|
+
trace_id: str
|
|
36
|
+
start_time: datetime
|
|
37
|
+
end_time: datetime
|
|
38
|
+
|
|
39
|
+
@strawberry.field
|
|
40
|
+
async def latency_ms(
|
|
41
|
+
self,
|
|
42
|
+
info: Info[Context, None],
|
|
43
|
+
) -> Optional[float]:
|
|
44
|
+
async with info.context.db() as session:
|
|
45
|
+
latency = await session.scalar(
|
|
46
|
+
select(
|
|
47
|
+
models.Trace.latency_ms,
|
|
48
|
+
).where(models.Trace.id == self.id_attr)
|
|
49
|
+
)
|
|
50
|
+
return latency
|
|
51
|
+
|
|
52
|
+
@strawberry.field
|
|
53
|
+
async def project_id(self) -> GlobalID:
|
|
54
|
+
from phoenix.server.api.types.Project import Project
|
|
55
|
+
|
|
56
|
+
return GlobalID(type_name=Project.__name__, node_id=str(self.project_rowid))
|
|
57
|
+
|
|
58
|
+
@strawberry.field
|
|
59
|
+
async def project_session_id(self) -> Optional[GlobalID]:
|
|
60
|
+
if self.project_session_rowid is None:
|
|
61
|
+
return None
|
|
62
|
+
from phoenix.server.api.types.ProjectSession import ProjectSession
|
|
63
|
+
|
|
64
|
+
return GlobalID(type_name=ProjectSession.__name__, node_id=str(self.project_session_rowid))
|
|
65
|
+
|
|
66
|
+
@strawberry.field
|
|
67
|
+
async def session(
|
|
68
|
+
self,
|
|
69
|
+
info: Info[Context, None],
|
|
70
|
+
) -> Union[Annotated["ProjectSession", lazy(".ProjectSession")], None]:
|
|
71
|
+
if self.project_session_rowid is None:
|
|
72
|
+
return None
|
|
73
|
+
from phoenix.server.api.types.ProjectSession import to_gql_project_session
|
|
74
|
+
|
|
75
|
+
stmt = select(models.ProjectSession).filter_by(id=self.project_session_rowid)
|
|
76
|
+
async with info.context.db() as session:
|
|
77
|
+
project_session = await session.scalar(stmt)
|
|
78
|
+
if project_session is None:
|
|
79
|
+
return None
|
|
80
|
+
return to_gql_project_session(project_session)
|
|
81
|
+
|
|
82
|
+
@strawberry.field
|
|
83
|
+
async def root_span(
|
|
84
|
+
self,
|
|
85
|
+
info: Info[Context, None],
|
|
86
|
+
) -> Optional[Span]:
|
|
87
|
+
span = await info.context.data_loaders.trace_root_spans.load(self.id_attr)
|
|
88
|
+
if span is None:
|
|
89
|
+
return None
|
|
90
|
+
return to_gql_span(span)
|
|
91
|
+
|
|
92
|
+
@strawberry.field
|
|
93
|
+
async def spans(
|
|
94
|
+
self,
|
|
95
|
+
info: Info[Context, None],
|
|
96
|
+
first: Optional[int] = 50,
|
|
97
|
+
last: Optional[int] = UNSET,
|
|
98
|
+
after: Optional[CursorString] = UNSET,
|
|
99
|
+
before: Optional[CursorString] = UNSET,
|
|
100
|
+
) -> Connection[Span]:
|
|
101
|
+
args = ConnectionArgs(
|
|
102
|
+
first=first,
|
|
103
|
+
after=after if isinstance(after, CursorString) else None,
|
|
104
|
+
last=last,
|
|
105
|
+
before=before if isinstance(before, CursorString) else None,
|
|
106
|
+
)
|
|
107
|
+
stmt = (
|
|
108
|
+
select(models.Span)
|
|
109
|
+
.join(models.Trace)
|
|
110
|
+
.where(models.Trace.id == self.id_attr)
|
|
111
|
+
.options(contains_eager(models.Span.trace).load_only(models.Trace.trace_id))
|
|
112
|
+
# Sort descending because the root span tends to show up later
|
|
113
|
+
# in the ingestion process.
|
|
114
|
+
.order_by(desc(models.Span.id))
|
|
115
|
+
.limit(first)
|
|
116
|
+
)
|
|
117
|
+
async with info.context.db() as session:
|
|
118
|
+
spans = await session.stream_scalars(stmt)
|
|
119
|
+
data = [to_gql_span(span) async for span in spans]
|
|
120
|
+
return connection_from_list(data=data, args=args)
|
|
121
|
+
|
|
122
|
+
@strawberry.field(description="Annotations associated with the trace.") # type: ignore
|
|
123
|
+
async def span_annotations(
|
|
124
|
+
self,
|
|
125
|
+
info: Info[Context, None],
|
|
126
|
+
sort: Optional[TraceAnnotationSort] = None,
|
|
127
|
+
) -> list[TraceAnnotation]:
|
|
128
|
+
async with info.context.db() as session:
|
|
129
|
+
stmt = select(models.TraceAnnotation).filter_by(span_rowid=self.id_attr)
|
|
130
|
+
if sort:
|
|
131
|
+
sort_col = getattr(models.TraceAnnotation, sort.col.value)
|
|
132
|
+
if sort.dir is SortDir.desc:
|
|
133
|
+
stmt = stmt.order_by(sort_col.desc(), models.TraceAnnotation.id.desc())
|
|
134
|
+
else:
|
|
135
|
+
stmt = stmt.order_by(sort_col.asc(), models.TraceAnnotation.id.asc())
|
|
136
|
+
else:
|
|
137
|
+
stmt = stmt.order_by(models.TraceAnnotation.created_at.desc())
|
|
138
|
+
annotations = await session.scalars(stmt)
|
|
139
|
+
return [to_gql_trace_annotation(annotation) for annotation in annotations]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def to_gql_trace(trace: models.Trace) -> Trace:
|
|
143
|
+
return Trace(
|
|
144
|
+
id_attr=trace.id,
|
|
145
|
+
project_rowid=trace.project_rowid,
|
|
146
|
+
project_session_rowid=trace.project_session_rowid,
|
|
147
|
+
trace_id=trace.trace_id,
|
|
148
|
+
start_time=trace.start_time,
|
|
149
|
+
end_time=trace.end_time,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
INPUT_VALUE = SpanAttributes.INPUT_VALUE.split(".")
|
|
154
|
+
OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE.split(".")
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import Private
|
|
5
|
+
from strawberry.relay import GlobalID, Node, NodeID
|
|
6
|
+
from strawberry.scalars import JSON
|
|
7
|
+
|
|
8
|
+
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.types.AnnotatorKind import AnnotatorKind
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@strawberry.type
|
|
13
|
+
class TraceAnnotation(Node):
|
|
14
|
+
id_attr: NodeID[int]
|
|
15
|
+
name: str
|
|
16
|
+
annotator_kind: AnnotatorKind
|
|
17
|
+
label: Optional[str]
|
|
18
|
+
score: Optional[float]
|
|
19
|
+
explanation: Optional[str]
|
|
20
|
+
metadata: JSON
|
|
21
|
+
trace_rowid: Private[Optional[int]]
|
|
22
|
+
|
|
23
|
+
@strawberry.field
|
|
24
|
+
async def trace_id(self) -> GlobalID:
|
|
25
|
+
from phoenix.server.api.types.Trace import Trace
|
|
26
|
+
|
|
27
|
+
return GlobalID(type_name=Trace.__name__, node_id=str(self.trace_rowid))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def to_gql_trace_annotation(
|
|
31
|
+
annotation: models.TraceAnnotation,
|
|
32
|
+
) -> TraceAnnotation:
|
|
33
|
+
"""
|
|
34
|
+
Converts an ORM trace annotation to a GraphQL TraceAnnotation.
|
|
35
|
+
"""
|
|
36
|
+
return TraceAnnotation(
|
|
37
|
+
id_attr=annotation.id,
|
|
38
|
+
trace_rowid=annotation.trace_rowid,
|
|
39
|
+
name=annotation.name,
|
|
40
|
+
annotator_kind=AnnotatorKind(annotation.annotator_kind),
|
|
41
|
+
label=annotation.label,
|
|
42
|
+
score=annotation.score,
|
|
43
|
+
explanation=annotation.explanation,
|
|
44
|
+
metadata=annotation.metadata_,
|
|
45
|
+
)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Union
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import numpy.typing as npt
|
|
5
5
|
import strawberry
|
|
6
|
+
from strawberry.relay.types import GlobalID
|
|
6
7
|
from strawberry.scalars import ID
|
|
7
8
|
|
|
8
9
|
from phoenix.server.api.types.Cluster import Cluster
|
|
9
10
|
|
|
10
11
|
from .EmbeddingMetadata import EmbeddingMetadata
|
|
11
12
|
from .EventMetadata import EventMetadata
|
|
12
|
-
from .node import GlobalID
|
|
13
13
|
from .Retrieval import Retrieval
|
|
14
14
|
|
|
15
15
|
|
|
@@ -57,8 +57,8 @@ class UMAPPoint:
|
|
|
57
57
|
|
|
58
58
|
@strawberry.type
|
|
59
59
|
class UMAPPoints:
|
|
60
|
-
data:
|
|
61
|
-
reference_data:
|
|
62
|
-
clusters:
|
|
63
|
-
corpus_data:
|
|
64
|
-
context_retrievals:
|
|
60
|
+
data: list[UMAPPoint]
|
|
61
|
+
reference_data: list[UMAPPoint]
|
|
62
|
+
clusters: list[Cluster]
|
|
63
|
+
corpus_data: list[UMAPPoint] = strawberry.field(default_factory=list)
|
|
64
|
+
context_retrievals: list[Retrieval] = strawberry.field(default_factory=list)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import strawberry
|
|
5
|
+
from sqlalchemy import select
|
|
6
|
+
from strawberry import Private
|
|
7
|
+
from strawberry.relay import Node, NodeID
|
|
8
|
+
from strawberry.types import Info
|
|
9
|
+
|
|
10
|
+
from phoenix.db import models
|
|
11
|
+
from phoenix.server.api.context import Context
|
|
12
|
+
from phoenix.server.api.exceptions import NotFound
|
|
13
|
+
from phoenix.server.api.types.AuthMethod import AuthMethod
|
|
14
|
+
from phoenix.server.api.types.UserApiKey import UserApiKey, to_gql_api_key
|
|
15
|
+
|
|
16
|
+
from .UserRole import UserRole, to_gql_user_role
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@strawberry.type
|
|
20
|
+
class User(Node):
|
|
21
|
+
id_attr: NodeID[int]
|
|
22
|
+
password_needs_reset: bool
|
|
23
|
+
email: str
|
|
24
|
+
username: str
|
|
25
|
+
profile_picture_url: Optional[str]
|
|
26
|
+
created_at: datetime
|
|
27
|
+
user_role_id: Private[int]
|
|
28
|
+
auth_method: AuthMethod
|
|
29
|
+
|
|
30
|
+
@strawberry.field
|
|
31
|
+
async def role(self, info: Info[Context, None]) -> UserRole:
|
|
32
|
+
role = await info.context.data_loaders.user_roles.load(self.user_role_id)
|
|
33
|
+
if role is None:
|
|
34
|
+
raise NotFound(f"User role with id {self.user_role_id} not found")
|
|
35
|
+
return to_gql_user_role(role)
|
|
36
|
+
|
|
37
|
+
@strawberry.field
|
|
38
|
+
async def api_keys(self, info: Info[Context, None]) -> list[UserApiKey]:
|
|
39
|
+
async with info.context.db() as session:
|
|
40
|
+
api_keys = await session.scalars(
|
|
41
|
+
select(models.ApiKey).where(models.ApiKey.user_id == self.id_attr)
|
|
42
|
+
)
|
|
43
|
+
return [to_gql_api_key(api_key) for api_key in api_keys]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def to_gql_user(user: models.User, api_keys: Optional[list[models.ApiKey]] = None) -> User:
|
|
47
|
+
"""
|
|
48
|
+
Converts an ORM user to a GraphQL user.
|
|
49
|
+
"""
|
|
50
|
+
assert user.auth_method is not None
|
|
51
|
+
return User(
|
|
52
|
+
id_attr=user.id,
|
|
53
|
+
password_needs_reset=user.reset_password,
|
|
54
|
+
username=user.username,
|
|
55
|
+
email=user.email,
|
|
56
|
+
profile_picture_url=user.profile_picture_url,
|
|
57
|
+
created_at=user.created_at,
|
|
58
|
+
user_role_id=user.user_role_id,
|
|
59
|
+
auth_method=AuthMethod(user.auth_method),
|
|
60
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import Private
|
|
5
|
+
from strawberry.relay import Node, NodeID
|
|
6
|
+
from strawberry.types import Info
|
|
7
|
+
from typing_extensions import Annotated
|
|
8
|
+
|
|
9
|
+
from phoenix.db.models import ApiKey as OrmApiKey
|
|
10
|
+
from phoenix.server.api.context import Context
|
|
11
|
+
from phoenix.server.api.exceptions import NotFound
|
|
12
|
+
|
|
13
|
+
from .ApiKey import ApiKey
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from .User import User
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@strawberry.type
|
|
20
|
+
class UserApiKey(ApiKey, Node):
|
|
21
|
+
id_attr: NodeID[int]
|
|
22
|
+
user_id: Private[int]
|
|
23
|
+
|
|
24
|
+
@strawberry.field
|
|
25
|
+
async def user(self, info: Info[Context, None]) -> Annotated["User", strawberry.lazy(".User")]:
|
|
26
|
+
user = await info.context.data_loaders.users.load(self.user_id)
|
|
27
|
+
if user is None:
|
|
28
|
+
raise NotFound(f"User with id {self.user_id} not found")
|
|
29
|
+
from .User import to_gql_user
|
|
30
|
+
|
|
31
|
+
return to_gql_user(user)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def to_gql_api_key(api_key: OrmApiKey) -> UserApiKey:
|
|
35
|
+
"""
|
|
36
|
+
Converts an ORM API key to a GraphQL UserApiKey type.
|
|
37
|
+
"""
|
|
38
|
+
return UserApiKey(
|
|
39
|
+
id_attr=api_key.id,
|
|
40
|
+
user_id=api_key.user_id,
|
|
41
|
+
name=api_key.name,
|
|
42
|
+
description=api_key.description,
|
|
43
|
+
created_at=api_key.created_at,
|
|
44
|
+
expires_at=api_key.expires_at,
|
|
45
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import strawberry
|
|
2
|
+
from strawberry.relay import Node, NodeID
|
|
3
|
+
|
|
4
|
+
from phoenix.db import models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@strawberry.type
|
|
8
|
+
class UserRole(Node):
|
|
9
|
+
id_attr: NodeID[int]
|
|
10
|
+
name: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def to_gql_user_role(role: models.UserRole) -> UserRole:
|
|
14
|
+
"""Convert an ORM user role to a GraphQL user role."""
|
|
15
|
+
return UserRole(id_attr=role.id, name=role.name)
|
phoenix/server/api/types/node.py
CHANGED
|
@@ -1,36 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import dataclasses
|
|
3
|
-
from typing import Tuple, Union
|
|
1
|
+
from strawberry.relay import GlobalID
|
|
4
2
|
|
|
5
|
-
import strawberry
|
|
6
|
-
from graphql import GraphQLID
|
|
7
|
-
from strawberry.custom_scalar import ScalarDefinition
|
|
8
|
-
from strawberry.schema.types.scalar import DEFAULT_SCALAR_REGISTRY
|
|
9
3
|
|
|
10
|
-
|
|
11
|
-
def to_global_id(type_name: str, node_id: int) -> str:
|
|
12
|
-
"""
|
|
13
|
-
Encode the given id into a global id.
|
|
14
|
-
|
|
15
|
-
:param type_name: The type of the node.
|
|
16
|
-
:param node_id: The id of the node.
|
|
17
|
-
:return: A global id.
|
|
18
|
-
"""
|
|
19
|
-
return base64.b64encode(f"{type_name}:{node_id}".encode("utf-8")).decode()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def from_global_id(global_id: str) -> Tuple[str, int]:
|
|
4
|
+
def from_global_id(global_id: GlobalID) -> tuple[str, int]:
|
|
23
5
|
"""
|
|
24
6
|
Decode the given global id into a type and id.
|
|
25
7
|
|
|
26
8
|
:param global_id: The global id to decode.
|
|
27
9
|
:return: A tuple of type and id.
|
|
28
10
|
"""
|
|
29
|
-
type_name,
|
|
30
|
-
return type_name, int(node_id)
|
|
11
|
+
return global_id.type_name, int(global_id.node_id)
|
|
31
12
|
|
|
32
13
|
|
|
33
|
-
def from_global_id_with_expected_type(global_id:
|
|
14
|
+
def from_global_id_with_expected_type(global_id: GlobalID, expected_type_name: str) -> int:
|
|
34
15
|
"""
|
|
35
16
|
Decodes the given global id and return the id, checking that the type
|
|
36
17
|
matches the expected type.
|
|
@@ -42,92 +23,3 @@ def from_global_id_with_expected_type(global_id: str, expected_type_name: str) -
|
|
|
42
23
|
f"but instead corresponds to a node of type: {type_name}"
|
|
43
24
|
)
|
|
44
25
|
return node_id
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class GlobalIDValueError(ValueError):
|
|
48
|
-
"""GlobalID value error, usually related to parsing or serialization."""
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclasses.dataclass(frozen=True)
|
|
52
|
-
class GlobalID:
|
|
53
|
-
"""Global ID for relay types.
|
|
54
|
-
Different from `strawberry.ID`, this ID wraps the original object ID in a string
|
|
55
|
-
that contains both its GraphQL type name and the ID itself, and encodes it
|
|
56
|
-
to a base64_ string.
|
|
57
|
-
This object contains helpers to work with that, including method to retrieve
|
|
58
|
-
the python object type or even the encoded node itself.
|
|
59
|
-
Attributes:
|
|
60
|
-
type_name:
|
|
61
|
-
The type name part of the id
|
|
62
|
-
node_id:
|
|
63
|
-
The node id part of the id
|
|
64
|
-
.. _base64:
|
|
65
|
-
https://en.wikipedia.org/wiki/Base64
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
type_name: str
|
|
69
|
-
node_id: int
|
|
70
|
-
|
|
71
|
-
def __post_init__(self) -> None:
|
|
72
|
-
if not isinstance(self.type_name, str):
|
|
73
|
-
raise GlobalIDValueError(
|
|
74
|
-
f"type_name is expected to be a string, found {self.type_name}"
|
|
75
|
-
)
|
|
76
|
-
try:
|
|
77
|
-
# node_id could be numpy.int64, hence the need for coercion
|
|
78
|
-
object.__setattr__(self, "node_id", int(self.node_id))
|
|
79
|
-
except ValueError:
|
|
80
|
-
raise GlobalIDValueError(f"node_id is expected to be an int, found {self.node_id}")
|
|
81
|
-
|
|
82
|
-
def __str__(self) -> str:
|
|
83
|
-
return to_global_id(self.type_name, self.node_id)
|
|
84
|
-
|
|
85
|
-
@classmethod
|
|
86
|
-
def from_id(cls, value: Union[str, strawberry.ID]) -> "GlobalID":
|
|
87
|
-
"""Create a new GlobalID from parsing the given value.
|
|
88
|
-
Args:
|
|
89
|
-
value:
|
|
90
|
-
The value to be parsed, as a base64 string in the "TypeName:NodeID" format
|
|
91
|
-
Returns:
|
|
92
|
-
An instance of GLobalID
|
|
93
|
-
Raises:
|
|
94
|
-
GlobalIDValueError:
|
|
95
|
-
If the value is not in a GLobalID format
|
|
96
|
-
"""
|
|
97
|
-
try:
|
|
98
|
-
type_name, node_id = from_global_id(value)
|
|
99
|
-
except ValueError as e:
|
|
100
|
-
raise GlobalIDValueError(str(e)) from e
|
|
101
|
-
|
|
102
|
-
return cls(type_name=type_name, node_id=node_id)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@strawberry.interface(description="A node in the graph with a globally unique ID")
|
|
106
|
-
class Node:
|
|
107
|
-
"""
|
|
108
|
-
All types that are relay ready should inherit from this interface and
|
|
109
|
-
implement the following methods.
|
|
110
|
-
|
|
111
|
-
Attributes:
|
|
112
|
-
id_attr:
|
|
113
|
-
The raw id field of node. Typically a database id or index
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
id_attr: strawberry.Private[int]
|
|
117
|
-
|
|
118
|
-
@strawberry.field
|
|
119
|
-
def id(self) -> GlobalID:
|
|
120
|
-
return GlobalID(type(self).__name__, self.id_attr)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# Register our GlobalID scalar
|
|
124
|
-
DEFAULT_SCALAR_REGISTRY[GlobalID] = ScalarDefinition(
|
|
125
|
-
# Use the same name/description/parse_literal from GraphQLID
|
|
126
|
-
# specs expect this type to be "ID".
|
|
127
|
-
name="GlobalID",
|
|
128
|
-
description=GraphQLID.description,
|
|
129
|
-
parse_literal=lambda v, vars=None: GlobalID.from_id(GraphQLID.parse_literal(v, vars)),
|
|
130
|
-
parse_value=GlobalID.from_id,
|
|
131
|
-
serialize=str,
|
|
132
|
-
specified_by_url="https://relay.dev/graphql/objectidentification.htm",
|
|
133
|
-
)
|