pyspiral 0.7.5__cp312-abi3-macosx_11_0_arm64.whl → 0.7.7__cp312-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.

Potentially problematic release.


This version of pyspiral might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyspiral
3
- Version: 0.7.5
3
+ Version: 0.7.7
4
4
  Classifier: Intended Audience :: Science/Research
5
5
  Classifier: Operating System :: OS Independent
6
6
  Classifier: Programming Language :: Python
@@ -1,8 +1,8 @@
1
- pyspiral-0.7.5.dist-info/METADATA,sha256=ZZogea6_l7fIAEwj7iTpS9DEPJbjqHJnIK2QK3eOKBU,1874
2
- pyspiral-0.7.5.dist-info/WHEEL,sha256=KQvxBiy7GLcML6Ad3w_ZPrgSvER1uXd7aYb6wy6b44Y,103
3
- pyspiral-0.7.5.dist-info/entry_points.txt,sha256=R96Y3FpYX6XbQu9qMPfUTgiCcf4qM9OBQQZTDdBkZwA,74
1
+ pyspiral-0.7.7.dist-info/METADATA,sha256=5KbbTylag9ZfdffltxdGDcIK2fdzoMZHkQ3ASWi0ZRM,1874
2
+ pyspiral-0.7.7.dist-info/WHEEL,sha256=KQvxBiy7GLcML6Ad3w_ZPrgSvER1uXd7aYb6wy6b44Y,103
3
+ pyspiral-0.7.7.dist-info/entry_points.txt,sha256=R96Y3FpYX6XbQu9qMPfUTgiCcf4qM9OBQQZTDdBkZwA,74
4
4
  spiral/__init__.py,sha256=PwaYBWFBtB7cYi7peMmhk_Lm5XzjRoLwOtLbUhc1ZDo,1449
5
- spiral/_lib.abi3.so,sha256=h4T4kk4RigVd7Kq7F3Hmmf0XRvR3vx8_zC-KPaM0f_k,70522352
5
+ spiral/_lib.abi3.so,sha256=z8I6F_sOir9CkSTRIGhIV6Ww0vFmfmAn711ANoqM-X4,70897712
6
6
  spiral/adbc.py,sha256=7IxfWIeQN-fh0W5OdN_PP2x3pzQYg6ZUOLsHg3jktqw,14842
7
7
  spiral/api/__init__.py,sha256=ULBlVq3PnfNOO6T5naE_ULmmii-83--qTuN2PpAUQN0,2241
8
8
  spiral/api/admin.py,sha256=A1iVR1XYJSObZivPAD5UzmPuMgupXc9kaHNYYa_kwfs,585
@@ -30,7 +30,7 @@ spiral/cli/orgs.py,sha256=fmOuLxpeIFfKqePRi292Gv9k-EF5pPn_tbKd2BLl2Ig,2869
30
30
  spiral/cli/printer.py,sha256=aosc763hDFgoXJGkiANmNyO3kAsecAS1JWgjEhn8GCM,1784
31
31
  spiral/cli/projects.py,sha256=1M1nGrBT-t0aY9RV5Cnmzy7YrhIvmHwdkpa3y9j8rG8,5756
32
32
  spiral/cli/state.py,sha256=10wTIVQ0SJkY67Z6-KQ1LFlt3aVIPmZhoHFdTwp4kNA,130
33
- spiral/cli/tables.py,sha256=qm3izcysElJrQlerNZdfx5RWSVXtyVfkP3o_H51ltFw,6366
33
+ spiral/cli/tables.py,sha256=gp7v8K-6EUTa0P7ZcHXD9gYPPpp4nHABloo_elvUrBw,7757
34
34
  spiral/cli/telemetry.py,sha256=Uxo1Q1FkKJ6n6QNGOUmL3j_pRRWRx0qWIhoP-U9BuR0,589
35
35
  spiral/cli/text.py,sha256=DlWGe4JrkdERAiqyITNpk91Wqb63Re99rNYlIFsIamc,4031
36
36
  spiral/cli/types.py,sha256=XYzo1GgX7dBBItoBSrHI4vO5C2lLmS2sktb-2GnGH3E,1362
@@ -39,7 +39,7 @@ spiral/client.py,sha256=53dVv8wxYMmozUfR8MVcUufKGqdVIdb0yZ0gchczBoQ,6426
39
39
  spiral/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  spiral/core/_tools/__init__.pyi,sha256=b2KLfTOQ67pjfbYt07o0IGiTu5o2bZw69lllV8v0Dps,143
41
41
  spiral/core/authn/__init__.pyi,sha256=z_GWyIS62fuiYQrYO8hzw4W8oGaiciqS1u5qtAt54VY,769
42
- spiral/core/client/__init__.pyi,sha256=ZoeCQnEauDbaR0X7aMfHBJtLnoc7ib4JXvsmst6cAUM,6993
42
+ spiral/core/client/__init__.pyi,sha256=MmuIzluwaxAFFamr_J8iT15qP8AkA4smkz4zrF-yGnM,6993
43
43
  spiral/core/expr/__init__.pyi,sha256=3HSKjkotiEkxBvGBALXEBIie0JiyI9bCpehwA3nMQkU,571
44
44
  spiral/core/expr/images/__init__.pyi,sha256=wnE_wZXq7a4iqTg3SVm-ssxGw1WQZyk5dGOPaP4Btko,73
45
45
  spiral/core/expr/list_/__init__.pyi,sha256=Q_9c87eIQfZbqlaw_rq3fvs93YEsW7K5VYk6VZ4g6mU,126
@@ -49,7 +49,7 @@ spiral/core/expr/struct_/__init__.pyi,sha256=MXckd98eV_x3X0RhEWvlkA3DcDXRtLs5pNn
49
49
  spiral/core/expr/text/__init__.pyi,sha256=ed83n1xcsGY7_QDhMmJGnSQ20UrJFXcdv1AveSEcS1c,175
50
50
  spiral/core/expr/udf/__init__.pyi,sha256=zsZs081KVhY3-1JidqTkWMW81Qd_ScoTGZvasIhIK-4,358
51
51
  spiral/core/expr/video/__init__.pyi,sha256=nQJEcSsigZuRpMjkI_O4EEtMK_n2zRvorcL_KEeD5vU,95
52
- spiral/core/table/__init__.pyi,sha256=szCtZqZ_L0vF_99x7d3olwazJdEn5LwkgRK-8QEOzrI,3914
52
+ spiral/core/table/__init__.pyi,sha256=zcf4GripPZtiwh6uHkPgVyDij1g2nYL1DogN83z5ISU,4037
53
53
  spiral/core/table/manifests/__init__.pyi,sha256=eVfDpmhYSjafIvvALqAkZe5baN3Y1HpKpxYEbjwd4gQ,1043
54
54
  spiral/core/table/metastore/__init__.pyi,sha256=rc3u9MwEKRvL2kxOc8lBorddFRnM8o_o1frqtae86a4,1697
55
55
  spiral/core/table/spec/__init__.pyi,sha256=fVuc2j3uoTdWfYNm720OfUIgrLYw9fRwj44maI5bgdY,5709
@@ -60,7 +60,7 @@ spiral/debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  spiral/debug/manifests.py,sha256=7f1O3ba9mrA5nXpOF9cEIQuUAteP5wiBkFy_diQJ7No,3216
61
61
  spiral/debug/metrics.py,sha256=XdRDcjggtsLNGCAjam6IxG9072pz_d2C8iLApNRFUtk,2044
62
62
  spiral/debug/scan.py,sha256=UEm_aRnql5pwDPTpZgakMLNjlzkKL4RurBFFqH_BLAQ,9526
63
- spiral/enrichment.py,sha256=iKZn4tLsRQZPtaY-WdJSqPZ3H5UMfVyavcwTKO_3aCw,6980
63
+ spiral/enrichment.py,sha256=w0MrZ93wDuvS4sazw_8dPmnhzkQ4SAU5A1CGE7WF-F8,7046
64
64
  spiral/expressions/__init__.py,sha256=ZsD8g7vB0G7xy19GUiH4m79kw7KEkTQRwJl5Gn1cgtw,8049
65
65
  spiral/expressions/base.py,sha256=PvhJkcUSsPSIaxirHVzM9zlqyBXiaiia1HXohXdOmL4,5377
66
66
  spiral/expressions/file.py,sha256=7D9jIENJcoT0KFharBLkzK9dZgO4DYn5K_KCt0twefg,518
@@ -94,7 +94,7 @@ spiral/protogen/_/substrait/extensions/__init__.py,sha256=nhnEnho70GAT8WPj2xtwJU
94
94
  spiral/protogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
95
  spiral/protogen/util.py,sha256=smnvVo6nYH3FfDm9jqhNLaXz4bbTBaQezHQDCTvZyiQ,1486
96
96
  spiral/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
- spiral/scan.py,sha256=0ZgzPX5gZ3uvbCyifpjHKXYk_ERphf9xHbrOVKRNkXc,12574
97
+ spiral/scan.py,sha256=8IFuhqxzVGdXPW8uWWTFKiC38mTLpwkBZvK1YHqtbHM,12574
98
98
  spiral/server.py,sha256=ztBmB5lBnUz-smQxR_tC8AI5SOhz17wH0MI3GuzDUdM,600
99
99
  spiral/settings.py,sha256=sUhMMBCXaPvUYztN_gztD9TjeUYJwVeEcJrq4FLy6M0,3232
100
100
  spiral/snapshot.py,sha256=cTobi5jtiANxalGA-isokQHblNmXGtuUvgUGGNVybsI,1555
@@ -102,8 +102,8 @@ spiral/streaming_/__init__.py,sha256=s7MlW2ERsuZmZGExLFL6RcZon2e0tNBocBg5ANgki7k
102
102
  spiral/streaming_/reader.py,sha256=tl_lC9xgh1-QFhsZn4xQT7It3PVTzHCEUT2BG2dWBRQ,4166
103
103
  spiral/streaming_/stream.py,sha256=DM1hBDHnWm1ZFKZ-hZ4zxeSXITcUI6kWzwdJZvywI8o,5915
104
104
  spiral/substrait_.py,sha256=AKeOD4KIXvz2J4TYxnIneOiHddtBIyOhuNxVO_uH0eg,12592
105
- spiral/table.py,sha256=ep8ZYtl6POebkPViR2FrekhFazNmAbOAESoLUODlup8,12242
105
+ spiral/table.py,sha256=p95AYv6b7e14F3t7j-B-r45k9CtG84ngikdlAhh9WxA,12260
106
106
  spiral/text_index.py,sha256=FQ9rgIEGLSJryS9lFdMhKtPFey18BXoWbPXyvZPJJ04,442
107
- spiral/transaction.py,sha256=KQhx3DvQyxG2C8md-YGsF_PgBRfayI0r_7ebMItDHdI,3938
107
+ spiral/transaction.py,sha256=bI5oqBAmPMSF0yOOYcPfGbV37Xc1-_V-wQNKw1xOlTA,4136
108
108
  spiral/types_.py,sha256=W_jyO7F6rpPiH69jhgSgV7OxQZbOlb1Ho3InpKUP6Eo,155
109
- pyspiral-0.7.5.dist-info/RECORD,,
109
+ pyspiral-0.7.7.dist-info/RECORD,,
spiral/_lib.abi3.so CHANGED
Binary file
spiral/cli/tables.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ from collections.abc import Callable
2
3
  from typing import Annotated, Literal
3
4
 
4
5
  import questionary
@@ -60,6 +61,45 @@ def ls(
60
61
  CONSOLE.print(rich_table)
61
62
 
62
63
 
64
+ def validate_non_empty_str(text: str) -> bool | str:
65
+ if len(text) > 0:
66
+ return True
67
+
68
+ return "Must provide at least one character."
69
+
70
+
71
+ def get_string(message: str, validate: Callable[[str], bool | str] = validate_non_empty_str) -> str:
72
+ return questionary.text(message, validate=validate).ask()
73
+
74
+
75
+ @app.command(help="Move table to a different dataset.")
76
+ def move(
77
+ project: ProjectArg,
78
+ table: Annotated[str | None, Option(help="Table name.")] = None,
79
+ dataset: Annotated[str | None, Option(help="Dataset name.")] = None,
80
+ new_dataset: Annotated[str | None, Option(help="New dataset name.")] = None,
81
+ ):
82
+ identifier, _ = get_table(project, table, dataset)
83
+ new_dataset = get_string("Provide a new dataset name")
84
+
85
+ state.spiral.project(project).move_table(identifier, new_dataset)
86
+ CONSOLE.print("Success.")
87
+
88
+
89
+ @app.command(help="Rename table.")
90
+ def rename(
91
+ project: ProjectArg,
92
+ table: Annotated[str | None, Option(help="Table name.")] = None,
93
+ dataset: Annotated[str | None, Option(help="Dataset name.")] = None,
94
+ new_table: Annotated[str | None, Option(help="New table name.")] = None,
95
+ ):
96
+ identifier, _ = get_table(project, table, dataset)
97
+ new_table = get_string("Provide a new table name")
98
+
99
+ state.spiral.project(project).rename_table(identifier, new_table)
100
+ CONSOLE.print("Success.")
101
+
102
+
63
103
  @app.command(help="Show the table key schema.")
64
104
  def key_schema(
65
105
  project: ProjectArg,
@@ -30,7 +30,7 @@ class Spiral:
30
30
  """Construct a table scan."""
31
31
  ...
32
32
 
33
- def load_scan(self, scan_state: ScanState) -> Scan:
33
+ def load_scan(self, plan_state: ScanState) -> Scan:
34
34
  """Load a scan from a serialized scan state."""
35
35
  ...
36
36
 
@@ -57,6 +57,9 @@ class ScanState:
57
57
  @staticmethod
58
58
  def from_json(json: str) -> ScanState: ...
59
59
 
60
+ class MaterializablePlan:
61
+ pass
62
+
60
63
  class Scan:
61
64
  def key_schema(self) -> Schema: ...
62
65
  def schema(self) -> Schema: ...
@@ -67,7 +70,8 @@ class Scan:
67
70
  def column_groups(self) -> list[ColumnGroup]: ...
68
71
  def column_group_state(self, column_group: ColumnGroup) -> ColumnGroupState: ...
69
72
  def key_space_state(self, table_id: str) -> KeySpaceState: ...
70
- def scan_state(self) -> ScanState: ...
73
+ def plan_state(self) -> ScanState: ...
74
+ def materializable_plan(self) -> MaterializablePlan: ...
71
75
  def to_record_batches(
72
76
  self,
73
77
  key_range: KeyRange | None = None,
@@ -115,7 +119,7 @@ class Transaction:
115
119
  def ops(self) -> list[Operation]: ...
116
120
  def take(self) -> list[Operation]: ...
117
121
  def include(self, ops: list[Operation]): ...
118
- def commit(self): ...
122
+ def commit(self, *, compact: bool = False): ...
119
123
  def abort(self): ...
120
124
  def is_empty(self) -> bool: ...
121
125
  def metrics(self) -> dict[str, Any]: ...
spiral/enrichment.py CHANGED
@@ -136,7 +136,7 @@ class Enrichment:
136
136
  _compute = partial(
137
137
  _enrichment_task,
138
138
  settings_dict=self._table.spiral.config.model_dump(),
139
- state_json=plan_scan.core.scan_state().to_json(),
139
+ state_json=plan_scan.core.plan_state().to_json(),
140
140
  output_table_id=self._table.table_id,
141
141
  partition_size_bytes=partition_size_bytes,
142
142
  )
@@ -151,7 +151,8 @@ class Enrichment:
151
151
  logger.warning("Transaction not committed. No rows were read for enrichment.")
152
152
  return
153
153
 
154
- tx.commit(tx_dump=tx_dump)
154
+ # Always compact in distributed enrichment.
155
+ tx.commit(compact=True, tx_dump=tx_dump)
155
156
 
156
157
 
157
158
  @dataclasses.dataclass
spiral/scan.py CHANGED
@@ -125,7 +125,7 @@ class Scan:
125
125
  _read_shard = partial(
126
126
  _read_shard_task,
127
127
  settings_dict=self.spiral.config.model_dump(),
128
- state_json=self.core.scan_state().to_json(),
128
+ state_json=self.core.plan_state().to_json(),
129
129
  )
130
130
  return dd.from_map(_read_shard, self.shards())
131
131
 
spiral/table.py CHANGED
@@ -83,7 +83,7 @@ class Table(Expr):
83
83
  def __repr__(self):
84
84
  return f'Table("{self.identifier}")'
85
85
 
86
- def __getitem__(self, item: str) -> Expr:
86
+ def __getitem__(self, item: str | int | list[str]) -> Expr:
87
87
  return super().__getitem__(item)
88
88
 
89
89
  def select(self, *paths: str, exclude: list[str] = None) -> "Expr":
spiral/transaction.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from pathlib import Path
2
3
 
3
4
  from spiral.core.table import KeyRange
4
5
  from spiral.core.table import Transaction as CoreTransaction
@@ -95,18 +96,23 @@ class Transaction:
95
96
  """
96
97
  self._core.include(ops)
97
98
 
98
- def commit(self, *, tx_dump: str | None = None):
99
+ def commit(self, *, compact: bool = False, tx_dump: str | None = None):
99
100
  """Commit the transaction."""
100
- # TODO(marko): We can remove this when I have more trust in large tx commits.
101
101
  if tx_dump is not None:
102
102
  try:
103
- with open(tx_dump, "w") as f:
103
+ # Create parent directories if they don't exist
104
+ dump_path = Path(tx_dump)
105
+ dump_path.parent.mkdir(parents=True, exist_ok=True)
106
+
107
+ # Write operations to file
108
+ with open(dump_path, "w") as f:
104
109
  f.writelines([op.to_json() for op in self._core.ops()])
110
+
105
111
  logger.info(f"Transaction dumped to {tx_dump}")
106
112
  except Exception as e:
107
113
  logger.error(f"Failed to dump transaction to {tx_dump}: {e}")
108
114
 
109
- self._core.commit()
115
+ self._core.commit(compact=compact)
110
116
 
111
117
  def abort(self):
112
118
  """Abort the transaction."""