pixeltable 0.2.16__py3-none-any.whl → 0.2.18__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/__version__.py +2 -2
- pixeltable/catalog/catalog.py +8 -7
- pixeltable/catalog/column.py +11 -8
- pixeltable/catalog/insertable_table.py +1 -1
- pixeltable/catalog/path_dict.py +8 -6
- pixeltable/catalog/table.py +20 -13
- pixeltable/catalog/table_version.py +91 -54
- pixeltable/catalog/table_version_path.py +7 -9
- pixeltable/catalog/view.py +2 -1
- pixeltable/dataframe.py +1 -1
- pixeltable/env.py +173 -82
- pixeltable/exec/aggregation_node.py +2 -1
- pixeltable/exec/component_iteration_node.py +1 -1
- pixeltable/exec/sql_node.py +11 -8
- pixeltable/exprs/__init__.py +1 -0
- pixeltable/exprs/arithmetic_expr.py +4 -4
- pixeltable/exprs/array_slice.py +2 -1
- pixeltable/exprs/column_property_ref.py +9 -7
- pixeltable/exprs/column_ref.py +2 -1
- pixeltable/exprs/comparison.py +10 -7
- pixeltable/exprs/compound_predicate.py +3 -2
- pixeltable/exprs/data_row.py +19 -4
- pixeltable/exprs/expr.py +46 -35
- pixeltable/exprs/expr_set.py +32 -9
- pixeltable/exprs/function_call.py +56 -32
- pixeltable/exprs/in_predicate.py +3 -2
- pixeltable/exprs/inline_array.py +2 -1
- pixeltable/exprs/inline_dict.py +2 -1
- pixeltable/exprs/is_null.py +3 -2
- pixeltable/exprs/json_mapper.py +5 -4
- pixeltable/exprs/json_path.py +7 -1
- pixeltable/exprs/literal.py +34 -7
- pixeltable/exprs/method_ref.py +3 -3
- pixeltable/exprs/object_ref.py +6 -5
- pixeltable/exprs/row_builder.py +25 -17
- pixeltable/exprs/rowid_ref.py +2 -1
- pixeltable/exprs/similarity_expr.py +2 -1
- pixeltable/exprs/sql_element_cache.py +30 -0
- pixeltable/exprs/type_cast.py +3 -3
- pixeltable/exprs/variable.py +2 -1
- pixeltable/ext/functions/whisperx.py +4 -4
- pixeltable/ext/functions/yolox.py +6 -6
- pixeltable/func/aggregate_function.py +1 -0
- pixeltable/func/function.py +28 -4
- pixeltable/functions/__init__.py +4 -2
- pixeltable/functions/anthropic.py +107 -0
- pixeltable/functions/fireworks.py +2 -2
- pixeltable/functions/globals.py +6 -1
- pixeltable/functions/huggingface.py +2 -2
- pixeltable/functions/image.py +17 -2
- pixeltable/functions/json.py +5 -5
- pixeltable/functions/mistralai.py +188 -0
- pixeltable/functions/openai.py +6 -10
- pixeltable/functions/string.py +3 -2
- pixeltable/functions/timestamp.py +95 -7
- pixeltable/functions/together.py +5 -5
- pixeltable/functions/video.py +2 -2
- pixeltable/functions/vision.py +27 -17
- pixeltable/functions/whisper.py +1 -1
- pixeltable/io/hf_datasets.py +17 -15
- pixeltable/io/pandas.py +0 -2
- pixeltable/io/parquet.py +15 -14
- pixeltable/iterators/document.py +16 -15
- pixeltable/metadata/__init__.py +1 -1
- pixeltable/metadata/converters/convert_19.py +46 -0
- pixeltable/metadata/notes.py +1 -0
- pixeltable/metadata/schema.py +5 -4
- pixeltable/plan.py +100 -78
- pixeltable/store.py +5 -1
- pixeltable/tool/create_test_db_dump.py +4 -3
- pixeltable/type_system.py +12 -14
- pixeltable/utils/documents.py +45 -42
- pixeltable/utils/formatter.py +2 -2
- {pixeltable-0.2.16.dist-info → pixeltable-0.2.18.dist-info}/METADATA +79 -21
- pixeltable-0.2.18.dist-info/RECORD +147 -0
- pixeltable-0.2.16.dist-info/RECORD +0 -143
- {pixeltable-0.2.16.dist-info → pixeltable-0.2.18.dist-info}/LICENSE +0 -0
- {pixeltable-0.2.16.dist-info → pixeltable-0.2.18.dist-info}/WHEEL +0 -0
- {pixeltable-0.2.16.dist-info → pixeltable-0.2.18.dist-info}/entry_points.txt +0 -0
|
@@ -6,7 +6,7 @@ import inspect
|
|
|
6
6
|
import logging
|
|
7
7
|
import time
|
|
8
8
|
import uuid
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Iterable, Optional
|
|
10
10
|
from uuid import UUID
|
|
11
11
|
|
|
12
12
|
import sqlalchemy as sql
|
|
@@ -23,9 +23,13 @@ from pixeltable.iterators import ComponentIterator
|
|
|
23
23
|
from pixeltable.metadata import schema
|
|
24
24
|
from pixeltable.utils.filecache import FileCache
|
|
25
25
|
from pixeltable.utils.media_store import MediaStore
|
|
26
|
-
|
|
27
|
-
from .globals import UpdateStatus, _POS_COLUMN_NAME, is_valid_identifier, _ROWID_COLUMN_NAME
|
|
26
|
+
|
|
28
27
|
from ..func.globals import resolve_symbol
|
|
28
|
+
from .column import Column
|
|
29
|
+
from .globals import _POS_COLUMN_NAME, _ROWID_COLUMN_NAME, UpdateStatus, is_valid_identifier
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from pixeltable import exec, store
|
|
29
33
|
|
|
30
34
|
_logger = logging.getLogger('pixeltable')
|
|
31
35
|
|
|
@@ -44,6 +48,41 @@ class TableVersion:
|
|
|
44
48
|
have TableVersions reference those
|
|
45
49
|
- mutable TableVersions record their TableVersionPath, which is needed for expr evaluation in updates
|
|
46
50
|
"""
|
|
51
|
+
|
|
52
|
+
id: UUID
|
|
53
|
+
name: str
|
|
54
|
+
version: int
|
|
55
|
+
comment: str
|
|
56
|
+
num_retained_versions: int
|
|
57
|
+
schema_version: int
|
|
58
|
+
view_md: Optional[schema.ViewMd]
|
|
59
|
+
is_snapshot: bool
|
|
60
|
+
effective_version: Optional[int]
|
|
61
|
+
path: Optional[pxt.catalog.TableVersionPath]
|
|
62
|
+
base: Optional[TableVersion]
|
|
63
|
+
next_col_id: int
|
|
64
|
+
next_idx_id: int
|
|
65
|
+
next_rowid: int
|
|
66
|
+
predicate: Optional[exprs.Expr]
|
|
67
|
+
mutable_views: list[TableVersion]
|
|
68
|
+
iterator_cls: Optional[type[ComponentIterator]]
|
|
69
|
+
iterator_args: Optional[exprs.InlineDict]
|
|
70
|
+
num_iterator_cols: int
|
|
71
|
+
|
|
72
|
+
# contains complete history of columns, incl dropped ones
|
|
73
|
+
cols: list[Column]
|
|
74
|
+
# contains only user-facing (named) columns visible in this version
|
|
75
|
+
cols_by_name: dict[str, Column]
|
|
76
|
+
# contains only columns visible in this version, both system and user
|
|
77
|
+
cols_by_id: dict[int, Column]
|
|
78
|
+
# needed for _create_tbl_md()
|
|
79
|
+
idx_md: dict[int, schema.IndexMd]
|
|
80
|
+
# contains only actively maintained indices
|
|
81
|
+
idxs_by_name: dict[str, TableVersion.IndexInfo]
|
|
82
|
+
|
|
83
|
+
external_stores: dict[str, pxt.io.ExternalStore]
|
|
84
|
+
store_tbl: 'store.StoreBase'
|
|
85
|
+
|
|
47
86
|
@dataclasses.dataclass
|
|
48
87
|
class IndexInfo:
|
|
49
88
|
id: int
|
|
@@ -56,7 +95,7 @@ class TableVersion:
|
|
|
56
95
|
|
|
57
96
|
def __init__(
|
|
58
97
|
self, id: UUID, tbl_md: schema.TableMd, version: int, schema_version_md: schema.TableSchemaVersionMd,
|
|
59
|
-
base: Optional[TableVersion] = None, base_path: Optional[
|
|
98
|
+
base: Optional[TableVersion] = None, base_path: Optional[pxt.catalog.TableVersionPath] = None,
|
|
60
99
|
is_snapshot: Optional[bool] = None
|
|
61
100
|
):
|
|
62
101
|
# only one of base and base_path can be non-None
|
|
@@ -95,36 +134,34 @@ class TableVersion:
|
|
|
95
134
|
from pixeltable import exprs
|
|
96
135
|
predicate_dict = None if not is_view or tbl_md.view_md.predicate is None else tbl_md.view_md.predicate
|
|
97
136
|
self.predicate = exprs.Expr.from_dict(predicate_dict) if predicate_dict is not None else None
|
|
98
|
-
self.mutable_views
|
|
137
|
+
self.mutable_views = [] # targets for update propagation
|
|
99
138
|
if self.base is not None and not self.base.is_snapshot and not self.is_snapshot:
|
|
100
139
|
self.base.mutable_views.append(self)
|
|
101
140
|
|
|
102
141
|
# component view-specific initialization
|
|
103
|
-
self.iterator_cls
|
|
104
|
-
self.iterator_args
|
|
142
|
+
self.iterator_cls = None
|
|
143
|
+
self.iterator_args = None
|
|
105
144
|
self.num_iterator_cols = 0
|
|
106
145
|
if is_view and tbl_md.view_md.iterator_class_fqn is not None:
|
|
107
146
|
module_name, class_name = tbl_md.view_md.iterator_class_fqn.rsplit('.', 1)
|
|
108
147
|
module = importlib.import_module(module_name)
|
|
109
148
|
self.iterator_cls = getattr(module, class_name)
|
|
110
|
-
self.iterator_args = exprs.
|
|
111
|
-
assert isinstance(self.iterator_args, exprs.InlineDict)
|
|
149
|
+
self.iterator_args = exprs.InlineDict.from_dict(tbl_md.view_md.iterator_args)
|
|
112
150
|
output_schema, _ = self.iterator_cls.output_schema(**self.iterator_args.to_dict())
|
|
113
151
|
self.num_iterator_cols = len(output_schema)
|
|
114
152
|
assert tbl_md.view_md.iterator_args is not None
|
|
115
153
|
|
|
116
154
|
# register this table version now so that it's available when we're re-creating value exprs
|
|
117
|
-
|
|
118
|
-
cat = catalog.Catalog.get()
|
|
155
|
+
cat = pxt.catalog.Catalog.get()
|
|
119
156
|
cat.tbl_versions[(self.id, self.effective_version)] = self
|
|
120
157
|
|
|
121
158
|
# init schema after we determined whether we're a component view, and before we create the store table
|
|
122
|
-
self.cols
|
|
123
|
-
self.cols_by_name
|
|
124
|
-
self.cols_by_id
|
|
125
|
-
self.idx_md = tbl_md.index_md
|
|
126
|
-
self.idxs_by_name
|
|
127
|
-
self.external_stores
|
|
159
|
+
self.cols = []
|
|
160
|
+
self.cols_by_name = {}
|
|
161
|
+
self.cols_by_id = {}
|
|
162
|
+
self.idx_md = tbl_md.index_md
|
|
163
|
+
self.idxs_by_name = {}
|
|
164
|
+
self.external_stores = {}
|
|
128
165
|
|
|
129
166
|
self._init_schema(tbl_md, schema_version_md)
|
|
130
167
|
|
|
@@ -144,12 +181,12 @@ class TableVersion:
|
|
|
144
181
|
|
|
145
182
|
@classmethod
|
|
146
183
|
def create(
|
|
147
|
-
cls, session: orm.Session, dir_id: UUID, name: str, cols:
|
|
148
|
-
comment: str, base_path: Optional[
|
|
184
|
+
cls, session: orm.Session, dir_id: UUID, name: str, cols: list[Column], num_retained_versions: int,
|
|
185
|
+
comment: str, base_path: Optional[pxt.catalog.TableVersionPath] = None,
|
|
149
186
|
view_md: Optional[schema.ViewMd] = None
|
|
150
|
-
) ->
|
|
187
|
+
) -> tuple[UUID, Optional[TableVersion]]:
|
|
151
188
|
# assign ids
|
|
152
|
-
cols_by_name:
|
|
189
|
+
cols_by_name: dict[str, Column] = {}
|
|
153
190
|
for pos, col in enumerate(cols):
|
|
154
191
|
col.id = pos
|
|
155
192
|
col.schema_version_add = 0
|
|
@@ -244,8 +281,6 @@ class TableVersion:
|
|
|
244
281
|
|
|
245
282
|
def _init_cols(self, tbl_md: schema.TableMd, schema_version_md: schema.TableSchemaVersionMd) -> None:
|
|
246
283
|
"""Initialize self.cols with the columns visible in our effective version"""
|
|
247
|
-
import pixeltable.exprs as exprs
|
|
248
|
-
|
|
249
284
|
self.cols = []
|
|
250
285
|
self.cols_by_name = {}
|
|
251
286
|
self.cols_by_id = {}
|
|
@@ -305,13 +340,13 @@ class TableVersion:
|
|
|
305
340
|
def _init_sa_schema(self) -> None:
|
|
306
341
|
# create the sqlalchemy schema; do this after instantiating columns, in order to determine whether they
|
|
307
342
|
# need to record errors
|
|
308
|
-
from pixeltable.store import
|
|
343
|
+
from pixeltable.store import StoreComponentView, StoreTable, StoreView
|
|
309
344
|
if self.is_component_view():
|
|
310
|
-
self.store_tbl
|
|
345
|
+
self.store_tbl = StoreComponentView(self)
|
|
311
346
|
elif self.is_view():
|
|
312
|
-
self.store_tbl
|
|
347
|
+
self.store_tbl = StoreView(self)
|
|
313
348
|
else:
|
|
314
|
-
self.store_tbl
|
|
349
|
+
self.store_tbl = StoreTable(self)
|
|
315
350
|
|
|
316
351
|
def _update_md(
|
|
317
352
|
self, timestamp: float, conn: sql.engine.Connection, update_tbl_version: bool = True, preceding_schema_version: Optional[int] = None
|
|
@@ -488,7 +523,7 @@ class TableVersion:
|
|
|
488
523
|
f'Cannot add non-nullable column "{col.name}" to table {self.name} with existing rows')
|
|
489
524
|
|
|
490
525
|
num_excs = 0
|
|
491
|
-
cols_with_excs:
|
|
526
|
+
cols_with_excs: list[Column] = []
|
|
492
527
|
for col in cols:
|
|
493
528
|
col.schema_version_add = self.schema_version
|
|
494
529
|
# add the column to the lookup structures now, rather than after the store changes executed successfully,
|
|
@@ -555,7 +590,7 @@ class TableVersion:
|
|
|
555
590
|
with Env.get().engine.begin() as conn:
|
|
556
591
|
# drop this column and all dependent index columns and indices
|
|
557
592
|
dropped_cols = [col]
|
|
558
|
-
dropped_idx_names:
|
|
593
|
+
dropped_idx_names: list[str] = []
|
|
559
594
|
for idx_info in self.idxs_by_name.values():
|
|
560
595
|
if idx_info.col != col:
|
|
561
596
|
continue
|
|
@@ -661,7 +696,7 @@ class TableVersion:
|
|
|
661
696
|
return self._insert(plan, conn, time.time(), print_stats)
|
|
662
697
|
|
|
663
698
|
def _insert(
|
|
664
|
-
|
|
699
|
+
self, exec_plan: 'exec.ExecNode', conn: sql.engine.Connection, timestamp: float, print_stats: bool = False,
|
|
665
700
|
) -> UpdateStatus:
|
|
666
701
|
"""Insert rows produced by exec_plan and propagate to views"""
|
|
667
702
|
# we're creating a new version
|
|
@@ -692,7 +727,7 @@ class TableVersion:
|
|
|
692
727
|
return result
|
|
693
728
|
|
|
694
729
|
def update(
|
|
695
|
-
self, value_spec: dict[str, Any], where: Optional[
|
|
730
|
+
self, value_spec: dict[str, Any], where: Optional[exprs.Expr] = None, cascade: bool = True
|
|
696
731
|
) -> UpdateStatus:
|
|
697
732
|
"""Update rows in this TableVersionPath.
|
|
698
733
|
Args:
|
|
@@ -719,14 +754,15 @@ class TableVersion:
|
|
|
719
754
|
plan, updated_cols, recomputed_cols = (
|
|
720
755
|
Planner.create_update_plan(self.path, update_spec, [], where, cascade)
|
|
721
756
|
)
|
|
757
|
+
from pixeltable.exprs import SqlElementCache
|
|
722
758
|
result = self.propagate_update(
|
|
723
|
-
plan, where.sql_expr() if where is not None else None, recomputed_cols,
|
|
759
|
+
plan, where.sql_expr(SqlElementCache()) if where is not None else None, recomputed_cols,
|
|
724
760
|
base_versions=[], conn=conn, timestamp=time.time(), cascade=cascade, show_progress=True)
|
|
725
761
|
result.updated_cols = updated_cols
|
|
726
762
|
return result
|
|
727
763
|
|
|
728
764
|
def batch_update(
|
|
729
|
-
self, batch: list[dict[Column,
|
|
765
|
+
self, batch: list[dict[Column, exprs.Expr]], rowids: list[tuple[int, ...]], insert_if_not_exists: bool,
|
|
730
766
|
error_if_not_exists: bool, cascade: bool = True,
|
|
731
767
|
) -> UpdateStatus:
|
|
732
768
|
"""Update rows in batch.
|
|
@@ -759,7 +795,7 @@ class TableVersion:
|
|
|
759
795
|
|
|
760
796
|
def _validate_update_spec(
|
|
761
797
|
self, value_spec: dict[str, Any], allow_pk: bool, allow_exprs: bool
|
|
762
|
-
) -> dict[Column,
|
|
798
|
+
) -> dict[Column, exprs.Expr]:
|
|
763
799
|
update_targets: dict[Column, exprs.Expr] = {}
|
|
764
800
|
for col_name, val in value_spec.items():
|
|
765
801
|
if not isinstance(col_name, str):
|
|
@@ -782,7 +818,7 @@ class TableVersion:
|
|
|
782
818
|
# make sure that the value is compatible with the column type
|
|
783
819
|
try:
|
|
784
820
|
# check if this is a literal
|
|
785
|
-
value_expr = exprs.Literal(val, col_type=col.col_type)
|
|
821
|
+
value_expr: exprs.Expr = exprs.Literal(val, col_type=col.col_type)
|
|
786
822
|
except TypeError:
|
|
787
823
|
if not allow_exprs:
|
|
788
824
|
raise excs.Error(
|
|
@@ -802,8 +838,8 @@ class TableVersion:
|
|
|
802
838
|
return update_targets
|
|
803
839
|
|
|
804
840
|
def propagate_update(
|
|
805
|
-
self, plan: Optional[exec.ExecNode], where_clause: Optional[sql.
|
|
806
|
-
recomputed_view_cols:
|
|
841
|
+
self, plan: Optional[exec.ExecNode], where_clause: Optional[sql.ColumnElement],
|
|
842
|
+
recomputed_view_cols: list[Column], base_versions: list[Optional[int]], conn: sql.engine.Connection,
|
|
807
843
|
timestamp: float, cascade: bool, show_progress: bool = True
|
|
808
844
|
) -> UpdateStatus:
|
|
809
845
|
result = UpdateStatus()
|
|
@@ -822,7 +858,7 @@ class TableVersion:
|
|
|
822
858
|
# propagate to views
|
|
823
859
|
for view in self.mutable_views:
|
|
824
860
|
recomputed_cols = [col for col in recomputed_view_cols if col.tbl is view]
|
|
825
|
-
plan
|
|
861
|
+
plan = None
|
|
826
862
|
if len(recomputed_cols) > 0:
|
|
827
863
|
from pixeltable.plan import Planner
|
|
828
864
|
plan = Planner.create_view_update_plan(view.path, recompute_targets=recomputed_cols)
|
|
@@ -835,7 +871,7 @@ class TableVersion:
|
|
|
835
871
|
result.cols_with_excs = list(dict.fromkeys(result.cols_with_excs).keys()) # remove duplicates
|
|
836
872
|
return result
|
|
837
873
|
|
|
838
|
-
def delete(self, where: Optional[
|
|
874
|
+
def delete(self, where: Optional[exprs.Expr] = None) -> UpdateStatus:
|
|
839
875
|
"""Delete rows in this table.
|
|
840
876
|
Args:
|
|
841
877
|
where: a predicate to filter rows to delete.
|
|
@@ -843,6 +879,7 @@ class TableVersion:
|
|
|
843
879
|
assert self.is_insertable()
|
|
844
880
|
from pixeltable.exprs import Expr
|
|
845
881
|
from pixeltable.plan import Planner
|
|
882
|
+
sql_where_clause: Optional[Expr] = None
|
|
846
883
|
if where is not None:
|
|
847
884
|
if not isinstance(where, Expr):
|
|
848
885
|
raise excs.Error(f"'where' argument must be a predicate, got {type(where)}")
|
|
@@ -850,16 +887,16 @@ class TableVersion:
|
|
|
850
887
|
# for now we require that the updated rows can be identified via SQL, rather than via a Python filter
|
|
851
888
|
if analysis_info.filter is not None:
|
|
852
889
|
raise excs.Error(f'Filter {analysis_info.filter} not expressible in SQL')
|
|
890
|
+
sql_where_clause = analysis_info.sql_where_clause
|
|
853
891
|
|
|
854
|
-
analysis_info = Planner.analyze(self.path, where)
|
|
855
892
|
with Env.get().engine.begin() as conn:
|
|
856
|
-
num_rows = self.propagate_delete(
|
|
893
|
+
num_rows = self.propagate_delete(sql_where_clause, base_versions=[], conn=conn, timestamp=time.time())
|
|
857
894
|
|
|
858
895
|
status = UpdateStatus(num_rows=num_rows)
|
|
859
896
|
return status
|
|
860
897
|
|
|
861
898
|
def propagate_delete(
|
|
862
|
-
self, where: Optional[
|
|
899
|
+
self, where: Optional[exprs.Expr], base_versions: list[Optional[int]],
|
|
863
900
|
conn: sql.engine.Connection, timestamp: float) -> int:
|
|
864
901
|
"""Delete rows in this table and propagate to views.
|
|
865
902
|
Args:
|
|
@@ -867,7 +904,7 @@ class TableVersion:
|
|
|
867
904
|
Returns:
|
|
868
905
|
number of deleted rows
|
|
869
906
|
"""
|
|
870
|
-
sql_where_clause = where.sql_expr() if where is not None else None
|
|
907
|
+
sql_where_clause = where.sql_expr(exprs.SqlElementCache()) if where is not None else None
|
|
871
908
|
num_rows = self.store_tbl.delete_rows(
|
|
872
909
|
self.version + 1, base_versions=base_versions, match_on_vmin=False, where_clause=sql_where_clause,
|
|
873
910
|
conn=conn)
|
|
@@ -926,7 +963,7 @@ class TableVersion:
|
|
|
926
963
|
conn.execute(sql.delete(self.store_tbl.sa_tbl).where(self.store_tbl.sa_tbl.c.v_min == self.version))
|
|
927
964
|
|
|
928
965
|
# revert new deletions
|
|
929
|
-
set_clause = {self.store_tbl.sa_tbl.c.v_max: schema.Table.MAX_VERSION}
|
|
966
|
+
set_clause: dict[sql.Column, Any] = {self.store_tbl.sa_tbl.c.v_max: schema.Table.MAX_VERSION}
|
|
930
967
|
for index_info in self.idxs_by_name.values():
|
|
931
968
|
# copy the index value back from the undo column and reset the undo column to NULL
|
|
932
969
|
set_clause[index_info.val_col.sa_col] = index_info.undo_col.sa_col
|
|
@@ -1050,27 +1087,27 @@ class TableVersion:
|
|
|
1050
1087
|
return True
|
|
1051
1088
|
return False
|
|
1052
1089
|
|
|
1053
|
-
def user_columns(self) ->
|
|
1090
|
+
def user_columns(self) -> list[Column]:
|
|
1054
1091
|
"""Return all non-system columns"""
|
|
1055
1092
|
return [c for c in self.cols if not self.is_system_column(c)]
|
|
1056
1093
|
|
|
1057
|
-
def primary_key_columns(self) ->
|
|
1094
|
+
def primary_key_columns(self) -> list[Column]:
|
|
1058
1095
|
"""Return all non-system columns"""
|
|
1059
1096
|
return [c for c in self.cols if c.is_pk]
|
|
1060
1097
|
|
|
1061
|
-
def get_required_col_names(self) ->
|
|
1098
|
+
def get_required_col_names(self) -> list[str]:
|
|
1062
1099
|
"""Return the names of all columns for which values must be specified in insert()"""
|
|
1063
1100
|
assert not self.is_view()
|
|
1064
1101
|
names = [c.name for c in self.cols_by_name.values() if not c.is_computed and not c.col_type.nullable]
|
|
1065
1102
|
return names
|
|
1066
1103
|
|
|
1067
|
-
def get_computed_col_names(self) ->
|
|
1104
|
+
def get_computed_col_names(self) -> list[str]:
|
|
1068
1105
|
"""Return the names of all computed columns"""
|
|
1069
1106
|
names = [c.name for c in self.cols_by_name.values() if c.is_computed]
|
|
1070
1107
|
return names
|
|
1071
1108
|
|
|
1072
1109
|
@classmethod
|
|
1073
|
-
def _create_value_expr(cls, col: Column, path:
|
|
1110
|
+
def _create_value_expr(cls, col: Column, path: pxt.catalog.TableVersionPath) -> None:
|
|
1074
1111
|
"""
|
|
1075
1112
|
Create col.value_expr, given col.compute_func.
|
|
1076
1113
|
Interprets compute_func's parameters to be references to columns and construct ColumnRefs as args.
|
|
@@ -1080,7 +1117,7 @@ class TableVersion:
|
|
|
1080
1117
|
assert col.compute_func is not None
|
|
1081
1118
|
from pixeltable import exprs
|
|
1082
1119
|
params = inspect.signature(col.compute_func).parameters
|
|
1083
|
-
args:
|
|
1120
|
+
args: list[exprs.ColumnRef] = []
|
|
1084
1121
|
for param_name in params:
|
|
1085
1122
|
param = path.get_column(param_name)
|
|
1086
1123
|
if param is None:
|
|
@@ -1123,7 +1160,7 @@ class TableVersion:
|
|
|
1123
1160
|
return 1
|
|
1124
1161
|
|
|
1125
1162
|
@classmethod
|
|
1126
|
-
def _create_column_md(cls, cols:
|
|
1163
|
+
def _create_column_md(cls, cols: list[Column]) -> dict[int, schema.ColumnMd]:
|
|
1127
1164
|
column_md: dict[int, schema.ColumnMd] = {}
|
|
1128
1165
|
for col in cols:
|
|
1129
1166
|
value_expr_dict = col.value_expr.as_dict() if col.value_expr is not None else None
|
|
@@ -1134,7 +1171,7 @@ class TableVersion:
|
|
|
1134
1171
|
return column_md
|
|
1135
1172
|
|
|
1136
1173
|
@classmethod
|
|
1137
|
-
def _create_stores_md(cls, stores: Iterable[
|
|
1174
|
+
def _create_stores_md(cls, stores: Iterable[pxt.io.ExternalStore]) -> list[dict[str, Any]]:
|
|
1138
1175
|
return [
|
|
1139
1176
|
{
|
|
1140
1177
|
'class': f'{type(store).__module__}.{type(store).__qualname__}',
|
|
@@ -1154,7 +1191,7 @@ class TableVersion:
|
|
|
1154
1191
|
return schema.TableVersionMd(created_at=timestamp, version=self.version, schema_version=self.schema_version)
|
|
1155
1192
|
|
|
1156
1193
|
def _create_schema_version_md(self, preceding_schema_version: int) -> schema.TableSchemaVersionMd:
|
|
1157
|
-
column_md:
|
|
1194
|
+
column_md: dict[int, schema.SchemaColumn] = {}
|
|
1158
1195
|
for pos, col in enumerate(self.cols_by_name.values()):
|
|
1159
1196
|
column_md[col.id] = schema.SchemaColumn(pos=pos, name=col.name)
|
|
1160
1197
|
# preceding_schema_version to be set by the caller
|
|
@@ -1166,7 +1203,7 @@ class TableVersion:
|
|
|
1166
1203
|
return {'id': str(self.id), 'effective_version': self.effective_version}
|
|
1167
1204
|
|
|
1168
1205
|
@classmethod
|
|
1169
|
-
def from_dict(cls, d: dict) ->
|
|
1206
|
+
def from_dict(cls, d: dict) -> TableVersion:
|
|
1170
1207
|
import pixeltable.catalog as catalog
|
|
1171
1208
|
id = UUID(d['id'])
|
|
1172
1209
|
effective_version = d['effective_version']
|
|
@@ -4,9 +4,10 @@ import logging
|
|
|
4
4
|
from typing import Optional, Union
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
|
-
import pixeltable
|
|
7
|
+
import pixeltable as pxt
|
|
8
|
+
from pixeltable import exprs
|
|
9
|
+
|
|
8
10
|
from .column import Column
|
|
9
|
-
from .globals import _POS_COLUMN_NAME
|
|
10
11
|
from .table_version import TableVersion
|
|
11
12
|
|
|
12
13
|
_logger = logging.getLogger('pixeltable')
|
|
@@ -80,11 +81,9 @@ class TableVersionPath:
|
|
|
80
81
|
return None
|
|
81
82
|
return self.base.find_tbl_version(id)
|
|
82
83
|
|
|
83
|
-
def __getattr__(self, col_name: str) ->
|
|
84
|
+
def __getattr__(self, col_name: str) -> exprs.ColumnRef:
|
|
84
85
|
"""Return a ColumnRef for the given column name."""
|
|
85
|
-
from pixeltable.exprs import ColumnRef
|
|
86
|
-
if col_name == _POS_COLUMN_NAME and self.is_component_view():
|
|
87
|
-
return RowidRef(self.tbl_version, self.tbl_version.store_tbl.pos_col_idx)
|
|
86
|
+
from pixeltable.exprs import ColumnRef
|
|
88
87
|
if col_name not in self.tbl_version.cols_by_name:
|
|
89
88
|
if self.base is None:
|
|
90
89
|
raise AttributeError(f'Column {col_name} unknown')
|
|
@@ -92,14 +91,13 @@ class TableVersionPath:
|
|
|
92
91
|
col = self.tbl_version.cols_by_name[col_name]
|
|
93
92
|
return ColumnRef(col)
|
|
94
93
|
|
|
95
|
-
def __getitem__(self, index: object) -> Union[
|
|
94
|
+
def __getitem__(self, index: object) -> Union[exprs.ColumnRef, pxt.DataFrame]:
|
|
96
95
|
"""Return a ColumnRef for the given column name, or a DataFrame for the given slice.
|
|
97
96
|
"""
|
|
98
97
|
if isinstance(index, str):
|
|
99
98
|
# basically <tbl>.<colname>
|
|
100
99
|
return self.__getattr__(index)
|
|
101
|
-
|
|
102
|
-
return DataFrame(self).__getitem__(index)
|
|
100
|
+
return pxt.DataFrame(self).__getitem__(index)
|
|
103
101
|
|
|
104
102
|
def columns(self) -> list[Column]:
|
|
105
103
|
"""Return all user columns visible in this tbl version path, including columns from bases"""
|
pixeltable/catalog/view.py
CHANGED
|
@@ -9,6 +9,7 @@ import sqlalchemy.orm as orm
|
|
|
9
9
|
|
|
10
10
|
import pixeltable.catalog as catalog
|
|
11
11
|
import pixeltable.exceptions as excs
|
|
12
|
+
import pixeltable.exprs as exprs
|
|
12
13
|
import pixeltable.func as func
|
|
13
14
|
import pixeltable.metadata.schema as md_schema
|
|
14
15
|
from pixeltable.env import Env
|
|
@@ -220,5 +221,5 @@ class View(Table):
|
|
|
220
221
|
) -> UpdateStatus:
|
|
221
222
|
raise excs.Error(f'{self._display_name()} {self._name!r}: cannot insert into view')
|
|
222
223
|
|
|
223
|
-
def delete(self, where: Optional[
|
|
224
|
+
def delete(self, where: Optional[exprs.Expr] = None) -> UpdateStatus:
|
|
224
225
|
raise excs.Error(f'{self._display_name()} {self._name!r}: cannot delete from view')
|
pixeltable/dataframe.py
CHANGED
|
@@ -279,7 +279,7 @@ class DataFrame:
|
|
|
279
279
|
"""
|
|
280
280
|
plan = self._create_query_plan()
|
|
281
281
|
|
|
282
|
-
def exec_plan(conn: sql.engine.Connection) -> Iterator[
|
|
282
|
+
def exec_plan(conn: sql.engine.Connection) -> Iterator[exprs.DataRow]:
|
|
283
283
|
plan.ctx.set_conn(conn)
|
|
284
284
|
plan.open()
|
|
285
285
|
try:
|