pyspiral 0.4.4__cp310-abi3-macosx_11_0_arm64.whl → 0.6.0__cp310-abi3-macosx_11_0_arm64.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.4.4.dist-info → pyspiral-0.6.0.dist-info}/METADATA +10 -5
- pyspiral-0.6.0.dist-info/RECORD +99 -0
- {pyspiral-0.4.4.dist-info → pyspiral-0.6.0.dist-info}/WHEEL +1 -1
- spiral/__init__.py +10 -3
- spiral/_lib.abi3.so +0 -0
- spiral/adbc.py +29 -11
- spiral/api/__init__.py +14 -0
- spiral/api/client.py +5 -1
- spiral/api/key_space_indexes.py +23 -0
- spiral/api/projects.py +17 -2
- spiral/api/text_indexes.py +56 -0
- spiral/api/types.py +2 -0
- spiral/api/workers.py +40 -0
- spiral/cli/__init__.py +15 -6
- spiral/cli/admin.py +2 -4
- spiral/cli/app.py +4 -2
- spiral/cli/fs.py +5 -6
- spiral/cli/iceberg.py +97 -0
- spiral/cli/key_spaces.py +68 -0
- spiral/cli/login.py +6 -7
- spiral/cli/orgs.py +7 -8
- spiral/cli/printer.py +3 -3
- spiral/cli/projects.py +5 -6
- spiral/cli/tables.py +131 -0
- spiral/cli/telemetry.py +3 -4
- spiral/cli/text.py +115 -0
- spiral/cli/types.py +3 -4
- spiral/cli/workloads.py +7 -8
- spiral/client.py +111 -8
- spiral/core/authn/__init__.pyi +27 -0
- spiral/core/client/__init__.pyi +135 -63
- spiral/core/table/__init__.pyi +36 -26
- spiral/core/table/metastore/__init__.pyi +0 -4
- spiral/core/table/spec/__init__.pyi +0 -2
- spiral/{tables/dataset.py → dataset.py} +13 -7
- spiral/{tables/debug → debug}/manifests.py +17 -6
- spiral/{tables/debug → debug}/scan.py +7 -7
- spiral/expressions/base.py +3 -3
- spiral/expressions/udf.py +1 -1
- spiral/{iceberg/client.py → iceberg.py} +1 -3
- spiral/key_space_index.py +44 -0
- spiral/project.py +171 -18
- spiral/protogen/_/arrow/flight/protocol/sql/__init__.py +1668 -1110
- spiral/protogen/_/google/protobuf/__init__.py +2190 -0
- spiral/protogen/_/message_pool.py +3 -0
- spiral/protogen/_/py.typed +0 -0
- spiral/protogen/_/scandal/__init__.py +138 -126
- spiral/protogen/_/spfs/__init__.py +72 -0
- spiral/protogen/_/spql/__init__.py +61 -0
- spiral/protogen/_/substrait/__init__.py +5256 -2459
- spiral/protogen/_/substrait/extensions/__init__.py +103 -49
- spiral/{tables/scan.py → scan.py} +37 -44
- spiral/settings.py +14 -3
- spiral/snapshot.py +55 -0
- spiral/streaming_/__init__.py +3 -0
- spiral/streaming_/reader.py +117 -0
- spiral/streaming_/stream.py +146 -0
- spiral/substrait_.py +9 -9
- spiral/table.py +257 -0
- spiral/text_index.py +17 -0
- spiral/{tables/transaction.py → transaction.py} +11 -15
- pyspiral-0.4.4.dist-info/RECORD +0 -98
- spiral/cli/iceberg/__init__.py +0 -7
- spiral/cli/iceberg/namespaces.py +0 -47
- spiral/cli/iceberg/tables.py +0 -60
- spiral/cli/indexes/__init__.py +0 -19
- spiral/cli/tables/__init__.py +0 -121
- spiral/core/index/__init__.pyi +0 -15
- spiral/iceberg/__init__.py +0 -3
- spiral/indexes/__init__.py +0 -5
- spiral/indexes/client.py +0 -137
- spiral/indexes/index.py +0 -34
- spiral/indexes/scan.py +0 -22
- spiral/protogen/_/spiral/table/__init__.py +0 -22
- spiral/protogen/substrait/__init__.py +0 -3399
- spiral/protogen/substrait/extensions/__init__.py +0 -115
- spiral/tables/__init__.py +0 -12
- spiral/tables/client.py +0 -130
- spiral/tables/maintenance.py +0 -12
- spiral/tables/snapshot.py +0 -78
- spiral/tables/table.py +0 -145
- {pyspiral-0.4.4.dist-info → pyspiral-0.6.0.dist-info}/entry_points.txt +0 -0
- /spiral/{protogen/_/spiral → debug}/__init__.py +0 -0
- /spiral/{tables/debug → debug}/metrics.py +0 -0
- /spiral/{tables/debug → protogen/_/google}/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pyspiral
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.6.0
|
4
4
|
Classifier: Intended Audience :: Science/Research
|
5
5
|
Classifier: Operating System :: OS Independent
|
6
6
|
Classifier: Programming Language :: Python
|
@@ -12,29 +12,34 @@ Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
13
13
|
Classifier: Programming Language :: Rust
|
14
14
|
Classifier: License :: Other/Proprietary License
|
15
|
-
Requires-Dist:
|
15
|
+
Requires-Dist: betterproto2>=0.8.0
|
16
16
|
Requires-Dist: google-re2>=1.1.20240702
|
17
17
|
Requires-Dist: grpclib>=0.4.7
|
18
18
|
Requires-Dist: hishel>=0.0.30
|
19
19
|
Requires-Dist: httpx>=0.27.0
|
20
|
+
Requires-Dist: nanoid>=2.0.0
|
20
21
|
Requires-Dist: numpy>=2
|
21
22
|
Requires-Dist: pyarrow>=21.0.0
|
22
23
|
Requires-Dist: pydantic-settings>=2.3.4
|
23
24
|
Requires-Dist: pydantic[email]>=2.5.3
|
24
25
|
Requires-Dist: pyjwt[crypto]>=2.9.0
|
26
|
+
Requires-Dist: pyperclip>=1.9.0
|
25
27
|
Requires-Dist: questionary>=2.0.1
|
28
|
+
Requires-Dist: sqlglot[rs]>=25.25.1
|
26
29
|
Requires-Dist: tqdm>=4.66.5
|
27
30
|
Requires-Dist: typer>=0.16
|
28
31
|
Requires-Dist: xxhash>=3.4.1
|
29
|
-
Requires-Dist: nanoid>=2.0.0
|
30
|
-
Requires-Dist: sqlglot[rs]>=25.25.1
|
31
|
-
Requires-Dist: pyperclip>=1.9.0
|
32
32
|
Requires-Dist: polars>=1.31.0 ; extra == 'polars'
|
33
33
|
Requires-Dist: duckdb>=1.3.2 ; extra == 'duckdb'
|
34
|
+
Requires-Dist: datasets>=4.0.0 ; extra == 'datasets'
|
34
35
|
Requires-Dist: pyiceberg>=0.9.1 ; extra == 'pyiceberg'
|
36
|
+
Requires-Dist: mosaicml-streaming>=0.13.0 ; extra == 'streaming'
|
37
|
+
Requires-Dist: vortex-data>=0.52.1 ; extra == 'streaming'
|
35
38
|
Provides-Extra: polars
|
36
39
|
Provides-Extra: duckdb
|
40
|
+
Provides-Extra: datasets
|
37
41
|
Provides-Extra: pyiceberg
|
42
|
+
Provides-Extra: streaming
|
38
43
|
Summary: Python client for Spiral.
|
39
44
|
Home-Page: https://spiraldb.com
|
40
45
|
Author-email: SpiralDB <hello@spiraldb.com>
|
@@ -0,0 +1,99 @@
|
|
1
|
+
pyspiral-0.6.0.dist-info/METADATA,sha256=ETkF1eW1JfgWeoRKxgF7eDX0K9LWDOOixTO8mWW7GlA,1836
|
2
|
+
pyspiral-0.6.0.dist-info/WHEEL,sha256=Eg6gwEJKNVa1g53Yg4W5oLzLA6e9MoXTlIiHdDxmtOw,103
|
3
|
+
pyspiral-0.6.0.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
|
4
|
+
spiral/__init__.py,sha256=iAicRWWphlRNKjIS_BFTSqIweCLwJTJTbyWF0BvqMLY,667
|
5
|
+
spiral/_lib.abi3.so,sha256=hvWlKDITuH96YLRuRwpd_wHN406BaWM7ud6x_ht6Nyc,62669904
|
6
|
+
spiral/adbc.py,sha256=7IxfWIeQN-fh0W5OdN_PP2x3pzQYg6ZUOLsHg3jktqw,14842
|
7
|
+
spiral/api/__init__.py,sha256=ULBlVq3PnfNOO6T5naE_ULmmii-83--qTuN2PpAUQN0,2241
|
8
|
+
spiral/api/admin.py,sha256=A1iVR1XYJSObZivPAD5UzmPuMgupXc9kaHNYYa_kwfs,585
|
9
|
+
spiral/api/client.py,sha256=c63u4Nv0XqXW3BpGAofMk44d-1_4RymKwbcMzq9qxeY,4649
|
10
|
+
spiral/api/filesystems.py,sha256=EA4iqhTeaIlvObvEUxHmZl0pQ24IOxUVWM3GPhFLw8o,4969
|
11
|
+
spiral/api/key_space_indexes.py,sha256=-38rZXTdkL4mLhp9h3CtqyIyutzzq88tV6bhK05MqYE,640
|
12
|
+
spiral/api/organizations.py,sha256=B-8zZ7lFJANGK7dUNbo_aU-cgI959JBP9VcWb6wdgi0,1895
|
13
|
+
spiral/api/projects.py,sha256=62Y1lqI_TpUh3WKQqrjbLWJHiZsI_X3g8u2RTbUwkoA,6162
|
14
|
+
spiral/api/telemetry.py,sha256=tfdA3E_EWJwFVxkQfkm8tiYGRubnx2LuE5nbfsk1oG4,474
|
15
|
+
spiral/api/text_indexes.py,sha256=_zVlGBytl-9-Unbu2POfZgLh40H1YRcagFtplgIG428,1828
|
16
|
+
spiral/api/types.py,sha256=lGdiKViRgIEJXD2ubwnyEIEwHkfRumlZjVEaHMV3Tm8,682
|
17
|
+
spiral/api/workers.py,sha256=0wZNUHMioDT53P1OBJfpjyDfIodHwwT6858z2IlRIM4,636
|
18
|
+
spiral/api/workloads.py,sha256=XAyXV7vgZcoyyoPoGvOT4jTpyFKFMvrrAfhL6d1h1kE,1748
|
19
|
+
spiral/arrow_.py,sha256=T1LZ7bh9aMDbXfpUsf0dR0E1roTQyAYSgZ2mL4s8J_4,7681
|
20
|
+
spiral/cli/__init__.py,sha256=LutjpWZu5Rvmba8C8bPa5vOCv74JuAoE1kvz0nd48dE,2476
|
21
|
+
spiral/cli/__main__.py,sha256=kNaKM2xgJo7GRogf83nYldLM-RGUR6vymdGwZxywQu0,71
|
22
|
+
spiral/cli/admin.py,sha256=-ubYqs8nKjnQStbQ68jpWx_9xh0TsaxI0wM1Hfko8_U,319
|
23
|
+
spiral/cli/app.py,sha256=HWCjMJLzSz_JaiLF046jzC9A4-yvzS6506D3cOR2Vgc,1773
|
24
|
+
spiral/cli/console.py,sha256=6JHbAQV6MFWz3P-VzqPOjhHpkIQagsCdzTMvmuDKMkU,2580
|
25
|
+
spiral/cli/fs.py,sha256=UREIJhjr6MfIdcKK7pjUKICd0wsQULhQiWRVWUnQ0dc,4376
|
26
|
+
spiral/cli/iceberg.py,sha256=Q14tcGcn1LixbFCYP0GhfYwFFXTmmi8tqBPYwalJEyE,3248
|
27
|
+
spiral/cli/key_spaces.py,sha256=EEgn7Zjc16CkeQO-4vWdwEqCTddTMiUAdLh4vG4AoYk,2218
|
28
|
+
spiral/cli/login.py,sha256=TgTr37ImgG1NKN8VbtqkxVAYaZFpMXMwPAb23gVldEw,649
|
29
|
+
spiral/cli/orgs.py,sha256=fmOuLxpeIFfKqePRi292Gv9k-EF5pPn_tbKd2BLl2Ig,2869
|
30
|
+
spiral/cli/printer.py,sha256=HcvSUpaMItzmhBUfIHROK1Z3SL8J8wDopS3Qo8H00uw,1781
|
31
|
+
spiral/cli/projects.py,sha256=UYrBlLcFacuXExdLX1sZByfvkz9MRtk_0oRAZvqHa0w,5105
|
32
|
+
spiral/cli/state.py,sha256=10wTIVQ0SJkY67Z6-KQ1LFlt3aVIPmZhoHFdTwp4kNA,130
|
33
|
+
spiral/cli/tables.py,sha256=8-9ay0mXS1Ew7DMoYFfHqC-Ro0TWsOTTinusS7M1slE,4639
|
34
|
+
spiral/cli/telemetry.py,sha256=Uxo1Q1FkKJ6n6QNGOUmL3j_pRRWRx0qWIhoP-U9BuR0,589
|
35
|
+
spiral/cli/text.py,sha256=DlWGe4JrkdERAiqyITNpk91Wqb63Re99rNYlIFsIamc,4031
|
36
|
+
spiral/cli/types.py,sha256=XYzo1GgX7dBBItoBSrHI4vO5C2lLmS2sktb-2GnGH3E,1362
|
37
|
+
spiral/cli/workloads.py,sha256=2_SLfQTFN6y73R9H0i9dk8VIOVagKxSxOpHXC56yptY,2015
|
38
|
+
spiral/client.py,sha256=Po9xgCH3NwVsCeRZMm3eJUPV77Rknyj-9MfCS1TbdTg,6623
|
39
|
+
spiral/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
|
+
spiral/core/authn/__init__.pyi,sha256=Jw_8ywTMDTwgAtGxMtFED63rU0jOgrv-eZtaZ5sR5t4,757
|
41
|
+
spiral/core/client/__init__.pyi,sha256=uONPrQbKvlNjnIDLT7c0wG9GMWwNveRd6aHJu6NuQ74,5228
|
42
|
+
spiral/core/table/__init__.pyi,sha256=uZHXdm160fNAAoz3jnFPtbZl8EFEyLwS3wo0r7jEMOo,3807
|
43
|
+
spiral/core/table/manifests/__init__.pyi,sha256=3V59-K1qr1z2dGfgRKXaHSVheK8NNw8Q8PFhfbeQd_4,1065
|
44
|
+
spiral/core/table/metastore/__init__.pyi,sha256=rc3u9MwEKRvL2kxOc8lBorddFRnM8o_o1frqtae86a4,1697
|
45
|
+
spiral/core/table/spec/__init__.pyi,sha256=0NyGeyEhV_ebwKWVU3sqSvdF2D9v8kEVwo6wYAHF99M,5579
|
46
|
+
spiral/dataset.py,sha256=NNqG-oOrhbmNC2OMZ9AYAm4YkwwBozeRI6zXtz4cspA,8008
|
47
|
+
spiral/datetime_.py,sha256=1TA1RYIRU22qcUuipIjVhAtGnPDVn2z9WttuhkmfkwY,964
|
48
|
+
spiral/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
|
+
spiral/debug/manifests.py,sha256=CGC5C1HG4XCMhlkNZI-woBAIO-EQSVSqXuDUsiV-d7g,2935
|
50
|
+
spiral/debug/metrics.py,sha256=XdRDcjggtsLNGCAjam6IxG9072pz_d2C8iLApNRFUtk,2044
|
51
|
+
spiral/debug/scan.py,sha256=9bMmVQFs5M6Rldm0fmrmmvn9LbSSTKBV5tIu37mEn78,8938
|
52
|
+
spiral/expressions/__init__.py,sha256=T8PIb0_UB9kynK0dpWbUD4No5lKRTG-wKnao8xOcXjY,6381
|
53
|
+
spiral/expressions/base.py,sha256=OOUDrbkLBE0lSkAmM-6FP2F2N8zhN_in3S_UDrWLDeQ,4805
|
54
|
+
spiral/expressions/http.py,sha256=begUydWoFHEqjeLkATvI_v66Ez6_rR-OQBWO5cHbb9c,2742
|
55
|
+
spiral/expressions/io.py,sha256=gJ2a0FKMmdxarWKENulPRwH7KDvSJTIh_OUxX306xAM,3045
|
56
|
+
spiral/expressions/list_.py,sha256=MMt5lf5H1M3O-x6N_PvqOLGq9NOk6Ukv0fPWwPC_uy4,1809
|
57
|
+
spiral/expressions/mp4.py,sha256=_xGVnkygddzxP9a8OACJ8_KXnejuVbYCVKBCXBQ798Y,2151
|
58
|
+
spiral/expressions/png.py,sha256=KO8X0OmMzUFwpg2I_j0JTyldPzVXDWIMzjWMWDV9vIY,506
|
59
|
+
spiral/expressions/qoi.py,sha256=gvIbb6fXb_Bb080sn9wkpbGGrPs2UEcTXCfuv4-kcYQ,506
|
60
|
+
spiral/expressions/refs.py,sha256=omeHBQ5o6N4xgZ3x5Xz7IRrWwYBBtQY8DYK0NNAxeGo,2109
|
61
|
+
spiral/expressions/str_.py,sha256=tY8RXW3JWvr1-bEfCZtk5FAf11wKJnXPuA9EoeJ9tA4,1265
|
62
|
+
spiral/expressions/struct.py,sha256=pGAnCDh6AK0BK1XfZ1qG4ce4ranIQEE1HQsgmzBcfwQ,2038
|
63
|
+
spiral/expressions/text.py,sha256=-02gBWYoyNQ3qQ1--9HTa8IryUDojYQVIp8C7rgnOWQ,1893
|
64
|
+
spiral/expressions/tiff.py,sha256=fQwIn0kLFBM2Y3YYIHmTgb_EIRHKT2fNc77nioDQQw4,8044
|
65
|
+
spiral/expressions/udf.py,sha256=yb9MIcrFftpNDxgBF228cvdv6TY-hEFikYz2fq_nzWo,1353
|
66
|
+
spiral/grpc_.py,sha256=f3czdP1Mxme42Y5--a5ogYq1TTiWn-J_MlGjwJ2mWwM,1015
|
67
|
+
spiral/iceberg.py,sha256=JGq62Qnf296r9_hRAoH85GQq45-uSBjwXWw_CvPi6G4,930
|
68
|
+
spiral/key_space_index.py,sha256=NAB_nONEjpMYbse8suz42w7Qb5OPHuKN9h9CT2NJe08,1460
|
69
|
+
spiral/project.py,sha256=CO_Pn6vPqaonNvRdCNRFcBWr4TqO2AsAUTH5xawIeCE,7283
|
70
|
+
spiral/protogen/_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
71
|
+
spiral/protogen/_/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
|
+
spiral/protogen/_/arrow/flight/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
73
|
+
spiral/protogen/_/arrow/flight/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
|
+
spiral/protogen/_/arrow/flight/protocol/sql/__init__.py,sha256=yt4_UDWfOaVpyCBeQa2aVXIfZzRSrcfIQHsXFCWv0qI,90023
|
75
|
+
spiral/protogen/_/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
76
|
+
spiral/protogen/_/google/protobuf/__init__.py,sha256=lsfhHEPczGOxrOmkstAqh64V0Kt8hQE_6N0tIpc27HU,75116
|
77
|
+
spiral/protogen/_/message_pool.py,sha256=4-cRhhiM6bmfpUJZ8qxc8LEyqHBHpLCcotjbyZxl7JM,71
|
78
|
+
spiral/protogen/_/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
|
+
spiral/protogen/_/scandal/__init__.py,sha256=-4m9DHPjtLFzpnesaAv8W_p8R_kfGjA5z3l0GPPbjD8,4965
|
80
|
+
spiral/protogen/_/spfs/__init__.py,sha256=4lnc88HhuH4t-JR9NjXz5r5WVESxCEbyUpV7Xfc-SBI,2028
|
81
|
+
spiral/protogen/_/spql/__init__.py,sha256=JJBlNacSIIoo5cazHFyLtdkGRLYgwNru1FstFpuPGg8,1548
|
82
|
+
spiral/protogen/_/substrait/__init__.py,sha256=-PqWiWMN0hl3Gntj5l1wpEhOMdGDgv3PskGPouaRct8,209839
|
83
|
+
spiral/protogen/_/substrait/extensions/__init__.py,sha256=sCMvwWCXWu2cSGiTEH0hRjkn0WTsePLDIxRBBNpENJs,5326
|
84
|
+
spiral/protogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
|
+
spiral/protogen/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
|
86
|
+
spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
87
|
+
spiral/scan.py,sha256=nItu2SNqp5-f2LPMl4EXrEUxV5tJJGEVQEPMSko3STY,7044
|
88
|
+
spiral/server.py,sha256=ztBmB5lBnUz-smQxR_tC8AI5SOhz17wH0MI3GuzDUdM,600
|
89
|
+
spiral/settings.py,sha256=Nap68xM-1ZvF3yDhkyRnNDIAVMIgxmIksglg_1iT0-0,3069
|
90
|
+
spiral/snapshot.py,sha256=_l2wrqUXz2RARjIDxOWw4aQpegJohvggIoWuCllzStA,1506
|
91
|
+
spiral/streaming_/__init__.py,sha256=s7MlW2ERsuZmZGExLFL6RcZon2e0tNBocBg5ANgki7k,61
|
92
|
+
spiral/streaming_/reader.py,sha256=CahNNeJznRuUUTtWNexoEBZtKh9bikfaI6UCnER3Jhw,3451
|
93
|
+
spiral/streaming_/stream.py,sha256=xFTtGB6CspEKstzBeyyaOeOR3KDiJc21m07ZpD1AXZQ,5669
|
94
|
+
spiral/substrait_.py,sha256=AKeOD4KIXvz2J4TYxnIneOiHddtBIyOhuNxVO_uH0eg,12592
|
95
|
+
spiral/table.py,sha256=Y5_FqZGjXwt7LT_SYzUA-M-zOBcOdJs7d_t919TAc1k,9605
|
96
|
+
spiral/text_index.py,sha256=FQ9rgIEGLSJryS9lFdMhKtPFey18BXoWbPXyvZPJJ04,442
|
97
|
+
spiral/transaction.py,sha256=O3vSaTc7zpeC5qbqnj-VWKwK6rrp_mYV2JuPHp2ZJ80,1464
|
98
|
+
spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
|
99
|
+
pyspiral-0.6.0.dist-info/RECORD,,
|
spiral/__init__.py
CHANGED
@@ -3,8 +3,15 @@
|
|
3
3
|
# This is here to make sure we load the native extension first
|
4
4
|
from spiral import _lib
|
5
5
|
|
6
|
-
|
6
|
+
# Eagerly import the Spiral library
|
7
|
+
assert _lib, "Spiral library"
|
7
8
|
|
8
|
-
from spiral.client import Spiral # noqa: E402
|
9
|
+
from spiral.client import Spiral # noqa: E402
|
10
|
+
from spiral.key_space_index import KeySpaceIndex # noqa: E402
|
11
|
+
from spiral.project import Project # noqa: E402
|
12
|
+
from spiral.scan import Scan, ShuffleStrategy # noqa: E402
|
13
|
+
from spiral.snapshot import Snapshot # noqa: E402
|
14
|
+
from spiral.table import Table # noqa: E402
|
15
|
+
from spiral.text_index import TextIndex # noqa: E402
|
9
16
|
|
10
|
-
__all__ = ["Spiral"]
|
17
|
+
__all__ = ["Spiral", "Project", "Table", "Snapshot", "Scan", "ShuffleStrategy", "TextIndex", "KeySpaceIndex"]
|
spiral/_lib.abi3.so
CHANGED
Binary file
|
spiral/adbc.py
CHANGED
@@ -8,7 +8,6 @@ import pyarrow as pa
|
|
8
8
|
import pyarrow.compute as pc
|
9
9
|
import sqlglot
|
10
10
|
import sqlglot.expressions as exp
|
11
|
-
from betterproto.lib.google.protobuf import Any
|
12
11
|
from pyarrow.flight import (
|
13
12
|
Action,
|
14
13
|
FlightDescriptor,
|
@@ -35,6 +34,8 @@ from spiral.protogen._.arrow.flight.protocol.sql import (
|
|
35
34
|
SqlInfo,
|
36
35
|
SqlSupportedTransaction,
|
37
36
|
)
|
37
|
+
from spiral.protogen._.google.protobuf import Any
|
38
|
+
from spiral.snapshot import Snapshot
|
38
39
|
|
39
40
|
log = logging.getLogger(__name__)
|
40
41
|
logging.getLogger("sqlx").setLevel(logging.WARNING)
|
@@ -64,7 +65,6 @@ def debuggable(func):
|
|
64
65
|
return wrapper_decorator
|
65
66
|
|
66
67
|
|
67
|
-
# TODO(marko): This should work for Iceberg tables.
|
68
68
|
class ADBCServerBase:
|
69
69
|
def get_sql_info(self, _req: CommandGetSqlInfo) -> pa.RecordBatchReader:
|
70
70
|
"""Default implementation that reports no support for any complex features."""
|
@@ -143,6 +143,17 @@ class SpiralADBCServer(ADBCServerBase):
|
|
143
143
|
|
144
144
|
self.pool = ThreadPoolExecutor()
|
145
145
|
|
146
|
+
def open_snapshot(self, tbl) -> Snapshot:
|
147
|
+
"""Open a table in the Spiral project and return it as a PyArrow Dataset."""
|
148
|
+
if tbl.catalog is None or tbl.catalog == "":
|
149
|
+
raise FlightError("Project (Data Catalog) must be specified to open a table.")
|
150
|
+
|
151
|
+
project = tbl.catalog
|
152
|
+
dataset = tbl.db or "default"
|
153
|
+
table = tbl.name
|
154
|
+
|
155
|
+
return self.sp.project(project).table(f"{dataset}.{table}").snapshot()
|
156
|
+
|
146
157
|
def get_catalogs(self, req: CommandGetCatalogs) -> pa.RecordBatchReader:
|
147
158
|
schema = pa.schema([pa.field("catalog_name", pa.string(), nullable=False)])
|
148
159
|
|
@@ -170,15 +181,16 @@ class SpiralADBCServer(ADBCServerBase):
|
|
170
181
|
if req.catalog == "":
|
171
182
|
# Empty string means databases _without_ a catalog, which we don't support
|
172
183
|
return
|
184
|
+
catalog = req.catalog
|
173
185
|
|
174
186
|
# Otherwise, catalog is either the project ID, or None.
|
175
|
-
if
|
187
|
+
if catalog is None:
|
176
188
|
projects = self.sp.list_projects()
|
177
189
|
else:
|
178
190
|
projects = [self.sp.project(req.catalog)]
|
179
191
|
|
180
192
|
for project in projects:
|
181
|
-
datasets = {
|
193
|
+
datasets = {tbl.dataset for tbl in project.list_tables()}
|
182
194
|
|
183
195
|
batch = pa.RecordBatch.from_arrays(
|
184
196
|
[
|
@@ -219,9 +231,10 @@ class SpiralADBCServer(ADBCServerBase):
|
|
219
231
|
projects = list(self.sp.list_projects())
|
220
232
|
else:
|
221
233
|
projects = [self.sp.project(req.catalog)]
|
234
|
+
projects = sorted(projects, key=lambda p: p.id)
|
222
235
|
|
223
236
|
def _process_project(project):
|
224
|
-
tables: list[TableResource] = project.
|
237
|
+
tables: list[TableResource] = project.list_tables()
|
225
238
|
|
226
239
|
rows = []
|
227
240
|
for table in tables:
|
@@ -233,7 +246,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
233
246
|
}
|
234
247
|
|
235
248
|
if req.include_schema:
|
236
|
-
open_table = project.
|
249
|
+
open_table = project.table(f"{table.dataset}.{table.table}")
|
237
250
|
row["table_schema"] = open_table.snapshot().to_dataset().schema.serialize().to_pybytes()
|
238
251
|
|
239
252
|
rows.append(row)
|
@@ -248,12 +261,13 @@ class SpiralADBCServer(ADBCServerBase):
|
|
248
261
|
def statement_query(self, req: CommandStatementQuery, limit: int | None = None) -> pa.RecordBatchReader:
|
249
262
|
# Extract the tables from the query, and bring them into the Python locals scope.
|
250
263
|
expr = sqlglot.parse_one(req.query, dialect="duckdb")
|
264
|
+
datasets = {}
|
251
265
|
for tbl in expr.find_all(exp.Table):
|
252
266
|
# We swap the three-part identifier out for a single identifier
|
253
|
-
# This lets us
|
254
|
-
|
255
|
-
name =
|
256
|
-
|
267
|
+
# This lets us register a PyArrow Dataset with DuckDB for the query.
|
268
|
+
snapshot = self.open_snapshot(tbl)
|
269
|
+
name = snapshot.table.table_id
|
270
|
+
datasets[name] = snapshot.to_dataset()
|
257
271
|
tbl.replace(exp.table_(table=name))
|
258
272
|
|
259
273
|
try:
|
@@ -262,7 +276,11 @@ class SpiralADBCServer(ADBCServerBase):
|
|
262
276
|
raise FlightError("DuckDB is required for SQL queries.")
|
263
277
|
|
264
278
|
try:
|
265
|
-
|
279
|
+
# Create a DuckDB connection and register the datasets
|
280
|
+
conn = duckdb.connect()
|
281
|
+
for name, dataset in datasets.items():
|
282
|
+
conn.register(name, dataset)
|
283
|
+
sql = conn.sql(expr.sql(dialect="duckdb"))
|
266
284
|
except Exception as e:
|
267
285
|
raise FlightError(str(e))
|
268
286
|
|
spiral/api/__init__.py
CHANGED
@@ -10,9 +10,11 @@ if TYPE_CHECKING:
|
|
10
10
|
|
11
11
|
from .admin import AdminService
|
12
12
|
from .filesystems import FileSystemService
|
13
|
+
from .key_space_indexes import KeySpaceIndexesService
|
13
14
|
from .organizations import OrganizationService
|
14
15
|
from .projects import ProjectService
|
15
16
|
from .telemetry import TelemetryService
|
17
|
+
from .text_indexes import TextIndexesService
|
16
18
|
from .workloads import WorkloadService
|
17
19
|
|
18
20
|
|
@@ -57,6 +59,18 @@ class SpiralAPI:
|
|
57
59
|
|
58
60
|
return WorkloadService(self.client)
|
59
61
|
|
62
|
+
@property
|
63
|
+
def text_indexes(self) -> "TextIndexesService":
|
64
|
+
from .text_indexes import TextIndexesService
|
65
|
+
|
66
|
+
return TextIndexesService(self.client)
|
67
|
+
|
68
|
+
@property
|
69
|
+
def key_space_indexes(self) -> "KeySpaceIndexesService":
|
70
|
+
from .key_space_indexes import KeySpaceIndexesService
|
71
|
+
|
72
|
+
return KeySpaceIndexesService(self.client)
|
73
|
+
|
60
74
|
@property
|
61
75
|
def telemetry(self) -> "TelemetryService":
|
62
76
|
from .telemetry import TelemetryService
|
spiral/api/client.py
CHANGED
@@ -6,7 +6,7 @@ import httpx
|
|
6
6
|
from httpx import HTTPStatusError
|
7
7
|
from pydantic import BaseModel, Field, TypeAdapter
|
8
8
|
|
9
|
-
from spiral.core.
|
9
|
+
from spiral.core.authn import Authn
|
10
10
|
|
11
11
|
log = logging.getLogger(__name__)
|
12
12
|
|
@@ -146,6 +146,10 @@ class _Client:
|
|
146
146
|
# Enrich the exception with the response body
|
147
147
|
raise SpiralHTTPError(body=resp.text, code=resp.status_code) from e
|
148
148
|
|
149
|
+
if response_cls == type[None]:
|
150
|
+
assert resp.text == ""
|
151
|
+
return None
|
152
|
+
|
149
153
|
return TypeAdapter(response_cls).validate_python(resp.json())
|
150
154
|
|
151
155
|
def paged(
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
|
3
|
+
from .client import ServiceBase
|
4
|
+
from .types import IndexId, WorkerId
|
5
|
+
from .workers import ResourceClass
|
6
|
+
|
7
|
+
|
8
|
+
class SyncIndexRequest(BaseModel):
|
9
|
+
"""Request to sync a text index."""
|
10
|
+
|
11
|
+
resources: ResourceClass
|
12
|
+
|
13
|
+
|
14
|
+
class SyncIndexResponse(BaseModel):
|
15
|
+
worker_id: WorkerId
|
16
|
+
|
17
|
+
|
18
|
+
class KeySpaceIndexesService(ServiceBase):
|
19
|
+
"""Service for key space index operations."""
|
20
|
+
|
21
|
+
def sync_index(self, index_id: IndexId, request: SyncIndexRequest) -> SyncIndexResponse:
|
22
|
+
"""Start a job to sync an index."""
|
23
|
+
return self.client.post(f"/v1/key-space-indexes/{index_id}/sync", request, SyncIndexResponse)
|
spiral/api/projects.py
CHANGED
@@ -138,6 +138,12 @@ class TextIndexResource(BaseModel):
|
|
138
138
|
name: str
|
139
139
|
|
140
140
|
|
141
|
+
class KeySpaceIndexResource(BaseModel):
|
142
|
+
id: str
|
143
|
+
project_id: ProjectId
|
144
|
+
name: str
|
145
|
+
|
146
|
+
|
141
147
|
class ProjectService(ServiceBase):
|
142
148
|
"""Service for project operations."""
|
143
149
|
|
@@ -169,6 +175,15 @@ class ProjectService(ServiceBase):
|
|
169
175
|
f"/v1/projects/{project_id}/text-indexes", PagedResponse[TextIndexResource], params=params
|
170
176
|
)
|
171
177
|
|
178
|
+
def list_key_space_indexes(self, project_id: ProjectId, name: str | None = None) -> Paged[KeySpaceIndexResource]:
|
179
|
+
"""List key space indexes in a project."""
|
180
|
+
params = {}
|
181
|
+
if name:
|
182
|
+
params["name"] = name
|
183
|
+
return self.client.paged(
|
184
|
+
f"/v1/projects/{project_id}/key-space-indexes", PagedResponse[KeySpaceIndexResource], params=params
|
185
|
+
)
|
186
|
+
|
172
187
|
def get(self, project_id: ProjectId) -> Project:
|
173
188
|
"""Get a project."""
|
174
189
|
return self.client.get(f"/v1/projects/{project_id}", Project)
|
@@ -192,6 +207,6 @@ class ProjectService(ServiceBase):
|
|
192
207
|
"""Get a grant."""
|
193
208
|
return self.client.get(f"/v1/grants/{grant_id}", Grant)
|
194
209
|
|
195
|
-
def revoke_grant(self, grant_id: str)
|
210
|
+
def revoke_grant(self, grant_id: str):
|
196
211
|
"""Revoke a grant."""
|
197
|
-
return self.client.delete(f"/v1/grants/{grant_id}", None)
|
212
|
+
return self.client.delete(f"/v1/grants/{grant_id}", type[None])
|
@@ -0,0 +1,56 @@
|
|
1
|
+
from pydantic import BaseModel
|
2
|
+
|
3
|
+
from .client import Paged, PagedResponse, ServiceBase
|
4
|
+
from .types import IndexId, ProjectId, WorkerId
|
5
|
+
from .workers import CPU, GcpRegion, Memory, ResourceClass
|
6
|
+
|
7
|
+
|
8
|
+
class TextSearchWorker(BaseModel):
|
9
|
+
worker_id: WorkerId
|
10
|
+
project_id: ProjectId
|
11
|
+
index_id: IndexId
|
12
|
+
url: str | None
|
13
|
+
|
14
|
+
|
15
|
+
class CreateWorkerRequest(BaseModel):
|
16
|
+
cpu: CPU
|
17
|
+
memory: Memory
|
18
|
+
region: GcpRegion
|
19
|
+
|
20
|
+
|
21
|
+
class CreateWorkerResponse(BaseModel):
|
22
|
+
worker_id: WorkerId
|
23
|
+
|
24
|
+
|
25
|
+
class SyncIndexRequest(BaseModel):
|
26
|
+
"""Request to sync a text index."""
|
27
|
+
|
28
|
+
resources: ResourceClass
|
29
|
+
|
30
|
+
|
31
|
+
class SyncIndexResponse(BaseModel):
|
32
|
+
worker_id: WorkerId
|
33
|
+
|
34
|
+
|
35
|
+
class TextIndexesService(ServiceBase):
|
36
|
+
"""Service for text index operations."""
|
37
|
+
|
38
|
+
def create_worker(self, index_id: IndexId, request: CreateWorkerRequest) -> CreateWorkerResponse:
|
39
|
+
"""Create a new search worker."""
|
40
|
+
return self.client.post(f"/v1/text-indexes/{index_id}/workers", request, CreateWorkerResponse)
|
41
|
+
|
42
|
+
def list_workers(self, index_id: IndexId) -> Paged[WorkerId]:
|
43
|
+
"""List text index workers for the given index."""
|
44
|
+
return self.client.paged(f"/v1/text-indexes/{index_id}/workers", PagedResponse[WorkerId])
|
45
|
+
|
46
|
+
def get_worker(self, worker_id: WorkerId) -> TextSearchWorker:
|
47
|
+
"""Get a text index worker."""
|
48
|
+
return self.client.get(f"/v1/text-index-workers/{worker_id}", TextSearchWorker)
|
49
|
+
|
50
|
+
def shutdown_worker(self, worker_id: WorkerId) -> None:
|
51
|
+
"""Shutdown a text index worker."""
|
52
|
+
return self.client.delete(f"/v1/text-index-workers/{worker_id}", type[None])
|
53
|
+
|
54
|
+
def sync_index(self, index_id: IndexId, request: SyncIndexRequest) -> SyncIndexResponse:
|
55
|
+
"""Start a job to sync an index."""
|
56
|
+
return self.client.post(f"/v1/text-indexes/{index_id}/sync", request, SyncIndexResponse)
|
spiral/api/types.py
CHANGED
@@ -13,6 +13,8 @@ UserId = str
|
|
13
13
|
OrgId = str
|
14
14
|
ProjectId = str
|
15
15
|
RoleId = str
|
16
|
+
IndexId = str
|
17
|
+
WorkerId = str
|
16
18
|
|
17
19
|
RootUri = Annotated[str, AfterValidator(_validate_root_uri)]
|
18
20
|
DatasetName = Annotated[str, StringConstraints(max_length=128, pattern=r"^[a-zA-Z_][a-zA-Z0-9_-]+$")]
|
spiral/api/workers.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
from enum import Enum, IntEnum
|
2
|
+
|
3
|
+
|
4
|
+
class CPU(IntEnum):
|
5
|
+
ONE = 1
|
6
|
+
TWO = 2
|
7
|
+
FOUR = 4
|
8
|
+
EIGHT = 8
|
9
|
+
|
10
|
+
def __str__(self):
|
11
|
+
return str(self.value)
|
12
|
+
|
13
|
+
|
14
|
+
class Memory(str, Enum):
|
15
|
+
MB_512 = "512Mi"
|
16
|
+
GB_1 = "1Gi"
|
17
|
+
GB_2 = "2Gi"
|
18
|
+
GB_4 = "4Gi"
|
19
|
+
GB_8 = "8Gi"
|
20
|
+
|
21
|
+
def __str__(self):
|
22
|
+
return self.value
|
23
|
+
|
24
|
+
|
25
|
+
class GcpRegion(str, Enum):
|
26
|
+
US_EAST4 = "us-east4"
|
27
|
+
EUROPE_WEST4 = "europe-west4"
|
28
|
+
|
29
|
+
def __str__(self):
|
30
|
+
return self.value
|
31
|
+
|
32
|
+
|
33
|
+
class ResourceClass(str, Enum):
|
34
|
+
"""Resource class for text index sync."""
|
35
|
+
|
36
|
+
SMALL = "small"
|
37
|
+
LARGE = "large"
|
38
|
+
|
39
|
+
def __str__(self):
|
40
|
+
return self.value
|
spiral/cli/__init__.py
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
import asyncio
|
2
2
|
import functools
|
3
3
|
import inspect
|
4
|
-
from
|
4
|
+
from collections.abc import Callable
|
5
|
+
from typing import IO, Generic, ParamSpec, TypeVar, override
|
5
6
|
|
6
|
-
import rich
|
7
7
|
import typer
|
8
8
|
from click import ClickException
|
9
9
|
from grpclib import GRPCError
|
10
10
|
from httpx import HTTPStatusError
|
11
|
+
from rich.console import Console
|
11
12
|
|
13
|
+
P = ParamSpec("P")
|
14
|
+
T = TypeVar("T")
|
12
15
|
|
13
|
-
|
16
|
+
CONSOLE = Console()
|
17
|
+
ERR_CONSOLE = Console(stderr=True, style="red")
|
18
|
+
|
19
|
+
|
20
|
+
class AsyncTyper(typer.Typer, Generic[P]):
|
14
21
|
"""Wrapper to allow async functions to be used as commands.
|
15
22
|
|
16
23
|
We also pre-bake some configuration.
|
@@ -25,13 +32,15 @@ class AsyncTyper(typer.Typer):
|
|
25
32
|
**kwargs,
|
26
33
|
)
|
27
34
|
|
28
|
-
|
35
|
+
@override
|
36
|
+
def callback(self, *args, **kwargs) -> Callable[[Callable[P, T]], Callable[P, T]]:
|
29
37
|
decorator = super().callback(*args, **kwargs)
|
30
38
|
for wrapper in (_wrap_exceptions, _maybe_run_async):
|
31
39
|
decorator = functools.partial(wrapper, decorator)
|
32
40
|
return decorator
|
33
41
|
|
34
|
-
|
42
|
+
@override
|
43
|
+
def command(self, *args, **kwargs) -> Callable[[Callable[P, T]], Callable[P, T]]:
|
35
44
|
decorator = super().command(*args, **kwargs)
|
36
45
|
for wrapper in (_wrap_exceptions, _maybe_run_async):
|
37
46
|
decorator = functools.partial(wrapper, decorator)
|
@@ -50,7 +59,7 @@ class _ClickGRPCException(ClickException):
|
|
50
59
|
return self.message
|
51
60
|
|
52
61
|
def show(self, file: IO[str] | None = None) -> None:
|
53
|
-
|
62
|
+
ERR_CONSOLE.print(f"Error: {self.format_message()}")
|
54
63
|
|
55
64
|
|
56
65
|
def _maybe_run_async(decorator, f):
|
spiral/cli/admin.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
from rich import print
|
2
|
-
|
3
1
|
from spiral.api.types import OrgId
|
4
|
-
from spiral.cli import AsyncTyper, state
|
2
|
+
from spiral.cli import CONSOLE, AsyncTyper, state
|
5
3
|
|
6
4
|
app = AsyncTyper()
|
7
5
|
|
@@ -13,4 +11,4 @@ def sync(
|
|
13
11
|
state.settings.api._admin.sync_orgs()
|
14
12
|
|
15
13
|
for membership in state.settings.api._admin.sync_memberships(org_id):
|
16
|
-
print(membership)
|
14
|
+
CONSOLE.print(membership)
|
spiral/cli/app.py
CHANGED
@@ -8,13 +8,14 @@ from spiral.cli import (
|
|
8
8
|
console,
|
9
9
|
fs,
|
10
10
|
iceberg,
|
11
|
-
|
11
|
+
key_spaces,
|
12
12
|
login,
|
13
13
|
orgs,
|
14
14
|
projects,
|
15
15
|
state,
|
16
16
|
tables,
|
17
17
|
telemetry,
|
18
|
+
text,
|
18
19
|
workloads,
|
19
20
|
)
|
20
21
|
from spiral.settings import LOG_DIR, Settings
|
@@ -36,7 +37,8 @@ app.add_typer(orgs.app, name="orgs")
|
|
36
37
|
app.add_typer(projects.app, name="projects")
|
37
38
|
app.add_typer(iceberg.app, name="iceberg")
|
38
39
|
app.add_typer(tables.app, name="tables")
|
39
|
-
app.add_typer(
|
40
|
+
app.add_typer(key_spaces.app, name="ks")
|
41
|
+
app.add_typer(text.app, name="text")
|
40
42
|
app.add_typer(telemetry.app, name="telemetry")
|
41
43
|
app.command("console")(console.command)
|
42
44
|
app.command("login")(login.command)
|
spiral/cli/fs.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
from typing import Annotated
|
2
2
|
|
3
3
|
import questionary
|
4
|
-
import rich
|
5
4
|
from pydantic import SecretStr
|
6
5
|
from typer import Option
|
7
6
|
|
@@ -13,7 +12,7 @@ from spiral.api.filesystems import (
|
|
13
12
|
UpdateS3FileSystem,
|
14
13
|
UpstreamFileSystem,
|
15
14
|
)
|
16
|
-
from spiral.cli import AsyncTyper, state
|
15
|
+
from spiral.cli import CONSOLE, AsyncTyper, state
|
17
16
|
from spiral.cli.types import ProjectArg, ask_project
|
18
17
|
|
19
18
|
app = AsyncTyper(short_help="File Systems.")
|
@@ -24,9 +23,9 @@ def show(project: ProjectArg):
|
|
24
23
|
file_system = state.settings.api.file_system.get_file_system(project)
|
25
24
|
match file_system:
|
26
25
|
case BuiltinFileSystem(provider=provider):
|
27
|
-
|
26
|
+
CONSOLE.print(f"provider: {provider}")
|
28
27
|
case _:
|
29
|
-
|
28
|
+
CONSOLE.print(file_system)
|
30
29
|
|
31
30
|
|
32
31
|
def ask_provider():
|
@@ -103,10 +102,10 @@ def update(
|
|
103
102
|
raise ValueError("Must specify either --s3 or --gcs.")
|
104
103
|
|
105
104
|
res = state.settings.api.file_system.update_file_system(project, file_system)
|
106
|
-
|
105
|
+
CONSOLE.print(res.file_system)
|
107
106
|
|
108
107
|
|
109
108
|
@app.command(help="Lists the available built-in file system providers.")
|
110
109
|
def list_providers():
|
111
110
|
for provider in state.settings.api.file_system.list_providers():
|
112
|
-
|
111
|
+
CONSOLE.print(provider)
|