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.
- {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.dist-info}/METADATA +12 -14
- pyspiral-0.4.3.dist-info/RECORD +98 -0
- {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.dist-info}/WHEEL +1 -1
- spiral/__init__.py +6 -7
- spiral/_lib.abi3.so +0 -0
- spiral/adbc.py +21 -14
- spiral/api/__init__.py +15 -172
- spiral/api/admin.py +12 -26
- spiral/api/client.py +160 -0
- spiral/api/filesystems.py +100 -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 +83 -18
- 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} +22 -21
- spiral/core/client/__init__.pyi +118 -0
- spiral/core/index/__init__.pyi +15 -0
- spiral/core/table/__init__.pyi +108 -0
- spiral/core/{manifests → table/manifests}/__init__.pyi +5 -23
- spiral/core/table/metastore/__init__.pyi +62 -0
- spiral/core/{spec → table/spec}/__init__.pyi +49 -92
- spiral/datetime_.py +27 -0
- spiral/expressions/__init__.py +41 -18
- spiral/expressions/base.py +5 -5
- spiral/expressions/list_.py +1 -1
- spiral/expressions/mp4.py +62 -0
- spiral/expressions/png.py +18 -0
- spiral/expressions/qoi.py +18 -0
- spiral/expressions/refs.py +23 -9
- spiral/expressions/struct.py +7 -5
- spiral/expressions/text.py +62 -0
- spiral/expressions/tiff.py +88 -88
- 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 +32 -77
- 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 +31 -87
- spiral/substrait_.py +10 -6
- spiral/tables/__init__.py +12 -0
- spiral/tables/client.py +130 -0
- spiral/{dataset.py → tables/dataset.py} +36 -25
- spiral/tables/debug/manifests.py +70 -0
- spiral/tables/debug/metrics.py +56 -0
- spiral/{debug.py → tables/debug/scan.py} +6 -9
- spiral/tables/maintenance.py +12 -0
- spiral/tables/scan.py +193 -0
- spiral/tables/snapshot.py +78 -0
- spiral/tables/table.py +157 -0
- spiral/tables/transaction.py +52 -0
- pyspiral-0.2.5.dist-info/RECORD +0 -81
- spiral/api/tables.py +0 -94
- 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 -107
- spiral/cli/table.py +0 -20
- spiral/cli/token.py +0 -27
- spiral/config.py +0 -26
- spiral/core/core/__init__.pyi +0 -53
- spiral/core/metastore/__init__.pyi +0 -91
- spiral/proto/_/spfs/__init__.py +0 -36
- spiral/proto/_/spiral/table/__init__.py +0 -225
- 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/scan_.py +0 -168
- spiral/table.py +0 -157
- {pyspiral-0.2.5.dist-info → pyspiral-0.4.3.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.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>=
|
21
|
-
Requires-Dist:
|
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.
|
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
|
-
|
38
|
-
|
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,,
|
spiral/__init__.py
CHANGED
@@ -1,11 +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.scan_ import Scan, scan
|
6
|
-
from spiral.table import Table
|
7
5
|
|
8
|
-
|
9
|
-
assert _lib, "Spiral library"
|
6
|
+
assert _lib
|
10
7
|
|
11
|
-
|
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,164 +1,28 @@
|
|
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 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
|
198
|
-
from .
|
49
|
+
def file_system(self) -> "FileSystemService":
|
50
|
+
from .filesystems import FileSystemService
|
199
51
|
|
200
|
-
return
|
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
|
-
|
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
|
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)
|