pyspiral 0.8.9__cp311-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.
Files changed (114) hide show
  1. pyspiral-0.8.9.dist-info/METADATA +53 -0
  2. pyspiral-0.8.9.dist-info/RECORD +114 -0
  3. pyspiral-0.8.9.dist-info/WHEEL +4 -0
  4. pyspiral-0.8.9.dist-info/entry_points.txt +3 -0
  5. spiral/__init__.py +55 -0
  6. spiral/_lib.abi3.so +0 -0
  7. spiral/adbc.py +411 -0
  8. spiral/api/__init__.py +78 -0
  9. spiral/api/admin.py +15 -0
  10. spiral/api/client.py +165 -0
  11. spiral/api/filesystems.py +152 -0
  12. spiral/api/key_space_indexes.py +23 -0
  13. spiral/api/organizations.py +78 -0
  14. spiral/api/projects.py +219 -0
  15. spiral/api/telemetry.py +19 -0
  16. spiral/api/text_indexes.py +56 -0
  17. spiral/api/types.py +23 -0
  18. spiral/api/workers.py +40 -0
  19. spiral/api/workloads.py +52 -0
  20. spiral/arrow_.py +202 -0
  21. spiral/cli/__init__.py +89 -0
  22. spiral/cli/__main__.py +4 -0
  23. spiral/cli/admin.py +33 -0
  24. spiral/cli/app.py +108 -0
  25. spiral/cli/console.py +95 -0
  26. spiral/cli/fs.py +109 -0
  27. spiral/cli/iceberg.py +97 -0
  28. spiral/cli/key_spaces.py +103 -0
  29. spiral/cli/login.py +25 -0
  30. spiral/cli/orgs.py +81 -0
  31. spiral/cli/printer.py +53 -0
  32. spiral/cli/projects.py +148 -0
  33. spiral/cli/state.py +7 -0
  34. spiral/cli/tables.py +225 -0
  35. spiral/cli/telemetry.py +17 -0
  36. spiral/cli/text.py +115 -0
  37. spiral/cli/types.py +50 -0
  38. spiral/cli/workloads.py +86 -0
  39. spiral/client.py +279 -0
  40. spiral/core/__init__.pyi +0 -0
  41. spiral/core/_tools/__init__.pyi +5 -0
  42. spiral/core/authn/__init__.pyi +21 -0
  43. spiral/core/client/__init__.pyi +270 -0
  44. spiral/core/config/__init__.pyi +35 -0
  45. spiral/core/expr/__init__.pyi +15 -0
  46. spiral/core/expr/images/__init__.pyi +3 -0
  47. spiral/core/expr/list_/__init__.pyi +4 -0
  48. spiral/core/expr/pushdown/__init__.pyi +3 -0
  49. spiral/core/expr/refs/__init__.pyi +4 -0
  50. spiral/core/expr/s3/__init__.pyi +3 -0
  51. spiral/core/expr/str_/__init__.pyi +3 -0
  52. spiral/core/expr/struct_/__init__.pyi +6 -0
  53. spiral/core/expr/text/__init__.pyi +5 -0
  54. spiral/core/expr/udf/__init__.pyi +14 -0
  55. spiral/core/expr/video/__init__.pyi +3 -0
  56. spiral/core/table/__init__.pyi +142 -0
  57. spiral/core/table/manifests/__init__.pyi +35 -0
  58. spiral/core/table/metastore/__init__.pyi +58 -0
  59. spiral/core/table/spec/__init__.pyi +214 -0
  60. spiral/dataloader.py +310 -0
  61. spiral/dataset.py +264 -0
  62. spiral/datetime_.py +27 -0
  63. spiral/debug/__init__.py +0 -0
  64. spiral/debug/manifests.py +103 -0
  65. spiral/debug/metrics.py +56 -0
  66. spiral/debug/scan.py +266 -0
  67. spiral/demo.py +100 -0
  68. spiral/enrichment.py +290 -0
  69. spiral/expressions/__init__.py +274 -0
  70. spiral/expressions/base.py +186 -0
  71. spiral/expressions/file.py +17 -0
  72. spiral/expressions/http.py +17 -0
  73. spiral/expressions/list_.py +77 -0
  74. spiral/expressions/pushdown.py +12 -0
  75. spiral/expressions/s3.py +16 -0
  76. spiral/expressions/str_.py +39 -0
  77. spiral/expressions/struct.py +59 -0
  78. spiral/expressions/text.py +62 -0
  79. spiral/expressions/tiff.py +225 -0
  80. spiral/expressions/udf.py +66 -0
  81. spiral/grpc_.py +32 -0
  82. spiral/iceberg.py +31 -0
  83. spiral/iterable_dataset.py +106 -0
  84. spiral/key_space_index.py +44 -0
  85. spiral/project.py +247 -0
  86. spiral/protogen/_/__init__.py +0 -0
  87. spiral/protogen/_/arrow/__init__.py +0 -0
  88. spiral/protogen/_/arrow/flight/__init__.py +0 -0
  89. spiral/protogen/_/arrow/flight/protocol/__init__.py +0 -0
  90. spiral/protogen/_/arrow/flight/protocol/sql/__init__.py +2548 -0
  91. spiral/protogen/_/google/__init__.py +0 -0
  92. spiral/protogen/_/google/protobuf/__init__.py +2310 -0
  93. spiral/protogen/_/message_pool.py +3 -0
  94. spiral/protogen/_/py.typed +0 -0
  95. spiral/protogen/_/scandal/__init__.py +190 -0
  96. spiral/protogen/_/spfs/__init__.py +72 -0
  97. spiral/protogen/_/spql/__init__.py +61 -0
  98. spiral/protogen/_/substrait/__init__.py +6196 -0
  99. spiral/protogen/_/substrait/extensions/__init__.py +169 -0
  100. spiral/protogen/__init__.py +0 -0
  101. spiral/protogen/util.py +41 -0
  102. spiral/py.typed +0 -0
  103. spiral/scan.py +383 -0
  104. spiral/server.py +37 -0
  105. spiral/settings.py +36 -0
  106. spiral/snapshot.py +61 -0
  107. spiral/streaming_/__init__.py +3 -0
  108. spiral/streaming_/reader.py +133 -0
  109. spiral/streaming_/stream.py +156 -0
  110. spiral/substrait_.py +274 -0
  111. spiral/table.py +216 -0
  112. spiral/text_index.py +17 -0
  113. spiral/transaction.py +156 -0
  114. spiral/types_.py +6 -0
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyspiral
3
+ Version: 0.8.9
4
+ Classifier: Intended Audience :: Science/Research
5
+ Classifier: Operating System :: OS Independent
6
+ Classifier: Programming Language :: Python
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Rust
14
+ Classifier: License :: Other/Proprietary License
15
+ Requires-Dist: betterproto2>=0.9.0
16
+ Requires-Dist: google-re2>=1.1.20240702
17
+ Requires-Dist: grpclib>=0.4.7
18
+ Requires-Dist: hishel>=0.0.30
19
+ Requires-Dist: httpx>=0.27.0
20
+ Requires-Dist: nanoid>=2.0.0
21
+ Requires-Dist: pyarrow>=21.0.0
22
+ Requires-Dist: pydantic-settings>=2.3.4
23
+ Requires-Dist: pydantic[email]>=2.12.4,<2.13
24
+ Requires-Dist: pyjwt[crypto]>=2.9.0
25
+ Requires-Dist: pyperclip>=1.9.0
26
+ Requires-Dist: questionary>=2.0.1
27
+ Requires-Dist: sqlglot[rs]>=25.25.1
28
+ Requires-Dist: tqdm>=4.66.5
29
+ Requires-Dist: typer>=0.16
30
+ Requires-Dist: xxhash>=3.4.1
31
+ Requires-Dist: polars>=1.31.0 ; extra == 'polars'
32
+ Requires-Dist: duckdb>=1.3.2 ; extra == 'duckdb'
33
+ Requires-Dist: pyiceberg[s3fs]>=0.9.1 ; extra == 'iceberg'
34
+ Requires-Dist: datasets>=4.0.0 ; extra == 'huggingface'
35
+ Requires-Dist: mosaicml-streaming>=0.13.0 ; extra == 'streaming'
36
+ Requires-Dist: vortex-data>=0.52.1 ; extra == 'streaming'
37
+ Requires-Dist: dask>=2025.10.0 ; extra == 'dask'
38
+ Requires-Dist: distributed>=2025.10.0 ; extra == 'dask'
39
+ Provides-Extra: polars
40
+ Provides-Extra: duckdb
41
+ Provides-Extra: iceberg
42
+ Provides-Extra: huggingface
43
+ Provides-Extra: streaming
44
+ Provides-Extra: dask
45
+ Summary: Python client for Spiral.
46
+ Home-Page: https://spiraldb.com
47
+ Author-email: SpiralDB <hello@spiraldb.com>
48
+ License: Proprietary License
49
+ Requires-Python: >=3.11
50
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
51
+
52
+ # PySpiral
53
+
@@ -0,0 +1,114 @@
1
+ pyspiral-0.8.9.dist-info/METADATA,sha256=Ti8e0-xOdp5VUMbJ8X30eLyH-tkaPi-9MdG0DDWLZuI,1953
2
+ pyspiral-0.8.9.dist-info/WHEEL,sha256=wLM-4-OuCEmDufFmMnL4mT6DsF8lSbFPkcIGjsPxDb0,104
3
+ pyspiral-0.8.9.dist-info/entry_points.txt,sha256=R96Y3FpYX6XbQu9qMPfUTgiCcf4qM9OBQQZTDdBkZwA,74
4
+ spiral/__init__.py,sha256=PwaYBWFBtB7cYi7peMmhk_Lm5XzjRoLwOtLbUhc1ZDo,1449
5
+ spiral/_lib.abi3.so,sha256=EA4kgWe6pzgxACe8OELMyZfscv2wOE8ADrPk0CikrZ0,80996768
6
+ spiral/adbc.py,sha256=Mc2wdC_fqvE4jqlgHqCI7M9Y-jRH4SaAjxJMibmIvbc,14854
7
+ spiral/api/__init__.py,sha256=XlDdWLyEfnK3FRyYaA02JN91890QYpcPnyvilz9XcTk,2140
8
+ spiral/api/admin.py,sha256=A1iVR1XYJSObZivPAD5UzmPuMgupXc9kaHNYYa_kwfs,585
9
+ spiral/api/client.py,sha256=v1_FD46Hy4XMAUGfoNBcbnqwRX10WfkTpPQfVsLkozM,4665
10
+ spiral/api/filesystems.py,sha256=8g_YdFjFFZLybQqV1xSH91SxVvOer4O6sGECexWXRnw,4548
11
+ spiral/api/key_space_indexes.py,sha256=-38rZXTdkL4mLhp9h3CtqyIyutzzq88tV6bhK05MqYE,640
12
+ spiral/api/organizations.py,sha256=eXAzxrKPmd3IVFfEaEbqbhqG0AjBM4IDz3O-ZoxJI5w,1928
13
+ spiral/api/projects.py,sha256=j2sYhhh_Q3Pk9MBukb8pQgKN2JP00RKyDYdAcgLbmtw,6357
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=HpHsoBuf7IdlXb7Dw-BkBkEvxBVIhkI8JviqhuoP9pY,696
17
+ spiral/api/workers.py,sha256=0wZNUHMioDT53P1OBJfpjyDfIodHwwT6858z2IlRIM4,636
18
+ spiral/api/workloads.py,sha256=GBZ4tLa_-NtZvV-P5GTJgPSxBQ_YiLyWaOpr9ELojOo,1764
19
+ spiral/arrow_.py,sha256=fUpXmjUjG-rGfqMhKR332QzC7zrfIU2yjLaWKYzefwU,6778
20
+ spiral/cli/__init__.py,sha256=GdTQZVArIw19zSKi92ZtwD8pXQExuubnaN854XLTSzY,2505
21
+ spiral/cli/__main__.py,sha256=kNaKM2xgJo7GRogf83nYldLM-RGUR6vymdGwZxywQu0,71
22
+ spiral/cli/admin.py,sha256=sC_XUZvi7t91qHMR5vea_KD3lXUcygil1MUw7zVFmpE,945
23
+ spiral/cli/app.py,sha256=nNDoMxnGCJIiaD8PMDqSL2rK_QErmtZGOGHT4V29CRA,2825
24
+ spiral/cli/console.py,sha256=6JHbAQV6MFWz3P-VzqPOjhHpkIQagsCdzTMvmuDKMkU,2580
25
+ spiral/cli/fs.py,sha256=Swawf9oPQjL0NOE-sB96xtK7G6hhfTu8q9XxSwflSQw,4173
26
+ spiral/cli/iceberg.py,sha256=wdMyl0j821MLnXNZ6Kwm65ogh98C-pjMJm3Y6YqlnTI,3249
27
+ spiral/cli/key_spaces.py,sha256=84MibTdjI5bFK7lhL0w1WOlw-uBZtFnPPlTQuI2PPGw,3524
28
+ spiral/cli/login.py,sha256=2l2i38XNHGKtV4DP6PZPN4LHxceCn3AdHDE5nM2iK5M,760
29
+ spiral/cli/orgs.py,sha256=QHvpUQrKqaNC99efa8v0l-bg38aJCE6m7N9LU6VmMlc,2537
30
+ spiral/cli/printer.py,sha256=HcvSUpaMItzmhBUfIHROK1Z3SL8J8wDopS3Qo8H00uw,1781
31
+ spiral/cli/projects.py,sha256=2d-um9qlX9TK7ehvDUq5hUTsqvj-4S9DoL_h5U111-Y,5802
32
+ spiral/cli/state.py,sha256=3sKQuFtV2vCn3E1Dv7Sw9-IK5jiXCVBEQ9Ze17NZXDs,129
33
+ spiral/cli/tables.py,sha256=JnTJbHzUC48SOeb8sgzj8dfpR67y4eTTdg7T5fEZzAs,7914
34
+ spiral/cli/telemetry.py,sha256=9kp7lmimShsGoLRUic5aOEQ4hti-pPFMBFc4cdlPDmk,587
35
+ spiral/cli/text.py,sha256=DlWGe4JrkdERAiqyITNpk91Wqb63Re99rNYlIFsIamc,4031
36
+ spiral/cli/types.py,sha256=0Zau84chh3XGIdFYqzC3LvgRtY8Ljw7WnKpzvjQ45SA,1360
37
+ spiral/cli/workloads.py,sha256=r6f5y_MTPW460wpd50hC4BkFrg7WM4NOqUkgEI4Vg-U,2997
38
+ spiral/client.py,sha256=UGFYteCv02_8vt46N3dC_nGNxHeJ6feUhKPLvuidg-4,9918
39
+ spiral/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
+ spiral/core/_tools/__init__.pyi,sha256=b2KLfTOQ67pjfbYt07o0IGiTu5o2bZw69lllV8v0Dps,143
41
+ spiral/core/authn/__init__.pyi,sha256=deZvPlCyiPC6PpXxpEZVglxL5mUJ1Qqg20ieEQgU6ik,582
42
+ spiral/core/client/__init__.pyi,sha256=CxoshdsdmaEff7eoBf1eWMNMqNw6PfQKgy0QVzjSwKg,7395
43
+ spiral/core/config/__init__.pyi,sha256=1BaB7fTGly_fW-qTSQtxbGrYErzkqxuJokDFPupP7d0,955
44
+ spiral/core/expr/__init__.pyi,sha256=3HSKjkotiEkxBvGBALXEBIie0JiyI9bCpehwA3nMQkU,571
45
+ spiral/core/expr/images/__init__.pyi,sha256=wnE_wZXq7a4iqTg3SVm-ssxGw1WQZyk5dGOPaP4Btko,73
46
+ spiral/core/expr/list_/__init__.pyi,sha256=Q_9c87eIQfZbqlaw_rq3fvs93YEsW7K5VYk6VZ4g6mU,126
47
+ spiral/core/expr/pushdown/__init__.pyi,sha256=zcpBHFz-uriK0WccBUrPOuR8Mi8jPzEzpv9kGpp_PRw,60
48
+ spiral/core/expr/refs/__init__.pyi,sha256=nZZP3l_Z6bLx6V8lTcH3Jgo--xwfADOU2XdTAvM5IMk,127
49
+ spiral/core/expr/s3/__init__.pyi,sha256=GlgT6HtRqNbf31enHhkoM6HXHHxlgic7mApob_R3tOQ,76
50
+ spiral/core/expr/str_/__init__.pyi,sha256=Bm6fZK-d4fNbJuuBhVoWMACXUbQQ2SjlhgrOpdOHIPM,86
51
+ spiral/core/expr/struct_/__init__.pyi,sha256=MXckd98eV_x3X0RhEWvlkA3DcDXRtLs5pNnTQkc09nE,296
52
+ spiral/core/expr/text/__init__.pyi,sha256=ed83n1xcsGY7_QDhMmJGnSQ20UrJFXcdv1AveSEcS1c,175
53
+ spiral/core/expr/udf/__init__.pyi,sha256=zsZs081KVhY3-1JidqTkWMW81Qd_ScoTGZvasIhIK-4,358
54
+ spiral/core/expr/video/__init__.pyi,sha256=nQJEcSsigZuRpMjkI_O4EEtMK_n2zRvorcL_KEeD5vU,95
55
+ spiral/core/table/__init__.pyi,sha256=_BvwxwaTxILYTh2O5nDGpx23gqv3rxh-awNbDWsPKU0,4600
56
+ spiral/core/table/manifests/__init__.pyi,sha256=eVfDpmhYSjafIvvALqAkZe5baN3Y1HpKpxYEbjwd4gQ,1043
57
+ spiral/core/table/metastore/__init__.pyi,sha256=rc3u9MwEKRvL2kxOc8lBorddFRnM8o_o1frqtae86a4,1697
58
+ spiral/core/table/spec/__init__.pyi,sha256=839FNXvUS1PD-jYx2pXIIlTEjKszZUGfVD7WKSpflIQ,5659
59
+ spiral/dataloader.py,sha256=FAaV_B3HTH_gz2FQDDG_5gLjQYR3jScgyHaOa8fSoQk,10766
60
+ spiral/dataset.py,sha256=xse0evrNDKPXNrqaS5ZklyvPsrTPaFov5A2uwwMd9sU,8429
61
+ spiral/datetime_.py,sha256=elXaUWtZuuLVcu9E0aXnvYRPB9XWqZbLDToozQYQYjU,950
62
+ spiral/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
+ spiral/debug/manifests.py,sha256=IJjF5mqpTUeTLpSQ10PBn0DnkkNvPl0c1ghN-7s3PMI,3999
64
+ spiral/debug/metrics.py,sha256=_B1LoHejOQk7sfKX1dhVmHrcB3HNZzhr2M4iQfsyOUQ,2058
65
+ spiral/debug/scan.py,sha256=bYLY4nZNdo0cv7Ldcy3hkXix3aFClHOCG6QbOtn8954,9549
66
+ spiral/demo.py,sha256=YXjKAlxetzpZ9g3rEP0E9fa1bngWtaVicrECZa7IdTg,3173
67
+ spiral/enrichment.py,sha256=DpnCtKcdqwvogCu3ReR1iDktSQqA_GOXXLTzvHKb64w,10713
68
+ spiral/expressions/__init__.py,sha256=ZsD8g7vB0G7xy19GUiH4m79kw7KEkTQRwJl5Gn1cgtw,8049
69
+ spiral/expressions/base.py,sha256=ooTtXy5QkCmPNMYa7lJuFAguFpBrd59UWIxOGxhQ5h0,6261
70
+ spiral/expressions/file.py,sha256=7D9jIENJcoT0KFharBLkzK9dZgO4DYn5K_KCt0twefg,518
71
+ spiral/expressions/http.py,sha256=OOHh0WBxg3vwza_m74-rkoQWSclRMI60aPAbQ6yKZi0,486
72
+ spiral/expressions/list_.py,sha256=-OHzTkTYvTY_Q2IuATfK5QNx7KEyic3DzZLEYn8otIk,2050
73
+ spiral/expressions/pushdown.py,sha256=6ZHke34_YLFYiqp14tXIRWH3K2yVHADeNiRDY_tF5N8,371
74
+ spiral/expressions/s3.py,sha256=PhQhMP-d8PLsSRtGCZbytnm7lI9VbDAbuSs2LBM4G7Q,505
75
+ spiral/expressions/str_.py,sha256=tY8RXW3JWvr1-bEfCZtk5FAf11wKJnXPuA9EoeJ9tA4,1265
76
+ spiral/expressions/struct.py,sha256=pGAnCDh6AK0BK1XfZ1qG4ce4ranIQEE1HQsgmzBcfwQ,2038
77
+ spiral/expressions/text.py,sha256=-02gBWYoyNQ3qQ1--9HTa8IryUDojYQVIp8C7rgnOWQ,1893
78
+ spiral/expressions/tiff.py,sha256=B1N6ck1-CcIPSU9_Vnol7fXNnTbhV1CnMxvtAG5wmx0,7979
79
+ spiral/expressions/udf.py,sha256=XhePtyzrMgX0SQ5mOmf2XrdkhN7BSyyZpLZtF862B1U,2046
80
+ spiral/grpc_.py,sha256=f3czdP1Mxme42Y5--a5ogYq1TTiWn-J_MlGjwJ2mWwM,1015
81
+ spiral/iceberg.py,sha256=02OkA348eFxkEbgreeTuVlzavVvZmM4hldrZI76PZ9I,914
82
+ spiral/iterable_dataset.py,sha256=Eekg9ad8tcwXcloHWReBbvCSr5ZappRHn2ldKTvwqS0,4622
83
+ spiral/key_space_index.py,sha256=NAB_nONEjpMYbse8suz42w7Qb5OPHuKN9h9CT2NJe08,1460
84
+ spiral/project.py,sha256=bUqfROIouk_2WSZXc8DPbFwJuzPac8ucxOM7qHpw6gE,8796
85
+ spiral/protogen/_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ spiral/protogen/_/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
+ spiral/protogen/_/arrow/flight/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
+ spiral/protogen/_/arrow/flight/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
+ spiral/protogen/_/arrow/flight/protocol/sql/__init__.py,sha256=ooZZsDCRFpktUCH11OdxMRa_GLQYnY9w-1fBr5a7vBk,90023
90
+ spiral/protogen/_/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ spiral/protogen/_/google/protobuf/__init__.py,sha256=H0FVEXusqww2j5dl7Ee05tR6qMG_hQioUp1qFfDgnco,80036
92
+ spiral/protogen/_/message_pool.py,sha256=4-cRhhiM6bmfpUJZ8qxc8LEyqHBHpLCcotjbyZxl7JM,71
93
+ spiral/protogen/_/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
+ spiral/protogen/_/scandal/__init__.py,sha256=liUQAICLd2sPccCmqo0_c1duSbNj_m8p_IgmdnHsB3E,4965
95
+ spiral/protogen/_/spfs/__init__.py,sha256=zMMEDIfPXQNBkisLI-iMWbJABye-vK42Gf2BUQQYR_c,2028
96
+ spiral/protogen/_/spql/__init__.py,sha256=PEC4bI-PHdJ4Zd8Jb1k6Xk2iFYoYqIUbTGlL2JVGnT0,1548
97
+ spiral/protogen/_/substrait/__init__.py,sha256=-ngqHcYfio6s1B4M1_e1VsDymUcFK9qdM17ECA31qLw,209837
98
+ spiral/protogen/_/substrait/extensions/__init__.py,sha256=nhnEnho70GAT8WPj2xtwJUzk5GJ6X2e-HTvyk7emGsk,5326
99
+ spiral/protogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
+ spiral/protogen/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
101
+ spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
+ spiral/scan.py,sha256=PNjoY_GpjbdAQxXFXLNsB-P8Q1d_GLgQ_1whXvgpC_k,14268
103
+ spiral/server.py,sha256=Q1FcOAV0EsDespdBJI25R5K2mihP_i1xNRe99SYUhsY,1401
104
+ spiral/settings.py,sha256=zeiEhWC2H94r3o5-jsOqSIHu-hthRYO48ShWnXvGrQ8,895
105
+ spiral/snapshot.py,sha256=nf0ywmFy1Z2v6NCDBKBzfwmht5nGqWv2V_BifP_Q6Ag,1995
106
+ spiral/streaming_/__init__.py,sha256=s7MlW2ERsuZmZGExLFL6RcZon2e0tNBocBg5ANgki7k,61
107
+ spiral/streaming_/reader.py,sha256=tl_lC9xgh1-QFhsZn4xQT7It3PVTzHCEUT2BG2dWBRQ,4166
108
+ spiral/streaming_/stream.py,sha256=efqhExky4YgI1f3Me5ctfayFbTExoyS3TRMkrPIjvv0,5918
109
+ spiral/substrait_.py,sha256=AKeOD4KIXvz2J4TYxnIneOiHddtBIyOhuNxVO_uH0eg,12592
110
+ spiral/table.py,sha256=vRgNRvKld1kdCTpHgHNcb1VcRXyWZ-2O-3iRUGFIGkU,8031
111
+ spiral/text_index.py,sha256=FQ9rgIEGLSJryS9lFdMhKtPFey18BXoWbPXyvZPJJ04,442
112
+ spiral/transaction.py,sha256=rifPjzGsLl2hdoQmFMSGI049EWr7yNh1PnTvvohZU6Y,5418
113
+ spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
114
+ pyspiral-0.8.9.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-abi3-macosx_11_0_arm64
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ spiral=spiral.cli.app:main
3
+ pyspiral=spiral.cli.app:main
spiral/__init__.py ADDED
@@ -0,0 +1,55 @@
1
+ """Python client for Spiral"""
2
+
3
+ import importlib
4
+ import os
5
+ import warnings
6
+
7
+ # This is here to make sure we load the native extension first
8
+ from spiral import _lib
9
+
10
+ # Eagerly import the Spiral library
11
+ assert _lib, "Spiral library"
12
+
13
+
14
+ from spiral.client import Spiral # noqa: E402
15
+ from spiral.core.client import Shard, ShuffleConfig # noqa: E402
16
+ from spiral.dataloader import SpiralDataLoader, World # noqa: E402
17
+ from spiral.enrichment import Enrichment # noqa: E402
18
+ from spiral.iceberg import Iceberg # noqa: E402
19
+ from spiral.key_space_index import KeySpaceIndex # noqa: E402
20
+ from spiral.project import Project # noqa: E402
21
+ from spiral.scan import Scan # noqa: E402
22
+ from spiral.snapshot import Snapshot # noqa: E402
23
+ from spiral.table import Table # noqa: E402
24
+ from spiral.text_index import TextIndex # noqa: E402
25
+ from spiral.transaction import Transaction # noqa: E402
26
+
27
+ __all__ = [
28
+ "Spiral",
29
+ "Project",
30
+ "Table",
31
+ "Snapshot",
32
+ "Transaction",
33
+ "Enrichment",
34
+ "Scan",
35
+ "Shard",
36
+ "ShuffleConfig",
37
+ "TextIndex",
38
+ "KeySpaceIndex",
39
+ "SpiralDataLoader",
40
+ "World",
41
+ "Iceberg",
42
+ ]
43
+
44
+ __version__ = importlib.metadata.version("pyspiral")
45
+
46
+
47
+ def _warn_msg():
48
+ warnings.warn(
49
+ "Spiral does not support forking, and it may cause undefined behavior. \
50
+ Please use `spawn` or `forkserver` multiprocessing."
51
+ )
52
+
53
+
54
+ if hasattr(os, "register_at_fork"):
55
+ os.register_at_fork(before=_warn_msg)
spiral/_lib.abi3.so ADDED
Binary file
spiral/adbc.py ADDED
@@ -0,0 +1,411 @@
1
+ import abc
2
+ import functools
3
+ import logging
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from urllib.parse import urlparse
6
+
7
+ import pyarrow as pa
8
+ import pyarrow.compute as pc
9
+ import sqlglot
10
+ import sqlglot.expressions as exp
11
+ from pyarrow.flight import (
12
+ Action,
13
+ FlightDescriptor,
14
+ FlightEndpoint,
15
+ FlightError,
16
+ FlightInfo,
17
+ FlightMetadataWriter,
18
+ FlightServerBase,
19
+ MetadataRecordBatchReader,
20
+ RecordBatchStream,
21
+ ServerCallContext,
22
+ Ticket,
23
+ )
24
+
25
+ from spiral import Spiral
26
+ from spiral.api.projects import TableResource
27
+ from spiral.protogen._.arrow.flight.protocol import sql as rpc
28
+ from spiral.protogen._.arrow.flight.protocol.sql import (
29
+ CommandGetCatalogs,
30
+ CommandGetDbSchemas,
31
+ CommandGetSqlInfo,
32
+ CommandGetTables,
33
+ CommandStatementQuery,
34
+ SqlInfo,
35
+ SqlSupportedTransaction,
36
+ )
37
+ from spiral.protogen._.google.protobuf import Any
38
+ from spiral.snapshot import Snapshot
39
+
40
+ log = logging.getLogger(__name__)
41
+ logging.getLogger("sqlx").setLevel(logging.WARNING)
42
+
43
+
44
+ def debuggable(func):
45
+ """A decorator to enable GUI (i.e. PyCharm) debugging in the
46
+ decorated Arrow Flight RPC Server function.
47
+
48
+ See: https://github.com/apache/arrow/issues/36844
49
+ for more details...
50
+ """
51
+
52
+ @functools.wraps(func)
53
+ def wrapper_decorator(*args, **kwargs):
54
+ try:
55
+ import pydevd
56
+
57
+ pydevd.connected = True
58
+ pydevd.settrace(suspend=False)
59
+ except ImportError:
60
+ # Not running in debugger
61
+ pass
62
+ value = func(*args, **kwargs)
63
+ return value
64
+
65
+ return wrapper_decorator
66
+
67
+
68
+ class ADBCServerBase:
69
+ def get_sql_info(self, _req: CommandGetSqlInfo) -> pa.RecordBatchReader:
70
+ """Default implementation that reports no support for any complex features."""
71
+ info = {
72
+ SqlInfo.FLIGHT_SQL_SERVER_NAME: "Spiral ADBC Server",
73
+ SqlInfo.FLIGHT_SQL_SERVER_VERSION: "0.0.1",
74
+ SqlInfo.FLIGHT_SQL_SERVER_ARROW_VERSION: pa.__version__,
75
+ SqlInfo.FLIGHT_SQL_SERVER_READ_ONLY: True,
76
+ SqlInfo.FLIGHT_SQL_SERVER_TRANSACTION: SqlSupportedTransaction.NONE.value,
77
+ }
78
+
79
+ # See https://github.com/apache/arrow-adbc/blob/38c21c2311a59803559cb0091b3f34180c28b25f/rust/core/src/schemas.rs#L35
80
+ union_fields = [
81
+ pa.field("string_value", pa.string()),
82
+ pa.field("bool_value", pa.bool_()),
83
+ pa.field("int64_value", pa.int64()),
84
+ pa.field("int32_bitmask", pa.int32()),
85
+ pa.field("string_list", pa.list_(pa.string())),
86
+ pa.field(
87
+ "int32_to_int32_list_map",
88
+ pa.map_(pa.int32(), pa.list_(pa.int32()), keys_sorted=False),
89
+ ),
90
+ ]
91
+ schema = pa.schema(
92
+ [
93
+ pa.field("info_name", pa.uint32(), nullable=False),
94
+ pa.field("info_value", pa.dense_union(union_fields), nullable=False),
95
+ ]
96
+ )
97
+
98
+ # PyArrow doesn't support creating a dense union for us :(
99
+ types = []
100
+ offsets = []
101
+ ints = []
102
+ bools = []
103
+ strs = []
104
+ for value in info.values():
105
+ if isinstance(value, str):
106
+ types.append(0)
107
+ offsets.append(len(strs))
108
+ strs.append(value)
109
+ elif isinstance(value, bool):
110
+ types.append(1)
111
+ offsets.append(len(bools))
112
+ bools.append(value)
113
+ else:
114
+ types.append(1)
115
+ offsets.append(len(ints))
116
+ ints.append(value)
117
+
118
+ values = pa.UnionArray.from_dense(
119
+ pa.array(types, type=pa.int8()),
120
+ pa.array(offsets, type=pa.int32()),
121
+ [pa.array(data, type=f.type) for data, f in zip([strs, bools, ints, [], [], []], union_fields)],
122
+ [f.name for f in union_fields],
123
+ )
124
+
125
+ return pa.table(data=[pa.array(list(info.keys()), type=pa.uint32()), values], schema=schema).to_reader()
126
+
127
+ @abc.abstractmethod
128
+ def get_catalogs(self, req: CommandGetCatalogs) -> pa.RecordBatchReader: ...
129
+
130
+ @abc.abstractmethod
131
+ def get_db_schemas(self, req: CommandGetDbSchemas) -> pa.RecordBatchReader: ...
132
+
133
+ @abc.abstractmethod
134
+ def get_tables(self, req: CommandGetTables) -> pa.RecordBatchReader: ...
135
+
136
+ @abc.abstractmethod
137
+ def statement_query(self, req: CommandStatementQuery, limit: int | None = None) -> pa.RecordBatchReader: ...
138
+
139
+
140
+ class SpiralADBCServer(ADBCServerBase):
141
+ def __init__(self, spiral: Spiral):
142
+ self.sp = spiral
143
+
144
+ self.pool = ThreadPoolExecutor()
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
+
157
+ def get_catalogs(self, req: CommandGetCatalogs) -> pa.RecordBatchReader:
158
+ schema = pa.schema([pa.field("catalog_name", pa.string(), nullable=False)])
159
+
160
+ @debuggable
161
+ def batches():
162
+ yield pa.RecordBatch.from_arrays(
163
+ [[p.id for p in self.sp.list_projects()]],
164
+ schema=schema,
165
+ )
166
+
167
+ return pa.RecordBatchReader.from_batches(schema, batches())
168
+
169
+ def get_db_schemas(self, req: CommandGetDbSchemas) -> pa.RecordBatchReader:
170
+ """Get the schemas from the database."""
171
+
172
+ schema = pa.schema(
173
+ [
174
+ pa.field("catalog_name", pa.string()),
175
+ pa.field("db_schema_name", pa.string(), nullable=False),
176
+ ]
177
+ )
178
+
179
+ @debuggable
180
+ def batches():
181
+ if req.catalog == "":
182
+ # Empty string means databases _without_ a catalog, which we don't support
183
+ return
184
+ catalog = req.catalog
185
+
186
+ # Otherwise, catalog is either the project ID, or None.
187
+ if catalog is None:
188
+ projects = self.sp.list_projects()
189
+ else:
190
+ projects = [self.sp.project(req.catalog)]
191
+
192
+ for project in projects:
193
+ datasets = {tbl.dataset for tbl in project.list_tables()}
194
+
195
+ batch = pa.RecordBatch.from_arrays(
196
+ [
197
+ [project.id] * len(datasets),
198
+ list(datasets),
199
+ ],
200
+ schema=schema,
201
+ )
202
+
203
+ if req.db_schema_filter_pattern:
204
+ mask = pc.match_like(batch["db_schema_name"], req.db_schema_filter_pattern)
205
+ batch = batch.filter(mask)
206
+
207
+ yield batch
208
+
209
+ return pa.RecordBatchReader.from_batches(schema, batches())
210
+
211
+ def get_tables(self, req: CommandGetTables) -> pa.RecordBatchReader:
212
+ schema = pa.schema(
213
+ [
214
+ pa.field("catalog_name", pa.string()),
215
+ pa.field("db_schema_name", pa.string()),
216
+ pa.field("table_name", pa.string(), nullable=False),
217
+ pa.field("table_type", pa.string(), nullable=False),
218
+ ]
219
+ + [pa.field("table_schema", pa.binary(), nullable=False)]
220
+ if req.include_schema
221
+ else []
222
+ )
223
+
224
+ @debuggable
225
+ def batches():
226
+ if req.catalog == "":
227
+ # Empty string means databases _without_ a catalog, which we don't support
228
+ return
229
+
230
+ if req.catalog is None:
231
+ projects = list(self.sp.list_projects())
232
+ else:
233
+ projects = [self.sp.project(req.catalog)]
234
+ projects = sorted(projects, key=lambda p: p.id)
235
+
236
+ def _process_project(project):
237
+ tables: list[TableResource] = project.list_tables()
238
+
239
+ rows = []
240
+ for table in tables:
241
+ row = {
242
+ "catalog_name": project.id,
243
+ "db_schema_name": table.dataset,
244
+ "table_name": table.table,
245
+ "table_type": "TABLE",
246
+ }
247
+
248
+ if req.include_schema:
249
+ open_table = project.table(f"{table.dataset}.{table.table}")
250
+ row["table_schema"] = open_table.snapshot().to_arrow_dataset().schema.serialize().to_pybytes()
251
+
252
+ rows.append(row)
253
+
254
+ return pa.RecordBatch.from_pylist(rows, schema=schema)
255
+
256
+ yield from self.pool.map(_process_project, projects)
257
+
258
+ return pa.RecordBatchReader.from_batches(schema, batches())
259
+
260
+ @debuggable
261
+ def statement_query(self, req: CommandStatementQuery, limit: int | None = None) -> pa.RecordBatchReader:
262
+ # Extract the tables from the query, and bring them into the Python locals scope.
263
+ expr = sqlglot.parse_one(req.query, dialect="duckdb")
264
+ datasets = {}
265
+ for tbl in expr.find_all(exp.Table):
266
+ # We swap the three-part identifier out for a single identifier
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_arrow_dataset()
271
+ tbl.replace(exp.table_(table=name))
272
+
273
+ try:
274
+ import duckdb
275
+ except ImportError:
276
+ raise FlightError("DuckDB is required for SQL queries.")
277
+
278
+ try:
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"))
284
+ except Exception as e:
285
+ raise FlightError(str(e))
286
+
287
+ if limit is not None:
288
+ sql = sql.limit(limit)
289
+
290
+ return sql.fetch_arrow_reader(batch_size=1_000)
291
+
292
+
293
+ class ADBCFlightServer(FlightServerBase):
294
+ """An implementation of a FlightSQL ADBC server."""
295
+
296
+ def __init__(self, abdc: ADBCServerBase, *, location=None, **kwargs):
297
+ super().__init__(location=location, **kwargs)
298
+ self.location = location
299
+ self.adbc = abdc
300
+
301
+ self.host = "localhost"
302
+ self.tls = False
303
+ if location:
304
+ parts = urlparse(location)
305
+ self.host = parts.hostname
306
+ self.tls = parts.scheme.endswith("s")
307
+
308
+ @debuggable
309
+ def do_action(self, context: ServerCallContext, action: Action):
310
+ log.info("DoAction %s: %s", context.peer(), action)
311
+ super().do_action(context, action)
312
+
313
+ @debuggable
314
+ def do_exchange(self, context: ServerCallContext, descriptor: FlightDescriptor, reader, writer):
315
+ log.info("DoExchange %s: %s", context.peer(), descriptor)
316
+ super().do_exchange(context, descriptor, reader, writer)
317
+
318
+ @debuggable
319
+ def do_get(self, context: ServerCallContext, ticket: Ticket):
320
+ log.info("DoGet %s: %s", context.peer(), ticket)
321
+ req = self.parse_command(ticket.ticket)
322
+ match req:
323
+ case CommandGetSqlInfo():
324
+ return RecordBatchStream(self.adbc.get_sql_info(req))
325
+ case CommandGetCatalogs():
326
+ return RecordBatchStream(self.adbc.get_catalogs(req))
327
+ case CommandGetDbSchemas():
328
+ return RecordBatchStream(self.adbc.get_db_schemas(req))
329
+ case CommandGetTables():
330
+ return RecordBatchStream(self.adbc.get_tables(req))
331
+ case CommandStatementQuery():
332
+ return RecordBatchStream(self.adbc.statement_query(req))
333
+ case _:
334
+ raise NotImplementedError(f"Unsupported do_Get: {req}")
335
+
336
+ @debuggable
337
+ def do_put(
338
+ self,
339
+ context: ServerCallContext,
340
+ descriptor: FlightDescriptor,
341
+ reader: MetadataRecordBatchReader,
342
+ writer: FlightMetadataWriter,
343
+ ):
344
+ log.info("DoPut %s: %s", context.peer(), descriptor)
345
+ super().do_put(context, descriptor, reader, writer)
346
+
347
+ @debuggable
348
+ def get_flight_info(self, context: ServerCallContext, descriptor: FlightDescriptor) -> FlightInfo:
349
+ log.info("GetFlightInfo %s: %s", context.peer(), descriptor)
350
+ req = self.parse_command(descriptor.command)
351
+ match req:
352
+ case CommandGetSqlInfo():
353
+ # Each metadata type contributes to the schema.
354
+ schema = self.adbc.get_sql_info(req).schema
355
+ case CommandGetCatalogs():
356
+ schema = self.adbc.get_catalogs(req).schema
357
+ case CommandGetDbSchemas():
358
+ schema = self.adbc.get_db_schemas(req).schema
359
+ case CommandGetTables():
360
+ schema = self.adbc.get_tables(req).schema
361
+ case CommandStatementQuery():
362
+ schema = self.adbc.statement_query(req, limit=0).schema
363
+ case _:
364
+ raise NotImplementedError(f"Unsupported command: {req}")
365
+
366
+ return self._make_flight_info(self.descriptor_to_key(descriptor), descriptor, schema)
367
+
368
+ @staticmethod
369
+ def parse_command(command: bytes):
370
+ command = Any().parse(command)
371
+
372
+ if not command.type_url.startswith("type.googleapis.com/arrow.flight.protocol.sql."):
373
+ raise NotImplementedError(f"Unsupported command: {command.type_url}")
374
+
375
+ proto_cls_name = command.type_url[len("type.googleapis.com/arrow.flight.protocol.sql.") :]
376
+ proto_cls = getattr(rpc, proto_cls_name)
377
+ return proto_cls().parse(command.value)
378
+
379
+ @staticmethod
380
+ def descriptor_to_key(descriptor):
381
+ return descriptor.command
382
+
383
+ @debuggable
384
+ def get_schema(self, context: ServerCallContext, descriptor: FlightDescriptor):
385
+ log.info("GetSchema %s: %s", context.peer(), descriptor)
386
+ return super().get_schema(context, descriptor)
387
+
388
+ @debuggable
389
+ def list_actions(self, context: ServerCallContext):
390
+ log.info("ListActions %s", context.peer())
391
+ super().list_actions(context)
392
+
393
+ @debuggable
394
+ def list_flights(self, context: ServerCallContext, criteria):
395
+ log.info("ListFlights %s: %s", context.peer(), criteria)
396
+ super().list_flights(context, criteria)
397
+
398
+ def _make_flight_info(self, key, descriptor, schema: pa.Schema):
399
+ # If we pass zero locations, the FlightSQL client should attempt to use the original connection.
400
+ endpoints = [FlightEndpoint(key, [])]
401
+ return FlightInfo(schema, descriptor, endpoints, -1, -1)
402
+
403
+
404
+ if __name__ == "__main__":
405
+ import logging
406
+
407
+ logging.basicConfig()
408
+ logging.getLogger("spiral").setLevel(logging.DEBUG)
409
+
410
+ server = ADBCFlightServer(SpiralADBCServer(Spiral()), location="grpc://localhost:5005")
411
+ server.serve()