pyspiral 0.5.0__cp310-abi3-macosx_11_0_arm64.whl → 0.6.1__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.5.0.dist-info → pyspiral-0.6.1.dist-info}/METADATA +7 -3
- pyspiral-0.6.1.dist-info/RECORD +99 -0
- {pyspiral-0.5.0.dist-info → pyspiral-0.6.1.dist-info}/WHEEL +1 -1
- spiral/__init__.py +11 -3
- spiral/_lib.abi3.so +0 -0
- spiral/adbc.py +6 -6
- spiral/api/__init__.py +8 -2
- spiral/api/client.py +1 -1
- spiral/api/key_space_indexes.py +23 -0
- spiral/api/projects.py +15 -0
- spiral/api/text_indexes.py +1 -1
- 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 +89 -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 +152 -63
- spiral/core/table/__init__.pyi +17 -27
- 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 +15 -6
- spiral/{tables/debug → debug}/scan.py +3 -3
- 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} +38 -44
- spiral/settings.py +14 -3
- spiral/snapshot.py +55 -0
- spiral/streaming_/__init__.py +3 -0
- spiral/streaming_/reader.py +131 -0
- spiral/streaming_/stream.py +146 -0
- spiral/substrait_.py +9 -9
- spiral/table.py +259 -0
- spiral/text_index.py +17 -0
- spiral/{tables/transaction.py → transaction.py} +11 -15
- pyspiral-0.5.0.dist-info/RECORD +0 -103
- 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 -40
- spiral/cli/indexes/args.py +0 -39
- spiral/cli/indexes/workers.py +0 -59
- spiral/cli/tables/__init__.py +0 -88
- spiral/cli/tables/args.py +0 -42
- spiral/core/index/__init__.pyi +0 -7
- spiral/iceberg/__init__.py +0 -3
- spiral/indexes/__init__.py +0 -5
- spiral/indexes/client.py +0 -137
- spiral/indexes/index.py +0 -28
- 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 -133
- spiral/tables/maintenance.py +0 -12
- spiral/tables/snapshot.py +0 -78
- spiral/tables/table.py +0 -145
- {pyspiral-0.5.0.dist-info → pyspiral-0.6.1.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.1
|
4
4
|
Classifier: Intended Audience :: Science/Research
|
5
5
|
Classifier: Operating System :: OS Independent
|
6
6
|
Classifier: Programming Language :: Python
|
@@ -12,8 +12,7 @@ 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:
|
16
|
-
Requires-Dist: datasets>=4.0.0
|
15
|
+
Requires-Dist: betterproto2>=0.8.0
|
17
16
|
Requires-Dist: google-re2>=1.1.20240702
|
18
17
|
Requires-Dist: grpclib>=0.4.7
|
19
18
|
Requires-Dist: hishel>=0.0.30
|
@@ -32,10 +31,15 @@ Requires-Dist: typer>=0.16
|
|
32
31
|
Requires-Dist: xxhash>=3.4.1
|
33
32
|
Requires-Dist: polars>=1.31.0 ; extra == 'polars'
|
34
33
|
Requires-Dist: duckdb>=1.3.2 ; extra == 'duckdb'
|
34
|
+
Requires-Dist: datasets>=4.0.0 ; extra == 'datasets'
|
35
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'
|
36
38
|
Provides-Extra: polars
|
37
39
|
Provides-Extra: duckdb
|
40
|
+
Provides-Extra: datasets
|
38
41
|
Provides-Extra: pyiceberg
|
42
|
+
Provides-Extra: streaming
|
39
43
|
Summary: Python client for Spiral.
|
40
44
|
Home-Page: https://spiraldb.com
|
41
45
|
Author-email: SpiralDB <hello@spiraldb.com>
|
@@ -0,0 +1,99 @@
|
|
1
|
+
pyspiral-0.6.1.dist-info/METADATA,sha256=dvU4zmSKjosVkzzsl8kYTMvaVneaplCKGJ0ml4SBRxo,1836
|
2
|
+
pyspiral-0.6.1.dist-info/WHEEL,sha256=Eg6gwEJKNVa1g53Yg4W5oLzLA6e9MoXTlIiHdDxmtOw,103
|
3
|
+
pyspiral-0.6.1.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
|
4
|
+
spiral/__init__.py,sha256=5c0faqg-kHZBDwriQ7LzLAMcFolIucp-IA1EzNvCZ3k,711
|
5
|
+
spiral/_lib.abi3.so,sha256=PBqFvphQEfKc4zSGihmAZIq_t1uO1EvVJYzZXz1P5dI,62642240
|
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=x3IFRP5d47pKiAHeWExYMOBaT2TwxbWjVM01SUqKrwI,2943
|
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=48lZ0wPQSCTul1vn-Qx6Be5eGnw75Abtw2zxMK9dCPg,4613
|
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=iEhZgbySG5LScfrtkiiHW1iHghgehsrVmPP-v5Pv_vk,5740
|
42
|
+
spiral/core/table/__init__.pyi,sha256=_N9JyGoJXcbJWXjZal0HSSxNbbMptrqKZJHj5GA_mQg,2974
|
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=oaPB4534pQdqvPXCZetVNSvvhpdXTrv_1pN-_bAkeAo,2893
|
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=20-NSGsoXYf6uKQ7yEdbbwT8ijIK7KxKTctycsl0AIk,7073
|
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=Kpqknv2jn12jUhHOEEDArj0JZwrWb8XjoOGs9HrdVyA,4047
|
93
|
+
spiral/streaming_/stream.py,sha256=xFTtGB6CspEKstzBeyyaOeOR3KDiJc21m07ZpD1AXZQ,5669
|
94
|
+
spiral/substrait_.py,sha256=AKeOD4KIXvz2J4TYxnIneOiHddtBIyOhuNxVO_uH0eg,12592
|
95
|
+
spiral/table.py,sha256=knJjSCPrFLXmjCbUzslGZ7avH0V_Z0o-rsctWDzmGK4,9821
|
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.1.dist-info/RECORD,,
|
spiral/__init__.py
CHANGED
@@ -3,8 +3,16 @@
|
|
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.core.client import ShuffleStrategy # noqa: E402
|
11
|
+
from spiral.key_space_index import KeySpaceIndex # noqa: E402
|
12
|
+
from spiral.project import Project # noqa: E402
|
13
|
+
from spiral.scan import Scan # noqa: E402
|
14
|
+
from spiral.snapshot import Snapshot # noqa: E402
|
15
|
+
from spiral.table import Table # noqa: E402
|
16
|
+
from spiral.text_index import TextIndex # noqa: E402
|
9
17
|
|
10
|
-
__all__ = ["Spiral"]
|
18
|
+
__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,7 +34,8 @@ from spiral.protogen._.arrow.flight.protocol.sql import (
|
|
35
34
|
SqlInfo,
|
36
35
|
SqlSupportedTransaction,
|
37
36
|
)
|
38
|
-
from spiral.
|
37
|
+
from spiral.protogen._.google.protobuf import Any
|
38
|
+
from spiral.snapshot import Snapshot
|
39
39
|
|
40
40
|
log = logging.getLogger(__name__)
|
41
41
|
logging.getLogger("sqlx").setLevel(logging.WARNING)
|
@@ -152,7 +152,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
152
152
|
dataset = tbl.db or "default"
|
153
153
|
table = tbl.name
|
154
154
|
|
155
|
-
return self.sp.project(project).
|
155
|
+
return self.sp.project(project).table(f"{dataset}.{table}").snapshot()
|
156
156
|
|
157
157
|
def get_catalogs(self, req: CommandGetCatalogs) -> pa.RecordBatchReader:
|
158
158
|
schema = pa.schema([pa.field("catalog_name", pa.string(), nullable=False)])
|
@@ -190,7 +190,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
190
190
|
projects = [self.sp.project(req.catalog)]
|
191
191
|
|
192
192
|
for project in projects:
|
193
|
-
datasets = {tbl.dataset for tbl in project.
|
193
|
+
datasets = {tbl.dataset for tbl in project.list_tables()}
|
194
194
|
|
195
195
|
batch = pa.RecordBatch.from_arrays(
|
196
196
|
[
|
@@ -234,7 +234,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
234
234
|
projects = sorted(projects, key=lambda p: p.id)
|
235
235
|
|
236
236
|
def _process_project(project):
|
237
|
-
tables: list[TableResource] = project.
|
237
|
+
tables: list[TableResource] = project.list_tables()
|
238
238
|
|
239
239
|
rows = []
|
240
240
|
for table in tables:
|
@@ -246,7 +246,7 @@ class SpiralADBCServer(ADBCServerBase):
|
|
246
246
|
}
|
247
247
|
|
248
248
|
if req.include_schema:
|
249
|
-
open_table = project.
|
249
|
+
open_table = project.table(f"{table.dataset}.{table.table}")
|
250
250
|
row["table_schema"] = open_table.snapshot().to_dataset().schema.serialize().to_pybytes()
|
251
251
|
|
252
252
|
rows.append(row)
|
spiral/api/__init__.py
CHANGED
@@ -3,8 +3,6 @@ from typing import TYPE_CHECKING
|
|
3
3
|
|
4
4
|
import httpx
|
5
5
|
|
6
|
-
from spiral.api.text_indexes import TextIndexesService
|
7
|
-
|
8
6
|
from .client import _Client
|
9
7
|
|
10
8
|
if TYPE_CHECKING:
|
@@ -12,9 +10,11 @@ if TYPE_CHECKING:
|
|
12
10
|
|
13
11
|
from .admin import AdminService
|
14
12
|
from .filesystems import FileSystemService
|
13
|
+
from .key_space_indexes import KeySpaceIndexesService
|
15
14
|
from .organizations import OrganizationService
|
16
15
|
from .projects import ProjectService
|
17
16
|
from .telemetry import TelemetryService
|
17
|
+
from .text_indexes import TextIndexesService
|
18
18
|
from .workloads import WorkloadService
|
19
19
|
|
20
20
|
|
@@ -65,6 +65,12 @@ class SpiralAPI:
|
|
65
65
|
|
66
66
|
return TextIndexesService(self.client)
|
67
67
|
|
68
|
+
@property
|
69
|
+
def key_space_indexes(self) -> "KeySpaceIndexesService":
|
70
|
+
from .key_space_indexes import KeySpaceIndexesService
|
71
|
+
|
72
|
+
return KeySpaceIndexesService(self.client)
|
73
|
+
|
68
74
|
@property
|
69
75
|
def telemetry(self) -> "TelemetryService":
|
70
76
|
from .telemetry import TelemetryService
|
spiral/api/client.py
CHANGED
@@ -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)
|
spiral/api/text_indexes.py
CHANGED
@@ -33,7 +33,7 @@ class SyncIndexResponse(BaseModel):
|
|
33
33
|
|
34
34
|
|
35
35
|
class TextIndexesService(ServiceBase):
|
36
|
-
"""Service for
|
36
|
+
"""Service for text index operations."""
|
37
37
|
|
38
38
|
def create_worker(self, index_id: IndexId, request: CreateWorkerRequest) -> CreateWorkerResponse:
|
39
39
|
"""Create a new search worker."""
|
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)
|
spiral/cli/iceberg.py
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
import sys
|
2
|
+
from typing import Annotated
|
3
|
+
|
4
|
+
import rich
|
5
|
+
import typer
|
6
|
+
from typer import Argument
|
7
|
+
|
8
|
+
from spiral.cli import CONSOLE, ERR_CONSOLE, AsyncTyper, state
|
9
|
+
from spiral.cli.types import ProjectArg
|
10
|
+
|
11
|
+
app = AsyncTyper(short_help="Apache Iceberg Catalog")
|
12
|
+
|
13
|
+
|
14
|
+
@app.command(help="List namespaces.")
|
15
|
+
def namespaces(
|
16
|
+
project: ProjectArg,
|
17
|
+
namespace: Annotated[str | None, Argument(help="List only namespaces under this namespace.")] = None,
|
18
|
+
):
|
19
|
+
"""List Iceberg namespaces."""
|
20
|
+
import pyiceberg.exceptions
|
21
|
+
|
22
|
+
catalog = state.spiral.iceberg.catalog()
|
23
|
+
|
24
|
+
if namespace is None:
|
25
|
+
try:
|
26
|
+
namespaces = catalog.list_namespaces(project)
|
27
|
+
except pyiceberg.exceptions.ForbiddenError:
|
28
|
+
ERR_CONSOLE.print(
|
29
|
+
f"The project, {repr(project)}, does not exist or you lack the "
|
30
|
+
f"`iceberg:view` permission to list namespaces in it.",
|
31
|
+
)
|
32
|
+
raise typer.Exit(code=1)
|
33
|
+
else:
|
34
|
+
try:
|
35
|
+
namespaces = catalog.list_namespaces((project, namespace))
|
36
|
+
except pyiceberg.exceptions.ForbiddenError:
|
37
|
+
ERR_CONSOLE.print(
|
38
|
+
f"The namespace, {repr(project)}.{repr(namespace)}, does not exist or you lack the "
|
39
|
+
f"`iceberg:view` permission to list namespaces in it.",
|
40
|
+
)
|
41
|
+
raise typer.Exit(code=1)
|
42
|
+
|
43
|
+
table = CONSOLE.table.Table("Namespace ID", title="Iceberg namespaces")
|
44
|
+
for ns in namespaces:
|
45
|
+
table.add_row(".".join(ns))
|
46
|
+
CONSOLE.print(table)
|
47
|
+
|
48
|
+
|
49
|
+
@app.command(help="List tables.")
|
50
|
+
def tables(
|
51
|
+
project: ProjectArg,
|
52
|
+
namespace: Annotated[str | None, Argument(help="Show only tables in the given namespace.")] = None,
|
53
|
+
):
|
54
|
+
import pyiceberg.exceptions
|
55
|
+
|
56
|
+
catalog = state.spiral.iceberg.catalog()
|
57
|
+
|
58
|
+
try:
|
59
|
+
if namespace is None:
|
60
|
+
tables = catalog.list_tables(project)
|
61
|
+
else:
|
62
|
+
tables = catalog.list_tables((project, namespace))
|
63
|
+
except pyiceberg.exceptions.ForbiddenError:
|
64
|
+
ERR_CONSOLE.print(
|
65
|
+
f"The namespace, {repr(project)}.{repr(namespace)}, does not exist or you lack the "
|
66
|
+
f"`iceberg:view` permission to list tables in it.",
|
67
|
+
)
|
68
|
+
raise typer.Exit(code=1)
|
69
|
+
|
70
|
+
rich_table = rich.table.Table("table id", title="Iceberg tables")
|
71
|
+
for table in tables:
|
72
|
+
rich_table.add_row(".".join(table))
|
73
|
+
CONSOLE.print(rich_table)
|
74
|
+
|
75
|
+
|
76
|
+
@app.command(help="Show the table schema.")
|
77
|
+
def schema(
|
78
|
+
project: ProjectArg,
|
79
|
+
namespace: Annotated[str, Argument(help="Table namespace.")],
|
80
|
+
table: Annotated[str, Argument(help="Table name.")],
|
81
|
+
):
|
82
|
+
import pyiceberg.exceptions
|
83
|
+
|
84
|
+
catalog = state.spiral.iceberg.catalog()
|
85
|
+
|
86
|
+
try:
|
87
|
+
tbl = catalog.load_table((project, namespace, table))
|
88
|
+
except pyiceberg.exceptions.NoSuchTableError:
|
89
|
+
ERR_CONSOLE.print(f"No table {repr(table)} found in {repr(project)}.{repr(namespace)}", file=sys.stderr)
|
90
|
+
raise typer.Exit(code=1)
|
91
|
+
|
92
|
+
rich_table = rich.table.Table(
|
93
|
+
"Field ID", "Field name", "Type", "Required", "Doc", title=f"{project}.{namespace}.{table}"
|
94
|
+
)
|
95
|
+
for col in tbl.schema().columns:
|
96
|
+
rich_table.add_row(str(col.field_id), col.name, str(col.field_type), str(col.required), col.doc)
|
97
|
+
CONSOLE.print(rich_table)
|
spiral/cli/key_spaces.py
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
from typing import Annotated
|
2
|
+
|
3
|
+
import questionary
|
4
|
+
import rich
|
5
|
+
import typer
|
6
|
+
from questionary import Choice
|
7
|
+
from typer import Option
|
8
|
+
|
9
|
+
from spiral.api.key_space_indexes import SyncIndexRequest
|
10
|
+
from spiral.api.projects import KeySpaceIndexResource
|
11
|
+
from spiral.api.types import IndexId
|
12
|
+
from spiral.api.workers import ResourceClass
|
13
|
+
from spiral.cli import CONSOLE, AsyncTyper, state
|
14
|
+
from spiral.cli.types import ProjectArg
|
15
|
+
|
16
|
+
app = AsyncTyper(short_help="Key Space Indexes.")
|
17
|
+
|
18
|
+
|
19
|
+
def ask_index(project_id, title="Select an index"):
|
20
|
+
indexes: list[KeySpaceIndexResource] = list(state.spiral.project(project_id).list_key_space_indexes())
|
21
|
+
|
22
|
+
if not indexes:
|
23
|
+
CONSOLE.print("[red]No indexes found[/red]")
|
24
|
+
raise typer.Exit(1)
|
25
|
+
|
26
|
+
return questionary.select(
|
27
|
+
title,
|
28
|
+
choices=[Choice(title=index.name, value=index.id) for index in sorted(indexes, key=lambda t: (t.name, t.id))],
|
29
|
+
).ask()
|
30
|
+
|
31
|
+
|
32
|
+
def get_index_id(
|
33
|
+
project: ProjectArg,
|
34
|
+
name: Annotated[str | None, Option(help="Index name.")] = None,
|
35
|
+
) -> IndexId:
|
36
|
+
if name is None:
|
37
|
+
return ask_index(project)
|
38
|
+
|
39
|
+
indexes: list[KeySpaceIndexResource] = list(state.spiral.project(project).list_key_space_indexes())
|
40
|
+
for index in indexes:
|
41
|
+
if index.name == name:
|
42
|
+
return index.id
|
43
|
+
raise ValueError(f"Index not found: {name}")
|
44
|
+
|
45
|
+
|
46
|
+
@app.command(help="List indexes.")
|
47
|
+
def ls(
|
48
|
+
project: ProjectArg,
|
49
|
+
):
|
50
|
+
"""List indexes."""
|
51
|
+
indexes = state.spiral.project(project).list_key_space_indexes()
|
52
|
+
|
53
|
+
rich_table = rich.table.Table("id", "name", title="Key Space Indexes")
|
54
|
+
for index in indexes:
|
55
|
+
rich_table.add_row(index.id, index.name)
|
56
|
+
CONSOLE.print(rich_table)
|
57
|
+
|
58
|
+
|
59
|
+
@app.command(help="Show index partitions.")
|
60
|
+
def show(
|
61
|
+
project: ProjectArg,
|
62
|
+
name: Annotated[str | None, Option(help="Index name.")] = None,
|
63
|
+
):
|
64
|
+
"""Show index partitions."""
|
65
|
+
index_id = get_index_id(project, name)
|
66
|
+
index = state.spiral.key_space_index(index_id)
|
67
|
+
shards = state.spiral._ops().compute_shards(index.core)
|
68
|
+
|
69
|
+
rich_table = rich.table.Table("Begin", "End", "Cardinality", title=f"Index {index.name} Partitions")
|
70
|
+
for partition in shards:
|
71
|
+
rich_table.add_row(
|
72
|
+
# TODO(marko): This isn't really pretty...
|
73
|
+
repr(partition.key_range.begin),
|
74
|
+
repr(partition.key_range.end),
|
75
|
+
str(partition.cardinality),
|
76
|
+
)
|
77
|
+
CONSOLE.print(rich_table)
|
78
|
+
|
79
|
+
|
80
|
+
@app.command(help="Trigger a sync job for an index.")
|
81
|
+
def sync(
|
82
|
+
project: ProjectArg,
|
83
|
+
name: Annotated[str | None, Option(help="Index name.")] = None,
|
84
|
+
resources: Annotated[ResourceClass, Option(help="Resources to use for the sync job.")] = ResourceClass.SMALL,
|
85
|
+
):
|
86
|
+
"""Trigger a sync job."""
|
87
|
+
index_id = get_index_id(project, name)
|
88
|
+
response = state.spiral.api.key_space_indexes.sync_index(index_id, SyncIndexRequest(resources=resources))
|
89
|
+
CONSOLE.print(f"Triggered sync job {response.worker_id} for index {index_id}.")
|