pyspiral 0.2.5__cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 0.4.3__cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.dist-info}/METADATA +12 -14
  2. pyspiral-0.4.3.dist-info/RECORD +98 -0
  3. {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.dist-info}/WHEEL +1 -1
  4. spiral/__init__.py +6 -7
  5. spiral/_lib.abi3.so +0 -0
  6. spiral/adbc.py +21 -14
  7. spiral/api/__init__.py +15 -172
  8. spiral/api/admin.py +12 -26
  9. spiral/api/client.py +160 -0
  10. spiral/api/filesystems.py +100 -72
  11. spiral/api/organizations.py +45 -58
  12. spiral/api/projects.py +171 -134
  13. spiral/api/telemetry.py +19 -0
  14. spiral/api/types.py +20 -0
  15. spiral/api/workloads.py +32 -25
  16. spiral/{arrow.py → arrow_.py} +12 -0
  17. spiral/cli/__init__.py +2 -5
  18. spiral/cli/admin.py +7 -12
  19. spiral/cli/app.py +23 -6
  20. spiral/cli/console.py +1 -1
  21. spiral/cli/fs.py +83 -18
  22. spiral/cli/iceberg/__init__.py +7 -0
  23. spiral/cli/iceberg/namespaces.py +47 -0
  24. spiral/cli/iceberg/tables.py +60 -0
  25. spiral/cli/indexes/__init__.py +19 -0
  26. spiral/cli/login.py +14 -5
  27. spiral/cli/orgs.py +90 -0
  28. spiral/cli/printer.py +9 -1
  29. spiral/cli/projects.py +136 -0
  30. spiral/cli/state.py +2 -0
  31. spiral/cli/tables/__init__.py +121 -0
  32. spiral/cli/telemetry.py +18 -0
  33. spiral/cli/types.py +8 -10
  34. spiral/cli/{workload.py → workloads.py} +11 -11
  35. spiral/{catalog.py → client.py} +22 -21
  36. spiral/core/client/__init__.pyi +118 -0
  37. spiral/core/index/__init__.pyi +15 -0
  38. spiral/core/table/__init__.pyi +108 -0
  39. spiral/core/{manifests → table/manifests}/__init__.pyi +5 -23
  40. spiral/core/table/metastore/__init__.pyi +62 -0
  41. spiral/core/{spec → table/spec}/__init__.pyi +49 -92
  42. spiral/datetime_.py +27 -0
  43. spiral/expressions/__init__.py +41 -18
  44. spiral/expressions/base.py +5 -5
  45. spiral/expressions/list_.py +1 -1
  46. spiral/expressions/mp4.py +62 -0
  47. spiral/expressions/png.py +18 -0
  48. spiral/expressions/qoi.py +18 -0
  49. spiral/expressions/refs.py +23 -9
  50. spiral/expressions/struct.py +7 -5
  51. spiral/expressions/text.py +62 -0
  52. spiral/expressions/tiff.py +88 -88
  53. spiral/expressions/udf.py +3 -3
  54. spiral/iceberg/__init__.py +3 -0
  55. spiral/iceberg/client.py +33 -0
  56. spiral/indexes/__init__.py +5 -0
  57. spiral/indexes/client.py +137 -0
  58. spiral/indexes/index.py +34 -0
  59. spiral/indexes/scan.py +22 -0
  60. spiral/project.py +19 -110
  61. spiral/{proto → protogen}/_/scandal/__init__.py +32 -77
  62. spiral/protogen/_/spiral/table/__init__.py +22 -0
  63. spiral/protogen/substrait/__init__.py +3399 -0
  64. spiral/protogen/substrait/extensions/__init__.py +115 -0
  65. spiral/server.py +17 -0
  66. spiral/settings.py +31 -87
  67. spiral/substrait_.py +10 -6
  68. spiral/tables/__init__.py +12 -0
  69. spiral/tables/client.py +130 -0
  70. spiral/{dataset.py → tables/dataset.py} +36 -25
  71. spiral/tables/debug/manifests.py +70 -0
  72. spiral/tables/debug/metrics.py +56 -0
  73. spiral/{debug.py → tables/debug/scan.py} +6 -9
  74. spiral/tables/maintenance.py +12 -0
  75. spiral/tables/scan.py +193 -0
  76. spiral/tables/snapshot.py +78 -0
  77. spiral/tables/table.py +157 -0
  78. spiral/tables/transaction.py +52 -0
  79. pyspiral-0.2.5.dist-info/RECORD +0 -81
  80. spiral/api/tables.py +0 -94
  81. spiral/api/tokens.py +0 -56
  82. spiral/authn/authn.py +0 -89
  83. spiral/authn/device.py +0 -206
  84. spiral/authn/github_.py +0 -33
  85. spiral/authn/modal_.py +0 -18
  86. spiral/cli/org.py +0 -90
  87. spiral/cli/project.py +0 -107
  88. spiral/cli/table.py +0 -20
  89. spiral/cli/token.py +0 -27
  90. spiral/config.py +0 -26
  91. spiral/core/core/__init__.pyi +0 -53
  92. spiral/core/metastore/__init__.pyi +0 -91
  93. spiral/proto/_/spfs/__init__.py +0 -36
  94. spiral/proto/_/spiral/table/__init__.py +0 -225
  95. spiral/proto/_/spiraldb/metastore/__init__.py +0 -499
  96. spiral/proto/__init__.py +0 -0
  97. spiral/proto/scandal/__init__.py +0 -45
  98. spiral/proto/spiral/__init__.py +0 -0
  99. spiral/proto/spiral/table/__init__.py +0 -96
  100. spiral/scan_.py +0 -168
  101. spiral/table.py +0 -157
  102. {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.dist-info}/entry_points.txt +0 -0
  103. /spiral/{authn/__init__.py → core/__init__.pyi} +0 -0
  104. /spiral/{core → protogen/_}/__init__.py +0 -0
  105. /spiral/{proto/_ → protogen/_/arrow}/__init__.py +0 -0
  106. /spiral/{proto/_/arrow → protogen/_/arrow/flight}/__init__.py +0 -0
  107. /spiral/{proto/_/arrow/flight → protogen/_/arrow/flight/protocol}/__init__.py +0 -0
  108. /spiral/{proto → protogen}/_/arrow/flight/protocol/sql/__init__.py +0 -0
  109. /spiral/{proto/_/arrow/flight/protocol → protogen/_/spiral}/__init__.py +0 -0
  110. /spiral/{proto → protogen/_}/substrait/__init__.py +0 -0
  111. /spiral/{proto → protogen/_}/substrait/extensions/__init__.py +0 -0
  112. /spiral/{proto/_/spiral → protogen}/__init__.py +0 -0
  113. /spiral/{proto → protogen}/util.py +0 -0
  114. /spiral/{proto/_/spiraldb → tables/debug}/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyspiral
3
- Version: 0.2.5
3
+ Version: 0.4.3
4
4
  Classifier: Intended Audience :: Science/Research
5
5
  Classifier: Operating System :: OS Independent
6
6
  Classifier: Programming Language :: Python
@@ -17,32 +17,30 @@ 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: numpy>=1.26.3
21
- Requires-Dist: opentelemetry-api>=1.27.0
22
- Requires-Dist: opentelemetry-sdk>=1.27.0
23
- Requires-Dist: polars>=1.6.0
24
- Requires-Dist: pyarrow>=17.0.0
20
+ Requires-Dist: numpy>=2
21
+ Requires-Dist: pyarrow>=21.0.0
25
22
  Requires-Dist: pydantic-settings>=2.3.4
26
23
  Requires-Dist: pydantic[email]>=2.5.3
27
24
  Requires-Dist: pyjwt[crypto]>=2.9.0
28
- Requires-Dist: pyroaring>=0.4.4
29
25
  Requires-Dist: questionary>=2.0.1
30
26
  Requires-Dist: tqdm>=4.66.5
31
- Requires-Dist: typer>=0.12.3
27
+ Requires-Dist: typer>=0.16
32
28
  Requires-Dist: xxhash>=3.4.1
33
29
  Requires-Dist: nanoid>=2.0.0
34
30
  Requires-Dist: sqlglot[rs]>=25.25.1
35
- Requires-Dist: duckdb>=1.1.1
36
31
  Requires-Dist: pyperclip>=1.9.0
37
- Summary: Python implementation of Spiral table format.
38
- Keywords: vortex,spiraldb
32
+ Requires-Dist: polars>=1.31.0 ; extra == 'polars'
33
+ Requires-Dist: duckdb>=1.3.2 ; extra == 'duckdb'
34
+ Requires-Dist: pyiceberg>=0.9.1 ; extra == 'pyiceberg'
35
+ Provides-Extra: polars
36
+ Provides-Extra: duckdb
37
+ Provides-Extra: pyiceberg
38
+ Summary: Python client for Spiral.
39
39
  Home-Page: https://spiraldb.com
40
- Author: Spiral<hello@spiraldb.com>
41
40
  Author-email: SpiralDB <hello@spiraldb.com>
42
- License: Proprietary
41
+ License: Proprietary License
43
42
  Requires-Python: >=3.10
44
43
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
45
- Project-URL: Source Code, https://github.com/spiraldb/spiraldb
46
44
 
47
45
  # PySpiral
48
46
 
@@ -0,0 +1,98 @@
1
+ pyspiral-0.4.3.dist-info/METADATA,sha256=vSc4ZGaqT4FiTed4rIQdo6sMQBXs690OKn-z6o1gfLQ,1610
2
+ pyspiral-0.4.3.dist-info/WHEEL,sha256=PjJMzJpvi5UGP0cjK5Ftx4x5YgThyrYgwpOwFQxcwHw,130
3
+ pyspiral-0.4.3.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
4
+ spiral/__init__.py,sha256=Jv1vbcnnmcTsBLN5mSNjnX3ae4C_mgojXDSBFaqIhN0,208
5
+ spiral/_lib.abi3.so,sha256=x_y69-2AtIFpTsj-IasbaXHK-Rv8jLOV6XGhLU0g55I,52399800
6
+ spiral/adbc.py,sha256=HcvR60uQeEK2oggSAK6y5VYtIrACIiCQ-85MEf18EZc,14199
7
+ spiral/api/__init__.py,sha256=_7BS1RhqEFjnt3XwFWZNCHVEQeSKpezPevAiGCsvDbE,1776
8
+ spiral/api/admin.py,sha256=A1iVR1XYJSObZivPAD5UzmPuMgupXc9kaHNYYa_kwfs,585
9
+ spiral/api/client.py,sha256=9-L6T8niQAXo90jRxllJD4hXXmcGfHj7CW9X3XTYa5Q,4551
10
+ spiral/api/filesystems.py,sha256=5Ky_otnresGj7WdsR8Xi7DDM3lkB8UES6Lru_xWAGDM,4559
11
+ spiral/api/organizations.py,sha256=B-8zZ7lFJANGK7dUNbo_aU-cgI959JBP9VcWb6wdgi0,1895
12
+ spiral/api/projects.py,sha256=JBGof9A2Ivasu2jrULMjHBwlna0M8WRrTNqU-Es4GJ8,5673
13
+ spiral/api/telemetry.py,sha256=tfdA3E_EWJwFVxkQfkm8tiYGRubnx2LuE5nbfsk1oG4,474
14
+ spiral/api/types.py,sha256=zx-BRKsi1GHg9aL9gMUaVQWYYMXJcP0A8OQUc7jSIAc,653
15
+ spiral/api/workloads.py,sha256=XAyXV7vgZcoyyoPoGvOT4jTpyFKFMvrrAfhL6d1h1kE,1748
16
+ spiral/arrow_.py,sha256=T1LZ7bh9aMDbXfpUsf0dR0E1roTQyAYSgZ2mL4s8J_4,7681
17
+ spiral/cli/__init__.py,sha256=ooAFz_iCpVCKHE0TiVElIynbP2PtTgD9cUw46Vh1lcw,2145
18
+ spiral/cli/__main__.py,sha256=kNaKM2xgJo7GRogf83nYldLM-RGUR6vymdGwZxywQu0,71
19
+ spiral/cli/admin.py,sha256=7WbU_tr05clUjmZ-RkKTlvcf1pbXIElRfHRJlCItFGk,326
20
+ spiral/cli/app.py,sha256=-k0rrLbfJRLay_2_MOCt57PLcx0VnNMCkrnKV7j7nos,1725
21
+ spiral/cli/console.py,sha256=6JHbAQV6MFWz3P-VzqPOjhHpkIQagsCdzTMvmuDKMkU,2580
22
+ spiral/cli/fs.py,sha256=dVPoAoAbuQ9yJlfI-JiFgS9VdnPmeBMygVHgehJRj34,4367
23
+ spiral/cli/iceberg/__init__.py,sha256=IQV_gwCFSj6Ubxs58VM9Pal1ymgG2bxdDgOPuk9E5bs,214
24
+ spiral/cli/iceberg/namespaces.py,sha256=x9pvHlcXtcATYYjqimHa6CtkyL3taQUJ--ni_Bfoemc,1510
25
+ spiral/cli/iceberg/tables.py,sha256=nSR4-t54otJfCmubB6vXnbOkbqPVGV0sHBlc-t9cIVg,1930
26
+ spiral/cli/indexes/__init__.py,sha256=-USfxCIdckzZKBNQ-DXqe3V5ttWVo_Fsa1Mfcx5hdIw,467
27
+ spiral/cli/login.py,sha256=InKMnpV8NATW5RPgB3ZL-DSVPzUuUByyK4Fx7pZEgfg,607
28
+ spiral/cli/orgs.py,sha256=V-4ZTT3FwFQLcs1-BenC8uCgvWOJcxkZPSdCPfsexhc,2848
29
+ spiral/cli/printer.py,sha256=W83KAE-7meoDD1yRltLQrZqrA2olGapBGy_2USWkY08,1778
30
+ spiral/cli/projects.py,sha256=TKXu_VzkIUccwXzdlg-wQMkrB-Py33g052NrbuJx-D4,5096
31
+ spiral/cli/state.py,sha256=10wTIVQ0SJkY67Z6-KQ1LFlt3aVIPmZhoHFdTwp4kNA,130
32
+ spiral/cli/tables/__init__.py,sha256=lkGLDeU28IVnuxJdlYSUh6QSB9fQ4_1MeZJL73iXcHo,3660
33
+ spiral/cli/telemetry.py,sha256=ABDCyV5QJGOIJp4AxvK0LG5xNPIysP37K5haL38T7P4,586
34
+ spiral/cli/types.py,sha256=YG1eHhRLaqlVU_18DQBuF_YMsabhMZLBY0V9CvbSxjY,1369
35
+ spiral/cli/workloads.py,sha256=SbxgwiBlX1AuqpOLV3gs7DFkH-Tbeend7qJTwq0Je84,1994
36
+ spiral/client.py,sha256=K-OuMOTgYxOA9vef5jSANjmPRBfGrzQ65fg6Fd-rHMY,2683
37
+ spiral/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ spiral/core/client/__init__.pyi,sha256=Tn1OJmkO1rQUsPE9BtfEyxIjoife6s16qOd8XiyHi2c,3475
39
+ spiral/core/index/__init__.pyi,sha256=NPOG1ztFO6siBGpmJU3boRzX26xfxw--2TiCydosGvo,314
40
+ spiral/core/table/__init__.pyi,sha256=dwOaxcOl6ZIlxoLjOnC3CNUgGetWfnEV1Jx06aCH8M8,3265
41
+ spiral/core/table/manifests/__init__.pyi,sha256=3V59-K1qr1z2dGfgRKXaHSVheK8NNw8Q8PFhfbeQd_4,1065
42
+ spiral/core/table/metastore/__init__.pyi,sha256=dMqySDnsjPUTBuFU2MaQGyocKEoGkWpeTQmUP2iIKbc,1880
43
+ spiral/core/table/spec/__init__.pyi,sha256=D4GQp9RWwyLKTlRW7eDXcQE-xA5rF2iBcXZ8y7b48EE,5595
44
+ spiral/datetime_.py,sha256=1TA1RYIRU22qcUuipIjVhAtGnPDVn2z9WttuhkmfkwY,964
45
+ spiral/expressions/__init__.py,sha256=hLh2qfHxM7hJg6GidRApqczwE80vatizkKN6YDUAAUA,6570
46
+ spiral/expressions/base.py,sha256=q_W9XslcdFQtOIE_d1VkEmLickaXKOAoIcFeMoh-nqQ,4751
47
+ spiral/expressions/http.py,sha256=begUydWoFHEqjeLkATvI_v66Ez6_rR-OQBWO5cHbb9c,2742
48
+ spiral/expressions/io.py,sha256=gJ2a0FKMmdxarWKENulPRwH7KDvSJTIh_OUxX306xAM,3045
49
+ spiral/expressions/list_.py,sha256=MMt5lf5H1M3O-x6N_PvqOLGq9NOk6Ukv0fPWwPC_uy4,1809
50
+ spiral/expressions/mp4.py,sha256=R-fcVYRI6KaH1Nwpmqnsc1VYd9wA7Nuiy2UDcNxEzpw,2165
51
+ spiral/expressions/png.py,sha256=KO8X0OmMzUFwpg2I_j0JTyldPzVXDWIMzjWMWDV9vIY,506
52
+ spiral/expressions/qoi.py,sha256=gvIbb6fXb_Bb080sn9wkpbGGrPs2UEcTXCfuv4-kcYQ,506
53
+ spiral/expressions/refs.py,sha256=ISMtJtUL--BjHF6rsvgN3Um4QcvVqQE9URngOxjQrhw,2115
54
+ spiral/expressions/str_.py,sha256=tY8RXW3JWvr1-bEfCZtk5FAf11wKJnXPuA9EoeJ9tA4,1265
55
+ spiral/expressions/struct.py,sha256=pGAnCDh6AK0BK1XfZ1qG4ce4ranIQEE1HQsgmzBcfwQ,2038
56
+ spiral/expressions/text.py,sha256=-02gBWYoyNQ3qQ1--9HTa8IryUDojYQVIp8C7rgnOWQ,1893
57
+ spiral/expressions/tiff.py,sha256=fQwIn0kLFBM2Y3YYIHmTgb_EIRHKT2fNc77nioDQQw4,8044
58
+ spiral/expressions/udf.py,sha256=r6398z2Aj7KnXtwEvCiGNbgOXa6xsb_bnnG-FEvFxV4,1370
59
+ spiral/grpc_.py,sha256=f3czdP1Mxme42Y5--a5ogYq1TTiWn-J_MlGjwJ2mWwM,1015
60
+ spiral/iceberg/__init__.py,sha256=jSIlTxWauAbJV5gsWglZisFbnfNNzLYN90scoYcdWzc,65
61
+ spiral/iceberg/client.py,sha256=E6FyE_h2HLgDW1cAFg1XgglJr6rbVOCWjRtRmqoMVkM,1003
62
+ spiral/indexes/__init__.py,sha256=TXLQ-_3xso3lFIp2lM58_ip9OPNwPKFv1FdsWiUF-d8,178
63
+ spiral/indexes/client.py,sha256=NsFBILEHMjyCUruFrUEKucRQRrN4OvqgbL4pmzWs07g,5600
64
+ spiral/indexes/index.py,sha256=4CmSFlZYp46B2CjqtiyZ7VF5EH3duiutz3nWFnyApLA,973
65
+ spiral/indexes/scan.py,sha256=B2m-UgNuawNB90HXK33GTQfMy2WLdNNxiiB6cIjFW2Y,697
66
+ spiral/project.py,sha256=0uJ1Jb88Ie-cCNnSdX3QfFtCUqrjLka4zCm_TxCpVak,1189
67
+ spiral/protogen/_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
+ spiral/protogen/_/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
+ spiral/protogen/_/arrow/flight/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
+ spiral/protogen/_/arrow/flight/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
+ spiral/protogen/_/arrow/flight/protocol/sql/__init__.py,sha256=_xhj9QkWEW1qZ-iVxcQ8k4EjYr7KJ5ofitJGqVUGQi4,79921
72
+ spiral/protogen/_/scandal/__init__.py,sha256=X5YJqErZDIXxTESw8fLqJp3P2wZlqAglBzPs3LpTd-w,5145
73
+ spiral/protogen/_/spiral/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ spiral/protogen/_/spiral/table/__init__.py,sha256=o_aNyTuJBIRY6MlAWceMsjbfaSUuZphRxiG_IXmC0mU,629
75
+ spiral/protogen/_/substrait/__init__.py,sha256=pV4-T-lwAHKkfFrNYSUGY4IkbIvuKjSo_imzF7BLj_s,126526
76
+ spiral/protogen/_/substrait/extensions/__init__.py,sha256=yD7dg0TBqn-GK_L0qeVof1GKnwSLg_kPyQSV3kcSljs,3655
77
+ spiral/protogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
+ spiral/protogen/substrait/__init__.py,sha256=pV4-T-lwAHKkfFrNYSUGY4IkbIvuKjSo_imzF7BLj_s,126526
79
+ spiral/protogen/substrait/extensions/__init__.py,sha256=yD7dg0TBqn-GK_L0qeVof1GKnwSLg_kPyQSV3kcSljs,3655
80
+ spiral/protogen/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
81
+ spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
+ spiral/server.py,sha256=ztBmB5lBnUz-smQxR_tC8AI5SOhz17wH0MI3GuzDUdM,600
83
+ spiral/settings.py,sha256=PIQV2ljtB3pEOWoMRVSRzSGJNrXviO2JBgZ5ZY_Nq2E,2794
84
+ spiral/substrait_.py,sha256=RNSmfbGFT_5uyo8AFtzS9A7IHW3DkacMTw2vKnj0Das,12762
85
+ spiral/tables/__init__.py,sha256=iiP7BkHA117em37_e75jtdvoZC10xCXtld18gRnPbTw,430
86
+ spiral/tables/client.py,sha256=l_wJJRf3BPD5lg4Q1Ll2lAqQIuBCnKwC6JtsAui91Tc,4915
87
+ spiral/tables/dataset.py,sha256=DuHeKVCJfXLsbxmde9QW6yvesW5uhswG6qAxV5X0ZgA,7890
88
+ spiral/tables/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
+ spiral/tables/debug/manifests.py,sha256=E_-DiMBg2EPL97cl9hLWhiqEsFtjEBgh_C7jZy8EWYc,2594
90
+ spiral/tables/debug/metrics.py,sha256=XdRDcjggtsLNGCAjam6IxG9072pz_d2C8iLApNRFUtk,2044
91
+ spiral/tables/debug/scan.py,sha256=-IWX_UjO4QP9Hj7PtZ1rLlbswJcryOin56GT-exqFm4,8942
92
+ spiral/tables/maintenance.py,sha256=7Xa2Jdu_OY1Qu6iN1sPVdywVZtk_Mv3EaC3G93cmQvI,305
93
+ spiral/tables/scan.py,sha256=3lPf5fSyF1fHGdGJ-pvu5HxPWoonf_XL7neWTqzB-0I,7582
94
+ spiral/tables/snapshot.py,sha256=2NTuVEp2uJ1pV3Q5tLj7FOzPSc9axlfb6uOITwHnj0g,2229
95
+ spiral/tables/table.py,sha256=4B2drwwfaoL6aIJ-5Ll-Bqza-EBeDIfMkuszSOZqSpk,5326
96
+ spiral/tables/transaction.py,sha256=3a64R-mf_cmR54BNn8U-05jmWonp6Ivxhe6u01Dyjzo,1573
97
+ spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
98
+ pyspiral-0.4.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.2)
2
+ Generator: maturin (1.9.3)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64
spiral/__init__.py CHANGED
@@ -1,11 +1,10 @@
1
- """Python client for the Spiral warehouse."""
1
+ """Python client for Spiral"""
2
2
 
3
+ # This is here to make sure we load the native extension first
3
4
  from spiral import _lib
4
- from spiral.catalog import Spiral
5
- from spiral.scan_ import Scan, scan
6
- from spiral.table import Table
7
5
 
8
- # Eagerly import the Spiral library
9
- assert _lib, "Spiral library"
6
+ assert _lib
10
7
 
11
- __all__ = ["scan", "Scan", "Table", "Spiral"]
8
+ from spiral.client import Spiral # noqa: E402, I001
9
+
10
+ __all__ = ["Spiral"]
spiral/_lib.abi3.so CHANGED
Binary file
spiral/adbc.py CHANGED
@@ -4,7 +4,6 @@ import logging
4
4
  from concurrent.futures import ThreadPoolExecutor
5
5
  from urllib.parse import urlparse
6
6
 
7
- import duckdb
8
7
  import pyarrow as pa
9
8
  import pyarrow.compute as pc
10
9
  import sqlglot
@@ -25,8 +24,9 @@ from pyarrow.flight import (
25
24
  )
26
25
 
27
26
  from spiral import Spiral
28
- from spiral.proto._.arrow.flight.protocol import sql as rpc
29
- from spiral.proto._.arrow.flight.protocol.sql import (
27
+ from spiral.api.projects import TableResource
28
+ from spiral.protogen._.arrow.flight.protocol import sql as rpc
29
+ from spiral.protogen._.arrow.flight.protocol.sql import (
30
30
  CommandGetCatalogs,
31
31
  CommandGetDbSchemas,
32
32
  CommandGetSqlInfo,
@@ -37,6 +37,7 @@ from spiral.proto._.arrow.flight.protocol.sql import (
37
37
  )
38
38
 
39
39
  log = logging.getLogger(__name__)
40
+ logging.getLogger("sqlx").setLevel(logging.WARNING)
40
41
 
41
42
 
42
43
  def debuggable(func):
@@ -63,6 +64,7 @@ def debuggable(func):
63
64
  return wrapper_decorator
64
65
 
65
66
 
67
+ # TODO(marko): This should work for Iceberg tables.
66
68
  class ADBCServerBase:
67
69
  def get_sql_info(self, _req: CommandGetSqlInfo) -> pa.RecordBatchReader:
68
70
  """Default implementation that reports no support for any complex features."""
@@ -71,7 +73,7 @@ class ADBCServerBase:
71
73
  SqlInfo.FLIGHT_SQL_SERVER_VERSION: "0.0.1",
72
74
  SqlInfo.FLIGHT_SQL_SERVER_ARROW_VERSION: pa.__version__,
73
75
  SqlInfo.FLIGHT_SQL_SERVER_READ_ONLY: True,
74
- SqlInfo.FLIGHT_SQL_SERVER_TRANSACTION: SqlSupportedTransaction.SQL_SUPPORTED_TRANSACTION_NONE.value,
76
+ SqlInfo.FLIGHT_SQL_SERVER_TRANSACTION: SqlSupportedTransaction.NONE.value,
75
77
  }
76
78
 
77
79
  # See https://github.com/apache/arrow-adbc/blob/38c21c2311a59803559cb0091b3f34180c28b25f/rust/core/src/schemas.rs#L35
@@ -147,7 +149,7 @@ class SpiralADBCServer(ADBCServerBase):
147
149
  @debuggable
148
150
  def batches():
149
151
  yield pa.RecordBatch.from_arrays(
150
- [list(self.sp.list_project_ids())],
152
+ [[p.id for p in self.sp.list_projects()]],
151
153
  schema=schema,
152
154
  )
153
155
 
@@ -171,12 +173,13 @@ class SpiralADBCServer(ADBCServerBase):
171
173
 
172
174
  # Otherwise, catalog is either the project ID, or None.
173
175
  if req.catalog is None:
174
- projects = list(self.sp.list_projects())
176
+ projects = self.sp.list_projects()
175
177
  else:
176
178
  projects = [self.sp.project(req.catalog)]
177
179
 
178
180
  for project in projects:
179
- datasets = {dt[0] for dt in project.list_table_names()}
181
+ datasets = {dt.dataset for dt in project.tables.list_tables()}
182
+
180
183
  batch = pa.RecordBatch.from_arrays(
181
184
  [
182
185
  [project.id] * len(datasets),
@@ -218,21 +221,20 @@ class SpiralADBCServer(ADBCServerBase):
218
221
  projects = [self.sp.project(req.catalog)]
219
222
 
220
223
  def _process_project(project):
221
- tables = project.list_tables()
224
+ tables: list[TableResource] = project.tables.list_tables()
222
225
 
223
226
  rows = []
224
227
  for table in tables:
225
- _project_id, dataset, name = str(table).split(".")
226
-
227
228
  row = {
228
229
  "catalog_name": project.id,
229
- "db_schema_name": dataset,
230
- "table_name": name,
230
+ "db_schema_name": table.dataset,
231
+ "table_name": table.table,
231
232
  "table_type": "TABLE",
232
233
  }
233
234
 
234
235
  if req.include_schema:
235
- row["table_schema"] = table.to_dataset().schema.serialize().to_pybytes()
236
+ open_table = project.tables.table(f"{table.project_id}.{table.dataset}.{table.table}")
237
+ row["table_schema"] = open_table.snapshot().to_dataset().schema.serialize().to_pybytes()
236
238
 
237
239
  rows.append(row)
238
240
 
@@ -251,9 +253,14 @@ class SpiralADBCServer(ADBCServerBase):
251
253
  # This lets us insert a PyArrow Dataset into Python locals such that
252
254
  # DuckDB will pick up on it for the query.
253
255
  name = exp.table_name(tbl)
254
- locals()[name] = self.sp.project(tbl.catalog).table(f"{tbl.db}.{tbl.name}").to_dataset()
256
+ locals()[name] = self.sp.tables.table(f"{tbl.catalog}.{tbl.db}.{tbl.name}").snapshot().to_dataset()
255
257
  tbl.replace(exp.table_(table=name))
256
258
 
259
+ try:
260
+ import duckdb
261
+ except ImportError:
262
+ raise FlightError("DuckDB is required for SQL queries.")
263
+
257
264
  try:
258
265
  sql = duckdb.sql(expr.sql(dialect="duckdb"))
259
266
  except Exception as e:
spiral/api/__init__.py CHANGED
@@ -1,164 +1,28 @@
1
- import abc
2
- import base64
3
- import logging
4
1
  import os
5
- import re
6
- import socket
7
- import time
8
- from collections.abc import Iterable, Iterator
9
- from typing import TYPE_CHECKING, Annotated, Generic, TypeVar
2
+ from typing import TYPE_CHECKING
10
3
 
11
- import betterproto
12
4
  import httpx
13
- import pyarrow as pa
14
- from httpx import HTTPStatusError
15
- from pydantic import (
16
- BaseModel,
17
- BeforeValidator,
18
- Field,
19
- GetPydanticSchema,
20
- PlainSerializer,
21
- StringConstraints,
22
- TypeAdapter,
23
- )
5
+
6
+ from .client import _Client
24
7
 
25
8
  if TYPE_CHECKING:
9
+ from spiral.core.client import Authn
10
+
26
11
  from .admin import AdminService
27
12
  from .filesystems import FileSystemService
28
13
  from .organizations import OrganizationService
29
14
  from .projects import ProjectService
30
- from .tables import TableService
31
- from .tokens import TokenService
15
+ from .telemetry import TelemetryService
32
16
  from .workloads import WorkloadService
33
17
 
34
- log = logging.getLogger(__name__)
35
-
36
- RE_ID = re.compile("[a-zA-Z0-9-]+")
37
-
38
- OrganizationId = Annotated[str, StringConstraints(min_length=1, max_length=64)] # , pattern=RE_ID)]
39
- ProjectId = Annotated[str, StringConstraints(min_length=1, max_length=64)] # , pattern=RE_ID)]
40
- RoleId = str
41
-
42
- #: Annotations to implement pa.Schema serde with byte arrays
43
- ArrowSchema = Annotated[
44
- pa.Schema,
45
- GetPydanticSchema(lambda tp, handler: handler(object)),
46
- BeforeValidator(
47
- lambda v: v
48
- if isinstance(v, pa.Schema)
49
- else pa.ipc.read_schema(pa.ipc.read_message(base64.urlsafe_b64decode(v)))
50
- ),
51
- PlainSerializer(lambda schema: base64.urlsafe_b64encode(schema.serialize().to_pybytes())),
52
- ]
53
-
54
- E = TypeVar("E")
55
-
56
-
57
- class PagedRequest(BaseModel):
58
- page_token: str | None = None
59
- page_size: int = 50
60
-
61
-
62
- class PagedResponse(BaseModel, Generic[E]):
63
- items: list[E] = Field(default_factory=list)
64
- next_page_token: str | None = None
65
-
66
-
67
- PagedReqT = TypeVar("PagedReqT", bound=PagedRequest)
68
-
69
-
70
- class Paged(Iterable[E], Generic[E]):
71
- def __init__(
72
- self,
73
- client: "_Client",
74
- path: str,
75
- request: PagedRequest,
76
- response_cls: type[PagedResponse[E]],
77
- ):
78
- self._client = client
79
- self._path = path
80
- self._request: PagedRequest = request
81
- self._response_cls = response_cls
82
-
83
- self._response: PagedResponse[E] = client.put(path, request, response_cls)
84
-
85
- @property
86
- def page(self) -> PagedResponse[E]:
87
- return self._response
88
-
89
- def __iter__(self) -> Iterator[E]:
90
- while True:
91
- yield from self._response.items
92
-
93
- if self._response.next_page_token is None:
94
- break
95
-
96
- self._request = self._request.model_copy(update=dict(page_token=self._response.next_page_token))
97
- self._response = self._client.put(self._path, self._request, self._response_cls)
98
-
99
-
100
- class ServiceBase:
101
- def __init__(self, client: "_Client"):
102
- self.client = client
103
-
104
-
105
- class Authn:
106
- """An abstract class for credential providers."""
107
-
108
- @abc.abstractmethod
109
- def token(self) -> str | None:
110
- """Return a token, if available."""
111
-
112
-
113
- class _Client:
114
- RequestT = TypeVar("RequestT")
115
- ResponseT = TypeVar("ResponseT")
116
-
117
- def __init__(self, http: httpx.Client, authn: Authn):
118
- self.http = http
119
- self.authn = authn
120
-
121
- def post(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
122
- return self.request("POST", path, req, response_cls)
123
-
124
- def put(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
125
- return self.request("PUT", path, req, response_cls)
126
-
127
- def request(self, method: str, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
128
- if isinstance(req, betterproto.Message):
129
- try:
130
- req = dict(content=bytes(req))
131
- except:
132
- raise
133
- else:
134
- req = dict(json=TypeAdapter(req.__class__).dump_python(req, mode="json") if req is not None else None)
135
-
136
- token = self.authn.token()
137
- resp = self.http.request(method, path, headers={"authorization": f"Bearer {token}" if token else None}, **req)
138
-
139
- try:
140
- resp.raise_for_status()
141
- except HTTPStatusError as e:
142
- # Enrich the exception with the response body
143
- raise HTTPStatusError(f"{str(e)}: {resp.text}", request=e.request, response=e.response)
144
-
145
- if issubclass(response_cls, betterproto.Message):
146
- return response_cls().parse(resp.content)
147
- else:
148
- return TypeAdapter(response_cls).validate_python(resp.json())
149
-
150
- def paged(self, path: str, req: PagedRequest, response_cls: type[PagedResponse[E]]) -> Paged[E]:
151
- return Paged(self, path, req, response_cls)
152
-
153
18
 
154
19
  class SpiralAPI:
155
- def __init__(self, authn: Authn, base_url: str | None = None):
20
+ def __init__(self, authn: "Authn", base_url: str | None = None):
156
21
  self.base_url = base_url or os.environ.get("SPIRAL_URL", "https://api.spiraldb.com")
157
22
  self.client = _Client(
158
23
  httpx.Client(
159
24
  base_url=self.base_url,
160
- timeout=60,
161
- # timeout=None if ("PYTEST_VERSION" in os.environ or bool(os.environ.get("SPIRAL_DEV", None))) else 60,
25
+ timeout=None if ("PYTEST_VERSION" in os.environ or bool(os.environ.get("SPIRAL_DEV", None))) else 60,
162
26
  ),
163
27
  authn,
164
28
  )
@@ -169,24 +33,12 @@ class SpiralAPI:
169
33
 
170
34
  return AdminService(self.client)
171
35
 
172
- @property
173
- def file_system(self) -> "FileSystemService":
174
- from .filesystems import FileSystemService
175
-
176
- return FileSystemService(self.client)
177
-
178
36
  @property
179
37
  def organization(self) -> "OrganizationService":
180
38
  from .organizations import OrganizationService
181
39
 
182
40
  return OrganizationService(self.client)
183
41
 
184
- @property
185
- def token(self) -> "TokenService":
186
- from .tokens import TokenService
187
-
188
- return TokenService(self.client)
189
-
190
42
  @property
191
43
  def project(self) -> "ProjectService":
192
44
  from .projects import ProjectService
@@ -194,10 +46,10 @@ class SpiralAPI:
194
46
  return ProjectService(self.client)
195
47
 
196
48
  @property
197
- def table(self) -> "TableService":
198
- from .tables import TableService
49
+ def file_system(self) -> "FileSystemService":
50
+ from .filesystems import FileSystemService
199
51
 
200
- return TableService(self.client)
52
+ return FileSystemService(self.client)
201
53
 
202
54
  @property
203
55
  def workload(self) -> "WorkloadService":
@@ -205,17 +57,8 @@ class SpiralAPI:
205
57
 
206
58
  return WorkloadService(self.client)
207
59
 
60
+ @property
61
+ def telemetry(self) -> "TelemetryService":
62
+ from .telemetry import TelemetryService
208
63
 
209
- def wait_for_port(port: int, host: str = "localhost", timeout: float = 5.0):
210
- """Wait until a port starts accepting TCP connections."""
211
- start_time = time.time()
212
- while True:
213
- try:
214
- with socket.create_connection((host, port), timeout=timeout):
215
- break
216
- except OSError as ex:
217
- time.sleep(0.01)
218
- if time.time() - start_time >= timeout:
219
- raise TimeoutError(
220
- f"Waited too long for the port {port} on host {host} to start accepting " "connections."
221
- ) from ex
64
+ return TelemetryService(self.client)
spiral/api/admin.py CHANGED
@@ -1,29 +1,15 @@
1
- from pydantic import BaseModel
2
-
3
- from . import OrganizationId, Paged, PagedRequest, PagedResponse, ServiceBase
4
-
5
-
6
- class SyncOrgs:
7
- class Request(PagedRequest): ...
8
-
9
- class Response(PagedResponse[OrganizationId]): ...
10
-
11
-
12
- class Membership(BaseModel):
13
- user_id: str
14
- organization_id: str
15
-
16
-
17
- class SyncMemberships:
18
- class Request(PagedRequest):
19
- organization_id: OrganizationId | None = None
20
-
21
- class Response(PagedResponse[Membership]): ...
1
+ from .client import Paged, PagedResponse, ServiceBase
2
+ from .organizations import OrgMembership
3
+ from .types import OrgId
22
4
 
23
5
 
24
6
  class AdminService(ServiceBase):
25
- def sync_orgs(self, request: SyncOrgs.Request) -> Paged[SyncOrgs.Response]:
26
- return self.client.paged("/admin/sync-orgs", request, SyncOrgs.Response)
27
-
28
- def sync_memberships(self, request: SyncMemberships.Request) -> Paged[Membership]:
29
- return self.client.paged("/admin/sync-memberships", request, SyncMemberships.Response)
7
+ def sync_memberships(self, org_id: OrgId | None = None) -> Paged[OrgMembership]:
8
+ params = {}
9
+ if org_id:
10
+ params["org_id"] = str(org_id)
11
+ return self.client.paged("/v1/admin/sync-memberships", PagedResponse[OrgMembership], params=params)
12
+
13
+ def sync_orgs(self) -> Paged[OrgId]:
14
+ params = {}
15
+ return self.client.paged("/v1/admin/sync-orgs", PagedResponse[OrgId], params=params)