pyspiral 0.2.5__cp310-abi3-macosx_11_0_arm64.whl → 0.3.1__cp310-abi3-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyspiral
3
- Version: 0.2.5
3
+ Version: 0.3.1
4
4
  Classifier: Intended Audience :: Science/Research
5
5
  Classifier: Operating System :: OS Independent
6
6
  Classifier: Programming Language :: Python
@@ -18,22 +18,24 @@ Requires-Dist: grpclib>=0.4.7
18
18
  Requires-Dist: hishel>=0.0.30
19
19
  Requires-Dist: httpx>=0.27.0
20
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
21
  Requires-Dist: pyarrow>=17.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
27
  Requires-Dist: typer>=0.12.3
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
32
+ Requires-Dist: boto3>=1.35.36
33
+ Requires-Dist: polars>=1.6.0 ; extra == 'polars'
34
+ Requires-Dist: duckdb>=1.1.1 ; extra == 'duckdb'
35
+ Requires-Dist: pyiceberg>=0.9.0 ; extra == 'pyiceberg'
36
+ Provides-Extra: polars
37
+ Provides-Extra: duckdb
38
+ Provides-Extra: pyiceberg
37
39
  Summary: Python implementation of Spiral table format.
38
40
  Keywords: vortex,spiraldb
39
41
  Home-Page: https://spiraldb.com
@@ -1,12 +1,11 @@
1
- pyspiral-0.2.5.dist-info/METADATA,sha256=v9fKmJB3Y9Qss3pzr-rtw4PGnry0iBaFLN3_fwefN2s,1699
2
- pyspiral-0.2.5.dist-info/WHEEL,sha256=j3ku1HwtRttgdyoybPiqmsz03FP6lDUkPQNFM63xZJo,103
3
- pyspiral-0.2.5.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
4
- spiral/catalog.py,sha256=BtthmRApU1RSb6KbUfVTM2aYeLsnlO0nKDYHBYhdr9M,2496
5
- spiral/scan_.py,sha256=rbLl85yeOkRuLsbk6QKng0_U4gtGGsW6C-aJiJSxuv8,5946
6
- spiral/substrait_.py,sha256=5ZXnYcsXEdrBogECnoL6IMlsjsseYHEnVARgRpy2vt8,12671
7
- spiral/config.py,sha256=ovtE5D3r6_g90ZRDJhlJyWhOBlxLjagvomOyA-VZmdc,911
8
- spiral/core/core/__init__.pyi,sha256=-OCtTgqjUN7sACAmgrAA_TrqmuP7epNSyL9XjqnNTa4,1914
9
- spiral/core/spec/__init__.pyi,sha256=zwOPhpBS_iOrPkOdc4ySpgzICZNbteMZf4c2wdkWw1Y,7251
1
+ pyspiral-0.3.1.dist-info/METADATA,sha256=QWHcYqfg46JUluQy_NZ3TKilWdvRFwOCqcJPYMo4g3c,1782
2
+ pyspiral-0.3.1.dist-info/WHEEL,sha256=WcVLymwUFXZZBOS7GhUoID5qvQcDPxnkUAYBKypRBtM,103
3
+ pyspiral-0.3.1.dist-info/entry_points.txt,sha256=uft7u-a6g40NLt4Q6BleWbK4NY0M8nZuYPpP8DV0EOk,45
4
+ spiral/catalog.py,sha256=o6b8yhVzHmk_CPNZMKyJU0H8xpjJKKcf2rjcopTSBKc,2912
5
+ spiral/scan_.py,sha256=TNAR_ELKRMJec6fIxhOwpW12WTwZc4sDLtfGdiok-lw,8239
6
+ spiral/substrait_.py,sha256=LmdRhyTX7vhgEbpxV6FUssyL-BiBEIPBeUZApeaKDM4,12671
7
+ spiral/core/core/__init__.pyi,sha256=zQhEB9X0B4EJGZf6AJYZdRt1tDQelF5tCsUaVdH7p4I,2706
8
+ spiral/core/spec/__init__.pyi,sha256=RAnvJjuQPxbcyPtjldvOU8zjVlHhnTKHAFa77sqxBdw,6714
10
9
  spiral/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
10
  spiral/core/manifests/__init__.pyi,sha256=DXr4Ab_Xo11AzrJlSj7FTSJc8qoO-SkL-_ik4kB855U,1516
12
11
  spiral/core/metastore/__init__.pyi,sha256=pdKED91GVJ9XWxTWc9gwkHvVHV_RKxvL43Ofs5ndmew,3145
@@ -16,21 +15,22 @@ spiral/proto/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
16
15
  spiral/proto/spiral/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
16
  spiral/proto/spiral/table/__init__.py,sha256=_F1f52RMkZsXofPXpJb2KE8KR5l6zxCtrGrabR1uDxo,2816
18
17
  spiral/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- spiral/proto/_/scandal/__init__.py,sha256=rQJdbN3UKDJ8vOJ5V7l3KumNHlRyY8iw25HCLsIDB4I,6582
18
+ spiral/proto/_/scandal/__init__.py,sha256=4UV2TipI1dJWCM2gFNmZM1qbM1_C_pilO3DTI1Kqq8M,8655
20
19
  spiral/proto/_/arrow/flight/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
20
  spiral/proto/_/arrow/flight/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
21
  spiral/proto/_/arrow/flight/protocol/sql/__init__.py,sha256=_xhj9QkWEW1qZ-iVxcQ8k4EjYr7KJ5ofitJGqVUGQi4,79921
23
22
  spiral/proto/_/arrow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
23
  spiral/proto/_/spiral/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- spiral/proto/_/spiral/table/__init__.py,sha256=sjK2dmvB09PqV3lxKMEk5QoHjC37HMW0MnxR1QDuBg0,7387
24
+ spiral/proto/_/spiral/table/__init__.py,sha256=WnBvPPGHphSIa5K6ct6G3S3pK5BJtcC0EIce7r4Jam4,8818
26
25
  spiral/proto/_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
26
  spiral/proto/_/spiraldb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
27
  spiral/proto/_/spiraldb/metastore/__init__.py,sha256=40Egtg8MRYTaTTYRKOHkwuiyXEkw3Yg7ETCQskIzpIg,16873
29
28
  spiral/proto/_/spfs/__init__.py,sha256=9WtIXr7HGslKWRHHieFDo8N_qnGL4QQyLOCWEkOKRvk,1017
30
29
  spiral/proto/substrait/__init__.py,sha256=pV4-T-lwAHKkfFrNYSUGY4IkbIvuKjSo_imzF7BLj_s,126526
31
30
  spiral/proto/substrait/extensions/__init__.py,sha256=yD7dg0TBqn-GK_L0qeVof1GKnwSLg_kPyQSV3kcSljs,3655
31
+ spiral/maintenance.py,sha256=UFvWBLf9L0qDxJa2VdyBzxQxN4W3D9F3QHFKWp1yWZU,304
32
32
  spiral/arrow.py,sha256=LBPwZcGkP4kXb42_kl5IUwWW3DO84CV3QJDwCHjG5Dg,7225
33
- spiral/__init__.py,sha256=4EiQkY17qHT9dpxu41fdOV1kqGl_b-HXNRQg--ZwJbo,286
33
+ spiral/__init__.py,sha256=Dlaha3kfmzIri8A3-d69tOC2iQrK5fXlYVSI6uU4Fus,394
34
34
  spiral/cli/console.py,sha256=-OP0bB_efxhWh4lZ95KRdu-SRgSUMJ47Rbi9FHv1TlY,2577
35
35
  spiral/cli/org.py,sha256=ezWhoGUkJQQAwI1jKvDP8uZPNlnou_hXtRDa1us5cSE,2935
36
36
  spiral/cli/token.py,sha256=dv30aa745bbS-c3tyzQUTSxGG_N0kCt8G4bip9fP_EM,968
@@ -38,38 +38,42 @@ spiral/cli/__init__.py,sha256=CoiAJ7FDgqjG_TrU-6SpP1hyZloIlEP4wcwnrF8flHM,2237
38
38
  spiral/cli/types.py,sha256=4cphJs-i0vfq_CcnHxT9FpHiZdGwxME5GnOmIGB6Thw,1436
39
39
  spiral/cli/workload.py,sha256=-XreFPJcX7kZvcYE3oQMeGkkYoXi25R5nuktJPg-PuY,2000
40
40
  spiral/cli/admin.py,sha256=3pIs6PxDugMtdgzfRpn_HfBDv-cwAYtF0cJP2INB01A,579
41
- spiral/cli/fs.py,sha256=8sQAgMahAq0gtXJqnuiKUkx4sO6vEEF4Iaq_-AF3wro,1524
41
+ spiral/cli/fs.py,sha256=rgI3QNKg0_B-3T2d0KgjcLYQNc2M6sRK95cJ_J0nth0,1523
42
42
  spiral/cli/app.py,sha256=2oZfDTgj_gZ-lFMMzzJJTnvVzQhp_iedvH-FJnaaMW0,1487
43
43
  spiral/cli/table.py,sha256=eh2NAk0GlfvthwRNeIbcZTsRWU3ypFx_uu9OaOLHPUo,628
44
44
  spiral/cli/login.py,sha256=C7VpqVyYO2daUeIWHoelWnSGN7cju8YEuqOy12ImH4c,381
45
45
  spiral/cli/printer.py,sha256=5HD3UcszFfPk-dK8U5akuvtXqMB7PMgOB1DFYMqspG8,1625
46
46
  spiral/cli/__main__.py,sha256=kNaKM2xgJo7GRogf83nYldLM-RGUR6vymdGwZxywQu0,71
47
- spiral/cli/project.py,sha256=aCxvw8UVwSmh_anArizIQ3_pLVT6QH9jYwMsGfpJUgM,4486
47
+ spiral/cli/project.py,sha256=N9ocPRtjLT5lfrPMGbX_-bUXP6o5gq3RpoGYQR3CJ74,4524
48
48
  spiral/cli/state.py,sha256=1quvei8TnDTT6mDRo58P8FUfy4w16Z9sggBz7cFgllY,70
49
- spiral/dataset.py,sha256=jUeXvE4B5nKh9VNmHxvROQbEkTUxqyYS8oS6EQyRbng,7555
49
+ spiral/dataset.py,sha256=53s1JGM9lQkzbZes9nXnax6XtMtCUDR0TBOeTA8wC38,14019
50
50
  spiral/grpc_.py,sha256=f3czdP1Mxme42Y5--a5ogYq1TTiWn-J_MlGjwJ2mWwM,1015
51
51
  spiral/debug.py,sha256=t590eAUtNWwMTsSdkjVNN7J1iMqY2p4PRJ3BWR_ozho,8999
52
- spiral/expressions/tiff.py,sha256=k5GMzm4FmGBJMyja-D6u_kt_-vHYIdj4bnYYZut5lK4,7579
52
+ spiral/expressions/tiff.py,sha256=fQwIn0kLFBM2Y3YYIHmTgb_EIRHKT2fNc77nioDQQw4,8044
53
53
  spiral/expressions/io.py,sha256=gJ2a0FKMmdxarWKENulPRwH7KDvSJTIh_OUxX306xAM,3045
54
- spiral/expressions/__init__.py,sha256=T2POn0Z-mQj9PY8ukYWYn5A832Fz7Y6F8RRASo6Xl3A,5638
54
+ spiral/expressions/__init__.py,sha256=LqvssKQTvoyX4s5UIG_HtYZbt5i5EkghkEpsE_37MWg,6118
55
+ spiral/expressions/png.py,sha256=3SjreqYcnDL4_EWMENcaGpZVoXR49KAfJiERkFSdT-w,511
55
56
  spiral/expressions/list_.py,sha256=nbo4xQAuqBsQGajq_JgORaJl8_CDvOAv14zMbqmtZh4,1814
56
57
  spiral/expressions/http.py,sha256=begUydWoFHEqjeLkATvI_v66Ez6_rR-OQBWO5cHbb9c,2742
57
- spiral/expressions/refs.py,sha256=F3xr7wmrbAawMkLTWcvVwczbOMNOnIttSMRDuzjZHbo,1774
58
+ spiral/expressions/refs.py,sha256=EndnGTLSA-s3hD6QOkxfUSWpw2IUm1hnKyyiPIlhZ7I,2370
58
59
  spiral/expressions/udf.py,sha256=vOlrdxiVpt7vdSgiTKX_XR86YKyu02Fdwb9xlINCby4,1363
60
+ spiral/expressions/mp4.py,sha256=0qhTP4HGI0WL-nVhke-ykqEnOYcb64Aqryplgelv-BA,2437
59
61
  spiral/expressions/str_.py,sha256=tY8RXW3JWvr1-bEfCZtk5FAf11wKJnXPuA9EoeJ9tA4,1265
62
+ spiral/expressions/qoi.py,sha256=FCAsoF-3ur7CMIk2Oz5Hm4qDdb901E_7_-aKT8yss6E,511
60
63
  spiral/expressions/base.py,sha256=mTBwS6CwdDaV8uotjZUiKi7GHQzX2TRPpnseJJUDrR0,4776
61
64
  spiral/expressions/struct.py,sha256=MuxoBP6ESpwmjzusG-_HxHGYKvQQz6AZWzvw7vNUHJM,2007
62
- spiral/settings.py,sha256=e_F6GQea6ljXzCRgFxMBMecoGhFpEhePhMRQkYOoVO4,4555
65
+ spiral/settings.py,sha256=H0ELgA1k_YENufIWscXV7gzdU8t7JOCw0AdUDVvCFH0,4704
63
66
  spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
- spiral/api/filesystems.py,sha256=NPf5PCyCQ7eEU723fOdKcuGPgn83pthkb_jJ9aB0fwM,3431
67
+ spiral/api/filesystems.py,sha256=_JWFbggORWOAg0yKASsEXbu8Vk-hIMOiiVrwcEcm_RA,3424
65
68
  spiral/api/workloads.py,sha256=4MWs2pp9AWvx6cZhgyW-ehyCRxpHc_NAQgHaoYOEBfg,1266
66
- spiral/api/__init__.py,sha256=Ub3IYeQUJ_z0-Y_SXmNasxb6uefKynQkuUZgRM1enyc,6660
69
+ spiral/api/__init__.py,sha256=Wy2ZEL0balniPP7LuYLhazxI9p3ZcgZ9g_MAZLWF3Hg,6828
67
70
  spiral/api/tokens.py,sha256=WaSRr_l3i81t5u2qi3kWW-fySbyKFm-PQK1ZlmoSByc,1464
68
71
  spiral/api/admin.py,sha256=HJBrRJScbcdDuFhF_06E0EyE-_Y0osfYPxVoRAyEoTc,837
69
72
  spiral/api/organizations.py,sha256=-PO93HTX02IxhXM6SJpAhnAXpVW1WjthFO4-AOzZAC4,2670
70
- spiral/api/tables.py,sha256=uPoWkkcW7lJUxU0fUgDK5Gy_DT8y7gJFXdgxQpqcc5w,2548
73
+ spiral/api/tables.py,sha256=3Kt0tPfu3jQGIIAMUSNAMRtDRGK-STRYoHHgzZ4qFNU,2532
71
74
  spiral/api/projects.py,sha256=-VGlu5V3TJ3XLCGu85bPHRFiktIADnAxfLWIH8Rmxug,4986
72
- spiral/table.py,sha256=iJ-Lhu9ieSNg728cvUNRERcxKz7pj8hMCXPGBFHg7tI,4845
75
+ spiral/txn.py,sha256=SIww2vAazE1nPxyAkeiN7NMvXmBK6jHhFM_uMkEUW0o,1508
76
+ spiral/table.py,sha256=HzSRNQAI9YscdfmeHlwZcIdrK2SJ9wWq-GRRCmint_M,5541
73
77
  spiral/authn/modal_.py,sha256=agcnR3dYTslkH2K_a2Eis_2JWn9Ps11FVrGG_jkOdGk,472
74
78
  spiral/authn/device.py,sha256=ohHSVLW3a-qLNYQGN-3kXxV_836xOe0UYBN8i63cqAQ,6796
75
79
  spiral/authn/authn.py,sha256=OCGJAUfoKLiXw9xAcAnX6i6mBRlvsl6qEFcimqQOu7g,2555
@@ -77,5 +81,5 @@ spiral/authn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
81
  spiral/authn/github_.py,sha256=K-0RUHDreINjnCDHyT9aeVDRk6WtNP7noBYEcwdz2W4,1313
78
82
  spiral/adbc.py,sha256=H_bzevPy5teyZKzjczh1gQ_zPcfk5sNASiJKQvyab9E,13830
79
83
  spiral/project.py,sha256=q9jHql7hz5OQzPfDfvE_hN3K9cZotD0cxkdug9EUTwM,4889
80
- spiral/_lib.abi3.so,sha256=Te1P4F2PJPY2E7qn69_ApKZwKkIp93sdpf21XZJZ6jU,61005104
81
- pyspiral-0.2.5.dist-info/RECORD,,
84
+ spiral/_lib.abi3.so,sha256=p285aXvfZS7XzjXERyb5tsrH0fwq9rVdZ0hX4rvbkrA,64644032
85
+ pyspiral-0.3.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.2)
2
+ Generator: maturin (1.8.3)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-abi3-macosx_11_0_arm64
spiral/__init__.py CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
3
  from spiral import _lib
4
4
  from spiral.catalog import Spiral
5
+ from spiral.maintenance import Maintenance
5
6
  from spiral.scan_ import Scan, scan
6
7
  from spiral.table import Table
8
+ from spiral.txn import Transaction
7
9
 
8
10
  # Eagerly import the Spiral library
9
11
  assert _lib, "Spiral library"
10
12
 
11
- __all__ = ["scan", "Scan", "Table", "Spiral"]
13
+ __all__ = ["scan", "Scan", "Table", "Spiral", "Transaction", "Maintenance"]
spiral/_lib.abi3.so CHANGED
Binary file
spiral/api/__init__.py CHANGED
@@ -118,20 +118,25 @@ class _Client:
118
118
  self.http = http
119
119
  self.authn = authn
120
120
 
121
+ def get(self, path: str, response_cls: type[ResponseT]) -> ResponseT:
122
+ return self.request("GET", path, None, response_cls)
123
+
121
124
  def post(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
122
125
  return self.request("POST", path, req, response_cls)
123
126
 
124
127
  def put(self, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
125
128
  return self.request("PUT", path, req, response_cls)
126
129
 
127
- def request(self, method: str, path: str, req: RequestT, response_cls: type[ResponseT]) -> ResponseT:
130
+ def request(self, method: str, path: str, req: RequestT | None, response_cls: type[ResponseT]) -> ResponseT:
128
131
  if isinstance(req, betterproto.Message):
129
132
  try:
130
133
  req = dict(content=bytes(req))
131
134
  except:
132
135
  raise
133
- else:
136
+ elif req is not None:
134
137
  req = dict(json=TypeAdapter(req.__class__).dump_python(req, mode="json") if req is not None else None)
138
+ else:
139
+ req = dict()
135
140
 
136
141
  token = self.authn.token()
137
142
  resp = self.http.request(method, path, headers={"authorization": f"Bearer {token}" if token else None}, **req)
@@ -157,8 +162,7 @@ class SpiralAPI:
157
162
  self.client = _Client(
158
163
  httpx.Client(
159
164
  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,
165
+ timeout=None if ("PYTEST_VERSION" in os.environ or bool(os.environ.get("SPIRAL_DEV", None))) else 60,
162
166
  ),
163
167
  authn,
164
168
  )
spiral/api/filesystems.py CHANGED
@@ -122,4 +122,4 @@ class FileSystemService(ServiceBase):
122
122
  return self.client.post("/file-system/create-mount", request, CreateMount.Response)
123
123
 
124
124
  def create_mount_token(self, request: CreateMountToken.Request) -> CreateMountToken.Response:
125
- return self.client.post("/file-system/create-mount-token", request, CreateMountToken.Response)
125
+ return self.client.post("/file-system/mount-token", request, CreateMountToken.Response)
spiral/api/tables.py CHANGED
@@ -1,10 +1,6 @@
1
1
  from typing import Annotated
2
2
 
3
- from pydantic import (
4
- AfterValidator,
5
- BaseModel,
6
- StringConstraints,
7
- )
3
+ from pydantic import AfterValidator, BaseModel, StringConstraints
8
4
 
9
5
  from . import ArrowSchema, Paged, PagedRequest, PagedResponse, ProjectId, ServiceBase
10
6
 
@@ -21,10 +17,11 @@ TableName = Annotated[str, StringConstraints(max_length=128, pattern=r"^[a-zA-Z_
21
17
 
22
18
 
23
19
  class TableMetadata(BaseModel):
24
- key_schema: ArrowSchema
25
20
  root_uri: RootUri
26
21
  spfs_mount_id: str | None = None
27
22
 
23
+ key_schema: ArrowSchema
24
+
28
25
  # TODO(marko): Randomize this on creation of metadata.
29
26
  # Column group salt is used to compute column group IDs.
30
27
  # It's used to ensure that column group IDs are unique
spiral/catalog.py CHANGED
@@ -7,6 +7,8 @@ from spiral.api.projects import CreateProject
7
7
  from spiral.settings import Settings, settings
8
8
 
9
9
  if TYPE_CHECKING:
10
+ from pyiceberg import catalog
11
+
10
12
  from spiral.project import Project
11
13
  from spiral.table import Table
12
14
 
@@ -76,3 +78,16 @@ class Spiral:
76
78
  project_id, dataset, table = parts
77
79
 
78
80
  return self.project(project_id).table(f"{dataset}.{table}")
81
+
82
+ def iceberg_catalog(self) -> "catalog.Catalog":
83
+ """Open the Iceberg catalog."""
84
+ from pyiceberg.catalog import load_catalog
85
+
86
+ return load_catalog(
87
+ "default",
88
+ **{
89
+ "type": "rest",
90
+ "uri": self._config.spiraldb.uri_iceberg,
91
+ "token": self._config.authn.token(),
92
+ },
93
+ )
spiral/cli/fs.py CHANGED
@@ -23,7 +23,7 @@ def show(project: ProjectArg):
23
23
 
24
24
  def _provider_default():
25
25
  res = state.settings.api.file_system.list_providers()
26
- questionary.select("Select a file system provider", choices=res.providers).ask()
26
+ return questionary.select("Select a file system provider", choices=res.providers).ask()
27
27
 
28
28
 
29
29
  ProviderOpt = Annotated[
@@ -37,7 +37,7 @@ def update(project: ProjectArg, provider: ProviderOpt):
37
37
  res = state.settings.api.file_system.update_file_system(
38
38
  UpdateFileSystem.Request(project_id=project, file_system=BuiltinFileSystem(provider=provider))
39
39
  )
40
- rich.print(res.file_system.builtin)
40
+ rich.print(res.file_system)
41
41
 
42
42
 
43
43
  @app.command(help="Lists the available built-in file system providers.")
spiral/cli/project.py CHANGED
@@ -55,11 +55,13 @@ def grant(
55
55
  OptionalStr,
56
56
  Option(help="Pass a `<workspace_id>/<env_name>` string to grant a role to a job running in Modal environment."),
57
57
  ] = None,
58
- conditions: list[str] = Option(
59
- default_factory=list,
58
+ conditions: list[str] | None = Option(
59
+ default=None,
60
60
  help="`<key>=<value>` token conditions to apply to the grant when using --github or --modal.",
61
61
  ),
62
62
  ):
63
+ conditions = conditions or []
64
+
63
65
  # Check mutual exclusion
64
66
  if sum(int(bool(opt)) for opt in {org_id, workload_id, github, modal}) != 1:
65
67
  raise typer.BadParameter("Only one of --org-id, --github or --modal may be specified.")
@@ -81,7 +83,7 @@ def grant(
81
83
 
82
84
  if user_id is not None:
83
85
  principal = GrantRole.OrgUserPrincipal(org_id=org_id, user_id=user_id)
84
- elif org_role is None:
86
+ elif org_role is not None:
85
87
  principal = GrantRole.OrgRolePrincipal(org_id=org_id, role=OrganizationRole(org_role))
86
88
  else:
87
89
  raise NotImplementedError("Only user or role principal is supported at this time.")
@@ -1,9 +1,9 @@
1
- from typing import Any
1
+ from typing import Any, Literal
2
2
 
3
3
  import pyarrow as pa
4
4
  from spiral.core.manifests import FragmentManifest
5
5
  from spiral.core.metastore import PyMetastore
6
- from spiral.core.spec import ColumnGroup, ColumnGroupMetadata, KeyRange, Schema, WriteAheadLog
6
+ from spiral.core.spec import ColumnGroup, ColumnGroupMetadata, FileFormat, KeyRange, Schema, WriteAheadLog
7
7
  from spiral.expressions import Expr
8
8
 
9
9
  class Table:
@@ -15,9 +15,9 @@ class Table:
15
15
  metastore: PyMetastore
16
16
 
17
17
  def get_wal(self, *, asof: int | None) -> WriteAheadLog: ...
18
+ def get_schema(self, *, asof: int | None) -> Schema: ...
18
19
  def get_column_group_metadata(self, column_group: ColumnGroup, *, asof: int | None) -> ColumnGroupMetadata: ...
19
20
  def list_column_groups(self, *, asof: int | None) -> list[ColumnGroup] | None: ...
20
- def get_schema(self, *, asof: int | None) -> Schema: ...
21
21
 
22
22
  class TableScan:
23
23
  def __init__(
@@ -34,7 +34,11 @@ class TableScan:
34
34
  def split(self) -> list[KeyRange]: ...
35
35
  def table_ids(self) -> list[str]: ...
36
36
  def column_groups(self) -> list[ColumnGroup]: ...
37
- def to_record_batches(self, aux_table: pa.Table | pa.RecordBatch | None = None) -> pa.RecordBatchReader: ...
37
+ def to_record_batches(
38
+ self,
39
+ key_table: pa.Table | pa.RecordBatch | None = None,
40
+ batch_readahead: int | None = None,
41
+ ) -> pa.RecordBatchReader: ...
38
42
  def column_group_scan(self, column_group: ColumnGroup) -> ColumnGroupScan: ...
39
43
  def key_space_scan(self, table_id: str) -> KeySpaceScan: ...
40
44
  def metrics(self) -> dict[str, Any]: ...
@@ -49,5 +53,29 @@ class ColumnGroupScan:
49
53
 
50
54
  def schema(self) -> Schema: ...
51
55
 
52
- def write(table: Table, expr: Expr, format: str = "parquet", *, partition_size: int | None = None): ...
53
- def flush_wal(table: Table, manifest_format: str = "parquet"): ...
56
+ class TableTransaction:
57
+ def __init__(self, metastore: PyMetastore, format: FileFormat): ...
58
+ @property
59
+ def status(self) -> str: ...
60
+ def write(self, expr: Expr, *, partition_size_bytes: int | None = None): ...
61
+ def commit(self): ...
62
+ def abort(self): ...
63
+ def metrics(self) -> dict[str, Any]: ...
64
+
65
+ class TableMaintenance:
66
+ def __init__(self, metastore: PyMetastore, format: FileFormat): ...
67
+ def flush_wal(self): ...
68
+ def compact_key_space(
69
+ self,
70
+ *,
71
+ mode: Literal["plan", "read", "write"] | None = None,
72
+ partition_bytes_min: int | None = None,
73
+ ): ...
74
+ def compact_column_group(
75
+ self,
76
+ column_group: ColumnGroup,
77
+ *,
78
+ mode: Literal["plan", "read", "write"] | None = None,
79
+ partition_bytes_min: int | None = None,
80
+ ): ...
81
+ def metrics(self) -> dict[str, Any]: ...
@@ -59,37 +59,13 @@ class LogEntry:
59
59
  def column_group(self) -> ColumnGroup | None:
60
60
  """Returns the column group of the entry if it is associated with one."""
61
61
 
62
- def replace_timestamp(self, ts: int) -> LogEntry:
63
- """Returns a copy of the entry with the timestamp replaced."""
64
-
65
- @staticmethod
66
- def schema_break(*, column_group: ColumnGroup, removed_column_names: list[str]) -> LogEntry: ...
67
- @staticmethod
68
- def schema_evolution(*, column_group: ColumnGroup, new_schema: Schema) -> LogEntry: ...
69
- @staticmethod
70
- def ks_write(
71
- *,
72
- ks_id: str,
73
- manifest_handle: ManifestHandle,
74
- ) -> LogEntry: ...
75
- @staticmethod
76
- def fs_write(
77
- *,
78
- column_group: ColumnGroup,
79
- fs_id: str,
80
- fs_level: FragmentLevel,
81
- manifest_handle: ManifestHandle,
82
- key_span: KeySpan,
83
- key_extent: KeyExtent,
84
- column_ids: list[str],
85
- ) -> LogEntry: ...
86
-
87
62
  class FileFormat:
88
63
  def __init__(self, value: int): ...
89
64
 
90
65
  Parquet: FileFormat
91
66
  Protobuf: FileFormat
92
67
  BinaryArray: FileFormat
68
+ Vortex: FileFormat
93
69
 
94
70
  def __int__(self) -> int:
95
71
  """Returns the protobuf enum int value."""
@@ -194,11 +170,17 @@ class Schema:
194
170
  def to_arrow(self) -> pa.Schema:
195
171
  """Returns the Arrow schema."""
196
172
  ...
197
-
198
173
  @staticmethod
199
174
  def from_arrow(arrow: pa.Schema) -> Schema:
200
175
  """Creates a Schema from an Arrow schema."""
201
176
  ...
177
+ def __len__(self):
178
+ """Returns the number of columns in the schema."""
179
+ ...
180
+ @property
181
+ def names(self) -> list[str]:
182
+ """Returns the names of the columns in the schema."""
183
+ ...
202
184
 
203
185
  class VersionedSchema:
204
186
  ts: int