arize-phoenix 3.16.1__py3-none-any.whl → 7.7.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (338) hide show
  1. arize_phoenix-7.7.1.dist-info/METADATA +261 -0
  2. arize_phoenix-7.7.1.dist-info/RECORD +345 -0
  3. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/WHEEL +1 -1
  4. arize_phoenix-7.7.1.dist-info/entry_points.txt +3 -0
  5. phoenix/__init__.py +86 -14
  6. phoenix/auth.py +309 -0
  7. phoenix/config.py +675 -45
  8. phoenix/core/model.py +32 -30
  9. phoenix/core/model_schema.py +102 -109
  10. phoenix/core/model_schema_adapter.py +48 -45
  11. phoenix/datetime_utils.py +24 -3
  12. phoenix/db/README.md +54 -0
  13. phoenix/db/__init__.py +4 -0
  14. phoenix/db/alembic.ini +85 -0
  15. phoenix/db/bulk_inserter.py +294 -0
  16. phoenix/db/engines.py +208 -0
  17. phoenix/db/enums.py +20 -0
  18. phoenix/db/facilitator.py +113 -0
  19. phoenix/db/helpers.py +159 -0
  20. phoenix/db/insertion/constants.py +2 -0
  21. phoenix/db/insertion/dataset.py +227 -0
  22. phoenix/db/insertion/document_annotation.py +171 -0
  23. phoenix/db/insertion/evaluation.py +191 -0
  24. phoenix/db/insertion/helpers.py +98 -0
  25. phoenix/db/insertion/span.py +193 -0
  26. phoenix/db/insertion/span_annotation.py +158 -0
  27. phoenix/db/insertion/trace_annotation.py +158 -0
  28. phoenix/db/insertion/types.py +256 -0
  29. phoenix/db/migrate.py +86 -0
  30. phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
  31. phoenix/db/migrations/env.py +114 -0
  32. phoenix/db/migrations/script.py.mako +26 -0
  33. phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
  34. phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
  35. phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
  36. phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
  37. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
  38. phoenix/db/models.py +807 -0
  39. phoenix/exceptions.py +5 -1
  40. phoenix/experiments/__init__.py +6 -0
  41. phoenix/experiments/evaluators/__init__.py +29 -0
  42. phoenix/experiments/evaluators/base.py +158 -0
  43. phoenix/experiments/evaluators/code_evaluators.py +184 -0
  44. phoenix/experiments/evaluators/llm_evaluators.py +473 -0
  45. phoenix/experiments/evaluators/utils.py +236 -0
  46. phoenix/experiments/functions.py +772 -0
  47. phoenix/experiments/tracing.py +86 -0
  48. phoenix/experiments/types.py +726 -0
  49. phoenix/experiments/utils.py +25 -0
  50. phoenix/inferences/__init__.py +0 -0
  51. phoenix/{datasets → inferences}/errors.py +6 -5
  52. phoenix/{datasets → inferences}/fixtures.py +49 -42
  53. phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
  54. phoenix/{datasets → inferences}/schema.py +11 -11
  55. phoenix/{datasets → inferences}/validation.py +13 -14
  56. phoenix/logging/__init__.py +3 -0
  57. phoenix/logging/_config.py +90 -0
  58. phoenix/logging/_filter.py +6 -0
  59. phoenix/logging/_formatter.py +69 -0
  60. phoenix/metrics/__init__.py +5 -4
  61. phoenix/metrics/binning.py +4 -3
  62. phoenix/metrics/metrics.py +2 -1
  63. phoenix/metrics/mixins.py +7 -6
  64. phoenix/metrics/retrieval_metrics.py +2 -1
  65. phoenix/metrics/timeseries.py +5 -4
  66. phoenix/metrics/wrappers.py +9 -3
  67. phoenix/pointcloud/clustering.py +5 -5
  68. phoenix/pointcloud/pointcloud.py +7 -5
  69. phoenix/pointcloud/projectors.py +5 -6
  70. phoenix/pointcloud/umap_parameters.py +53 -52
  71. phoenix/server/api/README.md +28 -0
  72. phoenix/server/api/auth.py +44 -0
  73. phoenix/server/api/context.py +152 -9
  74. phoenix/server/api/dataloaders/__init__.py +91 -0
  75. phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
  76. phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
  77. phoenix/server/api/dataloaders/cache/__init__.py +3 -0
  78. phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
  79. phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
  80. phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
  81. phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
  82. phoenix/server/api/dataloaders/document_evaluations.py +31 -0
  83. phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
  84. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
  85. phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
  86. phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
  87. phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
  88. phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
  89. phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
  90. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
  91. phoenix/server/api/dataloaders/project_by_name.py +31 -0
  92. phoenix/server/api/dataloaders/record_counts.py +116 -0
  93. phoenix/server/api/dataloaders/session_io.py +79 -0
  94. phoenix/server/api/dataloaders/session_num_traces.py +30 -0
  95. phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
  96. phoenix/server/api/dataloaders/session_token_usages.py +41 -0
  97. phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
  98. phoenix/server/api/dataloaders/span_annotations.py +26 -0
  99. phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
  100. phoenix/server/api/dataloaders/span_descendants.py +57 -0
  101. phoenix/server/api/dataloaders/span_projects.py +33 -0
  102. phoenix/server/api/dataloaders/token_counts.py +124 -0
  103. phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
  104. phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
  105. phoenix/server/api/dataloaders/user_roles.py +30 -0
  106. phoenix/server/api/dataloaders/users.py +33 -0
  107. phoenix/server/api/exceptions.py +48 -0
  108. phoenix/server/api/helpers/__init__.py +12 -0
  109. phoenix/server/api/helpers/dataset_helpers.py +217 -0
  110. phoenix/server/api/helpers/experiment_run_filters.py +763 -0
  111. phoenix/server/api/helpers/playground_clients.py +948 -0
  112. phoenix/server/api/helpers/playground_registry.py +70 -0
  113. phoenix/server/api/helpers/playground_spans.py +455 -0
  114. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
  115. phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
  116. phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
  117. phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
  118. phoenix/server/api/input_types/ClearProjectInput.py +15 -0
  119. phoenix/server/api/input_types/ClusterInput.py +2 -2
  120. phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
  121. phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
  122. phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
  123. phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
  124. phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
  125. phoenix/server/api/input_types/DatasetSort.py +17 -0
  126. phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
  127. phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
  128. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
  129. phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
  130. phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
  131. phoenix/server/api/input_types/DimensionFilter.py +4 -4
  132. phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
  133. phoenix/server/api/input_types/Granularity.py +1 -1
  134. phoenix/server/api/input_types/InvocationParameters.py +162 -0
  135. phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
  136. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
  137. phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
  138. phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
  139. phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
  140. phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
  141. phoenix/server/api/input_types/SpanSort.py +134 -69
  142. phoenix/server/api/input_types/TemplateOptions.py +10 -0
  143. phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
  144. phoenix/server/api/input_types/UserRoleInput.py +9 -0
  145. phoenix/server/api/mutations/__init__.py +28 -0
  146. phoenix/server/api/mutations/api_key_mutations.py +167 -0
  147. phoenix/server/api/mutations/chat_mutations.py +593 -0
  148. phoenix/server/api/mutations/dataset_mutations.py +591 -0
  149. phoenix/server/api/mutations/experiment_mutations.py +75 -0
  150. phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
  151. phoenix/server/api/mutations/project_mutations.py +57 -0
  152. phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
  153. phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
  154. phoenix/server/api/mutations/user_mutations.py +329 -0
  155. phoenix/server/api/openapi/__init__.py +0 -0
  156. phoenix/server/api/openapi/main.py +17 -0
  157. phoenix/server/api/openapi/schema.py +16 -0
  158. phoenix/server/api/queries.py +738 -0
  159. phoenix/server/api/routers/__init__.py +11 -0
  160. phoenix/server/api/routers/auth.py +284 -0
  161. phoenix/server/api/routers/embeddings.py +26 -0
  162. phoenix/server/api/routers/oauth2.py +488 -0
  163. phoenix/server/api/routers/v1/__init__.py +64 -0
  164. phoenix/server/api/routers/v1/datasets.py +1017 -0
  165. phoenix/server/api/routers/v1/evaluations.py +362 -0
  166. phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
  167. phoenix/server/api/routers/v1/experiment_runs.py +167 -0
  168. phoenix/server/api/routers/v1/experiments.py +308 -0
  169. phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
  170. phoenix/server/api/routers/v1/spans.py +267 -0
  171. phoenix/server/api/routers/v1/traces.py +208 -0
  172. phoenix/server/api/routers/v1/utils.py +95 -0
  173. phoenix/server/api/schema.py +44 -241
  174. phoenix/server/api/subscriptions.py +597 -0
  175. phoenix/server/api/types/Annotation.py +21 -0
  176. phoenix/server/api/types/AnnotationSummary.py +55 -0
  177. phoenix/server/api/types/AnnotatorKind.py +16 -0
  178. phoenix/server/api/types/ApiKey.py +27 -0
  179. phoenix/server/api/types/AuthMethod.py +9 -0
  180. phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
  181. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
  182. phoenix/server/api/types/Cluster.py +25 -24
  183. phoenix/server/api/types/CreateDatasetPayload.py +8 -0
  184. phoenix/server/api/types/DataQualityMetric.py +31 -13
  185. phoenix/server/api/types/Dataset.py +288 -63
  186. phoenix/server/api/types/DatasetExample.py +85 -0
  187. phoenix/server/api/types/DatasetExampleRevision.py +34 -0
  188. phoenix/server/api/types/DatasetVersion.py +14 -0
  189. phoenix/server/api/types/Dimension.py +32 -31
  190. phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
  191. phoenix/server/api/types/EmbeddingDimension.py +56 -49
  192. phoenix/server/api/types/Evaluation.py +25 -31
  193. phoenix/server/api/types/EvaluationSummary.py +30 -50
  194. phoenix/server/api/types/Event.py +20 -20
  195. phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
  196. phoenix/server/api/types/Experiment.py +152 -0
  197. phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
  198. phoenix/server/api/types/ExperimentComparison.py +17 -0
  199. phoenix/server/api/types/ExperimentRun.py +119 -0
  200. phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
  201. phoenix/server/api/types/GenerativeModel.py +9 -0
  202. phoenix/server/api/types/GenerativeProvider.py +85 -0
  203. phoenix/server/api/types/Inferences.py +80 -0
  204. phoenix/server/api/types/InferencesRole.py +23 -0
  205. phoenix/server/api/types/LabelFraction.py +7 -0
  206. phoenix/server/api/types/MimeType.py +2 -2
  207. phoenix/server/api/types/Model.py +54 -54
  208. phoenix/server/api/types/PerformanceMetric.py +8 -5
  209. phoenix/server/api/types/Project.py +407 -142
  210. phoenix/server/api/types/ProjectSession.py +139 -0
  211. phoenix/server/api/types/Segments.py +4 -4
  212. phoenix/server/api/types/Span.py +221 -176
  213. phoenix/server/api/types/SpanAnnotation.py +43 -0
  214. phoenix/server/api/types/SpanIOValue.py +15 -0
  215. phoenix/server/api/types/SystemApiKey.py +9 -0
  216. phoenix/server/api/types/TemplateLanguage.py +10 -0
  217. phoenix/server/api/types/TimeSeries.py +19 -15
  218. phoenix/server/api/types/TokenUsage.py +11 -0
  219. phoenix/server/api/types/Trace.py +154 -0
  220. phoenix/server/api/types/TraceAnnotation.py +45 -0
  221. phoenix/server/api/types/UMAPPoints.py +7 -7
  222. phoenix/server/api/types/User.py +60 -0
  223. phoenix/server/api/types/UserApiKey.py +45 -0
  224. phoenix/server/api/types/UserRole.py +15 -0
  225. phoenix/server/api/types/node.py +4 -112
  226. phoenix/server/api/types/pagination.py +156 -57
  227. phoenix/server/api/utils.py +34 -0
  228. phoenix/server/app.py +864 -115
  229. phoenix/server/bearer_auth.py +163 -0
  230. phoenix/server/dml_event.py +136 -0
  231. phoenix/server/dml_event_handler.py +256 -0
  232. phoenix/server/email/__init__.py +0 -0
  233. phoenix/server/email/sender.py +97 -0
  234. phoenix/server/email/templates/__init__.py +0 -0
  235. phoenix/server/email/templates/password_reset.html +19 -0
  236. phoenix/server/email/types.py +11 -0
  237. phoenix/server/grpc_server.py +102 -0
  238. phoenix/server/jwt_store.py +505 -0
  239. phoenix/server/main.py +305 -116
  240. phoenix/server/oauth2.py +52 -0
  241. phoenix/server/openapi/__init__.py +0 -0
  242. phoenix/server/prometheus.py +111 -0
  243. phoenix/server/rate_limiters.py +188 -0
  244. phoenix/server/static/.vite/manifest.json +87 -0
  245. phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
  246. phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
  247. phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
  248. phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
  249. phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
  250. phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
  251. phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
  252. phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
  253. phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
  254. phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
  255. phoenix/server/telemetry.py +68 -0
  256. phoenix/server/templates/index.html +82 -23
  257. phoenix/server/thread_server.py +3 -3
  258. phoenix/server/types.py +275 -0
  259. phoenix/services.py +27 -18
  260. phoenix/session/client.py +743 -68
  261. phoenix/session/data_extractor.py +31 -7
  262. phoenix/session/evaluation.py +3 -9
  263. phoenix/session/session.py +263 -219
  264. phoenix/settings.py +22 -0
  265. phoenix/trace/__init__.py +2 -22
  266. phoenix/trace/attributes.py +338 -0
  267. phoenix/trace/dsl/README.md +116 -0
  268. phoenix/trace/dsl/filter.py +663 -213
  269. phoenix/trace/dsl/helpers.py +73 -21
  270. phoenix/trace/dsl/query.py +574 -201
  271. phoenix/trace/exporter.py +24 -19
  272. phoenix/trace/fixtures.py +368 -32
  273. phoenix/trace/otel.py +71 -219
  274. phoenix/trace/projects.py +3 -2
  275. phoenix/trace/schemas.py +33 -11
  276. phoenix/trace/span_evaluations.py +21 -16
  277. phoenix/trace/span_json_decoder.py +6 -4
  278. phoenix/trace/span_json_encoder.py +2 -2
  279. phoenix/trace/trace_dataset.py +47 -32
  280. phoenix/trace/utils.py +21 -4
  281. phoenix/utilities/__init__.py +0 -26
  282. phoenix/utilities/client.py +132 -0
  283. phoenix/utilities/deprecation.py +31 -0
  284. phoenix/utilities/error_handling.py +3 -2
  285. phoenix/utilities/json.py +109 -0
  286. phoenix/utilities/logging.py +8 -0
  287. phoenix/utilities/project.py +2 -2
  288. phoenix/utilities/re.py +49 -0
  289. phoenix/utilities/span_store.py +0 -23
  290. phoenix/utilities/template_formatters.py +99 -0
  291. phoenix/version.py +1 -1
  292. arize_phoenix-3.16.1.dist-info/METADATA +0 -495
  293. arize_phoenix-3.16.1.dist-info/RECORD +0 -178
  294. phoenix/core/project.py +0 -619
  295. phoenix/core/traces.py +0 -96
  296. phoenix/experimental/evals/__init__.py +0 -73
  297. phoenix/experimental/evals/evaluators.py +0 -413
  298. phoenix/experimental/evals/functions/__init__.py +0 -4
  299. phoenix/experimental/evals/functions/classify.py +0 -453
  300. phoenix/experimental/evals/functions/executor.py +0 -353
  301. phoenix/experimental/evals/functions/generate.py +0 -138
  302. phoenix/experimental/evals/functions/processing.py +0 -76
  303. phoenix/experimental/evals/models/__init__.py +0 -14
  304. phoenix/experimental/evals/models/anthropic.py +0 -175
  305. phoenix/experimental/evals/models/base.py +0 -170
  306. phoenix/experimental/evals/models/bedrock.py +0 -221
  307. phoenix/experimental/evals/models/litellm.py +0 -134
  308. phoenix/experimental/evals/models/openai.py +0 -448
  309. phoenix/experimental/evals/models/rate_limiters.py +0 -246
  310. phoenix/experimental/evals/models/vertex.py +0 -173
  311. phoenix/experimental/evals/models/vertexai.py +0 -186
  312. phoenix/experimental/evals/retrievals.py +0 -96
  313. phoenix/experimental/evals/templates/__init__.py +0 -50
  314. phoenix/experimental/evals/templates/default_templates.py +0 -472
  315. phoenix/experimental/evals/templates/template.py +0 -195
  316. phoenix/experimental/evals/utils/__init__.py +0 -172
  317. phoenix/experimental/evals/utils/threads.py +0 -27
  318. phoenix/server/api/helpers.py +0 -11
  319. phoenix/server/api/routers/evaluation_handler.py +0 -109
  320. phoenix/server/api/routers/span_handler.py +0 -70
  321. phoenix/server/api/routers/trace_handler.py +0 -60
  322. phoenix/server/api/types/DatasetRole.py +0 -23
  323. phoenix/server/static/index.css +0 -6
  324. phoenix/server/static/index.js +0 -7447
  325. phoenix/storage/span_store/__init__.py +0 -23
  326. phoenix/storage/span_store/text_file.py +0 -85
  327. phoenix/trace/dsl/missing.py +0 -60
  328. phoenix/trace/langchain/__init__.py +0 -3
  329. phoenix/trace/langchain/instrumentor.py +0 -35
  330. phoenix/trace/llama_index/__init__.py +0 -3
  331. phoenix/trace/llama_index/callback.py +0 -102
  332. phoenix/trace/openai/__init__.py +0 -3
  333. phoenix/trace/openai/instrumentor.py +0 -30
  334. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/licenses/IP_NOTICE +0 -0
  335. {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.1.dist-info}/licenses/LICENSE +0 -0
  336. /phoenix/{datasets → db/insertion}/__init__.py +0 -0
  337. /phoenix/{experimental → db/migrations}/__init__.py +0 -0
  338. /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 typing import Generic, List, Optional, TypeVar
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
- GenericType = TypeVar("GenericType")
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
- Cursor = str
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
- def offset_to_cursor(offset: int) -> Cursor:
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: Cursor) -> int:
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[Cursor], default_offset: int) -> int:
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, 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[Cursor] = UNSET
173
+ after: Optional[CursorString] = UNSET
94
174
  last: Optional[int] = UNSET
95
- before: Optional[Cursor] = UNSET
175
+ before: Optional[CursorString] = UNSET
96
176
 
97
177
 
98
178
  def connection_from_list(
99
- data: List[GenericType],
179
+ data: list[NodeType],
100
180
  args: ConnectionArgs,
101
- ) -> Connection[GenericType]:
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: List[GenericType],
191
+ list_slice: list[NodeType],
112
192
  args: ConnectionArgs,
113
193
  slice_start: int,
114
194
  list_length: int,
115
- ) -> Connection[GenericType]:
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
- total_count=list_length,
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))