arize-phoenix 4.19.0__py3-none-any.whl → 4.20.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 (35) hide show
  1. {arize_phoenix-4.19.0.dist-info → arize_phoenix-4.20.1.dist-info}/METADATA +2 -1
  2. {arize_phoenix-4.19.0.dist-info → arize_phoenix-4.20.1.dist-info}/RECORD +35 -33
  3. phoenix/db/bulk_inserter.py +24 -98
  4. phoenix/db/insertion/document_annotation.py +13 -0
  5. phoenix/db/insertion/span_annotation.py +13 -0
  6. phoenix/db/insertion/trace_annotation.py +13 -0
  7. phoenix/db/insertion/types.py +34 -28
  8. phoenix/server/api/context.py +9 -7
  9. phoenix/server/api/dataloaders/__init__.py +0 -47
  10. phoenix/server/api/dataloaders/span_annotations.py +6 -9
  11. phoenix/server/api/mutations/dataset_mutations.py +44 -4
  12. phoenix/server/api/mutations/experiment_mutations.py +2 -0
  13. phoenix/server/api/mutations/project_mutations.py +5 -5
  14. phoenix/server/api/mutations/span_annotations_mutations.py +10 -2
  15. phoenix/server/api/mutations/trace_annotations_mutations.py +10 -2
  16. phoenix/server/api/queries.py +9 -0
  17. phoenix/server/api/routers/v1/datasets.py +2 -0
  18. phoenix/server/api/routers/v1/experiment_evaluations.py +2 -0
  19. phoenix/server/api/routers/v1/experiment_runs.py +2 -0
  20. phoenix/server/api/routers/v1/experiments.py +2 -0
  21. phoenix/server/api/routers/v1/spans.py +15 -9
  22. phoenix/server/api/routers/v1/traces.py +15 -11
  23. phoenix/server/api/types/Dataset.py +6 -1
  24. phoenix/server/api/types/Experiment.py +6 -1
  25. phoenix/server/api/types/Project.py +4 -1
  26. phoenix/server/api/types/Span.py +14 -13
  27. phoenix/server/app.py +25 -8
  28. phoenix/server/dml_event.py +136 -0
  29. phoenix/server/dml_event_handler.py +272 -0
  30. phoenix/server/types.py +106 -1
  31. phoenix/session/client.py +2 -2
  32. phoenix/version.py +1 -1
  33. {arize_phoenix-4.19.0.dist-info → arize_phoenix-4.20.1.dist-info}/WHEEL +0 -0
  34. {arize_phoenix-4.19.0.dist-info → arize_phoenix-4.20.1.dist-info}/licenses/IP_NOTICE +0 -0
  35. {arize_phoenix-4.19.0.dist-info → arize_phoenix-4.20.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 4.19.0
3
+ Version: 4.20.1
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -96,6 +96,7 @@ Requires-Dist: ruff==0.5.4; extra == 'dev'
96
96
  Requires-Dist: strawberry-graphql[debug-server,opentelemetry]==0.236.0; extra == 'dev'
97
97
  Requires-Dist: tabulate; extra == 'dev'
98
98
  Requires-Dist: types-tabulate; extra == 'dev'
99
+ Requires-Dist: uvloop; (platform_system != 'Windows') and extra == 'dev'
99
100
  Provides-Extra: evals
100
101
  Provides-Extra: experimental
101
102
  Provides-Extra: llama-index
@@ -5,7 +5,7 @@ phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
5
5
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
6
  phoenix/services.py,sha256=aTxhcOA1pZHB6U-B3TEcp6fqDF5oT0xCUvEUNMZVTUQ,5175
7
7
  phoenix/settings.py,sha256=cO-qgis_S27nHirTobYI9hHPfZH18R--WMmxNdsVUwc,273
8
- phoenix/version.py,sha256=Fp9FRZ7Y9YVSCh7eiorMVnopeqssImC_xE1F6sMNAaY,23
8
+ phoenix/version.py,sha256=x2GXndd_stTekM40AdALx0Eq-Nbip56uWQ4qvw-qCgE,23
9
9
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
11
11
  phoenix/core/model.py,sha256=km_a--PBHOuA337ClRw9xqhOHhrUT6Rl9pz_zV0JYkQ,4843
@@ -14,7 +14,7 @@ phoenix/core/model_schema_adapter.py,sha256=0Tm_Y_gV-WED8fKBCaFXAEFwE3CTEZS1dowq
14
14
  phoenix/db/README.md,sha256=IvKaZyf9ECbGBYYePaRhBveKZwDbxAc-c7BMxJYZh6Q,595
15
15
  phoenix/db/__init__.py,sha256=pDjEFXukHmJBM-1D8RjmXkvLsz85YWNxMQczt81ec3A,118
16
16
  phoenix/db/alembic.ini,sha256=p8DjVqGUs_tTx8oU56JP7qj-rMUebNFizItUSv_hPhs,3763
17
- phoenix/db/bulk_inserter.py,sha256=Mmtm5z44aHYIDcPT_8ImTeGC76VuhcG2KNkMfVKR0KU,16533
17
+ phoenix/db/bulk_inserter.py,sha256=qgg8pt5k4VnHKOE0-KoReXVAfXRhLt-sMZihI-b4X9I,12761
18
18
  phoenix/db/engines.py,sha256=R3btYTSOSd6BwRA59EmhhojL0HCQ7NnzFIXQrPYS0iU,4812
19
19
  phoenix/db/helpers.py,sha256=2zSc4n5IJfu-CaOFoBfqTB35M1nTFcAc8tqLsNtF2Jw,3488
20
20
  phoenix/db/migrate.py,sha256=MuhtNWnR24riROvarvKfbRb4_D5xuQi6P760vBUKl1E,2270
@@ -22,13 +22,13 @@ phoenix/db/models.py,sha256=7DBWbxY3cx3ve2P1I0kkDKXzlt04zEFJuRPJWsVpH-I,20422
22
22
  phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  phoenix/db/insertion/constants.py,sha256=8wifm7X-1XvroZ__R2Gc96NsgLhTDn0zXl4lehlXtcA,70
24
24
  phoenix/db/insertion/dataset.py,sha256=_vxy5e6W5jEuvO2fMKbbNCn9JvHkwI4LRKk_10eKFVg,7171
25
- phoenix/db/insertion/document_annotation.py,sha256=vMP1OkQ0GOC57aHLTErwF6cu6qHdBkjQFXbCwUtYYAs,5409
25
+ phoenix/db/insertion/document_annotation.py,sha256=qp8E63LzlthAScQg6opqln5Qg1d7UdtP3rkYL4riTgU,5983
26
26
  phoenix/db/insertion/evaluation.py,sha256=SoI85N3MYUSeNgjKa5WzFw14OfNjNTjExv-2m3sxaR8,6371
27
27
  phoenix/db/insertion/helpers.py,sha256=z_Wnckhdf-F7xadWgaAV5ScXnLft8EtaYJCuIkma2Vw,3486
28
28
  phoenix/db/insertion/span.py,sha256=T9jOW3lyWte-JGD7wlP2ZqtO0-V57d8z6U_TldnuGuk,5527
29
- phoenix/db/insertion/span_annotation.py,sha256=Aa33nhEsq6NlXbRZ46fl2rVVehityRtxi6NYDXzE9vU,4705
30
- phoenix/db/insertion/trace_annotation.py,sha256=eIza4k4ImOPu9iwlAt8gv-A0ESw5XLGEa4dKGVqNSxk,4765
31
- phoenix/db/insertion/types.py,sha256=H9o_LJ1DabMVyVv3NZYtmJ26WusyihwlzV7AA-TOgGY,8272
29
+ phoenix/db/insertion/span_annotation.py,sha256=eQK7fFjKjZGj25Qf_PTU9Q8DZiYJAw4lfcfdLKFsKe0,5259
30
+ phoenix/db/insertion/trace_annotation.py,sha256=36CwcxSvDo2r-_y_GlmMXGnlH4BKVaMu5BWM9w-9l7A,5324
31
+ phoenix/db/insertion/types.py,sha256=nQYYnpzcPxj2kdUoXfKE8ilOKlx1zpKLPc40OGuBlfk,8149
32
32
  phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  phoenix/db/migrations/env.py,sha256=QbzB5zrRs6XQQmrYeUpuzeilcMlM-MsbaAgHHYcIHTI,3626
34
34
  phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
@@ -65,20 +65,22 @@ phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYG
65
65
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
66
66
  phoenix/pointcloud/umap_parameters.py,sha256=3UQSjrysVOvq2V4KNpTMqNqNiK0BsTZnPBHWZ4fyJtQ,1708
67
67
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- phoenix/server/app.py,sha256=FqsV0CqFwzyPDmVeTSf3uwBC6DkyZXbiikSJkhS0Og8,19387
68
+ phoenix/server/app.py,sha256=1715YnPAPUUojIG6SYHCanSlMLahxPO3h0dKktLwVFU,19889
69
+ phoenix/server/dml_event.py,sha256=MpjCFqljxvgb9OB5Cez9vJesb3oHb3XxXictynBfcis,2851
70
+ phoenix/server/dml_event_handler.py,sha256=pKEWiDApy4mBHvp477mo0y94cm65r9gD5ggQgsA_hak,8460
69
71
  phoenix/server/grpc_server.py,sha256=jllxDNkpLQxDkvej4RhTokobowbvydF-SU8gSw1MTCc,3378
70
72
  phoenix/server/main.py,sha256=dvjv3g8ANpkvSGCUN02S2Yse643Nlwrp_bj4iXBSVTE,11082
71
73
  phoenix/server/prometheus.py,sha256=j9DHB2fERuq_ZKmwVaqR-9wx5WcPPuU1Cm5Bhg5241Y,2996
72
74
  phoenix/server/telemetry.py,sha256=T_2OKrxNViAeaANlNspEekg_Y5uZIFWvKAnpz8Aoqvk,2762
73
75
  phoenix/server/thread_server.py,sha256=RwXQGP_QhGD7le6WB7xEygEEuwBl5Ck_Zo8xGIYGi9M,2135
74
- phoenix/server/types.py,sha256=o3uwy8NvfLO-j86v2Dl3irko6er0hvB_x4Df3S1DveM,460
76
+ phoenix/server/types.py,sha256=UCCkwEzUAbRdu-hZpG7A2hdPM09onBezaXNtWX4A7og,3431
75
77
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
- phoenix/server/api/context.py,sha256=70fJ9_O2yD-JEiCUM6WuKr6Byw9Sq00z_q0gBFW0Acg,2940
78
+ phoenix/server/api/context.py,sha256=4YkrPe9AnB4l6qXSV5FsrqUdkXG1jxCU8ST7iTNlwZY,3047
77
79
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
78
- phoenix/server/api/queries.py,sha256=eq2xHaQF-x4k6AGSY6b6mU2pie9bj-AJML6P2Mr0_DM,19886
80
+ phoenix/server/api/queries.py,sha256=Nuw74Nh1XhDkLNV8hTO3WPPNeqcSlNhUF76r5HaytGc,20268
79
81
  phoenix/server/api/schema.py,sha256=BcxdqO5CSGqpKd-AAJHMjFlzaK9oJA8GJuxmMfcdjn4,434
80
82
  phoenix/server/api/utils.py,sha256=Kl47G-1A7QKTDrc75BU2QK6HupsG6MWuXxy351FOfKQ,858
81
- phoenix/server/api/dataloaders/__init__.py,sha256=aWL1--L5fOh6ouBS8VeJRJBtJogKTtRHySPpkr_AUGk,5506
83
+ phoenix/server/api/dataloaders/__init__.py,sha256=OaqWVJwb2BM2lDHVbILCdpjbB4M5w2UYFXIz_FEO0YI,3476
82
84
  phoenix/server/api/dataloaders/annotation_summaries.py,sha256=Wv8AORZoGd5TJ4Y-em8iqJu87AMpZP7lWOTr-SML-x8,5560
83
85
  phoenix/server/api/dataloaders/average_experiment_run_latency.py,sha256=q091UmkXx37OBKh7L-GJ5LXHyRXfX2w4XTk1NMHtPpw,1827
84
86
  phoenix/server/api/dataloaders/dataset_example_revisions.py,sha256=i0g8F4akEf3kQOzAvBjO27QwXNsq-kJEM8dtzduxQgY,3720
@@ -95,7 +97,7 @@ phoenix/server/api/dataloaders/latency_ms_quantile.py,sha256=5Y2OQ_GeH1My2573eOm
95
97
  phoenix/server/api/dataloaders/min_start_or_max_end_times.py,sha256=k82jVllBWkGI6xu2MAltqxdIqyw3DqoVCQcKbi-JsmM,2834
96
98
  phoenix/server/api/dataloaders/project_by_name.py,sha256=9p6DW_zXrsB9YGILFV0wkRwiapyHbZ1IgWK9HuHxl30,1105
97
99
  phoenix/server/api/dataloaders/record_counts.py,sha256=64OsyiQRDZASlibpQAXtRkzyA_ch89A3TvhSUByxoTI,4215
98
- phoenix/server/api/dataloaders/span_annotations.py,sha256=QsbAGPFitFxOCI9yJPPlueuMh0LqN18hMo-Vx2P8EsI,1194
100
+ phoenix/server/api/dataloaders/span_annotations.py,sha256=v3vGkLGTn-n4khxXZY2btgvfXitvytWgBahzrrWEz0I,1078
99
101
  phoenix/server/api/dataloaders/span_dataset_examples.py,sha256=BtLZp11fyyeaWGGBPZj2StzFM0m5jxt52zB2nFMVybo,1306
100
102
  phoenix/server/api/dataloaders/span_descendants.py,sha256=b7jGTn0Hi22gv2yskloLnf3BG3upS9z5hnKLMT9Sxac,2094
101
103
  phoenix/server/api/dataloaders/span_evaluations.py,sha256=IfwXW23GQaWti8F49wSJocWf7Tklf2ZJ0F6aB4cSVHs,1248
@@ -137,26 +139,26 @@ phoenix/server/api/input_types/TraceAnnotationSort.py,sha256=BzwiUnMh2VsgQYnhDlb
137
139
  phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
140
  phoenix/server/api/mutations/__init__.py,sha256=UKUAhD5NY-ZI7XONnRRkaHoFuuU3idmE4fk6Sjgy18M,776
139
141
  phoenix/server/api/mutations/auth.py,sha256=vPRFoj7J6PV6QeODewG4K0PhoOebS5AfMRpbi_wuhyQ,311
140
- phoenix/server/api/mutations/dataset_mutations.py,sha256=CuKhxsYfvwVcdN_9EXhKxB6444BQfObzKzzyfAeg-n8,23199
141
- phoenix/server/api/mutations/experiment_mutations.py,sha256=vV2lbJ7ccXZqe-LY7nXx6QxWqhKQE4UNZAFcML-KQ8I,3011
142
+ phoenix/server/api/mutations/dataset_mutations.py,sha256=p3cqYCLb6zf_Dx8ju0R8FMLT5ZBW_ZQXDyP1iw1zA3E,25280
143
+ phoenix/server/api/mutations/experiment_mutations.py,sha256=OXtLYdLA33RGy1MFctfv6ug2sODcDElhJph_J9vkIjk,3157
142
144
  phoenix/server/api/mutations/export_events_mutations.py,sha256=t_wYBxaqvBJYRoHslh3Bmoxmwlzoy0u8SsBKWIKN5hE,4028
143
- phoenix/server/api/mutations/project_mutations.py,sha256=d_xtYkYfZ5flpVgEkGknKB8rsEux-zZraczzqAs4e8A,2255
144
- phoenix/server/api/mutations/span_annotations_mutations.py,sha256=C6sBOe0EbClj6pYSODBsmJ_mrrYtMFaMZkPO0Be-5I0,5410
145
- phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=GtI_kDpzLDBFjh0CkYjCgVfdBCog7aKHlIVsEM2x92k,5379
145
+ phoenix/server/api/mutations/project_mutations.py,sha256=MLm7I97lJ85hTuc1tq8sdYA8Ps5WKMV-bGqeeN-Ey90,2279
146
+ phoenix/server/api/mutations/span_annotations_mutations.py,sha256=DM9gzxrMSAcxwXQ6jNaNGDVgl8oP50LZsBWRYQwLaSo,5955
147
+ phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=VDiNzX63Agci7WeMbiK-C770JedlC5R7TZVe1UaRhDE,5930
146
148
  phoenix/server/api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
149
  phoenix/server/api/openapi/main.py,sha256=KNutA_7AvV_WlGX8cOkvvDujcJKQ7AD1HT6rTpCpR8A,616
148
150
  phoenix/server/api/openapi/schema.py,sha256=oVZoflWMfzOrLKMIrjr3iLnJ13rmN-t_DOe9g6KoN5s,471
149
151
  phoenix/server/api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
152
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
151
153
  phoenix/server/api/routers/v1/__init__.py,sha256=nb49zcOdAi3DSGuC9gUubN9Yri-o7-WFdlGak4jGuFw,1462
152
- phoenix/server/api/routers/v1/datasets.py,sha256=QG6QeyfPi1tfBvVoa3jpNOcwtR5ntNfd3IW9rzP735Q,36920
154
+ phoenix/server/api/routers/v1/datasets.py,sha256=pyLtVEGnjwxh1wJySBOUFrsjtawatfpaF8F3WijK8qU,37049
153
155
  phoenix/server/api/routers/v1/evaluations.py,sha256=FSfz9MTi8s65F07abDXlb9-y97fDZSYbqsCXpimwO7g,12628
154
- phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=xoVhU71U3c1QJSXiKsAa4yiH-UAqkyVc7uKPyIHjrYY,4682
155
- phoenix/server/api/routers/v1/experiment_runs.py,sha256=7qvLYgqH58nxqhTnJ0hPf0PBfVmZnbxquodSnEGoQxk,6059
156
- phoenix/server/api/routers/v1/experiments.py,sha256=AFJb8Pi6SDKbIbkDRWUtPjikZIoRhc7cFLWm40l3mPk,9817
156
+ phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=RTQnjupjmh07xowjq77ajbuAZhzIEfYxA4ZtECvGwOU,4844
157
+ phoenix/server/api/routers/v1/experiment_runs.py,sha256=dr7oA3RMyFVON4Dq3fJtDoTeXETcglWVYAakVW8zyZw,6196
158
+ phoenix/server/api/routers/v1/experiments.py,sha256=GeT3Rya4bdaCr6sCf2Vx6fQ_gfMX5XyFHmODCSJiCfU,9951
157
159
  phoenix/server/api/routers/v1/pydantic_compat.py,sha256=FeK8oe2brqu-djsoqRxiKL4tw5cHmi89OHVfCFxYsAo,2890
158
- phoenix/server/api/routers/v1/spans.py,sha256=-nDcr0AjynS-0U6A2nxEQiUTLoNyfzE-3NiFObyfyVQ,8516
159
- phoenix/server/api/routers/v1/traces.py,sha256=4k_57UICPfRcyQsdPBK-Xo_n6oZ1p41XUwXhZEQpXwE,7568
160
+ phoenix/server/api/routers/v1/spans.py,sha256=Hd63VHQUqSy0VHsYQ5DPLf5WwKALMXZOIh_ig_5MStc,8780
161
+ phoenix/server/api/routers/v1/traces.py,sha256=HJDmYKMATL40dZEJro6uQ3imbCZBzk3nUun9d21jcDs,7799
160
162
  phoenix/server/api/routers/v1/utils.py,sha256=xvl2v-BKUkqmFVMmgmmWGFKuRBTrUdoiAeT3mCYEE68,3086
161
163
  phoenix/server/api/types/Annotation.py,sha256=7Ym7iuVcbwHlw2yIRylz4nATAF_Cm-Z17qcjiooj1cc,751
162
164
  phoenix/server/api/types/AnnotationSummary.py,sha256=8B2LIROqcrPOi8hvYygsblKvSEBfSrysnKOV7F36hgA,1518
@@ -164,7 +166,7 @@ phoenix/server/api/types/AnnotatorKind.py,sha256=rPgGdbN1Gvc109sGQ_ZH-gfJbp93V9w
164
166
  phoenix/server/api/types/Cluster.py,sha256=ac4YfT1OH3xLVmex7EUmB6b9IpULnhLTt554LR0jglE,5689
165
167
  phoenix/server/api/types/CreateDatasetPayload.py,sha256=R-6zCmuD0f76RU9Giu78xwTHlASQs6Aq8yzvX1Kxc3g,140
166
168
  phoenix/server/api/types/DataQualityMetric.py,sha256=zRKsNvHBu-NdcsunuLhqFpZhi6ks-HMqA1PJD27jTak,590
167
- phoenix/server/api/types/Dataset.py,sha256=zHxWuteqBA2dgO9BsCTpSaUTzrvTs4z9uRwaTCEi8eg,11470
169
+ phoenix/server/api/types/Dataset.py,sha256=ustwo9GVsiE14RvDzL37xlLKOAn_qdI0SwJTNr5JY3E,11724
168
170
  phoenix/server/api/types/DatasetExample.py,sha256=5f7DO6jRec1G5jaJW5FrykFU9R07jDn8jxDkNbQX0Ek,3107
169
171
  phoenix/server/api/types/DatasetExampleRevision.py,sha256=c-jWR6dTguEZTm54IMlFr0Ic84I3nefyDnZb7nF5hnI,874
170
172
  phoenix/server/api/types/DatasetValues.py,sha256=7VbCOLlzOXpZN80-zYF2UGuafRcPsZF-8WQNc0YsKFc,1119
@@ -183,7 +185,7 @@ phoenix/server/api/types/EvaluationSummary.py,sha256=N1DhPXGhBbOOQakF43OGuZ5fl4v
183
185
  phoenix/server/api/types/Event.py,sha256=XdYgaIxcVIW-YFViCkxj5l9OaVNepyIrCtm5Iqg2le8,3989
184
186
  phoenix/server/api/types/EventMetadata.py,sha256=-J0tYF9eZTHwCjwxQHY7Gckr2_MNW5OoWT1mydweZNM,635
185
187
  phoenix/server/api/types/ExampleRevisionInterface.py,sha256=gV3Gt9-3Oi5wjaVtepC6nOt3FzTzZFD1KebNnqiw56E,294
186
- phoenix/server/api/types/Experiment.py,sha256=K-3w6dniPRSMO4v-4ToDRwH2xr4fPaDumoyeT4We7g4,5228
188
+ phoenix/server/api/types/Experiment.py,sha256=YNs8SzOMSYUKiAMANuWSv8NxSNFzSIFOBOWb_yztE0s,5482
187
189
  phoenix/server/api/types/ExperimentAnnotationSummary.py,sha256=Uk3JtxIrsMoZT5tqc4nJdUOM3XegVzjUyoV3pkjNotE,256
188
190
  phoenix/server/api/types/ExperimentComparison.py,sha256=0sFz6MoBDw39dds0qVyaqhVs9qqO5rkG1FMSjmfBeCc,441
189
191
  phoenix/server/api/types/ExperimentRun.py,sha256=122_SID7SLKPUq2dJ2Y4BBw40DNUtcxo6QCZuO8UbBs,2997
@@ -197,13 +199,13 @@ phoenix/server/api/types/MimeType.py,sha256=Zpi6zCalkSFgsvhzvOs-O1gYA04usAi9H__Q
197
199
  phoenix/server/api/types/Model.py,sha256=BRIzH5xSGiDrAUYvhwDpwxT6--ddS3Xr3vCvP8_vzdo,8051
198
200
  phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
199
201
  phoenix/server/api/types/PerformanceMetric.py,sha256=W92B7OghEOgzFvmY0LCqpgavHaQggTGshdgfD0yqHX4,350
200
- phoenix/server/api/types/Project.py,sha256=w9SMSBSZeir_biPtgsDa8B30ASyGQH1JoBvxIy-Oz-M,15418
202
+ phoenix/server/api/types/Project.py,sha256=f29k2bsDIQTvqDkgW_dA9ufpQAmw6XEWwiPrv-AaASk,15506
201
203
  phoenix/server/api/types/PromptResponse.py,sha256=Q8HKtpp8GpUOcxPCzZpkkokidDd6u0aZOv_SuPZZd5Q,630
202
204
  phoenix/server/api/types/Retrieval.py,sha256=OhMK2ncjoyp5h1yjKhjlKpoTbQrMHuxmgSFw-AO1rWw,285
203
205
  phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2Te38SspXGyEs-S1fY23_A,232
204
206
  phoenix/server/api/types/Segments.py,sha256=m2yoegrxA1Tn7ZAy1rMjjD1isc752MaAXMoffkBlvrM,2921
205
207
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
206
- phoenix/server/api/types/Span.py,sha256=PRVjcC79qyxz8FW-YT90rDgcW8dkVO9_5pXxUXeH31g,15448
208
+ phoenix/server/api/types/Span.py,sha256=k3j8P06927jNK5P8VrqQLRhOu3pyiPlV5wdiGdXC1cE,15263
207
209
  phoenix/server/api/types/SpanAnnotation.py,sha256=6b5G-b_OoRvDL2ayWk7MkbqarLK-F-pQMx21CpUuNGY,1168
208
210
  phoenix/server/api/types/TimeSeries.py,sha256=wjzuxHFqCey0O7Ys25qiXyuqXK8an-osyNWUE8A_8G4,5227
209
211
  phoenix/server/api/types/Trace.py,sha256=-nh3A-S_BlQK1VSSOTWqM85l-WwJsRHifxeDi0sFWZE,3246
@@ -238,7 +240,7 @@ phoenix/server/static/assets/vendor-three-DwGkEfCM.js,sha256=0D12ZgKzfKCTSdSTKJB
238
240
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
241
  phoenix/server/templates/index.html,sha256=gVpjB8pCMiubdMh2DA9mTCtV5AVTXJH_9u5PmG2t7Vk,4238
240
242
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
241
- phoenix/session/client.py,sha256=RSaEALbFu-En5oJLv7K4BmwdkrsIC5ZbjMX7Mlny8_Y,32665
243
+ phoenix/session/client.py,sha256=C-NpmDkcyGZHR0vv5gWtteUi01cIorjWnqie9WuZb9s,32663
242
244
  phoenix/session/data_extractor.py,sha256=gkEM3WWZAlWGMfRgQopAQlid4cSi6GNco-sdrGir0qc,2788
243
245
  phoenix/session/evaluation.py,sha256=aKeV8UVOyq3b7CYOwt3cWuLz0xzvMjX7vlEPILJ_fcs,5311
244
246
  phoenix/session/session.py,sha256=l10fiotlO1b-SFehcm8N3aVupdFUYYLiLSBrOCJO9as,26911
@@ -279,8 +281,8 @@ phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,
279
281
  phoenix/utilities/project.py,sha256=8IJuMM4yUMoooPi37sictGj8Etu9rGmq6RFtc9848cQ,436
280
282
  phoenix/utilities/re.py,sha256=PDve_OLjRTM8yQQJHC8-n3HdIONi7aNils3ZKRZ5uBM,2045
281
283
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
282
- arize_phoenix-4.19.0.dist-info/METADATA,sha256=XNi1_9Af0PcDBKgp1T34UljJcp4wbJ21lXL4b4o0s5s,11829
283
- arize_phoenix-4.19.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
284
- arize_phoenix-4.19.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
285
- arize_phoenix-4.19.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
286
- arize_phoenix-4.19.0.dist-info/RECORD,,
284
+ arize_phoenix-4.20.1.dist-info/METADATA,sha256=m65-hbRGN_Pg_ajtvbWhoKoGdqvq4Y8o3_850jJTGKM,11902
285
+ arize_phoenix-4.20.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
286
+ arize_phoenix-4.20.1.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
287
+ arize_phoenix-4.20.1.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
288
+ arize_phoenix-4.20.1.dist-info/RECORD,,
@@ -1,38 +1,29 @@
1
1
  import asyncio
2
2
  import logging
3
3
  from asyncio import Queue, as_completed
4
- from collections import defaultdict
5
4
  from dataclasses import dataclass, field
6
- from datetime import datetime, timezone
7
5
  from functools import singledispatchmethod
8
6
  from itertools import islice
9
7
  from time import perf_counter
10
8
  from typing import (
11
9
  Any,
10
+ AsyncIterator,
12
11
  Awaitable,
13
12
  Callable,
14
- DefaultDict,
15
- Dict,
16
13
  Iterable,
17
14
  List,
18
- Mapping,
19
15
  Optional,
20
16
  Set,
21
17
  Tuple,
22
- Type,
23
18
  cast,
24
19
  )
25
20
 
26
- from cachetools import LRUCache
27
- from sqlalchemy import Select, select
28
21
  from typing_extensions import TypeAlias
29
22
 
30
23
  import phoenix.trace.v1 as pb
31
- from phoenix.db import models
32
24
  from phoenix.db.insertion.constants import DEFAULT_RETRY_ALLOWANCE, DEFAULT_RETRY_DELAY_SEC
33
25
  from phoenix.db.insertion.document_annotation import DocumentAnnotationQueueInserter
34
26
  from phoenix.db.insertion.evaluation import (
35
- EvaluationInsertionEvent,
36
27
  InsertEvaluationError,
37
28
  insert_evaluation,
38
29
  )
@@ -41,8 +32,8 @@ from phoenix.db.insertion.span import SpanInsertionEvent, insert_span
41
32
  from phoenix.db.insertion.span_annotation import SpanAnnotationQueueInserter
42
33
  from phoenix.db.insertion.trace_annotation import TraceAnnotationQueueInserter
43
34
  from phoenix.db.insertion.types import Insertables, Precursors
44
- from phoenix.server.api.dataloaders import CacheForDataLoaders
45
- from phoenix.server.types import DbSessionFactory
35
+ from phoenix.server.dml_event import DmlEvent, SpanInsertEvent
36
+ from phoenix.server.types import CanPutItem, DbSessionFactory
46
37
  from phoenix.trace.schemas import Span
47
38
 
48
39
  logger = logging.getLogger(__name__)
@@ -60,8 +51,7 @@ class BulkInserter:
60
51
  self,
61
52
  db: DbSessionFactory,
62
53
  *,
63
- cache_for_dataloaders: Optional[CacheForDataLoaders] = None,
64
- initial_batch_of_operations: Iterable[DataManipulation] = (),
54
+ event_queue: CanPutItem[DmlEvent],
65
55
  initial_batch_of_spans: Optional[Iterable[Tuple[Span, str]]] = None,
66
56
  initial_batch_of_evaluations: Optional[Iterable[pb.Evaluation]] = None,
67
57
  sleep: float = 0.1,
@@ -93,18 +83,12 @@ class BulkInserter:
93
83
  [] if initial_batch_of_evaluations is None else list(initial_batch_of_evaluations)
94
84
  )
95
85
  self._task: Optional[asyncio.Task[None]] = None
96
- self._last_updated_at_by_project: LRUCache[ProjectRowId, datetime] = LRUCache(maxsize=100)
97
- self._cache_for_dataloaders = cache_for_dataloaders
86
+ self._event_queue = event_queue
98
87
  self._enable_prometheus = enable_prometheus
99
88
  self._retry_delay_sec = retry_delay_sec
100
89
  self._retry_allowance = retry_allowance
101
90
  self._queue_inserters = _QueueInserters(db, self._retry_delay_sec, self._retry_allowance)
102
91
 
103
- def last_updated_at(self, project_rowid: Optional[ProjectRowId] = None) -> Optional[datetime]:
104
- if isinstance(project_rowid, ProjectRowId):
105
- return self._last_updated_at_by_project.get(project_rowid)
106
- return max(self._last_updated_at_by_project.values(), default=None)
107
-
108
92
  async def __aenter__(
109
93
  self,
110
94
  ) -> Tuple[
@@ -162,21 +146,20 @@ class BulkInserter:
162
146
  ):
163
147
  await asyncio.sleep(self._sleep)
164
148
  continue
165
- ops_remaining, events = self._max_ops_per_transaction, []
149
+ ops_remaining = self._max_ops_per_transaction
166
150
  async with self._db() as session:
167
151
  while ops_remaining and not self._operations.empty():
168
152
  ops_remaining -= 1
169
153
  op = await self._operations.get()
170
154
  try:
171
155
  async with session.begin_nested():
172
- events.append(await op(session))
156
+ await op(session)
173
157
  except Exception as e:
174
158
  if self._enable_prometheus:
175
159
  from phoenix.server.prometheus import BULK_LOADER_EXCEPTIONS
176
160
 
177
161
  BULK_LOADER_EXCEPTIONS.inc()
178
162
  logger.exception(str(e))
179
- await self._process_events(events)
180
163
  # It's important to grab the buffers at the same time so there's
181
164
  # no race condition, since an eval insertion will fail if the span
182
165
  # it references doesn't exist. Grabbing the eval buffer later may
@@ -190,25 +173,18 @@ class BulkInserter:
190
173
  self._evaluations = []
191
174
  # Spans should be inserted before the evaluations, since an evaluation
192
175
  # insertion will fail if the span it references doesn't exist.
193
- transaction_result = TransactionResult()
194
176
  if spans_buffer:
195
- result = await self._insert_spans(spans_buffer)
196
- transaction_result.updated_project_rowids.update(result.updated_project_rowids)
177
+ await self._insert_spans(spans_buffer)
197
178
  spans_buffer = None
198
179
  if evaluations_buffer:
199
- result = await self._insert_evaluations(evaluations_buffer)
200
- transaction_result.updated_project_rowids.update(result.updated_project_rowids)
180
+ await self._insert_evaluations(evaluations_buffer)
201
181
  evaluations_buffer = None
202
- for project_rowid in transaction_result.updated_project_rowids:
203
- self._last_updated_at_by_project[project_rowid] = datetime.now(timezone.utc)
204
- if not self._queue_inserters.empty:
205
- if inserted_ids := await self._queue_inserters.insert():
206
- for project_rowid in await self._get_project_rowids(inserted_ids):
207
- self._last_updated_at_by_project[project_rowid] = datetime.now(timezone.utc)
182
+ async for event in self._queue_inserters.insert():
183
+ self._event_queue.put(event)
208
184
  await asyncio.sleep(self._sleep)
209
185
 
210
- async def _insert_spans(self, spans: List[Tuple[Span, str]]) -> TransactionResult:
211
- transaction_result = TransactionResult()
186
+ async def _insert_spans(self, spans: List[Tuple[Span, str]]) -> None:
187
+ project_ids = set()
212
188
  for i in range(0, len(spans), self._max_ops_per_transaction):
213
189
  try:
214
190
  start = perf_counter()
@@ -231,9 +207,7 @@ class BulkInserter:
231
207
  f"Failed to insert span with span_id={span.context.span_id}"
232
208
  )
233
209
  if result is not None:
234
- transaction_result.updated_project_rowids.add(result.project_rowid)
235
- if (cache := self._cache_for_dataloaders) is not None:
236
- cache.invalidate(result)
210
+ project_ids.add(result.project_rowid)
237
211
  if self._enable_prometheus:
238
212
  from phoenix.server.prometheus import BULK_LOADER_INSERTION_TIME
239
213
 
@@ -244,10 +218,9 @@ class BulkInserter:
244
218
 
245
219
  BULK_LOADER_EXCEPTIONS.inc()
246
220
  logger.exception("Failed to insert spans")
247
- return transaction_result
221
+ self._event_queue.put(SpanInsertEvent(tuple(project_ids)))
248
222
 
249
- async def _insert_evaluations(self, evaluations: List[pb.Evaluation]) -> TransactionResult:
250
- transaction_result = TransactionResult()
223
+ async def _insert_evaluations(self, evaluations: List[pb.Evaluation]) -> None:
251
224
  for i in range(0, len(evaluations), self._max_ops_per_transaction):
252
225
  try:
253
226
  start = perf_counter()
@@ -257,20 +230,15 @@ class BulkInserter:
257
230
  from phoenix.server.prometheus import BULK_LOADER_EVALUATION_INSERTIONS
258
231
 
259
232
  BULK_LOADER_EVALUATION_INSERTIONS.inc()
260
- result: Optional[EvaluationInsertionEvent] = None
261
233
  try:
262
234
  async with session.begin_nested():
263
- result = await insert_evaluation(session, evaluation)
235
+ await insert_evaluation(session, evaluation)
264
236
  except InsertEvaluationError as error:
265
237
  if self._enable_prometheus:
266
238
  from phoenix.server.prometheus import BULK_LOADER_EXCEPTIONS
267
239
 
268
240
  BULK_LOADER_EXCEPTIONS.inc()
269
241
  logger.exception(f"Failed to insert evaluation: {str(error)}")
270
- if result is not None:
271
- transaction_result.updated_project_rowids.add(result.project_rowid)
272
- if (cache := self._cache_for_dataloaders) is not None:
273
- cache.invalidate(result)
274
242
  if self._enable_prometheus:
275
243
  from phoenix.server.prometheus import BULK_LOADER_INSERTION_TIME
276
244
 
@@ -281,48 +249,6 @@ class BulkInserter:
281
249
 
282
250
  BULK_LOADER_EXCEPTIONS.inc()
283
251
  logger.exception("Failed to insert evaluations")
284
- return transaction_result
285
-
286
- async def _get_project_rowids(
287
- self,
288
- inserted_ids: Mapping[Type[models.Base], List[int]],
289
- ) -> Set[int]:
290
- ans: Set[int] = set()
291
- if not inserted_ids:
292
- return ans
293
- stmt: Select[Tuple[int]]
294
- for table, ids in inserted_ids.items():
295
- if not ids:
296
- continue
297
- if issubclass(table, models.SpanAnnotation):
298
- stmt = (
299
- select(models.Project.id)
300
- .join(models.Trace)
301
- .join_from(models.Trace, models.Span)
302
- .join_from(models.Span, models.SpanAnnotation)
303
- .where(models.SpanAnnotation.id.in_(ids))
304
- )
305
- elif issubclass(table, models.DocumentAnnotation):
306
- stmt = (
307
- select(models.Project.id)
308
- .join(models.Trace)
309
- .join_from(models.Trace, models.Span)
310
- .join_from(models.Span, models.DocumentAnnotation)
311
- .where(models.DocumentAnnotation.id.in_(ids))
312
- )
313
- elif issubclass(table, models.TraceAnnotation):
314
- stmt = (
315
- select(models.Project.id)
316
- .join(models.Trace)
317
- .join_from(models.Trace, models.TraceAnnotation)
318
- .where(models.TraceAnnotation.id.in_(ids))
319
- )
320
- else:
321
- continue
322
- async with self._db() as session:
323
- project_rowids = [_ async for _ in await session.stream_scalars(stmt)]
324
- ans.update(project_rowids)
325
- return ans
326
252
 
327
253
 
328
254
  class _QueueInserters:
@@ -343,13 +269,13 @@ class _QueueInserters:
343
269
  self._document_annotations,
344
270
  )
345
271
 
346
- async def insert(self) -> Dict[Type[models.Base], List[int]]:
347
- ans: DefaultDict[Type[models.Base], List[int]] = defaultdict(list)
348
- for coro in as_completed([q.insert() for q in self._queues]):
349
- table, inserted_ids = await coro
350
- if inserted_ids:
351
- ans[table].extend(inserted_ids)
352
- return ans
272
+ async def insert(self) -> AsyncIterator[DmlEvent]:
273
+ if self.empty:
274
+ return
275
+ for coro in as_completed([q.insert() for q in self._queues if not q.empty]):
276
+ if events := cast(Optional[List[DmlEvent]], await coro):
277
+ for event in events:
278
+ yield event
353
279
 
354
280
  @property
355
281
  def empty(self) -> bool:
@@ -7,6 +7,7 @@ from typing_extensions import TypeAlias
7
7
 
8
8
  from phoenix.db import models
9
9
  from phoenix.db.helpers import dedup, num_docs_col
10
+ from phoenix.db.insertion.helpers import as_kv
10
11
  from phoenix.db.insertion.types import (
11
12
  Insertables,
12
13
  Postponed,
@@ -14,6 +15,7 @@ from phoenix.db.insertion.types import (
14
15
  QueueInserter,
15
16
  Received,
16
17
  )
18
+ from phoenix.server.dml_event import DocumentAnnotationDmlEvent
17
19
 
18
20
  _Name: TypeAlias = str
19
21
  _SpanId: TypeAlias = str
@@ -40,10 +42,21 @@ class DocumentAnnotationQueueInserter(
40
42
  Precursors.DocumentAnnotation,
41
43
  Insertables.DocumentAnnotation,
42
44
  models.DocumentAnnotation,
45
+ DocumentAnnotationDmlEvent,
43
46
  ],
44
47
  table=models.DocumentAnnotation,
45
48
  unique_by=("name", "span_rowid", "document_position"),
46
49
  ):
50
+ async def _events(
51
+ self,
52
+ session: AsyncSession,
53
+ *insertions: Insertables.DocumentAnnotation,
54
+ ) -> List[DocumentAnnotationDmlEvent]:
55
+ records = [dict(as_kv(ins.row)) for ins in insertions]
56
+ stmt = self._insert_on_conflict(*records).returning(self.table.id)
57
+ ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
58
+ return [DocumentAnnotationDmlEvent(ids)]
59
+
47
60
  async def _partition(
48
61
  self,
49
62
  session: AsyncSession,
@@ -7,6 +7,7 @@ from typing_extensions import TypeAlias
7
7
 
8
8
  from phoenix.db import models
9
9
  from phoenix.db.helpers import dedup
10
+ from phoenix.db.insertion.helpers import as_kv
10
11
  from phoenix.db.insertion.types import (
11
12
  Insertables,
12
13
  Postponed,
@@ -14,6 +15,7 @@ from phoenix.db.insertion.types import (
14
15
  QueueInserter,
15
16
  Received,
16
17
  )
18
+ from phoenix.server.dml_event import SpanAnnotationDmlEvent
17
19
 
18
20
  _Name: TypeAlias = str
19
21
  _SpanId: TypeAlias = str
@@ -36,10 +38,21 @@ class SpanAnnotationQueueInserter(
36
38
  Precursors.SpanAnnotation,
37
39
  Insertables.SpanAnnotation,
38
40
  models.SpanAnnotation,
41
+ SpanAnnotationDmlEvent,
39
42
  ],
40
43
  table=models.SpanAnnotation,
41
44
  unique_by=("name", "span_rowid"),
42
45
  ):
46
+ async def _events(
47
+ self,
48
+ session: AsyncSession,
49
+ *insertions: Insertables.SpanAnnotation,
50
+ ) -> List[SpanAnnotationDmlEvent]:
51
+ records = [dict(as_kv(ins.row)) for ins in insertions]
52
+ stmt = self._insert_on_conflict(*records).returning(self.table.id)
53
+ ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
54
+ return [SpanAnnotationDmlEvent(ids)]
55
+
43
56
  async def _partition(
44
57
  self,
45
58
  session: AsyncSession,
@@ -7,6 +7,7 @@ from typing_extensions import TypeAlias
7
7
 
8
8
  from phoenix.db import models
9
9
  from phoenix.db.helpers import dedup
10
+ from phoenix.db.insertion.helpers import as_kv
10
11
  from phoenix.db.insertion.types import (
11
12
  Insertables,
12
13
  Postponed,
@@ -14,6 +15,7 @@ from phoenix.db.insertion.types import (
14
15
  QueueInserter,
15
16
  Received,
16
17
  )
18
+ from phoenix.server.dml_event import TraceAnnotationDmlEvent
17
19
 
18
20
  _Name: TypeAlias = str
19
21
  _TraceId: TypeAlias = str
@@ -36,10 +38,21 @@ class TraceAnnotationQueueInserter(
36
38
  Precursors.TraceAnnotation,
37
39
  Insertables.TraceAnnotation,
38
40
  models.TraceAnnotation,
41
+ TraceAnnotationDmlEvent,
39
42
  ],
40
43
  table=models.TraceAnnotation,
41
44
  unique_by=("name", "trace_rowid"),
42
45
  ):
46
+ async def _events(
47
+ self,
48
+ session: AsyncSession,
49
+ *insertions: Insertables.TraceAnnotation,
50
+ ) -> List[TraceAnnotationDmlEvent]:
51
+ records = [dict(as_kv(ins.row)) for ins in insertions]
52
+ stmt = self._insert_on_conflict(*records).returning(self.table.id)
53
+ ids = tuple([_ async for _ in await session.stream_scalars(stmt)])
54
+ return [TraceAnnotationDmlEvent(ids)]
55
+
43
56
  async def _partition(
44
57
  self,
45
58
  session: AsyncSession,