pixeltable 0.4.0rc3__py3-none-any.whl → 0.4.1__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 -1
- pixeltable/__version__.py +2 -2
- pixeltable/catalog/__init__.py +9 -1
- pixeltable/catalog/catalog.py +333 -99
- pixeltable/catalog/column.py +28 -26
- pixeltable/catalog/globals.py +12 -0
- pixeltable/catalog/insertable_table.py +8 -8
- pixeltable/catalog/schema_object.py +6 -0
- pixeltable/catalog/table.py +111 -116
- pixeltable/catalog/table_version.py +36 -50
- pixeltable/catalog/table_version_handle.py +4 -1
- pixeltable/catalog/table_version_path.py +28 -4
- pixeltable/catalog/view.py +10 -18
- pixeltable/config.py +4 -0
- pixeltable/dataframe.py +10 -9
- pixeltable/env.py +5 -11
- pixeltable/exceptions.py +6 -0
- pixeltable/exec/exec_node.py +2 -0
- pixeltable/exec/expr_eval/expr_eval_node.py +4 -4
- pixeltable/exec/sql_node.py +47 -30
- pixeltable/exprs/column_property_ref.py +2 -1
- pixeltable/exprs/column_ref.py +7 -6
- pixeltable/exprs/expr.py +4 -4
- pixeltable/func/__init__.py +1 -0
- pixeltable/func/mcp.py +74 -0
- pixeltable/func/query_template_function.py +4 -2
- pixeltable/func/tools.py +12 -2
- pixeltable/func/udf.py +2 -2
- pixeltable/functions/__init__.py +1 -0
- pixeltable/functions/groq.py +108 -0
- pixeltable/functions/huggingface.py +8 -6
- pixeltable/functions/mistralai.py +2 -13
- pixeltable/functions/openai.py +1 -6
- pixeltable/functions/replicate.py +2 -2
- pixeltable/functions/util.py +6 -1
- pixeltable/globals.py +0 -2
- pixeltable/io/external_store.py +2 -2
- pixeltable/io/label_studio.py +4 -4
- pixeltable/io/table_data_conduit.py +1 -1
- pixeltable/metadata/__init__.py +1 -1
- pixeltable/metadata/converters/convert_37.py +15 -0
- pixeltable/metadata/notes.py +1 -0
- pixeltable/metadata/schema.py +5 -0
- pixeltable/plan.py +37 -121
- pixeltable/share/packager.py +2 -2
- pixeltable/type_system.py +30 -0
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.1.dist-info}/METADATA +1 -1
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.1.dist-info}/RECORD +51 -49
- pixeltable/utils/sample.py +0 -25
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.1.dist-info}/LICENSE +0 -0
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.1.dist-info}/WHEEL +0 -0
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.1.dist-info}/entry_points.txt +0 -0
pixeltable/catalog/table.py
CHANGED
|
@@ -48,21 +48,23 @@ class Table(SchemaObject):
|
|
|
48
48
|
"""
|
|
49
49
|
A handle to a table, view, or snapshot. This class is the primary interface through which table operations
|
|
50
50
|
(queries, insertions, updates, etc.) are performed in Pixeltable.
|
|
51
|
+
|
|
52
|
+
Every user-invoked operation that runs an ExecNode tree (directly or indirectly) needs to call
|
|
53
|
+
FileCache.emit_eviction_warnings() at the end of the operation.
|
|
51
54
|
"""
|
|
52
55
|
|
|
53
|
-
#
|
|
54
|
-
|
|
56
|
+
# the chain of TableVersions needed to run queries and supply metadata (eg, schema)
|
|
57
|
+
_tbl_version_path: TableVersionPath
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
# the physical TableVersion backing this Table; None for pure snapshots
|
|
60
|
+
_tbl_version: Optional[TableVersionHandle]
|
|
58
61
|
|
|
59
62
|
def __init__(self, id: UUID, dir_id: UUID, name: str, tbl_version_path: TableVersionPath):
|
|
60
63
|
super().__init__(id, name, dir_id)
|
|
61
|
-
self.
|
|
62
|
-
self.
|
|
64
|
+
self._tbl_version_path = tbl_version_path
|
|
65
|
+
self._tbl_version = None
|
|
63
66
|
|
|
64
67
|
def _move(self, new_name: str, new_dir_id: UUID) -> None:
|
|
65
|
-
self._check_is_dropped()
|
|
66
68
|
super()._move(new_name, new_dir_id)
|
|
67
69
|
conn = env.Env.get().conn
|
|
68
70
|
stmt = sql.text(
|
|
@@ -75,6 +77,7 @@ class Table(SchemaObject):
|
|
|
75
77
|
)
|
|
76
78
|
conn.execute(stmt, {'new_dir_id': new_dir_id, 'new_name': json.dumps(new_name), 'id': self._id})
|
|
77
79
|
|
|
80
|
+
# this is duplicated from SchemaObject so that our API docs show the docstring for Table
|
|
78
81
|
def get_metadata(self) -> dict[str, Any]:
|
|
79
82
|
"""
|
|
80
83
|
Retrieves metadata associated with this table.
|
|
@@ -100,42 +103,27 @@ class Table(SchemaObject):
|
|
|
100
103
|
}
|
|
101
104
|
```
|
|
102
105
|
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def _version(self) -> int:
|
|
106
|
+
return super().get_metadata()
|
|
107
|
+
|
|
108
|
+
def _get_metadata(self) -> dict[str, Any]:
|
|
109
|
+
md = super()._get_metadata()
|
|
110
|
+
base = self._get_base_table()
|
|
111
|
+
md['base'] = base._path() if base is not None else None
|
|
112
|
+
md['schema'] = self._get_schema()
|
|
113
|
+
md['is_replica'] = self._tbl_version_path.is_replica()
|
|
114
|
+
md['version'] = self._get_version()
|
|
115
|
+
md['schema_version'] = self._tbl_version_path.schema_version()
|
|
116
|
+
md['comment'] = self._get_comment()
|
|
117
|
+
md['num_retained_versions'] = self._get_num_retained_versions()
|
|
118
|
+
md['media_validation'] = self._get_media_validation().name.lower()
|
|
119
|
+
return md
|
|
120
|
+
|
|
121
|
+
def _get_version(self) -> int:
|
|
120
122
|
"""Return the version of this table. Used by tests to ascertain version changes."""
|
|
121
|
-
return self.
|
|
122
|
-
|
|
123
|
-
@property
|
|
124
|
-
def _tbl_version(self) -> TableVersionHandle:
|
|
125
|
-
"""Return TableVersion for just this table."""
|
|
126
|
-
return self._tbl_version_path.tbl_version
|
|
127
|
-
|
|
128
|
-
@property
|
|
129
|
-
def _tbl_version_path(self) -> TableVersionPath:
|
|
130
|
-
self._check_is_dropped()
|
|
131
|
-
return self.__tbl_version_path
|
|
123
|
+
return self._tbl_version_path.version()
|
|
132
124
|
|
|
133
125
|
def __hash__(self) -> int:
|
|
134
|
-
return hash(self.
|
|
135
|
-
|
|
136
|
-
def _check_is_dropped(self) -> None:
|
|
137
|
-
if self._is_dropped:
|
|
138
|
-
raise excs.Error(f'{self._display_name()} {self._name} has been dropped')
|
|
126
|
+
return hash(self._tbl_version_path.tbl_id)
|
|
139
127
|
|
|
140
128
|
def __getattr__(self, name: str) -> 'exprs.ColumnRef':
|
|
141
129
|
"""Return a ColumnRef for the given name."""
|
|
@@ -162,15 +150,18 @@ class Table(SchemaObject):
|
|
|
162
150
|
from pixeltable.catalog import Catalog
|
|
163
151
|
|
|
164
152
|
with Catalog.get().begin_xact(for_write=False):
|
|
165
|
-
self._check_is_dropped()
|
|
166
153
|
return [t._path() for t in self._get_views(recursive=recursive)]
|
|
167
154
|
|
|
168
|
-
def _get_views(self, *, recursive: bool = True) -> list['Table']:
|
|
155
|
+
def _get_views(self, *, recursive: bool = True, include_snapshots: bool = True) -> list['Table']:
|
|
169
156
|
cat = catalog.Catalog.get()
|
|
170
157
|
view_ids = cat.get_view_ids(self._id)
|
|
171
158
|
views = [cat.get_table_by_id(id) for id in view_ids]
|
|
159
|
+
if not include_snapshots:
|
|
160
|
+
views = [t for t in views if not t._tbl_version_path.is_snapshot()]
|
|
172
161
|
if recursive:
|
|
173
|
-
views.extend(
|
|
162
|
+
views.extend(
|
|
163
|
+
t for view in views for t in view._get_views(recursive=True, include_snapshots=include_snapshots)
|
|
164
|
+
)
|
|
174
165
|
return views
|
|
175
166
|
|
|
176
167
|
def _df(self) -> 'pxt.dataframe.DataFrame':
|
|
@@ -276,35 +267,32 @@ class Table(SchemaObject):
|
|
|
276
267
|
"""Return the number of rows in this table."""
|
|
277
268
|
return self._df().count()
|
|
278
269
|
|
|
279
|
-
@property
|
|
280
270
|
def columns(self) -> list[str]:
|
|
281
271
|
"""Return the names of the columns in this table."""
|
|
282
272
|
cols = self._tbl_version_path.columns()
|
|
283
273
|
return [c.name for c in cols]
|
|
284
274
|
|
|
285
|
-
|
|
286
|
-
def _schema(self) -> dict[str, ts.ColumnType]:
|
|
275
|
+
def _get_schema(self) -> dict[str, ts.ColumnType]:
|
|
287
276
|
"""Return the schema (column names and column types) of this table."""
|
|
288
277
|
return {c.name: c.col_type for c in self._tbl_version_path.columns()}
|
|
289
278
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
279
|
+
def get_base_table(self) -> Optional['Table']:
|
|
280
|
+
from pixeltable.catalog import Catalog
|
|
281
|
+
|
|
282
|
+
with Catalog.get().begin_xact(for_write=False):
|
|
283
|
+
return self._get_base_table()
|
|
294
284
|
|
|
295
|
-
@property
|
|
296
285
|
@abc.abstractmethod
|
|
297
|
-
def
|
|
298
|
-
"""The base's Table instance"""
|
|
286
|
+
def _get_base_table(self) -> Optional['Table']:
|
|
287
|
+
"""The base's Table instance. Requires a transaction context"""
|
|
299
288
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
base = self._base_table
|
|
289
|
+
def _get_base_tables(self) -> list['Table']:
|
|
290
|
+
"""The ancestor list of bases of this table, starting with its immediate base. Requires a transaction context"""
|
|
291
|
+
bases: list[Table] = []
|
|
292
|
+
base = self._get_base_table()
|
|
305
293
|
while base is not None:
|
|
306
294
|
bases.append(base)
|
|
307
|
-
base = base.
|
|
295
|
+
base = base._get_base_table()
|
|
308
296
|
return bases
|
|
309
297
|
|
|
310
298
|
@property
|
|
@@ -312,17 +300,14 @@ class Table(SchemaObject):
|
|
|
312
300
|
def _effective_base_versions(self) -> list[Optional[int]]:
|
|
313
301
|
"""The effective versions of the ancestor bases, starting with its immediate base."""
|
|
314
302
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
return self._tbl_version.get().comment
|
|
303
|
+
def _get_comment(self) -> str:
|
|
304
|
+
return self._tbl_version_path.comment()
|
|
318
305
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
return self._tbl_version.get().num_retained_versions
|
|
306
|
+
def _get_num_retained_versions(self) -> int:
|
|
307
|
+
return self._tbl_version_path.num_retained_versions()
|
|
322
308
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return self._tbl_version.get().media_validation
|
|
309
|
+
def _get_media_validation(self) -> MediaValidation:
|
|
310
|
+
return self._tbl_version_path.media_validation()
|
|
326
311
|
|
|
327
312
|
def __repr__(self) -> str:
|
|
328
313
|
return self._descriptors().to_string()
|
|
@@ -346,8 +331,8 @@ class Table(SchemaObject):
|
|
|
346
331
|
stores = self._external_store_descriptor()
|
|
347
332
|
if not stores.empty:
|
|
348
333
|
helper.append(stores)
|
|
349
|
-
if self.
|
|
350
|
-
helper.append(f'COMMENT: {self.
|
|
334
|
+
if self._get_comment():
|
|
335
|
+
helper.append(f'COMMENT: {self._get_comment()}')
|
|
351
336
|
return helper
|
|
352
337
|
|
|
353
338
|
def _col_descriptor(self, columns: Optional[list[str]] = None) -> pd.DataFrame:
|
|
@@ -364,6 +349,8 @@ class Table(SchemaObject):
|
|
|
364
349
|
def _index_descriptor(self, columns: Optional[list[str]] = None) -> pd.DataFrame:
|
|
365
350
|
from pixeltable import index
|
|
366
351
|
|
|
352
|
+
if self._tbl_version is None:
|
|
353
|
+
return pd.DataFrame([])
|
|
367
354
|
pd_rows = []
|
|
368
355
|
for name, info in self._tbl_version.get().idxs_by_name.items():
|
|
369
356
|
if isinstance(info.idx, index.EmbeddingIndex) and (columns is None or info.col.name in columns):
|
|
@@ -383,7 +370,7 @@ class Table(SchemaObject):
|
|
|
383
370
|
|
|
384
371
|
def _external_store_descriptor(self) -> pd.DataFrame:
|
|
385
372
|
pd_rows = []
|
|
386
|
-
for name, store in self.
|
|
373
|
+
for name, store in self._tbl_version_path.tbl_version.get().external_stores.items():
|
|
387
374
|
row = {'External Store': name, 'Type': type(store).__name__}
|
|
388
375
|
pd_rows.append(row)
|
|
389
376
|
return pd.DataFrame(pd_rows)
|
|
@@ -392,7 +379,6 @@ class Table(SchemaObject):
|
|
|
392
379
|
"""
|
|
393
380
|
Print the table schema.
|
|
394
381
|
"""
|
|
395
|
-
self._check_is_dropped()
|
|
396
382
|
if getattr(builtins, '__IPYTHON__', False):
|
|
397
383
|
from IPython.display import Markdown, display
|
|
398
384
|
|
|
@@ -400,11 +386,6 @@ class Table(SchemaObject):
|
|
|
400
386
|
else:
|
|
401
387
|
print(repr(self))
|
|
402
388
|
|
|
403
|
-
def _drop(self) -> None:
|
|
404
|
-
self._check_is_dropped()
|
|
405
|
-
self._tbl_version.get().drop()
|
|
406
|
-
self._is_dropped = True
|
|
407
|
-
|
|
408
389
|
# TODO Factor this out into a separate module.
|
|
409
390
|
# The return type is unresolvable, but torch can't be imported since it's an optional dependency.
|
|
410
391
|
def to_pytorch_dataset(self, image_format: str = 'pt') -> 'torch.utils.data.IterableDataset':
|
|
@@ -422,9 +403,11 @@ class Table(SchemaObject):
|
|
|
422
403
|
def _column_has_dependents(self, col: Column) -> bool:
|
|
423
404
|
"""Returns True if the column has dependents, False otherwise."""
|
|
424
405
|
assert col is not None
|
|
425
|
-
assert col.name in self.
|
|
426
|
-
|
|
406
|
+
assert col.name in self._get_schema()
|
|
407
|
+
cat = catalog.Catalog.get()
|
|
408
|
+
if any(c.name is not None for c in cat.get_column_dependents(col.tbl.id, col.id)):
|
|
427
409
|
return True
|
|
410
|
+
assert self._tbl_version is not None
|
|
428
411
|
return any(
|
|
429
412
|
col in store.get_local_columns()
|
|
430
413
|
for view in (self, *self._get_views(recursive=True))
|
|
@@ -436,8 +419,8 @@ class Table(SchemaObject):
|
|
|
436
419
|
|
|
437
420
|
If `if_exists='ignore'`, returns a list of existing columns, if any, in `new_col_names`.
|
|
438
421
|
"""
|
|
439
|
-
assert not
|
|
440
|
-
existing_col_names = set(self.
|
|
422
|
+
assert self._tbl_version is not None
|
|
423
|
+
existing_col_names = set(self._get_schema().keys())
|
|
441
424
|
cols_to_ignore = []
|
|
442
425
|
for new_col_name in new_col_names:
|
|
443
426
|
if new_col_name in existing_col_names:
|
|
@@ -507,9 +490,9 @@ class Table(SchemaObject):
|
|
|
507
490
|
"""
|
|
508
491
|
from pixeltable.catalog import Catalog
|
|
509
492
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if self.
|
|
493
|
+
# lock_mutable_tree=True: we might end up having to drop existing columns, which requires locking the tree
|
|
494
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
495
|
+
if self._tbl_version_path.is_snapshot():
|
|
513
496
|
raise excs.Error('Cannot add column to a snapshot.')
|
|
514
497
|
col_schema = {
|
|
515
498
|
col_name: {'type': ts.ColumnType.normalize_type(spec, nullable_default=True, allow_builtin_types=False)}
|
|
@@ -530,6 +513,7 @@ class Table(SchemaObject):
|
|
|
530
513
|
new_cols = self._create_columns(col_schema)
|
|
531
514
|
for new_col in new_cols:
|
|
532
515
|
self._verify_column(new_col)
|
|
516
|
+
assert self._tbl_version is not None
|
|
533
517
|
status = self._tbl_version.get().add_columns(new_cols, print_stats=False, on_error='abort')
|
|
534
518
|
FileCache.get().emit_eviction_warnings()
|
|
535
519
|
return status
|
|
@@ -570,10 +554,9 @@ class Table(SchemaObject):
|
|
|
570
554
|
"""
|
|
571
555
|
from pixeltable.catalog import Catalog
|
|
572
556
|
|
|
573
|
-
with Catalog.get().begin_xact(
|
|
574
|
-
self._check_is_dropped()
|
|
557
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
575
558
|
# verify kwargs
|
|
576
|
-
if self.
|
|
559
|
+
if self._tbl_version_path.is_snapshot():
|
|
577
560
|
raise excs.Error('Cannot add column to a snapshot.')
|
|
578
561
|
# verify kwargs and construct column schema dict
|
|
579
562
|
if len(kwargs) != 1:
|
|
@@ -637,9 +620,8 @@ class Table(SchemaObject):
|
|
|
637
620
|
"""
|
|
638
621
|
from pixeltable.catalog import Catalog
|
|
639
622
|
|
|
640
|
-
with Catalog.get().begin_xact(
|
|
641
|
-
self.
|
|
642
|
-
if self.get_metadata()['is_snapshot']:
|
|
623
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
624
|
+
if self._tbl_version_path.is_snapshot():
|
|
643
625
|
raise excs.Error('Cannot add column to a snapshot.')
|
|
644
626
|
if len(kwargs) != 1:
|
|
645
627
|
raise excs.Error(
|
|
@@ -676,6 +658,7 @@ class Table(SchemaObject):
|
|
|
676
658
|
|
|
677
659
|
new_col = self._create_columns({col_name: col_schema})[0]
|
|
678
660
|
self._verify_column(new_col)
|
|
661
|
+
assert self._tbl_version is not None
|
|
679
662
|
status = self._tbl_version.get().add_columns([new_col], print_stats=print_stats, on_error=on_error)
|
|
680
663
|
FileCache.get().emit_eviction_warnings()
|
|
681
664
|
return status
|
|
@@ -822,8 +805,9 @@ class Table(SchemaObject):
|
|
|
822
805
|
"""
|
|
823
806
|
from pixeltable.catalog import Catalog
|
|
824
807
|
|
|
825
|
-
|
|
826
|
-
|
|
808
|
+
cat = Catalog.get()
|
|
809
|
+
# lock_mutable_tree=True: we need to be able to see whether any transitive view has column dependents
|
|
810
|
+
with cat.begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
827
811
|
if self._tbl_version_path.is_snapshot():
|
|
828
812
|
raise excs.Error('Cannot drop column from a snapshot.')
|
|
829
813
|
col: Column = None
|
|
@@ -846,18 +830,19 @@ class Table(SchemaObject):
|
|
|
846
830
|
return
|
|
847
831
|
col = column.col
|
|
848
832
|
|
|
849
|
-
dependent_user_cols = [c for c in col.
|
|
833
|
+
dependent_user_cols = [c for c in cat.get_column_dependents(col.tbl.id, col.id) if c.name is not None]
|
|
850
834
|
if len(dependent_user_cols) > 0:
|
|
851
835
|
raise excs.Error(
|
|
852
836
|
f'Cannot drop column `{col.name}` because the following columns depend on it:\n'
|
|
853
837
|
f'{", ".join(c.name for c in dependent_user_cols)}'
|
|
854
838
|
)
|
|
855
839
|
|
|
840
|
+
_ = self._get_views(recursive=True, include_snapshots=False)
|
|
856
841
|
# See if this column has a dependent store. We need to look through all stores in all
|
|
857
842
|
# (transitive) views of this table.
|
|
858
843
|
dependent_stores = [
|
|
859
844
|
(view, store)
|
|
860
|
-
for view in (self, *self._get_views(recursive=True))
|
|
845
|
+
for view in (self, *self._get_views(recursive=True, include_snapshots=False))
|
|
861
846
|
for store in view._tbl_version.get().external_stores.values()
|
|
862
847
|
if col in store.get_local_columns()
|
|
863
848
|
]
|
|
@@ -891,7 +876,7 @@ class Table(SchemaObject):
|
|
|
891
876
|
"""
|
|
892
877
|
from pixeltable.catalog import Catalog
|
|
893
878
|
|
|
894
|
-
with Catalog.get().begin_xact(
|
|
879
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
895
880
|
self._tbl_version.get().rename_column(old_name, new_name)
|
|
896
881
|
|
|
897
882
|
def _list_index_info_for_test(self) -> list[dict[str, Any]]:
|
|
@@ -902,7 +887,6 @@ class Table(SchemaObject):
|
|
|
902
887
|
A list of index information, each containing the index's
|
|
903
888
|
id, name, and the name of the column it indexes.
|
|
904
889
|
"""
|
|
905
|
-
assert not self._is_dropped
|
|
906
890
|
index_info = []
|
|
907
891
|
for idx_name, idx in self._tbl_version.get().idxs_by_name.items():
|
|
908
892
|
index_info.append({'_id': idx.id, '_name': idx_name, '_column': idx.col.name})
|
|
@@ -1001,7 +985,7 @@ class Table(SchemaObject):
|
|
|
1001
985
|
"""
|
|
1002
986
|
from pixeltable.catalog import Catalog
|
|
1003
987
|
|
|
1004
|
-
with Catalog.get().begin_xact(
|
|
988
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1005
989
|
if self._tbl_version_path.is_snapshot():
|
|
1006
990
|
raise excs.Error('Cannot add an index to a snapshot')
|
|
1007
991
|
col = self._resolve_column_parameter(column)
|
|
@@ -1090,7 +1074,7 @@ class Table(SchemaObject):
|
|
|
1090
1074
|
if (column is None) == (idx_name is None):
|
|
1091
1075
|
raise excs.Error("Exactly one of 'column' or 'idx_name' must be provided")
|
|
1092
1076
|
|
|
1093
|
-
with Catalog.get().begin_xact(
|
|
1077
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1094
1078
|
col: Column = None
|
|
1095
1079
|
if idx_name is None:
|
|
1096
1080
|
col = self._resolve_column_parameter(column)
|
|
@@ -1169,7 +1153,7 @@ class Table(SchemaObject):
|
|
|
1169
1153
|
if (column is None) == (idx_name is None):
|
|
1170
1154
|
raise excs.Error("Exactly one of 'column' or 'idx_name' must be provided")
|
|
1171
1155
|
|
|
1172
|
-
with Catalog.get().begin_xact(
|
|
1156
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
1173
1157
|
col: Column = None
|
|
1174
1158
|
if idx_name is None:
|
|
1175
1159
|
col = self._resolve_column_parameter(column)
|
|
@@ -1185,6 +1169,8 @@ class Table(SchemaObject):
|
|
|
1185
1169
|
_idx_class: Optional[type[index.IndexBase]] = None,
|
|
1186
1170
|
if_not_exists: Literal['error', 'ignore'] = 'error',
|
|
1187
1171
|
) -> None:
|
|
1172
|
+
from pixeltable.catalog import Catalog
|
|
1173
|
+
|
|
1188
1174
|
if self._tbl_version_path.is_snapshot():
|
|
1189
1175
|
raise excs.Error('Cannot drop an index from a snapshot')
|
|
1190
1176
|
assert (col is None) != (idx_name is None)
|
|
@@ -1216,7 +1202,10 @@ class Table(SchemaObject):
|
|
|
1216
1202
|
idx_info = idx_info_list[0]
|
|
1217
1203
|
|
|
1218
1204
|
# Find out if anything depends on this index
|
|
1219
|
-
|
|
1205
|
+
val_col = idx_info.val_col
|
|
1206
|
+
dependent_user_cols = [
|
|
1207
|
+
c for c in Catalog.get().get_column_dependents(val_col.tbl.id, val_col.id) if c.name is not None
|
|
1208
|
+
]
|
|
1220
1209
|
if len(dependent_user_cols) > 0:
|
|
1221
1210
|
raise excs.Error(
|
|
1222
1211
|
f'Cannot drop index because the following columns depend on it:\n'
|
|
@@ -1351,7 +1340,9 @@ class Table(SchemaObject):
|
|
|
1351
1340
|
"""
|
|
1352
1341
|
from pixeltable.catalog import Catalog
|
|
1353
1342
|
|
|
1354
|
-
with Catalog.get().begin_xact(
|
|
1343
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1344
|
+
if self._tbl_version_path.is_snapshot():
|
|
1345
|
+
raise excs.Error('Cannot update a snapshot')
|
|
1355
1346
|
status = self._tbl_version.get().update(value_spec, where, cascade)
|
|
1356
1347
|
FileCache.get().emit_eviction_warnings()
|
|
1357
1348
|
return status
|
|
@@ -1389,7 +1380,7 @@ class Table(SchemaObject):
|
|
|
1389
1380
|
"""
|
|
1390
1381
|
from pixeltable.catalog import Catalog
|
|
1391
1382
|
|
|
1392
|
-
with Catalog.get().begin_xact(
|
|
1383
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1393
1384
|
if self._tbl_version_path.is_snapshot():
|
|
1394
1385
|
raise excs.Error('Cannot update a snapshot')
|
|
1395
1386
|
rows = list(rows)
|
|
@@ -1453,14 +1444,13 @@ class Table(SchemaObject):
|
|
|
1453
1444
|
"""
|
|
1454
1445
|
from pixeltable.catalog import Catalog
|
|
1455
1446
|
|
|
1456
|
-
with Catalog.get().begin_xact(
|
|
1447
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=True):
|
|
1457
1448
|
if self._tbl_version_path.is_snapshot():
|
|
1458
1449
|
raise excs.Error('Cannot revert a snapshot')
|
|
1459
1450
|
self._tbl_version.get().revert()
|
|
1460
1451
|
# remove cached md in order to force a reload on the next operation
|
|
1461
|
-
self.
|
|
1452
|
+
self._tbl_version_path.clear_cached_md()
|
|
1462
1453
|
|
|
1463
|
-
@property
|
|
1464
1454
|
def external_stores(self) -> list[str]:
|
|
1465
1455
|
return list(self._tbl_version.get().external_stores.keys())
|
|
1466
1456
|
|
|
@@ -1470,10 +1460,10 @@ class Table(SchemaObject):
|
|
|
1470
1460
|
"""
|
|
1471
1461
|
from pixeltable.catalog import Catalog
|
|
1472
1462
|
|
|
1473
|
-
with Catalog.get().begin_xact(
|
|
1474
|
-
if self.
|
|
1463
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
1464
|
+
if self._tbl_version_path.is_snapshot():
|
|
1475
1465
|
raise excs.Error(f'Table `{self._name}` is a snapshot, so it cannot be linked to an external store.')
|
|
1476
|
-
if store.name in self.external_stores:
|
|
1466
|
+
if store.name in self.external_stores():
|
|
1477
1467
|
raise excs.Error(f'Table `{self._name}` already has an external store with that name: {store.name}')
|
|
1478
1468
|
_logger.info(f'Linking external store `{store.name}` to table `{self._name}`')
|
|
1479
1469
|
|
|
@@ -1501,9 +1491,10 @@ class Table(SchemaObject):
|
|
|
1501
1491
|
"""
|
|
1502
1492
|
from pixeltable.catalog import Catalog
|
|
1503
1493
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1494
|
+
if self._tbl_version_path.is_snapshot():
|
|
1495
|
+
return
|
|
1496
|
+
with Catalog.get().begin_xact(tbl=self._tbl_version_path, for_write=True, lock_mutable_tree=False):
|
|
1497
|
+
all_stores = self.external_stores()
|
|
1507
1498
|
|
|
1508
1499
|
if stores is None:
|
|
1509
1500
|
stores = all_stores
|
|
@@ -1540,9 +1531,13 @@ class Table(SchemaObject):
|
|
|
1540
1531
|
"""
|
|
1541
1532
|
from pixeltable.catalog import Catalog
|
|
1542
1533
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1534
|
+
if self._tbl_version_path.is_snapshot():
|
|
1535
|
+
return pxt.io.SyncStatus.empty()
|
|
1536
|
+
# we lock the entire tree starting at the root base table in order to ensure that all synced columns can
|
|
1537
|
+
# have their updates propagated down the tree
|
|
1538
|
+
base_tv = self._tbl_version_path.get_tbl_versions()[-1]
|
|
1539
|
+
with Catalog.get().begin_xact(tbl=TableVersionPath(base_tv), for_write=True, lock_mutable_tree=True):
|
|
1540
|
+
all_stores = self.external_stores()
|
|
1546
1541
|
|
|
1547
1542
|
if stores is None:
|
|
1548
1543
|
stores = all_stores
|
|
@@ -1562,7 +1557,7 @@ class Table(SchemaObject):
|
|
|
1562
1557
|
return sync_status
|
|
1563
1558
|
|
|
1564
1559
|
def __dir__(self) -> list[str]:
|
|
1565
|
-
return list(super().__dir__()) + list(self.
|
|
1560
|
+
return list(super().__dir__()) + list(self._get_schema().keys())
|
|
1566
1561
|
|
|
1567
1562
|
def _ipython_key_completions_(self) -> list[str]:
|
|
1568
|
-
return list(self.
|
|
1563
|
+
return list(self._get_schema().keys())
|