pyspiral 0.8.1__cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 0.9.8__cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- {pyspiral-0.8.1.dist-info → pyspiral-0.9.8.dist-info}/METADATA +4 -2
- {pyspiral-0.8.1.dist-info → pyspiral-0.9.8.dist-info}/RECORD +53 -44
- spiral/__init__.py +3 -2
- spiral/_lib.abi3.so +0 -0
- spiral/adbc.py +2 -2
- spiral/api/__init__.py +26 -19
- spiral/api/client.py +86 -9
- spiral/api/filesystems.py +24 -6
- spiral/api/organizations.py +2 -1
- spiral/api/projects.py +5 -3
- spiral/api/tables.py +77 -0
- spiral/api/workloads.py +4 -4
- spiral/arrow_.py +4 -155
- spiral/cli/admin.py +19 -0
- spiral/cli/app.py +11 -5
- spiral/cli/chooser.py +30 -0
- spiral/cli/fs.py +43 -9
- spiral/cli/iceberg.py +1 -1
- spiral/cli/key_spaces.py +4 -4
- spiral/cli/orgs.py +10 -19
- spiral/cli/projects.py +6 -5
- spiral/cli/tables.py +70 -21
- spiral/cli/telemetry.py +13 -6
- spiral/cli/text.py +4 -4
- spiral/cli/transactions.py +84 -0
- spiral/cli/{types.py → types_.py} +8 -8
- spiral/cli/workloads.py +64 -36
- spiral/client.py +87 -13
- spiral/core/client/__init__.pyi +37 -20
- spiral/core/expr/pushdown/__init__.pyi +3 -0
- spiral/core/expr/s3/__init__.pyi +3 -0
- spiral/core/table/__init__.pyi +25 -22
- spiral/dataloader.py +13 -2
- spiral/debug/manifests.py +46 -18
- spiral/debug/scan.py +4 -6
- spiral/demo.py +207 -0
- spiral/enrichment.py +18 -23
- spiral/expressions/__init__.py +3 -75
- spiral/expressions/base.py +5 -10
- spiral/expressions/pushdown.py +12 -0
- spiral/expressions/udf.py +7 -1
- spiral/huggingface.py +456 -0
- spiral/input.py +131 -0
- spiral/project.py +32 -12
- spiral/ray_.py +85 -0
- spiral/scan.py +257 -65
- spiral/server.py +20 -0
- spiral/settings.py +1 -1
- spiral/snapshot.py +10 -5
- spiral/table.py +16 -11
- spiral/transaction.py +101 -15
- spiral/iterable_dataset.py +0 -106
- {pyspiral-0.8.1.dist-info → pyspiral-0.9.8.dist-info}/WHEEL +0 -0
- {pyspiral-0.8.1.dist-info → pyspiral-0.9.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyspiral
|
|
3
|
-
Version: 0.8
|
|
3
|
+
Version: 0.9.8
|
|
4
4
|
Classifier: Intended Audience :: Science/Research
|
|
5
5
|
Classifier: Operating System :: OS Independent
|
|
6
6
|
Classifier: Programming Language :: Python
|
|
@@ -31,17 +31,19 @@ Requires-Dist: xxhash>=3.4.1
|
|
|
31
31
|
Requires-Dist: polars>=1.31.0 ; extra == 'polars'
|
|
32
32
|
Requires-Dist: duckdb>=1.3.2 ; extra == 'duckdb'
|
|
33
33
|
Requires-Dist: pyiceberg[s3fs]>=0.9.1 ; extra == 'iceberg'
|
|
34
|
-
Requires-Dist: datasets>=4.
|
|
34
|
+
Requires-Dist: datasets>=4.3.0 ; extra == 'huggingface'
|
|
35
35
|
Requires-Dist: mosaicml-streaming>=0.13.0 ; extra == 'streaming'
|
|
36
36
|
Requires-Dist: vortex-data>=0.52.1 ; extra == 'streaming'
|
|
37
37
|
Requires-Dist: dask>=2025.10.0 ; extra == 'dask'
|
|
38
38
|
Requires-Dist: distributed>=2025.10.0 ; extra == 'dask'
|
|
39
|
+
Requires-Dist: ray[data]>=2.0.0 ; python_full_version < '3.14' and extra == 'ray'
|
|
39
40
|
Provides-Extra: polars
|
|
40
41
|
Provides-Extra: duckdb
|
|
41
42
|
Provides-Extra: iceberg
|
|
42
43
|
Provides-Extra: huggingface
|
|
43
44
|
Provides-Extra: streaming
|
|
44
45
|
Provides-Extra: dask
|
|
46
|
+
Provides-Extra: ray
|
|
45
47
|
Summary: Python client for Spiral.
|
|
46
48
|
Home-Page: https://spiraldb.com
|
|
47
49
|
Author-email: SpiralDB <hello@spiraldb.com>
|
|
@@ -1,83 +1,91 @@
|
|
|
1
|
-
pyspiral-0.8.
|
|
2
|
-
pyspiral-0.8.
|
|
3
|
-
pyspiral-0.8.
|
|
4
|
-
spiral/__init__.py,sha256=
|
|
5
|
-
spiral/_lib.abi3.so,sha256=
|
|
6
|
-
spiral/adbc.py,sha256=
|
|
7
|
-
spiral/api/__init__.py,sha256=
|
|
1
|
+
pyspiral-0.9.8.dist-info/METADATA,sha256=BZlkhMmVj7_ZWXDWYxf6xJ4fRt6rU4-4_PdP_7hg1vY,2055
|
|
2
|
+
pyspiral-0.9.8.dist-info/WHEEL,sha256=bx69zWyc-B09u77H7BhtavKljYQJK822O1mV8jKC1Q4,147
|
|
3
|
+
pyspiral-0.9.8.dist-info/entry_points.txt,sha256=R96Y3FpYX6XbQu9qMPfUTgiCcf4qM9OBQQZTDdBkZwA,74
|
|
4
|
+
spiral/__init__.py,sha256=8g-RFlbqvKOMgQtkXrtfXFjoqkDbym5n6RZSXsrmgcA,1492
|
|
5
|
+
spiral/_lib.abi3.so,sha256=kdHOPQlXHmFmjv2Zl-2meMZJlL3deRRtaFIp7MmY_Ag,71685080
|
|
6
|
+
spiral/adbc.py,sha256=Mc2wdC_fqvE4jqlgHqCI7M9Y-jRH4SaAjxJMibmIvbc,14854
|
|
7
|
+
spiral/api/__init__.py,sha256=JRLzPC3BYjkEBdcqAYBYv43C2V4Z51tClug6ztyEqBw,2319
|
|
8
8
|
spiral/api/admin.py,sha256=A1iVR1XYJSObZivPAD5UzmPuMgupXc9kaHNYYa_kwfs,585
|
|
9
|
-
spiral/api/client.py,sha256=
|
|
10
|
-
spiral/api/filesystems.py,sha256=
|
|
9
|
+
spiral/api/client.py,sha256=mrnFdmwDB6FYuNKl7QIJqyBVx-Y3ENYgNPXEQ6nLJuI,7932
|
|
10
|
+
spiral/api/filesystems.py,sha256=8g_YdFjFFZLybQqV1xSH91SxVvOer4O6sGECexWXRnw,4548
|
|
11
11
|
spiral/api/key_space_indexes.py,sha256=-38rZXTdkL4mLhp9h3CtqyIyutzzq88tV6bhK05MqYE,640
|
|
12
|
-
spiral/api/organizations.py,sha256=
|
|
13
|
-
spiral/api/projects.py,sha256=
|
|
12
|
+
spiral/api/organizations.py,sha256=eXAzxrKPmd3IVFfEaEbqbhqG0AjBM4IDz3O-ZoxJI5w,1928
|
|
13
|
+
spiral/api/projects.py,sha256=G9SXAYg6PH_dTbogB_roZQVUi3rXaFPI9_ytFg25i98,6430
|
|
14
|
+
spiral/api/tables.py,sha256=AH-Kdp2Jy6lReSoK7GcY9L8WsWMWAACaBjYcK3kbNlM,2070
|
|
14
15
|
spiral/api/telemetry.py,sha256=tfdA3E_EWJwFVxkQfkm8tiYGRubnx2LuE5nbfsk1oG4,474
|
|
15
16
|
spiral/api/text_indexes.py,sha256=_zVlGBytl-9-Unbu2POfZgLh40H1YRcagFtplgIG428,1828
|
|
16
17
|
spiral/api/types.py,sha256=HpHsoBuf7IdlXb7Dw-BkBkEvxBVIhkI8JviqhuoP9pY,696
|
|
17
18
|
spiral/api/workers.py,sha256=0wZNUHMioDT53P1OBJfpjyDfIodHwwT6858z2IlRIM4,636
|
|
18
|
-
spiral/api/workloads.py,sha256=
|
|
19
|
-
spiral/arrow_.py,sha256=
|
|
19
|
+
spiral/api/workloads.py,sha256=GBZ4tLa_-NtZvV-P5GTJgPSxBQ_YiLyWaOpr9ELojOo,1764
|
|
20
|
+
spiral/arrow_.py,sha256=pV36BbkPL2Gvq5z_O7w2iFySkZTecrTlWYcCkplhVto,1828
|
|
20
21
|
spiral/cli/__init__.py,sha256=GdTQZVArIw19zSKi92ZtwD8pXQExuubnaN854XLTSzY,2505
|
|
21
22
|
spiral/cli/__main__.py,sha256=kNaKM2xgJo7GRogf83nYldLM-RGUR6vymdGwZxywQu0,71
|
|
22
|
-
spiral/cli/admin.py,sha256=
|
|
23
|
-
spiral/cli/app.py,sha256=
|
|
23
|
+
spiral/cli/admin.py,sha256=sC_XUZvi7t91qHMR5vea_KD3lXUcygil1MUw7zVFmpE,945
|
|
24
|
+
spiral/cli/app.py,sha256=tr8vR1g_9aJBnn2Dea_a-E8Wpn73brbDHrm_zRg-wVA,3048
|
|
25
|
+
spiral/cli/chooser.py,sha256=JmlETVEfHd9JOkL4ILPly1TgyESVa8vZqNDgFMcnQm8,1091
|
|
24
26
|
spiral/cli/console.py,sha256=6JHbAQV6MFWz3P-VzqPOjhHpkIQagsCdzTMvmuDKMkU,2580
|
|
25
|
-
spiral/cli/fs.py,sha256=
|
|
26
|
-
spiral/cli/iceberg.py,sha256=
|
|
27
|
-
spiral/cli/key_spaces.py,sha256=
|
|
27
|
+
spiral/cli/fs.py,sha256=WcUeyh9sFoWJ2xn25-xKzLEi2u9KLdmoVXwyKynxrK8,4194
|
|
28
|
+
spiral/cli/iceberg.py,sha256=r5qJTy2YACGQALPwU5VQXsQvkY5Qv07qXgpA4qvmVGU,3250
|
|
29
|
+
spiral/cli/key_spaces.py,sha256=0Mv7jwY8coF_wBW8klLJHPpiXqLwFNfVzT06zokzqfU,3526
|
|
28
30
|
spiral/cli/login.py,sha256=2l2i38XNHGKtV4DP6PZPN4LHxceCn3AdHDE5nM2iK5M,760
|
|
29
|
-
spiral/cli/orgs.py,sha256=
|
|
31
|
+
spiral/cli/orgs.py,sha256=L68jO-SEHlocy-tMQYmQ7LAW0WuY0r7q5yr3QBUm0CM,2538
|
|
30
32
|
spiral/cli/printer.py,sha256=HcvSUpaMItzmhBUfIHROK1Z3SL8J8wDopS3Qo8H00uw,1781
|
|
31
|
-
spiral/cli/projects.py,sha256=
|
|
33
|
+
spiral/cli/projects.py,sha256=maH8uGJT_TopIEoPADiz5Qe4SziH0jYJW9bJK1QtWL4,5831
|
|
32
34
|
spiral/cli/state.py,sha256=3sKQuFtV2vCn3E1Dv7Sw9-IK5jiXCVBEQ9Ze17NZXDs,129
|
|
33
|
-
spiral/cli/tables.py,sha256=
|
|
34
|
-
spiral/cli/telemetry.py,sha256=
|
|
35
|
-
spiral/cli/text.py,sha256=
|
|
36
|
-
spiral/cli/
|
|
37
|
-
spiral/cli/
|
|
38
|
-
spiral/
|
|
35
|
+
spiral/cli/tables.py,sha256=r4cogd-4Az-KYoIAcrJ4Fxi1lPj5AEBB7_qdCdpmhgQ,8967
|
|
36
|
+
spiral/cli/telemetry.py,sha256=bhbFyMtQ2Wc_-Rl1u4VlQcr8Yt3hNlW-Gi2NbBHC09c,794
|
|
37
|
+
spiral/cli/text.py,sha256=u2XR9SOs0vIz5NjV5P5Lj3PC1XOlsD8RFQrGwc0AMUY,4033
|
|
38
|
+
spiral/cli/transactions.py,sha256=t3yB2pN3ishYQjlSkP_hVkENgBnqi0QvdBMyVS8pKXU,2748
|
|
39
|
+
spiral/cli/types_.py,sha256=8FEaKDNVtzrQswuX7KHKL1znHeJK7AKrDTRTPer5PWM,1335
|
|
40
|
+
spiral/cli/workloads.py,sha256=NOoYZQ2OewtIAgmWXhPpwGwio233VHhdDfdDgqFMVc8,2999
|
|
41
|
+
spiral/client.py,sha256=bpzXee4HqNaP6Q646LWa4wesQgA7tbqeA3rUS7rVXFU,12099
|
|
39
42
|
spiral/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
43
|
spiral/core/_tools/__init__.pyi,sha256=b2KLfTOQ67pjfbYt07o0IGiTu5o2bZw69lllV8v0Dps,143
|
|
41
44
|
spiral/core/authn/__init__.pyi,sha256=deZvPlCyiPC6PpXxpEZVglxL5mUJ1Qqg20ieEQgU6ik,582
|
|
42
|
-
spiral/core/client/__init__.pyi,sha256=
|
|
45
|
+
spiral/core/client/__init__.pyi,sha256=a5jsYTjBQVkH3WtxMHNHFK_U8z5yx-mh-FeSa5N0bYY,7655
|
|
43
46
|
spiral/core/config/__init__.pyi,sha256=1BaB7fTGly_fW-qTSQtxbGrYErzkqxuJokDFPupP7d0,955
|
|
44
47
|
spiral/core/expr/__init__.pyi,sha256=3HSKjkotiEkxBvGBALXEBIie0JiyI9bCpehwA3nMQkU,571
|
|
45
48
|
spiral/core/expr/images/__init__.pyi,sha256=wnE_wZXq7a4iqTg3SVm-ssxGw1WQZyk5dGOPaP4Btko,73
|
|
46
49
|
spiral/core/expr/list_/__init__.pyi,sha256=Q_9c87eIQfZbqlaw_rq3fvs93YEsW7K5VYk6VZ4g6mU,126
|
|
50
|
+
spiral/core/expr/pushdown/__init__.pyi,sha256=zcpBHFz-uriK0WccBUrPOuR8Mi8jPzEzpv9kGpp_PRw,60
|
|
47
51
|
spiral/core/expr/refs/__init__.pyi,sha256=nZZP3l_Z6bLx6V8lTcH3Jgo--xwfADOU2XdTAvM5IMk,127
|
|
52
|
+
spiral/core/expr/s3/__init__.pyi,sha256=GlgT6HtRqNbf31enHhkoM6HXHHxlgic7mApob_R3tOQ,76
|
|
48
53
|
spiral/core/expr/str_/__init__.pyi,sha256=Bm6fZK-d4fNbJuuBhVoWMACXUbQQ2SjlhgrOpdOHIPM,86
|
|
49
54
|
spiral/core/expr/struct_/__init__.pyi,sha256=MXckd98eV_x3X0RhEWvlkA3DcDXRtLs5pNnTQkc09nE,296
|
|
50
55
|
spiral/core/expr/text/__init__.pyi,sha256=ed83n1xcsGY7_QDhMmJGnSQ20UrJFXcdv1AveSEcS1c,175
|
|
51
56
|
spiral/core/expr/udf/__init__.pyi,sha256=zsZs081KVhY3-1JidqTkWMW81Qd_ScoTGZvasIhIK-4,358
|
|
52
57
|
spiral/core/expr/video/__init__.pyi,sha256=nQJEcSsigZuRpMjkI_O4EEtMK_n2zRvorcL_KEeD5vU,95
|
|
53
|
-
spiral/core/table/__init__.pyi,sha256=
|
|
58
|
+
spiral/core/table/__init__.pyi,sha256=hdAu59xHgMWsA1I2Vmz7sRq4DJhh8OVhnHPDgGoz6CQ,4802
|
|
54
59
|
spiral/core/table/manifests/__init__.pyi,sha256=eVfDpmhYSjafIvvALqAkZe5baN3Y1HpKpxYEbjwd4gQ,1043
|
|
55
60
|
spiral/core/table/metastore/__init__.pyi,sha256=rc3u9MwEKRvL2kxOc8lBorddFRnM8o_o1frqtae86a4,1697
|
|
56
61
|
spiral/core/table/spec/__init__.pyi,sha256=839FNXvUS1PD-jYx2pXIIlTEjKszZUGfVD7WKSpflIQ,5659
|
|
57
|
-
spiral/dataloader.py,sha256=
|
|
62
|
+
spiral/dataloader.py,sha256=FAaV_B3HTH_gz2FQDDG_5gLjQYR3jScgyHaOa8fSoQk,10766
|
|
58
63
|
spiral/dataset.py,sha256=xse0evrNDKPXNrqaS5ZklyvPsrTPaFov5A2uwwMd9sU,8429
|
|
59
64
|
spiral/datetime_.py,sha256=elXaUWtZuuLVcu9E0aXnvYRPB9XWqZbLDToozQYQYjU,950
|
|
60
65
|
spiral/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
-
spiral/debug/manifests.py,sha256=
|
|
66
|
+
spiral/debug/manifests.py,sha256=DvhDUkW9Ca8YfsPchArnajzEdedd1jg0Zx-xSRmnrmw,4282
|
|
62
67
|
spiral/debug/metrics.py,sha256=_B1LoHejOQk7sfKX1dhVmHrcB3HNZzhr2M4iQfsyOUQ,2058
|
|
63
|
-
spiral/debug/scan.py,sha256=
|
|
64
|
-
spiral/
|
|
65
|
-
spiral/
|
|
66
|
-
spiral/expressions/
|
|
68
|
+
spiral/debug/scan.py,sha256=PYU4FJiE5aZ0Rc7LkTK62UEjlLwdAm-gNe869KHpNTs,9475
|
|
69
|
+
spiral/demo.py,sha256=28jH4Y0VmBifFCEEPxsUVfzqBqWW-pTUI1__N8nwwPA,6793
|
|
70
|
+
spiral/enrichment.py,sha256=wp9EKN0baQwqwV7I2aL87BgTt5zSY0mvn8M2I6mxUe8,10771
|
|
71
|
+
spiral/expressions/__init__.py,sha256=bb54V06ybqrf9P7E8gyKktLrs01m94-NktZpN6mnfRA,5042
|
|
72
|
+
spiral/expressions/base.py,sha256=J9apXEX47ufrofHo37pFr-6Qj2t0mxCsVtabXFsCrD4,6080
|
|
67
73
|
spiral/expressions/file.py,sha256=7D9jIENJcoT0KFharBLkzK9dZgO4DYn5K_KCt0twefg,518
|
|
68
74
|
spiral/expressions/http.py,sha256=OOHh0WBxg3vwza_m74-rkoQWSclRMI60aPAbQ6yKZi0,486
|
|
69
75
|
spiral/expressions/list_.py,sha256=-OHzTkTYvTY_Q2IuATfK5QNx7KEyic3DzZLEYn8otIk,2050
|
|
76
|
+
spiral/expressions/pushdown.py,sha256=6ZHke34_YLFYiqp14tXIRWH3K2yVHADeNiRDY_tF5N8,371
|
|
70
77
|
spiral/expressions/s3.py,sha256=PhQhMP-d8PLsSRtGCZbytnm7lI9VbDAbuSs2LBM4G7Q,505
|
|
71
78
|
spiral/expressions/str_.py,sha256=tY8RXW3JWvr1-bEfCZtk5FAf11wKJnXPuA9EoeJ9tA4,1265
|
|
72
79
|
spiral/expressions/struct.py,sha256=pGAnCDh6AK0BK1XfZ1qG4ce4ranIQEE1HQsgmzBcfwQ,2038
|
|
73
80
|
spiral/expressions/text.py,sha256=-02gBWYoyNQ3qQ1--9HTa8IryUDojYQVIp8C7rgnOWQ,1893
|
|
74
81
|
spiral/expressions/tiff.py,sha256=B1N6ck1-CcIPSU9_Vnol7fXNnTbhV1CnMxvtAG5wmx0,7979
|
|
75
|
-
spiral/expressions/udf.py,sha256=
|
|
82
|
+
spiral/expressions/udf.py,sha256=XhePtyzrMgX0SQ5mOmf2XrdkhN7BSyyZpLZtF862B1U,2046
|
|
76
83
|
spiral/grpc_.py,sha256=f3czdP1Mxme42Y5--a5ogYq1TTiWn-J_MlGjwJ2mWwM,1015
|
|
84
|
+
spiral/huggingface.py,sha256=eJPX0npe4IBfZ8bwXPc374W22kN5iK00xOzTIklxPwA,15809
|
|
77
85
|
spiral/iceberg.py,sha256=02OkA348eFxkEbgreeTuVlzavVvZmM4hldrZI76PZ9I,914
|
|
78
|
-
spiral/
|
|
86
|
+
spiral/input.py,sha256=yCqojJDwdkXg92tfLcgfR0ltSrDwCwxS_GjoP9r9HGU,4195
|
|
79
87
|
spiral/key_space_index.py,sha256=NAB_nONEjpMYbse8suz42w7Qb5OPHuKN9h9CT2NJe08,1460
|
|
80
|
-
spiral/project.py,sha256=
|
|
88
|
+
spiral/project.py,sha256=bUqfROIouk_2WSZXc8DPbFwJuzPac8ucxOM7qHpw6gE,8796
|
|
81
89
|
spiral/protogen/_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
82
90
|
spiral/protogen/_/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
91
|
spiral/protogen/_/arrow/flight/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -95,16 +103,17 @@ spiral/protogen/_/substrait/extensions/__init__.py,sha256=nhnEnho70GAT8WPj2xtwJU
|
|
|
95
103
|
spiral/protogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
104
|
spiral/protogen/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
|
|
97
105
|
spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
|
-
spiral/
|
|
99
|
-
spiral/
|
|
100
|
-
spiral/
|
|
101
|
-
spiral/
|
|
106
|
+
spiral/ray_.py,sha256=iEpkEHu6V2ATtX1KHrRDF9R6dsiazHwltr5GUF35Svg,2749
|
|
107
|
+
spiral/scan.py,sha256=c-lLaoLydnGV5ydYgS8SFdFz0qIbiWnTVhn7QpU1Xdc,20003
|
|
108
|
+
spiral/server.py,sha256=Q1FcOAV0EsDespdBJI25R5K2mihP_i1xNRe99SYUhsY,1401
|
|
109
|
+
spiral/settings.py,sha256=zeiEhWC2H94r3o5-jsOqSIHu-hthRYO48ShWnXvGrQ8,895
|
|
110
|
+
spiral/snapshot.py,sha256=nf0ywmFy1Z2v6NCDBKBzfwmht5nGqWv2V_BifP_Q6Ag,1995
|
|
102
111
|
spiral/streaming_/__init__.py,sha256=s7MlW2ERsuZmZGExLFL6RcZon2e0tNBocBg5ANgki7k,61
|
|
103
112
|
spiral/streaming_/reader.py,sha256=tl_lC9xgh1-QFhsZn4xQT7It3PVTzHCEUT2BG2dWBRQ,4166
|
|
104
113
|
spiral/streaming_/stream.py,sha256=efqhExky4YgI1f3Me5ctfayFbTExoyS3TRMkrPIjvv0,5918
|
|
105
114
|
spiral/substrait_.py,sha256=AKeOD4KIXvz2J4TYxnIneOiHddtBIyOhuNxVO_uH0eg,12592
|
|
106
|
-
spiral/table.py,sha256=
|
|
115
|
+
spiral/table.py,sha256=qnppfbien_Ytogr9eQuK9pOtgRnV6iWgHw_ynvZtOno,8038
|
|
107
116
|
spiral/text_index.py,sha256=FQ9rgIEGLSJryS9lFdMhKtPFey18BXoWbPXyvZPJJ04,442
|
|
108
|
-
spiral/transaction.py,sha256=
|
|
117
|
+
spiral/transaction.py,sha256=EEz_1VnFojr0D553TF8_YntZE0UWlWvxq6C31P6ab_M,7866
|
|
109
118
|
spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
|
|
110
|
-
pyspiral-0.8.
|
|
119
|
+
pyspiral-0.9.8.dist-info/RECORD,,
|
spiral/__init__.py
CHANGED
|
@@ -22,7 +22,7 @@ from spiral.scan import Scan # noqa: E402
|
|
|
22
22
|
from spiral.snapshot import Snapshot # noqa: E402
|
|
23
23
|
from spiral.table import Table # noqa: E402
|
|
24
24
|
from spiral.text_index import TextIndex # noqa: E402
|
|
25
|
-
from spiral.transaction import Transaction # noqa: E402
|
|
25
|
+
from spiral.transaction import Transaction, TransactionOps # noqa: E402
|
|
26
26
|
|
|
27
27
|
__all__ = [
|
|
28
28
|
"Spiral",
|
|
@@ -30,6 +30,7 @@ __all__ = [
|
|
|
30
30
|
"Table",
|
|
31
31
|
"Snapshot",
|
|
32
32
|
"Transaction",
|
|
33
|
+
"TransactionOps",
|
|
33
34
|
"Enrichment",
|
|
34
35
|
"Scan",
|
|
35
36
|
"Shard",
|
|
@@ -41,7 +42,7 @@ __all__ = [
|
|
|
41
42
|
"Iceberg",
|
|
42
43
|
]
|
|
43
44
|
|
|
44
|
-
__version__ = importlib.metadata.version("pyspiral")
|
|
45
|
+
__version__: str = importlib.metadata.version("pyspiral")
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
def _warn_msg():
|
spiral/_lib.abi3.so
CHANGED
|
Binary file
|
spiral/adbc.py
CHANGED
|
@@ -247,7 +247,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
|
247
247
|
|
|
248
248
|
if req.include_schema:
|
|
249
249
|
open_table = project.table(f"{table.dataset}.{table.table}")
|
|
250
|
-
row["table_schema"] = open_table.snapshot().
|
|
250
|
+
row["table_schema"] = open_table.snapshot().to_arrow_dataset().schema.serialize().to_pybytes()
|
|
251
251
|
|
|
252
252
|
rows.append(row)
|
|
253
253
|
|
|
@@ -267,7 +267,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
|
267
267
|
# This lets us register a PyArrow Dataset with DuckDB for the query.
|
|
268
268
|
snapshot = self.open_snapshot(tbl)
|
|
269
269
|
name = snapshot.table.table_id
|
|
270
|
-
datasets[name] = snapshot.
|
|
270
|
+
datasets[name] = snapshot.to_arrow_dataset()
|
|
271
271
|
tbl.replace(exp.table_(table=name))
|
|
272
272
|
|
|
273
273
|
try:
|
spiral/api/__init__.py
CHANGED
|
@@ -9,22 +9,23 @@ if TYPE_CHECKING:
|
|
|
9
9
|
from spiral.core.authn import Authn
|
|
10
10
|
|
|
11
11
|
from .admin import AdminService
|
|
12
|
-
from .filesystems import
|
|
12
|
+
from .filesystems import FileSystemsService
|
|
13
13
|
from .key_space_indexes import KeySpaceIndexesService
|
|
14
|
-
from .organizations import
|
|
15
|
-
from .projects import
|
|
14
|
+
from .organizations import OrganizationsService
|
|
15
|
+
from .projects import ProjectsService
|
|
16
|
+
from .tables import TablesService
|
|
16
17
|
from .telemetry import TelemetryService
|
|
17
18
|
from .text_indexes import TextIndexesService
|
|
18
|
-
from .workloads import
|
|
19
|
+
from .workloads import WorkloadsService
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class SpiralAPI:
|
|
22
|
-
def __init__(self, authn: "Authn"
|
|
23
|
-
self.base_url = base_url
|
|
23
|
+
def __init__(self, base_url: str, authn: "Authn"):
|
|
24
|
+
self.base_url = base_url
|
|
24
25
|
self.client = _Client(
|
|
25
26
|
httpx.Client(
|
|
26
27
|
base_url=self.base_url,
|
|
27
|
-
timeout=None if
|
|
28
|
+
timeout=None if "PYTEST_VERSION" in os.environ else 60,
|
|
28
29
|
),
|
|
29
30
|
authn,
|
|
30
31
|
)
|
|
@@ -36,28 +37,34 @@ class SpiralAPI:
|
|
|
36
37
|
return AdminService(self.client)
|
|
37
38
|
|
|
38
39
|
@property
|
|
39
|
-
def
|
|
40
|
-
from .organizations import
|
|
40
|
+
def organizations(self) -> "OrganizationsService":
|
|
41
|
+
from .organizations import OrganizationsService
|
|
41
42
|
|
|
42
|
-
return
|
|
43
|
+
return OrganizationsService(self.client)
|
|
43
44
|
|
|
44
45
|
@property
|
|
45
|
-
def
|
|
46
|
-
from .projects import
|
|
46
|
+
def projects(self) -> "ProjectsService":
|
|
47
|
+
from .projects import ProjectsService
|
|
47
48
|
|
|
48
|
-
return
|
|
49
|
+
return ProjectsService(self.client)
|
|
49
50
|
|
|
50
51
|
@property
|
|
51
|
-
def
|
|
52
|
-
from .filesystems import
|
|
52
|
+
def file_systems(self) -> "FileSystemsService":
|
|
53
|
+
from .filesystems import FileSystemsService
|
|
53
54
|
|
|
54
|
-
return
|
|
55
|
+
return FileSystemsService(self.client)
|
|
55
56
|
|
|
56
57
|
@property
|
|
57
|
-
def
|
|
58
|
-
from .workloads import
|
|
58
|
+
def workloads(self) -> "WorkloadsService":
|
|
59
|
+
from .workloads import WorkloadsService
|
|
59
60
|
|
|
60
|
-
return
|
|
61
|
+
return WorkloadsService(self.client)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def tables(self) -> "TablesService":
|
|
65
|
+
from .tables import TablesService
|
|
66
|
+
|
|
67
|
+
return TablesService(self.client)
|
|
61
68
|
|
|
62
69
|
@property
|
|
63
70
|
def text_indexes(self) -> "TextIndexesService":
|
spiral/api/client.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import time
|
|
4
5
|
from collections.abc import Iterable, Iterator, Mapping
|
|
6
|
+
from datetime import UTC, datetime
|
|
7
|
+
from email.utils import parsedate_to_datetime
|
|
5
8
|
from typing import Any, Generic, TypeVar
|
|
6
9
|
|
|
7
10
|
import httpx
|
|
@@ -35,7 +38,7 @@ class Paged(Iterable[E], Generic[E]):
|
|
|
35
38
|
client: _Client,
|
|
36
39
|
path: str,
|
|
37
40
|
page_token: str | None,
|
|
38
|
-
page_size: int,
|
|
41
|
+
page_size: int | None,
|
|
39
42
|
response_cls: type[PagedResponse[E]],
|
|
40
43
|
params: Mapping[str, str] | None = None,
|
|
41
44
|
):
|
|
@@ -48,9 +51,8 @@ class Paged(Iterable[E], Generic[E]):
|
|
|
48
51
|
self._params = params or {}
|
|
49
52
|
if page_token is not None:
|
|
50
53
|
self._params["page_token"] = str(page_token)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# self._params["page_size"] = str(page_size)
|
|
54
|
+
if page_size is not None:
|
|
55
|
+
self._params["page_size"] = str(page_size)
|
|
54
56
|
|
|
55
57
|
self._response: PagedResponse[E] = client.get(path, response_cls, params=self._params)
|
|
56
58
|
|
|
@@ -58,6 +60,13 @@ class Paged(Iterable[E], Generic[E]):
|
|
|
58
60
|
def page(self) -> PagedResponse[E]:
|
|
59
61
|
return self._response
|
|
60
62
|
|
|
63
|
+
def _fetch_next_page(self):
|
|
64
|
+
assert self._response.next_page_token
|
|
65
|
+
|
|
66
|
+
params = self._params.copy()
|
|
67
|
+
params["page_token"] = self._response.next_page_token
|
|
68
|
+
self._response = self._client.get(self._path, self._response_cls, params=params)
|
|
69
|
+
|
|
61
70
|
def __iter__(self) -> Iterator[E]:
|
|
62
71
|
while True:
|
|
63
72
|
yield from self._response.items
|
|
@@ -65,9 +74,7 @@ class Paged(Iterable[E], Generic[E]):
|
|
|
65
74
|
if self._response.next_page_token is None:
|
|
66
75
|
break
|
|
67
76
|
|
|
68
|
-
|
|
69
|
-
params["page_token"] = self._response.next_page_token
|
|
70
|
-
self._response = self._client.get(self._path, self._response_cls, params=params)
|
|
77
|
+
self._fetch_next_page()
|
|
71
78
|
|
|
72
79
|
|
|
73
80
|
class ServiceBase:
|
|
@@ -90,6 +97,73 @@ class _Client:
|
|
|
90
97
|
self.http = http
|
|
91
98
|
self.authn = authn
|
|
92
99
|
|
|
100
|
+
def _handle_deprecation(self, response: httpx.Response, path: str) -> None:
|
|
101
|
+
"""Handle deprecation headers from API responses.
|
|
102
|
+
|
|
103
|
+
- Logs warnings if the endpoint is deprecated
|
|
104
|
+
- Sleeps progressively longer as sunset date approaches
|
|
105
|
+
- Logs errors if past the sunset date
|
|
106
|
+
"""
|
|
107
|
+
deprecation_header = response.headers.get("Deprecation")
|
|
108
|
+
sunset_header = response.headers.get("Sunset")
|
|
109
|
+
|
|
110
|
+
if not deprecation_header:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
deprecation_date = parsedate_to_datetime(deprecation_header)
|
|
115
|
+
sunset_date = parsedate_to_datetime(sunset_header) if sunset_header else None
|
|
116
|
+
except (ValueError, TypeError):
|
|
117
|
+
log.warning("Failed to parse deprecation headers for path %s", path)
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
sunset_str = sunset_date.isoformat() if sunset_date else "unknown"
|
|
121
|
+
log.warning(
|
|
122
|
+
"SpiralDB is using a deprecated API endpoint, please migrate to a supported version "
|
|
123
|
+
"(path=%s, deprecation_date=%s, sunset_date=%s)",
|
|
124
|
+
path,
|
|
125
|
+
deprecation_date.isoformat(),
|
|
126
|
+
sunset_str,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if sunset_date:
|
|
130
|
+
now = datetime.now(UTC)
|
|
131
|
+
|
|
132
|
+
if now > sunset_date:
|
|
133
|
+
# Past sunset date - log error and use maximum sleep
|
|
134
|
+
days_past_sunset = (now - sunset_date).days
|
|
135
|
+
log.error(
|
|
136
|
+
"SpiralDB API endpoint has been sunset, please migrate to a supported version "
|
|
137
|
+
"(path=%s, sunset_date=%s, days_past_sunset=%d)",
|
|
138
|
+
path,
|
|
139
|
+
sunset_date.isoformat(),
|
|
140
|
+
days_past_sunset,
|
|
141
|
+
)
|
|
142
|
+
sleep_ms = 5000 # Max sleep after sunset
|
|
143
|
+
else:
|
|
144
|
+
# Before sunset - calculate progressive sleep
|
|
145
|
+
time_until_sunset = (sunset_date - now).total_seconds()
|
|
146
|
+
time_since_deprecation = (now - deprecation_date).total_seconds()
|
|
147
|
+
total_deprecation_window = max((sunset_date - deprecation_date).total_seconds(), 1.0)
|
|
148
|
+
|
|
149
|
+
# Calculate progress: 0.0 (just deprecated) to 1.0 (at sunset)
|
|
150
|
+
progress = max(0.0, min(1.0, time_since_deprecation / total_deprecation_window))
|
|
151
|
+
|
|
152
|
+
# Exponential backoff: 0ms → 5000ms as we approach sunset
|
|
153
|
+
sleep_ms = int((progress**2) * 5000.0)
|
|
154
|
+
|
|
155
|
+
if sleep_ms > 0:
|
|
156
|
+
days_until_sunset = int(time_until_sunset / 86400) + 1
|
|
157
|
+
log.warning(
|
|
158
|
+
"Sleeping due to deprecated endpoint usage (path=%s, sleep_ms=%d, days_until_sunset=%d)",
|
|
159
|
+
path,
|
|
160
|
+
sleep_ms,
|
|
161
|
+
days_until_sunset,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
if sleep_ms > 0:
|
|
165
|
+
time.sleep(sleep_ms / 1000.0)
|
|
166
|
+
|
|
93
167
|
def get(
|
|
94
168
|
self, path: str, response_cls: type[ResponseT], *, params: Mapping[str, str | list[str]] | None = None
|
|
95
169
|
) -> ResponseT:
|
|
@@ -142,6 +216,9 @@ class _Client:
|
|
|
142
216
|
**req_data,
|
|
143
217
|
)
|
|
144
218
|
|
|
219
|
+
# Handle deprecation headers before processing response
|
|
220
|
+
self._handle_deprecation(resp, path)
|
|
221
|
+
|
|
145
222
|
try:
|
|
146
223
|
resp.raise_for_status()
|
|
147
224
|
except HTTPStatusError as e:
|
|
@@ -149,7 +226,6 @@ class _Client:
|
|
|
149
226
|
raise SpiralHTTPError(body=resp.text, code=resp.status_code) from e
|
|
150
227
|
|
|
151
228
|
if response_cls == type[None]:
|
|
152
|
-
assert resp.text == ""
|
|
153
229
|
return None
|
|
154
230
|
|
|
155
231
|
return TypeAdapter(response_cls).validate_python(resp.json())
|
|
@@ -160,7 +236,8 @@ class _Client:
|
|
|
160
236
|
response_cls: type[PagedResponse[E]],
|
|
161
237
|
*,
|
|
162
238
|
page_token: str | None = None,
|
|
163
|
-
page_size: int =
|
|
239
|
+
page_size: int | None = None,
|
|
164
240
|
params: Mapping[str, str] | None = None,
|
|
165
241
|
) -> Paged[E]:
|
|
242
|
+
# TODO(DK): When paging is uniformly supported, set a default page size *here* rather than in the callers.
|
|
166
243
|
return Paged(self, path, page_token, page_size, response_cls, params)
|
spiral/api/filesystems.py
CHANGED
|
@@ -40,16 +40,33 @@ class UpstreamFileSystem(BaseModel):
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class S3FileSystem(BaseModel):
|
|
43
|
-
"""File system backed by an S3
|
|
43
|
+
"""File system backed by an AWS S3 bucket."""
|
|
44
44
|
|
|
45
45
|
type: Literal["s3"] = "s3"
|
|
46
46
|
endpoint: str | None = None
|
|
47
47
|
region: str
|
|
48
48
|
bucket: str
|
|
49
49
|
directory: DirectoryPath | None = None
|
|
50
|
-
# ARN of the role to assume when accessing the bucket
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
# ARN of the role to assume when accessing the bucket
|
|
51
|
+
role_arn: str
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class VaultSecret(BaseModel):
|
|
55
|
+
type: Literal["secret"] = "secret"
|
|
56
|
+
# Reference to a secret stored in vault
|
|
57
|
+
secret: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class S3LikeFileSystem(BaseModel):
|
|
61
|
+
"""File system backed by an AWS S3 bucket that is compatible with S3 APIs."""
|
|
62
|
+
|
|
63
|
+
type: Literal["s3like"] = "s3like"
|
|
64
|
+
endpoint: str
|
|
65
|
+
region: str
|
|
66
|
+
bucket: str
|
|
67
|
+
directory: DirectoryPath | None = None
|
|
68
|
+
access_key_id: str
|
|
69
|
+
secret_access_key: str | VaultSecret
|
|
53
70
|
|
|
54
71
|
|
|
55
72
|
class GCSFileSystem(BaseModel):
|
|
@@ -62,7 +79,8 @@ class GCSFileSystem(BaseModel):
|
|
|
62
79
|
|
|
63
80
|
|
|
64
81
|
FileSystem = Annotated[
|
|
65
|
-
BuiltinFileSystem | UpstreamFileSystem | S3FileSystem | GCSFileSystem,
|
|
82
|
+
BuiltinFileSystem | UpstreamFileSystem | S3FileSystem | S3LikeFileSystem | GCSFileSystem,
|
|
83
|
+
Field(discriminator="type"),
|
|
66
84
|
]
|
|
67
85
|
|
|
68
86
|
|
|
@@ -97,7 +115,7 @@ class GetMountAndFileSystemResponse(BaseModel):
|
|
|
97
115
|
fs_loc: FsLoc
|
|
98
116
|
|
|
99
117
|
|
|
100
|
-
class
|
|
118
|
+
class FileSystemsService(ServiceBase):
|
|
101
119
|
"""Service for file system operations."""
|
|
102
120
|
|
|
103
121
|
def list_providers(self) -> list[str]:
|
spiral/api/organizations.py
CHANGED
|
@@ -37,6 +37,7 @@ class PortalLinkIntent(str, Enum):
|
|
|
37
37
|
AUDIT_LOGS = "audit-logs"
|
|
38
38
|
LOG_STREAMS = "log-streams"
|
|
39
39
|
DOMAIN_VERIFICATION = "domain-verification"
|
|
40
|
+
BYOK = "bring-your-own-key"
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
class PortalLinkRequest(BaseModel):
|
|
@@ -57,7 +58,7 @@ class InviteUserResponse(BaseModel):
|
|
|
57
58
|
invite_id: str
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
class
|
|
61
|
+
class OrganizationsService(ServiceBase):
|
|
61
62
|
"""Service for organization operations."""
|
|
62
63
|
|
|
63
64
|
def create(self, request: CreateOrgRequest) -> CreateOrgResponse:
|
spiral/api/projects.py
CHANGED
|
@@ -151,7 +151,7 @@ class KeySpaceIndexResource(BaseModel):
|
|
|
151
151
|
name: str
|
|
152
152
|
|
|
153
153
|
|
|
154
|
-
class
|
|
154
|
+
class ProjectsService(ServiceBase):
|
|
155
155
|
"""Service for project operations."""
|
|
156
156
|
|
|
157
157
|
def create(self, request: CreateProjectRequest) -> CreateProjectResponse:
|
|
@@ -163,7 +163,7 @@ class ProjectService(ServiceBase):
|
|
|
163
163
|
return self.client.paged("/v1/projects", PagedResponse[Project])
|
|
164
164
|
|
|
165
165
|
def list_tables(
|
|
166
|
-
self, project_id: ProjectId, dataset: str | None = None, table: str | None = None
|
|
166
|
+
self, project_id: ProjectId, dataset: str | None = None, table: str | None = None, page_size: int | None = None
|
|
167
167
|
) -> Paged[TableResource]:
|
|
168
168
|
"""List tables in a project."""
|
|
169
169
|
params = {}
|
|
@@ -171,7 +171,9 @@ class ProjectService(ServiceBase):
|
|
|
171
171
|
params["dataset"] = dataset
|
|
172
172
|
if table:
|
|
173
173
|
params["table"] = table
|
|
174
|
-
return self.client.paged(
|
|
174
|
+
return self.client.paged(
|
|
175
|
+
f"/v1/projects/{project_id}/tables", PagedResponse[TableResource], params=params, page_size=page_size
|
|
176
|
+
)
|
|
175
177
|
|
|
176
178
|
def list_text_indexes(self, project_id: ProjectId, name: str | None = None) -> Paged[TextIndexResource]:
|
|
177
179
|
"""List text indexes in a project."""
|
spiral/api/tables.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from ..types_ import Timestamp
|
|
6
|
+
from .client import _Client
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Transaction(BaseModel):
|
|
10
|
+
"""Represents a committed transaction in SpiralDB."""
|
|
11
|
+
|
|
12
|
+
txn_idx: int
|
|
13
|
+
committed_at: Timestamp
|
|
14
|
+
# TODO(marko): Define a proper Operation model
|
|
15
|
+
operations: list[dict[str, Any]]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TransactionsListResponse(BaseModel):
|
|
19
|
+
"""Response for listing transactions."""
|
|
20
|
+
|
|
21
|
+
items: list[Transaction]
|
|
22
|
+
next_page_token: Timestamp | None = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TablesService:
|
|
26
|
+
"""Service for managing table transactions."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, client: _Client):
|
|
29
|
+
self.client = client
|
|
30
|
+
|
|
31
|
+
def list_transactions(
|
|
32
|
+
self,
|
|
33
|
+
table_id: str,
|
|
34
|
+
*,
|
|
35
|
+
since: Timestamp | None = None,
|
|
36
|
+
) -> list[Transaction]:
|
|
37
|
+
"""List transactions for a table.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
table_id: The ID of the table
|
|
41
|
+
since: Only return transactions committed after this timestamp (microseconds since epoch)
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
List of transactions
|
|
45
|
+
"""
|
|
46
|
+
params = {"ordering": "asc"}
|
|
47
|
+
if since is not None:
|
|
48
|
+
params["page_token"] = str(since)
|
|
49
|
+
|
|
50
|
+
all_transactions = []
|
|
51
|
+
|
|
52
|
+
while True:
|
|
53
|
+
response = self.client.get(
|
|
54
|
+
f"/v1/tables/{table_id}/transactions-list",
|
|
55
|
+
TransactionsListResponse,
|
|
56
|
+
params=params,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Parse transactions from the API response
|
|
60
|
+
all_transactions.extend(response.items)
|
|
61
|
+
|
|
62
|
+
# Check for next page
|
|
63
|
+
if response.next_page_token is None:
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
params["page_token"] = str(response.next_page_token)
|
|
67
|
+
|
|
68
|
+
return all_transactions
|
|
69
|
+
|
|
70
|
+
def revert_transaction(self, table_id: str, txn_idx: int) -> None:
|
|
71
|
+
"""Revert a transaction by marking it as reverted.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
table_id: The ID of the table
|
|
75
|
+
txn_idx: The index of the transaction to revert
|
|
76
|
+
"""
|
|
77
|
+
self.client.delete(f"/v1/tables/{table_id}/transactions/{txn_idx}", type[None])
|