pixeltable 0.4.2__py3-none-any.whl → 0.4.4__py3-none-any.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 pixeltable might be problematic. Click here for more details.
- pixeltable/__init__.py +1 -0
- pixeltable/__version__.py +2 -2
- pixeltable/catalog/__init__.py +3 -11
- pixeltable/catalog/catalog.py +575 -220
- pixeltable/catalog/column.py +22 -23
- pixeltable/catalog/dir.py +1 -2
- pixeltable/catalog/globals.py +2 -148
- pixeltable/catalog/insertable_table.py +15 -13
- pixeltable/catalog/path.py +6 -0
- pixeltable/catalog/schema_object.py +9 -4
- pixeltable/catalog/table.py +96 -85
- pixeltable/catalog/table_version.py +257 -174
- pixeltable/catalog/table_version_path.py +1 -1
- pixeltable/catalog/tbl_ops.py +44 -0
- pixeltable/catalog/update_status.py +179 -0
- pixeltable/catalog/view.py +50 -56
- pixeltable/config.py +76 -12
- pixeltable/dataframe.py +19 -6
- pixeltable/env.py +50 -4
- pixeltable/exec/data_row_batch.py +3 -1
- pixeltable/exec/exec_node.py +7 -24
- pixeltable/exec/expr_eval/schedulers.py +134 -7
- pixeltable/exec/in_memory_data_node.py +6 -7
- pixeltable/exprs/column_property_ref.py +21 -9
- pixeltable/exprs/column_ref.py +7 -2
- pixeltable/exprs/function_call.py +2 -2
- pixeltable/exprs/row_builder.py +10 -9
- pixeltable/exprs/rowid_ref.py +0 -4
- pixeltable/func/function.py +3 -3
- pixeltable/functions/audio.py +36 -9
- pixeltable/functions/gemini.py +4 -4
- pixeltable/functions/openai.py +1 -2
- pixeltable/functions/video.py +59 -16
- pixeltable/globals.py +109 -24
- pixeltable/io/__init__.py +1 -1
- pixeltable/io/datarows.py +2 -1
- pixeltable/io/external_store.py +3 -55
- pixeltable/io/globals.py +4 -4
- pixeltable/io/hf_datasets.py +10 -2
- pixeltable/io/label_studio.py +16 -16
- pixeltable/io/pandas.py +1 -0
- pixeltable/io/table_data_conduit.py +12 -13
- pixeltable/iterators/audio.py +17 -8
- pixeltable/iterators/image.py +5 -2
- pixeltable/metadata/__init__.py +1 -1
- pixeltable/metadata/converters/convert_39.py +125 -0
- pixeltable/metadata/converters/util.py +3 -0
- pixeltable/metadata/notes.py +1 -0
- pixeltable/metadata/schema.py +50 -1
- pixeltable/plan.py +4 -0
- pixeltable/share/packager.py +20 -38
- pixeltable/store.py +40 -51
- pixeltable/type_system.py +2 -2
- pixeltable/utils/coroutine.py +6 -23
- pixeltable/utils/media_store.py +50 -0
- {pixeltable-0.4.2.dist-info → pixeltable-0.4.4.dist-info}/METADATA +1 -1
- {pixeltable-0.4.2.dist-info → pixeltable-0.4.4.dist-info}/RECORD +60 -57
- {pixeltable-0.4.2.dist-info → pixeltable-0.4.4.dist-info}/LICENSE +0 -0
- {pixeltable-0.4.2.dist-info → pixeltable-0.4.4.dist-info}/WHEEL +0 -0
- {pixeltable-0.4.2.dist-info → pixeltable-0.4.4.dist-info}/entry_points.txt +0 -0
pixeltable/catalog/table.py
CHANGED
|
@@ -6,7 +6,7 @@ import json
|
|
|
6
6
|
import logging
|
|
7
7
|
from keyword import iskeyword as is_python_keyword
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING, Any, Iterable, Literal, Optional, Union, overload
|
|
9
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Literal, Optional, Union, overload
|
|
10
10
|
|
|
11
11
|
from typing import _GenericAlias # type: ignore[attr-defined] # isort: skip
|
|
12
12
|
import datetime
|
|
@@ -29,13 +29,13 @@ from .globals import (
|
|
|
29
29
|
IfExistsParam,
|
|
30
30
|
IfNotExistsParam,
|
|
31
31
|
MediaValidation,
|
|
32
|
-
UpdateStatus,
|
|
33
32
|
is_system_column_name,
|
|
34
33
|
is_valid_identifier,
|
|
35
34
|
)
|
|
36
35
|
from .schema_object import SchemaObject
|
|
37
36
|
from .table_version_handle import TableVersionHandle
|
|
38
37
|
from .table_version_path import TableVersionPath
|
|
38
|
+
from .update_status import UpdateStatus
|
|
39
39
|
|
|
40
40
|
if TYPE_CHECKING:
|
|
41
41
|
import torch.utils.data
|
|
@@ -109,8 +109,6 @@ class Table(SchemaObject):
|
|
|
109
109
|
|
|
110
110
|
def _get_metadata(self) -> dict[str, Any]:
|
|
111
111
|
md = super()._get_metadata()
|
|
112
|
-
base = self._get_base_table()
|
|
113
|
-
md['base'] = base._path() if base is not None else None
|
|
114
112
|
md['schema'] = self._get_schema()
|
|
115
113
|
md['is_replica'] = self._tbl_version_path.is_replica()
|
|
116
114
|
md['version'] = self._get_version()
|
|
@@ -149,11 +147,15 @@ class Table(SchemaObject):
|
|
|
149
147
|
Returns:
|
|
150
148
|
A list of view paths.
|
|
151
149
|
"""
|
|
152
|
-
from pixeltable.catalog import
|
|
150
|
+
from pixeltable.catalog import retry_loop
|
|
153
151
|
|
|
154
|
-
|
|
152
|
+
# we need retry_loop() here, because we end up loading Tables for the views
|
|
153
|
+
@retry_loop(tbl=self._tbl_version_path, for_write=False)
|
|
154
|
+
def op() -> list[str]:
|
|
155
155
|
return [t._path() for t in self._get_views(recursive=recursive)]
|
|
156
156
|
|
|
157
|
+
return op()
|
|
158
|
+
|
|
157
159
|
def _get_views(self, *, recursive: bool = True, include_snapshots: bool = True) -> list['Table']:
|
|
158
160
|
cat = catalog.Catalog.get()
|
|
159
161
|
view_ids = cat.get_view_ids(self._id)
|
|
@@ -180,7 +182,7 @@ class Table(SchemaObject):
|
|
|
180
182
|
"""
|
|
181
183
|
from pixeltable.catalog import Catalog
|
|
182
184
|
|
|
183
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
185
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
184
186
|
return self._df().select(*items, **named_items)
|
|
185
187
|
|
|
186
188
|
def where(self, pred: 'exprs.Expr') -> 'pxt.DataFrame':
|
|
@@ -190,7 +192,7 @@ class Table(SchemaObject):
|
|
|
190
192
|
"""
|
|
191
193
|
from pixeltable.catalog import Catalog
|
|
192
194
|
|
|
193
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
195
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
194
196
|
return self._df().where(pred)
|
|
195
197
|
|
|
196
198
|
def join(
|
|
@@ -203,7 +205,7 @@ class Table(SchemaObject):
|
|
|
203
205
|
"""Join this table with another table."""
|
|
204
206
|
from pixeltable.catalog import Catalog
|
|
205
207
|
|
|
206
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
208
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
207
209
|
return self._df().join(other, on=on, how=how)
|
|
208
210
|
|
|
209
211
|
def order_by(self, *items: 'exprs.Expr', asc: bool = True) -> 'pxt.DataFrame':
|
|
@@ -213,7 +215,7 @@ class Table(SchemaObject):
|
|
|
213
215
|
"""
|
|
214
216
|
from pixeltable.catalog import Catalog
|
|
215
217
|
|
|
216
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
218
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
217
219
|
return self._df().order_by(*items, asc=asc)
|
|
218
220
|
|
|
219
221
|
def group_by(self, *items: 'exprs.Expr') -> 'pxt.DataFrame':
|
|
@@ -223,7 +225,7 @@ class Table(SchemaObject):
|
|
|
223
225
|
"""
|
|
224
226
|
from pixeltable.catalog import Catalog
|
|
225
227
|
|
|
226
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
228
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
227
229
|
return self._df().group_by(*items)
|
|
228
230
|
|
|
229
231
|
def distinct(self) -> 'pxt.DataFrame':
|
|
@@ -279,10 +281,7 @@ class Table(SchemaObject):
|
|
|
279
281
|
return {c.name: c.col_type for c in self._tbl_version_path.columns()}
|
|
280
282
|
|
|
281
283
|
def get_base_table(self) -> Optional['Table']:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
285
|
-
return self._get_base_table()
|
|
284
|
+
return self._get_base_table()
|
|
286
285
|
|
|
287
286
|
@abc.abstractmethod
|
|
288
287
|
def _get_base_table(self) -> Optional['Table']:
|
|
@@ -323,7 +322,7 @@ class Table(SchemaObject):
|
|
|
323
322
|
"""
|
|
324
323
|
from pixeltable.catalog import Catalog
|
|
325
324
|
|
|
326
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
325
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=False):
|
|
327
326
|
helper = DescriptionHelper()
|
|
328
327
|
helper.append(self._table_descriptor())
|
|
329
328
|
helper.append(self._col_descriptor())
|
|
@@ -494,8 +493,7 @@ class Table(SchemaObject):
|
|
|
494
493
|
|
|
495
494
|
# lock_mutable_tree=True: we might end up having to drop existing columns, which requires locking the tree
|
|
496
495
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
497
|
-
|
|
498
|
-
raise excs.Error('Cannot add column to a snapshot.')
|
|
496
|
+
self.__check_mutable('add columns to')
|
|
499
497
|
col_schema = {
|
|
500
498
|
col_name: {'type': ts.ColumnType.normalize_type(spec, nullable_default=True, allow_builtin_types=False)}
|
|
501
499
|
for col_name, spec in schema.items()
|
|
@@ -510,15 +508,16 @@ class Table(SchemaObject):
|
|
|
510
508
|
for cname in cols_to_ignore:
|
|
511
509
|
assert cname in col_schema
|
|
512
510
|
del col_schema[cname]
|
|
511
|
+
result = UpdateStatus()
|
|
513
512
|
if len(col_schema) == 0:
|
|
514
|
-
return
|
|
513
|
+
return result
|
|
515
514
|
new_cols = self._create_columns(col_schema)
|
|
516
515
|
for new_col in new_cols:
|
|
517
516
|
self._verify_column(new_col)
|
|
518
517
|
assert self._tbl_version is not None
|
|
519
|
-
|
|
518
|
+
result += self._tbl_version.get().add_columns(new_cols, print_stats=False, on_error='abort')
|
|
520
519
|
FileCache.get().emit_eviction_warnings()
|
|
521
|
-
return
|
|
520
|
+
return result
|
|
522
521
|
|
|
523
522
|
def add_column(
|
|
524
523
|
self,
|
|
@@ -554,24 +553,18 @@ class Table(SchemaObject):
|
|
|
554
553
|
|
|
555
554
|
>>> tbl.add_columns({'new_col': pxt.Int})
|
|
556
555
|
"""
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
col_type = next(iter(kwargs.values()))
|
|
570
|
-
if not isinstance(col_type, (ts.ColumnType, type, _GenericAlias)):
|
|
571
|
-
raise excs.Error(
|
|
572
|
-
'The argument to add_column() must be a type; did you intend to use add_computed_column() instead?'
|
|
573
|
-
)
|
|
574
|
-
return self.add_columns(kwargs, if_exists=if_exists)
|
|
556
|
+
# verify kwargs and construct column schema dict
|
|
557
|
+
if len(kwargs) != 1:
|
|
558
|
+
raise excs.Error(
|
|
559
|
+
f'add_column() requires exactly one keyword argument of the form "col_name=col_type"; '
|
|
560
|
+
f'got {len(kwargs)} instead ({", ".join(kwargs.keys())})'
|
|
561
|
+
)
|
|
562
|
+
col_type = next(iter(kwargs.values()))
|
|
563
|
+
if not isinstance(col_type, (ts.ColumnType, type, _GenericAlias)):
|
|
564
|
+
raise excs.Error(
|
|
565
|
+
'The argument to add_column() must be a type; did you intend to use add_computed_column() instead?'
|
|
566
|
+
)
|
|
567
|
+
return self.add_columns(kwargs, if_exists=if_exists)
|
|
575
568
|
|
|
576
569
|
def add_computed_column(
|
|
577
570
|
self,
|
|
@@ -595,7 +588,7 @@ class Table(SchemaObject):
|
|
|
595
588
|
- `'abort'`: an exception will be raised and the column will not be added.
|
|
596
589
|
- `'ignore'`: execution will continue and the column will be added. Any rows
|
|
597
590
|
with errors will have a `None` value for the column, with information about the error stored in the
|
|
598
|
-
corresponding `tbl.col_name.
|
|
591
|
+
corresponding `tbl.col_name.errormsg` tbl.col_name.errortype` fields.
|
|
599
592
|
if_exists: Determines the behavior if the column already exists. Must be one of the following:
|
|
600
593
|
|
|
601
594
|
- `'error'`: an exception will be raised.
|
|
@@ -623,8 +616,7 @@ class Table(SchemaObject):
|
|
|
623
616
|
from pixeltable.catalog import Catalog
|
|
624
617
|
|
|
625
618
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
626
|
-
|
|
627
|
-
raise excs.Error('Cannot add column to a snapshot.')
|
|
619
|
+
self.__check_mutable('add columns to')
|
|
628
620
|
if len(kwargs) != 1:
|
|
629
621
|
raise excs.Error(
|
|
630
622
|
f'add_computed_column() requires exactly one keyword argument of the form '
|
|
@@ -642,10 +634,10 @@ class Table(SchemaObject):
|
|
|
642
634
|
# Raise an error if the column expression refers to a column error property
|
|
643
635
|
if isinstance(spec, exprs.Expr):
|
|
644
636
|
for e in spec.subexprs(expr_class=exprs.ColumnPropertyRef, traverse_matches=False):
|
|
645
|
-
if e.
|
|
637
|
+
if e.is_cellmd_prop():
|
|
646
638
|
raise excs.Error(
|
|
647
|
-
'Use of a reference to
|
|
648
|
-
f'
|
|
639
|
+
f'Use of a reference to the {e.prop.name.lower()!r} property of another column '
|
|
640
|
+
f'is not allowed in a computed column.'
|
|
649
641
|
)
|
|
650
642
|
|
|
651
643
|
# handle existing columns based on if_exists parameter
|
|
@@ -654,16 +646,17 @@ class Table(SchemaObject):
|
|
|
654
646
|
)
|
|
655
647
|
# if the column to add already exists and user asked to ignore
|
|
656
648
|
# exiting column, there's nothing to do.
|
|
649
|
+
result = UpdateStatus()
|
|
657
650
|
if len(cols_to_ignore) != 0:
|
|
658
651
|
assert cols_to_ignore[0] == col_name
|
|
659
|
-
return
|
|
652
|
+
return result
|
|
660
653
|
|
|
661
654
|
new_col = self._create_columns({col_name: col_schema})[0]
|
|
662
655
|
self._verify_column(new_col)
|
|
663
656
|
assert self._tbl_version is not None
|
|
664
|
-
|
|
657
|
+
result += self._tbl_version.get().add_columns([new_col], print_stats=print_stats, on_error=on_error)
|
|
665
658
|
FileCache.get().emit_eviction_warnings()
|
|
666
|
-
return
|
|
659
|
+
return result
|
|
667
660
|
|
|
668
661
|
@classmethod
|
|
669
662
|
def _validate_column_spec(cls, name: str, spec: dict[str, Any]) -> None:
|
|
@@ -808,10 +801,10 @@ class Table(SchemaObject):
|
|
|
808
801
|
from pixeltable.catalog import Catalog
|
|
809
802
|
|
|
810
803
|
cat = Catalog.get()
|
|
804
|
+
|
|
811
805
|
# lock_mutable_tree=True: we need to be able to see whether any transitive view has column dependents
|
|
812
806
|
with cat.begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
813
|
-
|
|
814
|
-
raise excs.Error('Cannot drop column from a snapshot.')
|
|
807
|
+
self.__check_mutable('drop columns from')
|
|
815
808
|
col: Column = None
|
|
816
809
|
if_not_exists_ = IfNotExistsParam.validated(if_not_exists, 'if_not_exists')
|
|
817
810
|
|
|
@@ -835,7 +828,7 @@ class Table(SchemaObject):
|
|
|
835
828
|
dependent_user_cols = [c for c in cat.get_column_dependents(col.tbl.id, col.id) if c.name is not None]
|
|
836
829
|
if len(dependent_user_cols) > 0:
|
|
837
830
|
raise excs.Error(
|
|
838
|
-
f'Cannot drop column
|
|
831
|
+
f'Cannot drop column {col.name!r} because the following columns depend on it:\n'
|
|
839
832
|
f'{", ".join(c.name for c in dependent_user_cols)}'
|
|
840
833
|
)
|
|
841
834
|
|
|
@@ -989,8 +982,7 @@ class Table(SchemaObject):
|
|
|
989
982
|
from pixeltable.catalog import Catalog
|
|
990
983
|
|
|
991
984
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
992
|
-
|
|
993
|
-
raise excs.Error('Cannot add an index to a snapshot')
|
|
985
|
+
self.__check_mutable('add an index to')
|
|
994
986
|
col = self._resolve_column_parameter(column)
|
|
995
987
|
|
|
996
988
|
if idx_name is not None and idx_name in self._tbl_version.get().idxs_by_name:
|
|
@@ -1174,8 +1166,7 @@ class Table(SchemaObject):
|
|
|
1174
1166
|
) -> None:
|
|
1175
1167
|
from pixeltable.catalog import Catalog
|
|
1176
1168
|
|
|
1177
|
-
|
|
1178
|
-
raise excs.Error('Cannot drop an index from a snapshot')
|
|
1169
|
+
self.__check_mutable('drop an index from')
|
|
1179
1170
|
assert (col is None) != (idx_name is None)
|
|
1180
1171
|
|
|
1181
1172
|
if idx_name is not None:
|
|
@@ -1347,11 +1338,10 @@ class Table(SchemaObject):
|
|
|
1347
1338
|
from pixeltable.catalog import Catalog
|
|
1348
1339
|
|
|
1349
1340
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
status = self._tbl_version.get().update(value_spec, where, cascade)
|
|
1341
|
+
self.__check_mutable('update')
|
|
1342
|
+
result = self._tbl_version.get().update(value_spec, where, cascade)
|
|
1353
1343
|
FileCache.get().emit_eviction_warnings()
|
|
1354
|
-
return
|
|
1344
|
+
return result
|
|
1355
1345
|
|
|
1356
1346
|
def batch_update(
|
|
1357
1347
|
self,
|
|
@@ -1387,8 +1377,7 @@ class Table(SchemaObject):
|
|
|
1387
1377
|
from pixeltable.catalog import Catalog
|
|
1388
1378
|
|
|
1389
1379
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1390
|
-
|
|
1391
|
-
raise excs.Error('Cannot update a snapshot')
|
|
1380
|
+
self.__check_mutable('update')
|
|
1392
1381
|
rows = list(rows)
|
|
1393
1382
|
|
|
1394
1383
|
row_updates: list[dict[Column, exprs.Expr]] = []
|
|
@@ -1415,7 +1404,7 @@ class Table(SchemaObject):
|
|
|
1415
1404
|
raise excs.Error(f'Primary key columns ({", ".join(missing_cols)}) missing in {row_spec}')
|
|
1416
1405
|
row_updates.append(col_vals)
|
|
1417
1406
|
|
|
1418
|
-
|
|
1407
|
+
result = self._tbl_version.get().batch_update(
|
|
1419
1408
|
row_updates,
|
|
1420
1409
|
rowids,
|
|
1421
1410
|
error_if_not_exists=if_not_exists == 'error',
|
|
@@ -1423,7 +1412,7 @@ class Table(SchemaObject):
|
|
|
1423
1412
|
cascade=cascade,
|
|
1424
1413
|
)
|
|
1425
1414
|
FileCache.get().emit_eviction_warnings()
|
|
1426
|
-
return
|
|
1415
|
+
return result
|
|
1427
1416
|
|
|
1428
1417
|
def recompute_columns(
|
|
1429
1418
|
self, *columns: Union[str, ColumnRef], errors_only: bool = False, cascade: bool = True
|
|
@@ -1433,7 +1422,7 @@ class Table(SchemaObject):
|
|
|
1433
1422
|
Args:
|
|
1434
1423
|
columns: The names or references of the computed columns to recompute.
|
|
1435
1424
|
errors_only: If True, only run the recomputation for rows that have errors in the column (ie, the column's
|
|
1436
|
-
`errortype` property
|
|
1425
|
+
`errortype` property indicates that an error occurred). Only allowed for recomputing a single column.
|
|
1437
1426
|
cascade: if True, also update all computed columns that transitively depend on the recomputed columns.
|
|
1438
1427
|
|
|
1439
1428
|
Examples:
|
|
@@ -1456,8 +1445,7 @@ class Table(SchemaObject):
|
|
|
1456
1445
|
cat = Catalog.get()
|
|
1457
1446
|
# lock_mutable_tree=True: we need to be able to see whether any transitive view has column dependents
|
|
1458
1447
|
with cat.begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1459
|
-
|
|
1460
|
-
raise excs.Error('Cannot recompute columns of a snapshot.')
|
|
1448
|
+
self.__check_mutable('recompute columns of')
|
|
1461
1449
|
if len(columns) == 0:
|
|
1462
1450
|
raise excs.Error('At least one column must be specified to recompute')
|
|
1463
1451
|
if errors_only and len(columns) > 1:
|
|
@@ -1484,9 +1472,9 @@ class Table(SchemaObject):
|
|
|
1484
1472
|
raise excs.Error(f'Cannot recompute column of a base: {col_name!r}')
|
|
1485
1473
|
col_names.append(col_name)
|
|
1486
1474
|
|
|
1487
|
-
|
|
1475
|
+
result = self._tbl_version.get().recompute_columns(col_names, errors_only=errors_only, cascade=cascade)
|
|
1488
1476
|
FileCache.get().emit_eviction_warnings()
|
|
1489
|
-
return
|
|
1477
|
+
return result
|
|
1490
1478
|
|
|
1491
1479
|
def delete(self, where: Optional['exprs.Expr'] = None) -> UpdateStatus:
|
|
1492
1480
|
"""Delete rows in this table.
|
|
@@ -1514,8 +1502,7 @@ class Table(SchemaObject):
|
|
|
1514
1502
|
from pixeltable.catalog import Catalog
|
|
1515
1503
|
|
|
1516
1504
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1517
|
-
|
|
1518
|
-
raise excs.Error('Cannot revert a snapshot')
|
|
1505
|
+
self.__check_mutable('revert')
|
|
1519
1506
|
self._tbl_version.get().revert()
|
|
1520
1507
|
# remove cached md in order to force a reload on the next operation
|
|
1521
1508
|
self._tbl_version_path.clear_cached_md()
|
|
@@ -1530,8 +1517,7 @@ class Table(SchemaObject):
|
|
|
1530
1517
|
from pixeltable.catalog import Catalog
|
|
1531
1518
|
|
|
1532
1519
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
1533
|
-
|
|
1534
|
-
raise excs.Error(f'Table `{self._name}` is a snapshot, so it cannot be linked to an external store.')
|
|
1520
|
+
self.__check_mutable('link an external store to')
|
|
1535
1521
|
if store.name in self.external_stores():
|
|
1536
1522
|
raise excs.Error(f'Table `{self._name}` already has an external store with that name: {store.name}')
|
|
1537
1523
|
_logger.info(f'Linking external store `{store.name}` to table `{self._name}`')
|
|
@@ -1560,7 +1546,7 @@ class Table(SchemaObject):
|
|
|
1560
1546
|
"""
|
|
1561
1547
|
from pixeltable.catalog import Catalog
|
|
1562
1548
|
|
|
1563
|
-
if self._tbl_version_path.
|
|
1549
|
+
if not self._tbl_version_path.is_mutable():
|
|
1564
1550
|
return
|
|
1565
1551
|
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
1566
1552
|
all_stores = self.external_stores()
|
|
@@ -1588,7 +1574,7 @@ class Table(SchemaObject):
|
|
|
1588
1574
|
|
|
1589
1575
|
def sync(
|
|
1590
1576
|
self, stores: Optional[str | list[str]] = None, *, export_data: bool = True, import_data: bool = True
|
|
1591
|
-
) ->
|
|
1577
|
+
) -> UpdateStatus:
|
|
1592
1578
|
"""
|
|
1593
1579
|
Synchronizes this table with its linked external stores.
|
|
1594
1580
|
|
|
@@ -1600,8 +1586,8 @@ class Table(SchemaObject):
|
|
|
1600
1586
|
"""
|
|
1601
1587
|
from pixeltable.catalog import Catalog
|
|
1602
1588
|
|
|
1603
|
-
if self._tbl_version_path.
|
|
1604
|
-
return
|
|
1589
|
+
if not self._tbl_version_path.is_mutable():
|
|
1590
|
+
return UpdateStatus()
|
|
1605
1591
|
# we lock the entire tree starting at the root base table in order to ensure that all synced columns can
|
|
1606
1592
|
# have their updates propagated down the tree
|
|
1607
1593
|
base_tv = self._tbl_version_path.get_tbl_versions()[-1]
|
|
@@ -1617,7 +1603,7 @@ class Table(SchemaObject):
|
|
|
1617
1603
|
if store not in all_stores:
|
|
1618
1604
|
raise excs.Error(f'Table `{self._name}` has no external store with that name: {store}')
|
|
1619
1605
|
|
|
1620
|
-
sync_status =
|
|
1606
|
+
sync_status = UpdateStatus()
|
|
1621
1607
|
for store in stores:
|
|
1622
1608
|
store_obj = self._tbl_version.get().external_stores[store]
|
|
1623
1609
|
store_sync_status = store_obj.sync(self, export_data=export_data, import_data=import_data)
|
|
@@ -1631,6 +1617,19 @@ class Table(SchemaObject):
|
|
|
1631
1617
|
def _ipython_key_completions_(self) -> list[str]:
|
|
1632
1618
|
return list(self._get_schema().keys())
|
|
1633
1619
|
|
|
1620
|
+
_REPORT_SCHEMA: ClassVar[dict[str, ts.ColumnType]] = {
|
|
1621
|
+
'version': ts.IntType(),
|
|
1622
|
+
'created_at': ts.TimestampType(),
|
|
1623
|
+
'user': ts.StringType(nullable=True),
|
|
1624
|
+
'note': ts.StringType(),
|
|
1625
|
+
'inserts': ts.IntType(nullable=True),
|
|
1626
|
+
'updates': ts.IntType(nullable=True),
|
|
1627
|
+
'deletes': ts.IntType(nullable=True),
|
|
1628
|
+
'errors': ts.IntType(nullable=True),
|
|
1629
|
+
'computed': ts.IntType(),
|
|
1630
|
+
'schema_change': ts.StringType(),
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1634
1633
|
def history(self, n: Optional[int] = None) -> pixeltable.dataframe.DataFrameResultSet:
|
|
1635
1634
|
"""Returns rows of information about the versions of this table, most recent first.
|
|
1636
1635
|
|
|
@@ -1676,19 +1675,31 @@ class Table(SchemaObject):
|
|
|
1676
1675
|
for vers_md in vers_list[0 : len(vers_list) - over_count]:
|
|
1677
1676
|
version = vers_md.version_md.version
|
|
1678
1677
|
schema_change = md_dict.get(version, '')
|
|
1679
|
-
|
|
1678
|
+
update_status = vers_md.version_md.update_status
|
|
1679
|
+
if update_status is None:
|
|
1680
|
+
update_status = UpdateStatus()
|
|
1681
|
+
change_type = 'schema' if schema_change != '' else ''
|
|
1682
|
+
if change_type == '':
|
|
1683
|
+
change_type = 'data'
|
|
1684
|
+
rcs = update_status.row_count_stats + update_status.cascade_row_count_stats
|
|
1680
1685
|
report_line = [
|
|
1681
1686
|
version,
|
|
1682
1687
|
datetime.datetime.fromtimestamp(vers_md.version_md.created_at),
|
|
1688
|
+
vers_md.version_md.user,
|
|
1683
1689
|
change_type,
|
|
1690
|
+
rcs.ins_rows,
|
|
1691
|
+
rcs.upd_rows,
|
|
1692
|
+
rcs.del_rows,
|
|
1693
|
+
rcs.num_excs,
|
|
1694
|
+
rcs.computed_values,
|
|
1684
1695
|
schema_change,
|
|
1685
1696
|
]
|
|
1686
1697
|
report_lines.append(report_line)
|
|
1687
1698
|
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
'
|
|
1693
|
-
|
|
1694
|
-
|
|
1699
|
+
return pxt.dataframe.DataFrameResultSet(report_lines, self._REPORT_SCHEMA)
|
|
1700
|
+
|
|
1701
|
+
def __check_mutable(self, op_descr: str) -> None:
|
|
1702
|
+
if self._tbl_version_path.is_snapshot():
|
|
1703
|
+
raise excs.Error(f'{self._display_str()}: Cannot {op_descr} a snapshot.')
|
|
1704
|
+
if self._tbl_version_path.is_replica():
|
|
1705
|
+
raise excs.Error(f'{self._display_str()}: Cannot {op_descr} a {self._display_name()}.')
|