pyspiral 0.3.1__cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 0.4.4__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.
- {pyspiral-0.3.1.dist-info → pyspiral-0.4.4.dist-info}/METADATA +9 -13
- pyspiral-0.4.4.dist-info/RECORD +98 -0
- {pyspiral-0.3.1.dist-info → pyspiral-0.4.4.dist-info}/WHEEL +1 -1
- spiral/__init__.py +6 -9
- spiral/_lib.abi3.so +0 -0
- spiral/adbc.py +21 -14
- spiral/api/__init__.py +14 -175
- spiral/api/admin.py +12 -26
- spiral/api/client.py +160 -0
- spiral/api/filesystems.py +112 -72
- spiral/api/organizations.py +45 -58
- spiral/api/projects.py +171 -134
- spiral/api/telemetry.py +19 -0
- spiral/api/types.py +20 -0
- spiral/api/workloads.py +32 -25
- spiral/{arrow.py → arrow_.py} +12 -0
- spiral/cli/__init__.py +2 -5
- spiral/cli/admin.py +7 -12
- spiral/cli/app.py +23 -6
- spiral/cli/console.py +1 -1
- spiral/cli/fs.py +82 -17
- spiral/cli/iceberg/__init__.py +7 -0
- spiral/cli/iceberg/namespaces.py +47 -0
- spiral/cli/iceberg/tables.py +60 -0
- spiral/cli/indexes/__init__.py +19 -0
- spiral/cli/login.py +14 -5
- spiral/cli/orgs.py +90 -0
- spiral/cli/printer.py +9 -1
- spiral/cli/projects.py +136 -0
- spiral/cli/state.py +2 -0
- spiral/cli/tables/__init__.py +121 -0
- spiral/cli/telemetry.py +18 -0
- spiral/cli/types.py +8 -10
- spiral/cli/{workload.py → workloads.py} +11 -11
- spiral/{catalog.py → client.py} +23 -37
- spiral/core/client/__init__.pyi +118 -0
- spiral/core/index/__init__.pyi +15 -0
- spiral/core/{core → table}/__init__.pyi +45 -17
- spiral/core/{manifests → table/manifests}/__init__.pyi +5 -23
- spiral/core/table/metastore/__init__.pyi +62 -0
- spiral/core/{spec → table/spec}/__init__.pyi +41 -66
- spiral/datetime_.py +27 -0
- spiral/expressions/__init__.py +30 -31
- spiral/expressions/base.py +5 -5
- spiral/expressions/list_.py +1 -1
- spiral/expressions/mp4.py +9 -16
- spiral/expressions/png.py +1 -1
- spiral/expressions/qoi.py +1 -1
- spiral/expressions/refs.py +6 -12
- spiral/expressions/struct.py +7 -5
- spiral/expressions/text.py +62 -0
- spiral/expressions/udf.py +3 -3
- spiral/iceberg/__init__.py +3 -0
- spiral/iceberg/client.py +33 -0
- spiral/indexes/__init__.py +5 -0
- spiral/indexes/client.py +137 -0
- spiral/indexes/index.py +34 -0
- spiral/indexes/scan.py +22 -0
- spiral/project.py +19 -110
- spiral/{proto → protogen}/_/scandal/__init__.py +23 -135
- spiral/protogen/_/spiral/table/__init__.py +22 -0
- spiral/protogen/substrait/__init__.py +3399 -0
- spiral/protogen/substrait/extensions/__init__.py +115 -0
- spiral/server.py +17 -0
- spiral/settings.py +29 -91
- spiral/substrait_.py +9 -10
- spiral/tables/__init__.py +12 -0
- spiral/tables/client.py +130 -0
- spiral/{dataset.py → tables/dataset.py} +9 -199
- spiral/tables/debug/manifests.py +70 -0
- spiral/tables/debug/metrics.py +56 -0
- spiral/{debug.py → tables/debug/scan.py} +6 -9
- spiral/{maintenance.py → tables/maintenance.py} +1 -1
- spiral/{scan_.py → tables/scan.py} +63 -89
- spiral/tables/snapshot.py +78 -0
- spiral/tables/table.py +145 -0
- spiral/{txn.py → tables/transaction.py} +7 -3
- pyspiral-0.3.1.dist-info/RECORD +0 -85
- spiral/api/tables.py +0 -91
- spiral/api/tokens.py +0 -56
- spiral/authn/authn.py +0 -89
- spiral/authn/device.py +0 -206
- spiral/authn/github_.py +0 -33
- spiral/authn/modal_.py +0 -18
- spiral/cli/org.py +0 -90
- spiral/cli/project.py +0 -109
- spiral/cli/table.py +0 -20
- spiral/cli/token.py +0 -27
- spiral/core/metastore/__init__.pyi +0 -91
- spiral/proto/_/spfs/__init__.py +0 -36
- spiral/proto/_/spiral/table/__init__.py +0 -276
- spiral/proto/_/spiraldb/metastore/__init__.py +0 -499
- spiral/proto/__init__.py +0 -0
- spiral/proto/scandal/__init__.py +0 -45
- spiral/proto/spiral/__init__.py +0 -0
- spiral/proto/spiral/table/__init__.py +0 -96
- spiral/table.py +0 -171
- {pyspiral-0.3.1.dist-info → pyspiral-0.4.4.dist-info}/entry_points.txt +0 -0
- /spiral/{authn/__init__.py → core/__init__.pyi} +0 -0
- /spiral/{core → protogen/_}/__init__.py +0 -0
- /spiral/{proto/_ → protogen/_/arrow}/__init__.py +0 -0
- /spiral/{proto/_/arrow → protogen/_/arrow/flight}/__init__.py +0 -0
- /spiral/{proto/_/arrow/flight → protogen/_/arrow/flight/protocol}/__init__.py +0 -0
- /spiral/{proto → protogen}/_/arrow/flight/protocol/sql/__init__.py +0 -0
- /spiral/{proto/_/arrow/flight/protocol → protogen/_/spiral}/__init__.py +0 -0
- /spiral/{proto → protogen/_}/substrait/__init__.py +0 -0
- /spiral/{proto → protogen/_}/substrait/extensions/__init__.py +0 -0
- /spiral/{proto/_/spiral → protogen}/__init__.py +0 -0
- /spiral/{proto → protogen}/util.py +0 -0
- /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.
|
3
|
+
Version: 0.4.4
|
4
4
|
Classifier: Intended Audience :: Science/Research
|
5
5
|
Classifier: Operating System :: OS Independent
|
6
6
|
Classifier: Programming Language :: Python
|
@@ -17,34 +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>=
|
21
|
-
Requires-Dist: pyarrow>=
|
20
|
+
Requires-Dist: numpy>=2
|
21
|
+
Requires-Dist: pyarrow>=21.0.0
|
22
22
|
Requires-Dist: pydantic-settings>=2.3.4
|
23
23
|
Requires-Dist: pydantic[email]>=2.5.3
|
24
24
|
Requires-Dist: pyjwt[crypto]>=2.9.0
|
25
25
|
Requires-Dist: questionary>=2.0.1
|
26
26
|
Requires-Dist: tqdm>=4.66.5
|
27
|
-
Requires-Dist: typer>=0.
|
27
|
+
Requires-Dist: typer>=0.16
|
28
28
|
Requires-Dist: xxhash>=3.4.1
|
29
29
|
Requires-Dist: nanoid>=2.0.0
|
30
30
|
Requires-Dist: sqlglot[rs]>=25.25.1
|
31
31
|
Requires-Dist: pyperclip>=1.9.0
|
32
|
-
Requires-Dist:
|
33
|
-
Requires-Dist:
|
34
|
-
Requires-Dist:
|
35
|
-
Requires-Dist: pyiceberg>=0.9.0 ; extra == 'pyiceberg'
|
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'
|
36
35
|
Provides-Extra: polars
|
37
36
|
Provides-Extra: duckdb
|
38
37
|
Provides-Extra: pyiceberg
|
39
|
-
Summary: Python
|
40
|
-
Keywords: vortex,spiraldb
|
38
|
+
Summary: Python client for Spiral.
|
41
39
|
Home-Page: https://spiraldb.com
|
42
|
-
Author: Spiral<hello@spiraldb.com>
|
43
40
|
Author-email: SpiralDB <hello@spiraldb.com>
|
44
|
-
License: Proprietary
|
41
|
+
License: Proprietary License
|
45
42
|
Requires-Python: >=3.10
|
46
43
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
47
|
-
Project-URL: Source Code, https://github.com/spiraldb/spiraldb
|
48
44
|
|
49
45
|
# PySpiral
|
50
46
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
pyspiral-0.4.4.dist-info/METADATA,sha256=lVusDQ4LmIf3tRllkl2_hUNn1y0P_yMfNKhkRbpNLW0,1610
|
2
|
+
pyspiral-0.4.4.dist-info/WHEEL,sha256=PjJMzJpvi5UGP0cjK5Ftx4x5YgThyrYgwpOwFQxcwHw,130
|
3
|
+
pyspiral-0.4.4.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
|
4
|
+
spiral/__init__.py,sha256=Jv1vbcnnmcTsBLN5mSNjnX3ae4C_mgojXDSBFaqIhN0,208
|
5
|
+
spiral/_lib.abi3.so,sha256=U0ORTHXS8JECNJiMkppnZTQiRV1gb6G_wbTdCsGJlAk,52330824
|
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=EA4iqhTeaIlvObvEUxHmZl0pQ24IOxUVWM3GPhFLw8o,4969
|
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=agrxN1dYx--dte_edQOKgAXT8yPDeh_cHA8dYAOodbE,3290
|
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=T8PIb0_UB9kynK0dpWbUD4No5lKRTG-wKnao8xOcXjY,6381
|
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=_xGVnkygddzxP9a8OACJ8_KXnejuVbYCVKBCXBQ798Y,2151
|
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=omeHBQ5o6N4xgZ3x5Xz7IRrWwYBBtQY8DYK0NNAxeGo,2109
|
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=2BYvwFGcCwJ0JXNhXOLdPuhM1PqFyaeSqFpQCtv-M4E,12581
|
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=VM93Rsm67sJFendI1_VhlkFORIdBGfhCMBUBK4dve9I,4910
|
96
|
+
spiral/tables/transaction.py,sha256=3a64R-mf_cmR54BNn8U-05jmWonp6Ivxhe6u01Dyjzo,1573
|
97
|
+
spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
|
98
|
+
pyspiral-0.4.4.dist-info/RECORD,,
|
spiral/__init__.py
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
"""Python client for
|
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.maintenance import Maintenance
|
6
|
-
from spiral.scan_ import Scan, scan
|
7
|
-
from spiral.table import Table
|
8
|
-
from spiral.txn import Transaction
|
9
5
|
|
10
|
-
|
11
|
-
assert _lib, "Spiral library"
|
6
|
+
assert _lib
|
12
7
|
|
13
|
-
|
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.
|
29
|
-
from spiral.
|
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.
|
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
|
-
[
|
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 =
|
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
|
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":
|
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
|
-
|
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.
|
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,163 +1,23 @@
|
|
1
|
-
import abc
|
2
|
-
import base64
|
3
|
-
import logging
|
4
1
|
import os
|
5
|
-
import
|
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
|
-
|
14
|
-
from
|
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 .
|
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 get(self, path: str, response_cls: type[ResponseT]) -> ResponseT:
|
122
|
-
return self.request("GET", path, None, response_cls)
|
123
|
-
|
124
|
-
def post(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
|
125
|
-
return self.request("POST", path, req, response_cls)
|
126
|
-
|
127
|
-
def put(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
|
128
|
-
return self.request("PUT", path, req, response_cls)
|
129
|
-
|
130
|
-
def request(self, method: str, path: str, req: RequestT | None, response_cls: type[ResponseT]) -> ResponseT:
|
131
|
-
if isinstance(req, betterproto.Message):
|
132
|
-
try:
|
133
|
-
req = dict(content=bytes(req))
|
134
|
-
except:
|
135
|
-
raise
|
136
|
-
elif req is not None:
|
137
|
-
req = dict(json=TypeAdapter(req.__class__).dump_python(req, mode="json") if req is not None else None)
|
138
|
-
else:
|
139
|
-
req = dict()
|
140
|
-
|
141
|
-
token = self.authn.token()
|
142
|
-
resp = self.http.request(method, path, headers={"authorization": f"Bearer {token}" if token else None}, **req)
|
143
|
-
|
144
|
-
try:
|
145
|
-
resp.raise_for_status()
|
146
|
-
except HTTPStatusError as e:
|
147
|
-
# Enrich the exception with the response body
|
148
|
-
raise HTTPStatusError(f"{str(e)}: {resp.text}", request=e.request, response=e.response)
|
149
|
-
|
150
|
-
if issubclass(response_cls, betterproto.Message):
|
151
|
-
return response_cls().parse(resp.content)
|
152
|
-
else:
|
153
|
-
return TypeAdapter(response_cls).validate_python(resp.json())
|
154
|
-
|
155
|
-
def paged(self, path: str, req: PagedRequest, response_cls: type[PagedResponse[E]]) -> Paged[E]:
|
156
|
-
return Paged(self, path, req, response_cls)
|
157
|
-
|
158
18
|
|
159
19
|
class SpiralAPI:
|
160
|
-
def __init__(self, authn: Authn, base_url: str | None = None):
|
20
|
+
def __init__(self, authn: "Authn", base_url: str | None = None):
|
161
21
|
self.base_url = base_url or os.environ.get("SPIRAL_URL", "https://api.spiraldb.com")
|
162
22
|
self.client = _Client(
|
163
23
|
httpx.Client(
|
@@ -173,24 +33,12 @@ class SpiralAPI:
|
|
173
33
|
|
174
34
|
return AdminService(self.client)
|
175
35
|
|
176
|
-
@property
|
177
|
-
def file_system(self) -> "FileSystemService":
|
178
|
-
from .filesystems import FileSystemService
|
179
|
-
|
180
|
-
return FileSystemService(self.client)
|
181
|
-
|
182
36
|
@property
|
183
37
|
def organization(self) -> "OrganizationService":
|
184
38
|
from .organizations import OrganizationService
|
185
39
|
|
186
40
|
return OrganizationService(self.client)
|
187
41
|
|
188
|
-
@property
|
189
|
-
def token(self) -> "TokenService":
|
190
|
-
from .tokens import TokenService
|
191
|
-
|
192
|
-
return TokenService(self.client)
|
193
|
-
|
194
42
|
@property
|
195
43
|
def project(self) -> "ProjectService":
|
196
44
|
from .projects import ProjectService
|
@@ -198,10 +46,10 @@ class SpiralAPI:
|
|
198
46
|
return ProjectService(self.client)
|
199
47
|
|
200
48
|
@property
|
201
|
-
def
|
202
|
-
from .
|
49
|
+
def file_system(self) -> "FileSystemService":
|
50
|
+
from .filesystems import FileSystemService
|
203
51
|
|
204
|
-
return
|
52
|
+
return FileSystemService(self.client)
|
205
53
|
|
206
54
|
@property
|
207
55
|
def workload(self) -> "WorkloadService":
|
@@ -209,17 +57,8 @@ class SpiralAPI:
|
|
209
57
|
|
210
58
|
return WorkloadService(self.client)
|
211
59
|
|
60
|
+
@property
|
61
|
+
def telemetry(self) -> "TelemetryService":
|
62
|
+
from .telemetry import TelemetryService
|
212
63
|
|
213
|
-
|
214
|
-
"""Wait until a port starts accepting TCP connections."""
|
215
|
-
start_time = time.time()
|
216
|
-
while True:
|
217
|
-
try:
|
218
|
-
with socket.create_connection((host, port), timeout=timeout):
|
219
|
-
break
|
220
|
-
except OSError as ex:
|
221
|
-
time.sleep(0.01)
|
222
|
-
if time.time() - start_time >= timeout:
|
223
|
-
raise TimeoutError(
|
224
|
-
f"Waited too long for the port {port} on host {host} to start accepting " "connections."
|
225
|
-
) from ex
|
64
|
+
return TelemetryService(self.client)
|
spiral/api/admin.py
CHANGED
@@ -1,29 +1,15 @@
|
|
1
|
-
from
|
2
|
-
|
3
|
-
from . import
|
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
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return self.client.paged("/admin/sync-memberships",
|
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)
|