pixeltable 0.4.0rc3__py3-none-any.whl → 0.4.20__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 +23 -5
- pixeltable/_version.py +1 -0
- pixeltable/catalog/__init__.py +5 -3
- pixeltable/catalog/catalog.py +1318 -404
- pixeltable/catalog/column.py +186 -115
- pixeltable/catalog/dir.py +1 -2
- pixeltable/catalog/globals.py +11 -43
- pixeltable/catalog/insertable_table.py +167 -79
- pixeltable/catalog/path.py +61 -23
- pixeltable/catalog/schema_object.py +9 -10
- pixeltable/catalog/table.py +626 -308
- pixeltable/catalog/table_metadata.py +101 -0
- pixeltable/catalog/table_version.py +713 -569
- pixeltable/catalog/table_version_handle.py +37 -6
- pixeltable/catalog/table_version_path.py +42 -29
- pixeltable/catalog/tbl_ops.py +50 -0
- pixeltable/catalog/update_status.py +191 -0
- pixeltable/catalog/view.py +108 -94
- pixeltable/config.py +128 -22
- pixeltable/dataframe.py +188 -100
- pixeltable/env.py +407 -136
- pixeltable/exceptions.py +6 -0
- pixeltable/exec/__init__.py +3 -0
- pixeltable/exec/aggregation_node.py +7 -8
- pixeltable/exec/cache_prefetch_node.py +83 -110
- pixeltable/exec/cell_materialization_node.py +231 -0
- pixeltable/exec/cell_reconstruction_node.py +135 -0
- pixeltable/exec/component_iteration_node.py +4 -3
- pixeltable/exec/data_row_batch.py +8 -65
- pixeltable/exec/exec_context.py +16 -4
- pixeltable/exec/exec_node.py +13 -36
- pixeltable/exec/expr_eval/evaluators.py +7 -6
- pixeltable/exec/expr_eval/expr_eval_node.py +27 -12
- pixeltable/exec/expr_eval/globals.py +8 -5
- pixeltable/exec/expr_eval/row_buffer.py +1 -2
- pixeltable/exec/expr_eval/schedulers.py +190 -30
- pixeltable/exec/globals.py +32 -0
- pixeltable/exec/in_memory_data_node.py +18 -18
- pixeltable/exec/object_store_save_node.py +293 -0
- pixeltable/exec/row_update_node.py +16 -9
- pixeltable/exec/sql_node.py +206 -101
- pixeltable/exprs/__init__.py +1 -1
- pixeltable/exprs/arithmetic_expr.py +27 -22
- pixeltable/exprs/array_slice.py +3 -3
- pixeltable/exprs/column_property_ref.py +34 -30
- pixeltable/exprs/column_ref.py +92 -96
- pixeltable/exprs/comparison.py +5 -5
- pixeltable/exprs/compound_predicate.py +5 -4
- pixeltable/exprs/data_row.py +152 -55
- pixeltable/exprs/expr.py +62 -43
- pixeltable/exprs/expr_dict.py +3 -3
- pixeltable/exprs/expr_set.py +17 -10
- pixeltable/exprs/function_call.py +75 -37
- pixeltable/exprs/globals.py +1 -2
- pixeltable/exprs/in_predicate.py +4 -4
- pixeltable/exprs/inline_expr.py +10 -27
- pixeltable/exprs/is_null.py +1 -3
- pixeltable/exprs/json_mapper.py +8 -8
- pixeltable/exprs/json_path.py +56 -22
- pixeltable/exprs/literal.py +5 -5
- pixeltable/exprs/method_ref.py +2 -2
- pixeltable/exprs/object_ref.py +2 -2
- pixeltable/exprs/row_builder.py +127 -53
- pixeltable/exprs/rowid_ref.py +8 -12
- pixeltable/exprs/similarity_expr.py +50 -25
- pixeltable/exprs/sql_element_cache.py +4 -4
- pixeltable/exprs/string_op.py +5 -5
- pixeltable/exprs/type_cast.py +3 -5
- pixeltable/func/__init__.py +1 -0
- pixeltable/func/aggregate_function.py +8 -8
- pixeltable/func/callable_function.py +9 -9
- pixeltable/func/expr_template_function.py +10 -10
- pixeltable/func/function.py +18 -20
- pixeltable/func/function_registry.py +6 -7
- pixeltable/func/globals.py +2 -3
- pixeltable/func/mcp.py +74 -0
- pixeltable/func/query_template_function.py +20 -18
- pixeltable/func/signature.py +43 -16
- pixeltable/func/tools.py +23 -13
- pixeltable/func/udf.py +18 -20
- pixeltable/functions/__init__.py +6 -0
- pixeltable/functions/anthropic.py +93 -33
- pixeltable/functions/audio.py +114 -10
- pixeltable/functions/bedrock.py +13 -6
- pixeltable/functions/date.py +1 -1
- pixeltable/functions/deepseek.py +20 -9
- pixeltable/functions/fireworks.py +2 -2
- pixeltable/functions/gemini.py +28 -11
- pixeltable/functions/globals.py +13 -13
- pixeltable/functions/groq.py +108 -0
- pixeltable/functions/huggingface.py +1046 -23
- pixeltable/functions/image.py +9 -18
- pixeltable/functions/llama_cpp.py +23 -8
- pixeltable/functions/math.py +3 -4
- pixeltable/functions/mistralai.py +4 -15
- pixeltable/functions/ollama.py +16 -9
- pixeltable/functions/openai.py +104 -82
- pixeltable/functions/openrouter.py +143 -0
- pixeltable/functions/replicate.py +2 -2
- pixeltable/functions/reve.py +250 -0
- pixeltable/functions/string.py +21 -28
- pixeltable/functions/timestamp.py +13 -14
- pixeltable/functions/together.py +4 -6
- pixeltable/functions/twelvelabs.py +92 -0
- pixeltable/functions/util.py +6 -1
- pixeltable/functions/video.py +1388 -106
- pixeltable/functions/vision.py +7 -7
- pixeltable/functions/whisper.py +15 -7
- pixeltable/functions/whisperx.py +179 -0
- pixeltable/{ext/functions → functions}/yolox.py +2 -4
- pixeltable/globals.py +332 -105
- pixeltable/index/base.py +13 -22
- pixeltable/index/btree.py +23 -22
- pixeltable/index/embedding_index.py +32 -44
- pixeltable/io/__init__.py +4 -2
- pixeltable/io/datarows.py +7 -6
- pixeltable/io/external_store.py +49 -77
- pixeltable/io/fiftyone.py +11 -11
- pixeltable/io/globals.py +29 -28
- pixeltable/io/hf_datasets.py +17 -9
- pixeltable/io/label_studio.py +70 -66
- pixeltable/io/lancedb.py +3 -0
- pixeltable/io/pandas.py +12 -11
- pixeltable/io/parquet.py +13 -93
- pixeltable/io/table_data_conduit.py +71 -47
- pixeltable/io/utils.py +3 -3
- pixeltable/iterators/__init__.py +2 -1
- pixeltable/iterators/audio.py +21 -11
- pixeltable/iterators/document.py +116 -55
- pixeltable/iterators/image.py +5 -2
- pixeltable/iterators/video.py +293 -13
- pixeltable/metadata/__init__.py +4 -2
- pixeltable/metadata/converters/convert_18.py +2 -2
- pixeltable/metadata/converters/convert_19.py +2 -2
- pixeltable/metadata/converters/convert_20.py +2 -2
- pixeltable/metadata/converters/convert_21.py +2 -2
- pixeltable/metadata/converters/convert_22.py +2 -2
- pixeltable/metadata/converters/convert_24.py +2 -2
- pixeltable/metadata/converters/convert_25.py +2 -2
- pixeltable/metadata/converters/convert_26.py +2 -2
- pixeltable/metadata/converters/convert_29.py +4 -4
- pixeltable/metadata/converters/convert_34.py +2 -2
- pixeltable/metadata/converters/convert_36.py +2 -2
- pixeltable/metadata/converters/convert_37.py +15 -0
- pixeltable/metadata/converters/convert_38.py +39 -0
- pixeltable/metadata/converters/convert_39.py +124 -0
- pixeltable/metadata/converters/convert_40.py +73 -0
- pixeltable/metadata/converters/util.py +13 -12
- pixeltable/metadata/notes.py +4 -0
- pixeltable/metadata/schema.py +79 -42
- pixeltable/metadata/utils.py +74 -0
- pixeltable/mypy/__init__.py +3 -0
- pixeltable/mypy/mypy_plugin.py +123 -0
- pixeltable/plan.py +274 -223
- pixeltable/share/__init__.py +1 -1
- pixeltable/share/packager.py +259 -129
- pixeltable/share/protocol/__init__.py +34 -0
- pixeltable/share/protocol/common.py +170 -0
- pixeltable/share/protocol/operation_types.py +33 -0
- pixeltable/share/protocol/replica.py +109 -0
- pixeltable/share/publish.py +213 -57
- pixeltable/store.py +238 -175
- pixeltable/type_system.py +104 -63
- pixeltable/utils/__init__.py +2 -3
- pixeltable/utils/arrow.py +108 -13
- pixeltable/utils/av.py +298 -0
- pixeltable/utils/azure_store.py +305 -0
- pixeltable/utils/code.py +3 -3
- pixeltable/utils/console_output.py +4 -1
- pixeltable/utils/coroutine.py +6 -23
- pixeltable/utils/dbms.py +31 -5
- pixeltable/utils/description_helper.py +4 -5
- pixeltable/utils/documents.py +5 -6
- pixeltable/utils/exception_handler.py +7 -30
- pixeltable/utils/filecache.py +6 -6
- pixeltable/utils/formatter.py +4 -6
- pixeltable/utils/gcs_store.py +283 -0
- pixeltable/utils/http_server.py +2 -3
- pixeltable/utils/iceberg.py +1 -2
- pixeltable/utils/image.py +17 -0
- pixeltable/utils/lancedb.py +88 -0
- pixeltable/utils/local_store.py +316 -0
- pixeltable/utils/misc.py +5 -0
- pixeltable/utils/object_stores.py +528 -0
- pixeltable/utils/pydantic.py +60 -0
- pixeltable/utils/pytorch.py +5 -6
- pixeltable/utils/s3_store.py +392 -0
- pixeltable-0.4.20.dist-info/METADATA +587 -0
- pixeltable-0.4.20.dist-info/RECORD +218 -0
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.20.dist-info}/WHEEL +1 -1
- pixeltable-0.4.20.dist-info/entry_points.txt +2 -0
- pixeltable/__version__.py +0 -3
- pixeltable/ext/__init__.py +0 -17
- pixeltable/ext/functions/__init__.py +0 -11
- pixeltable/ext/functions/whisperx.py +0 -77
- pixeltable/utils/media_store.py +0 -77
- pixeltable/utils/s3.py +0 -17
- pixeltable/utils/sample.py +0 -25
- pixeltable-0.4.0rc3.dist-info/METADATA +0 -435
- pixeltable-0.4.0rc3.dist-info/RECORD +0 -189
- pixeltable-0.4.0rc3.dist-info/entry_points.txt +0 -3
- {pixeltable-0.4.0rc3.dist-info → pixeltable-0.4.20.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
5
6
|
from uuid import UUID
|
|
6
7
|
|
|
8
|
+
from pixeltable import exceptions as excs
|
|
9
|
+
|
|
7
10
|
from .table_version import TableVersion
|
|
8
11
|
|
|
9
12
|
if TYPE_CHECKING:
|
|
10
|
-
|
|
13
|
+
from pixeltable.catalog import Column
|
|
11
14
|
|
|
12
15
|
_logger = logging.getLogger('pixeltable')
|
|
13
16
|
|
|
@@ -18,10 +21,10 @@ class TableVersionHandle:
|
|
|
18
21
|
"""
|
|
19
22
|
|
|
20
23
|
id: UUID
|
|
21
|
-
effective_version:
|
|
22
|
-
_tbl_version:
|
|
24
|
+
effective_version: int | None
|
|
25
|
+
_tbl_version: TableVersion | None
|
|
23
26
|
|
|
24
|
-
def __init__(self, tbl_id: UUID, effective_version:
|
|
27
|
+
def __init__(self, tbl_id: UUID, effective_version: int | None, tbl_version: TableVersion | None = None):
|
|
25
28
|
self.id = tbl_id
|
|
26
29
|
self.effective_version = effective_version
|
|
27
30
|
self._tbl_version = tbl_version
|
|
@@ -34,6 +37,13 @@ class TableVersionHandle:
|
|
|
34
37
|
def __hash__(self) -> int:
|
|
35
38
|
return hash((self.id, self.effective_version))
|
|
36
39
|
|
|
40
|
+
def __repr__(self) -> str:
|
|
41
|
+
return f'TableVersionHandle(id={self.id!r}, effective_version={self.effective_version})'
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def is_snapshot(self) -> bool:
|
|
45
|
+
return self.effective_version is not None
|
|
46
|
+
|
|
37
47
|
@classmethod
|
|
38
48
|
def create(cls, tbl_version: TableVersion) -> TableVersionHandle:
|
|
39
49
|
return cls(tbl_version.id, tbl_version.effective_version, tbl_version)
|
|
@@ -53,7 +63,6 @@ class TableVersionHandle:
|
|
|
53
63
|
else:
|
|
54
64
|
self._tbl_version = Catalog.get().get_tbl_version(self.id, self.effective_version)
|
|
55
65
|
if self.effective_version is None:
|
|
56
|
-
# make sure we don't see a discarded instance of a live TableVersion
|
|
57
66
|
tvs = list(Catalog.get()._tbl_versions.values())
|
|
58
67
|
assert self._tbl_version in tvs
|
|
59
68
|
return self._tbl_version
|
|
@@ -64,3 +73,25 @@ class TableVersionHandle:
|
|
|
64
73
|
@classmethod
|
|
65
74
|
def from_dict(cls, d: dict) -> TableVersionHandle:
|
|
66
75
|
return cls(UUID(d['id']), d['effective_version'])
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass(frozen=True)
|
|
79
|
+
class ColumnHandle:
|
|
80
|
+
tbl_version: TableVersionHandle
|
|
81
|
+
col_id: int
|
|
82
|
+
|
|
83
|
+
def get(self) -> 'Column':
|
|
84
|
+
if self.col_id not in self.tbl_version.get().cols_by_id:
|
|
85
|
+
schema_version_drop = self.tbl_version.get()._tbl_md.column_md[self.col_id].schema_version_drop
|
|
86
|
+
raise excs.Error(
|
|
87
|
+
f'Column was dropped (no record for column ID {self.col_id} in table '
|
|
88
|
+
f'{self.tbl_version.get().versioned_name!r}; it was dropped in table version {schema_version_drop})'
|
|
89
|
+
)
|
|
90
|
+
return self.tbl_version.get().cols_by_id[self.col_id]
|
|
91
|
+
|
|
92
|
+
def as_dict(self) -> dict:
|
|
93
|
+
return {'tbl_version': self.tbl_version.as_dict(), 'col_id': self.col_id}
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def from_dict(cls, d: dict) -> ColumnHandle:
|
|
97
|
+
return cls(tbl_version=TableVersionHandle.from_dict(d['tbl_version']), col_id=d['col_id'])
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Optional
|
|
5
4
|
from uuid import UUID
|
|
6
5
|
|
|
7
6
|
from pixeltable.env import Env
|
|
8
7
|
from pixeltable.metadata import schema
|
|
9
8
|
|
|
10
9
|
from .column import Column
|
|
10
|
+
from .globals import MediaValidation
|
|
11
11
|
from .table_version import TableVersion
|
|
12
12
|
from .table_version_handle import TableVersionHandle
|
|
13
13
|
|
|
@@ -38,10 +38,10 @@ class TableVersionPath:
|
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
tbl_version: TableVersionHandle
|
|
41
|
-
base:
|
|
42
|
-
_cached_tbl_version:
|
|
41
|
+
base: TableVersionPath | None
|
|
42
|
+
_cached_tbl_version: TableVersion | None
|
|
43
43
|
|
|
44
|
-
def __init__(self, tbl_version: TableVersionHandle, base:
|
|
44
|
+
def __init__(self, tbl_version: TableVersionHandle, base: TableVersionPath | None = None):
|
|
45
45
|
assert tbl_version is not None
|
|
46
46
|
self.tbl_version = tbl_version
|
|
47
47
|
self.base = base
|
|
@@ -50,7 +50,7 @@ class TableVersionPath:
|
|
|
50
50
|
@classmethod
|
|
51
51
|
def from_md(cls, path: schema.TableVersionPath) -> TableVersionPath:
|
|
52
52
|
assert len(path) > 0
|
|
53
|
-
result:
|
|
53
|
+
result: TableVersionPath | None = None
|
|
54
54
|
for tbl_id_str, effective_version in path[::-1]:
|
|
55
55
|
tbl_id = UUID(tbl_id_str)
|
|
56
56
|
result = TableVersionPath(TableVersionHandle(tbl_id, effective_version), base=result)
|
|
@@ -75,7 +75,7 @@ class TableVersionPath:
|
|
|
75
75
|
elif self._cached_tbl_version is not None:
|
|
76
76
|
return
|
|
77
77
|
|
|
78
|
-
with Catalog.get().begin_xact(for_write=False):
|
|
78
|
+
with Catalog.get().begin_xact(tbl_id=self.tbl_version.id, for_write=False):
|
|
79
79
|
self._cached_tbl_version = self.tbl_version.get()
|
|
80
80
|
|
|
81
81
|
def clear_cached_md(self) -> None:
|
|
@@ -83,6 +83,7 @@ class TableVersionPath:
|
|
|
83
83
|
if self.base is not None:
|
|
84
84
|
self.base.clear_cached_md()
|
|
85
85
|
|
|
86
|
+
@property
|
|
86
87
|
def tbl_id(self) -> UUID:
|
|
87
88
|
"""Return the id of the table/view that this path represents"""
|
|
88
89
|
return self.tbl_version.id
|
|
@@ -92,6 +93,11 @@ class TableVersionPath:
|
|
|
92
93
|
self.refresh_cached_md()
|
|
93
94
|
return self._cached_tbl_version.version
|
|
94
95
|
|
|
96
|
+
def schema_version(self) -> int:
|
|
97
|
+
"""Return the version of the table/view that this path represents"""
|
|
98
|
+
self.refresh_cached_md()
|
|
99
|
+
return self._cached_tbl_version.schema_version
|
|
100
|
+
|
|
95
101
|
def tbl_name(self) -> str:
|
|
96
102
|
"""Return the name of the table/view that this path represents"""
|
|
97
103
|
self.refresh_cached_md()
|
|
@@ -103,10 +109,7 @@ class TableVersionPath:
|
|
|
103
109
|
|
|
104
110
|
def is_snapshot(self) -> bool:
|
|
105
111
|
"""Return True if this is a path of snapshot versions"""
|
|
106
|
-
self.
|
|
107
|
-
if not self._cached_tbl_version.is_snapshot:
|
|
108
|
-
return False
|
|
109
|
-
return self.base.is_snapshot() if self.base is not None else True
|
|
112
|
+
return self.tbl_version.is_snapshot
|
|
110
113
|
|
|
111
114
|
def is_view(self) -> bool:
|
|
112
115
|
self.refresh_cached_md()
|
|
@@ -116,10 +119,30 @@ class TableVersionPath:
|
|
|
116
119
|
self.refresh_cached_md()
|
|
117
120
|
return self._cached_tbl_version.is_component_view
|
|
118
121
|
|
|
122
|
+
def is_replica(self) -> bool:
|
|
123
|
+
self.refresh_cached_md()
|
|
124
|
+
return self._cached_tbl_version.is_replica
|
|
125
|
+
|
|
126
|
+
def is_mutable(self) -> bool:
|
|
127
|
+
self.refresh_cached_md()
|
|
128
|
+
return self._cached_tbl_version.is_mutable
|
|
129
|
+
|
|
119
130
|
def is_insertable(self) -> bool:
|
|
120
131
|
self.refresh_cached_md()
|
|
121
132
|
return self._cached_tbl_version.is_insertable
|
|
122
133
|
|
|
134
|
+
def comment(self) -> str:
|
|
135
|
+
self.refresh_cached_md()
|
|
136
|
+
return self._cached_tbl_version.comment
|
|
137
|
+
|
|
138
|
+
def num_retained_versions(self) -> int:
|
|
139
|
+
self.refresh_cached_md()
|
|
140
|
+
return self._cached_tbl_version.num_retained_versions
|
|
141
|
+
|
|
142
|
+
def media_validation(self) -> MediaValidation:
|
|
143
|
+
self.refresh_cached_md()
|
|
144
|
+
return self._cached_tbl_version.media_validation
|
|
145
|
+
|
|
123
146
|
def get_tbl_versions(self) -> list[TableVersionHandle]:
|
|
124
147
|
"""Return all tbl versions"""
|
|
125
148
|
if self.base is None:
|
|
@@ -132,7 +155,7 @@ class TableVersionPath:
|
|
|
132
155
|
return []
|
|
133
156
|
return self.base.get_tbl_versions()
|
|
134
157
|
|
|
135
|
-
def find_tbl_version(self, id: UUID) ->
|
|
158
|
+
def find_tbl_version(self, id: UUID) -> TableVersionHandle | None:
|
|
136
159
|
"""Return the matching TableVersion in the chain of TableVersions, starting with this one"""
|
|
137
160
|
if self.tbl_version.id == id:
|
|
138
161
|
return self.tbl_version
|
|
@@ -160,40 +183,30 @@ class TableVersionPath:
|
|
|
160
183
|
cols = self.columns()
|
|
161
184
|
return {col.id: col for col in cols}
|
|
162
185
|
|
|
163
|
-
def get_column(self, name: str
|
|
186
|
+
def get_column(self, name: str) -> Column | None:
|
|
164
187
|
"""Return the column with the given name, or None if not found"""
|
|
165
188
|
self.refresh_cached_md()
|
|
166
189
|
col = self._cached_tbl_version.cols_by_name.get(name)
|
|
167
190
|
if col is not None:
|
|
168
191
|
return col
|
|
169
|
-
elif self.base is not None and
|
|
192
|
+
elif self.base is not None and self._cached_tbl_version.include_base_columns:
|
|
170
193
|
return self.base.get_column(name)
|
|
171
194
|
else:
|
|
172
195
|
return None
|
|
173
196
|
|
|
174
|
-
def
|
|
175
|
-
"""Return the column for the given tbl/col id"""
|
|
176
|
-
self.refresh_cached_md()
|
|
177
|
-
if self.tbl_version.id == tbl_id:
|
|
178
|
-
assert col_id in self._cached_tbl_version.cols_by_id
|
|
179
|
-
return self._cached_tbl_version.cols_by_id[col_id]
|
|
180
|
-
elif self.base is not None:
|
|
181
|
-
return self.base.get_column_by_id(tbl_id, col_id)
|
|
182
|
-
else:
|
|
183
|
-
return None
|
|
184
|
-
|
|
185
|
-
def has_column(self, col: Column, include_bases: bool = True) -> bool:
|
|
197
|
+
def has_column(self, col: Column) -> bool:
|
|
186
198
|
"""Return True if this table has the given column."""
|
|
199
|
+
assert col.get_tbl() is not None
|
|
187
200
|
self.refresh_cached_md()
|
|
188
|
-
|
|
201
|
+
|
|
189
202
|
if (
|
|
190
|
-
col.
|
|
191
|
-
and col.
|
|
203
|
+
col.get_tbl().id == self.tbl_version.id
|
|
204
|
+
and col.get_tbl().effective_version == self.tbl_version.effective_version
|
|
192
205
|
and col.id in self._cached_tbl_version.cols_by_id
|
|
193
206
|
):
|
|
194
207
|
# the column is visible in this table version
|
|
195
208
|
return True
|
|
196
|
-
elif self.base is not None
|
|
209
|
+
elif self.base is not None:
|
|
197
210
|
return self.base.has_column(col)
|
|
198
211
|
else:
|
|
199
212
|
return False
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# This file contains all dataclasses related to schema.PendingTableOp:
|
|
2
|
+
# - TableOp: the container for each log entry
|
|
3
|
+
# - <>Op: the actual operation, which is performed by TableVersion.exec_op(); each <>Op class contains
|
|
4
|
+
# enough information for exec_op() to perform the operation without having to reference data outside of
|
|
5
|
+
# TableVersion
|
|
6
|
+
|
|
7
|
+
import dataclasses
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclasses.dataclass
|
|
12
|
+
class CreateStoreTableOp:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclasses.dataclass
|
|
17
|
+
class CreateIndexOp:
|
|
18
|
+
idx_id: int
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclasses.dataclass
|
|
22
|
+
class LoadViewOp:
|
|
23
|
+
view_path: dict[str, Any] # needed to create the view load plan
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclasses.dataclass
|
|
27
|
+
class DeleteTableMdOp:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclasses.dataclass
|
|
32
|
+
class DeleteTableMediaFilesOp:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclasses.dataclass
|
|
37
|
+
class DropStoreTableOp:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclasses.dataclass
|
|
42
|
+
class TableOp:
|
|
43
|
+
tbl_id: str # uuid.UUID
|
|
44
|
+
op_sn: int # sequence number within the update operation; [0, num_ops)
|
|
45
|
+
num_ops: int # total number of ops forming the update operation
|
|
46
|
+
needs_xact: bool # if True, op must be run as part of a transaction
|
|
47
|
+
|
|
48
|
+
create_store_table_op: CreateStoreTableOp | None = None
|
|
49
|
+
create_index_op: CreateIndexOp | None = None
|
|
50
|
+
load_view_op: LoadViewOp | None = None
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from IPython.lib.pretty import RepresentationPrinter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class RowCountStats:
|
|
12
|
+
"""
|
|
13
|
+
Statistics about the counts of rows affected by a table operation.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
ins_rows: int = 0 # rows inserted
|
|
17
|
+
del_rows: int = 0 # rows deleted
|
|
18
|
+
upd_rows: int = 0 # rows updated
|
|
19
|
+
num_excs: int = 0 # total number of exceptions
|
|
20
|
+
# TODO: disambiguate what this means: # of slots computed or # of columns computed?
|
|
21
|
+
computed_values: int = 0 # number of computed values (e.g., computed columns) affected by the operation
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def num_rows(self) -> int:
|
|
25
|
+
return self.ins_rows + self.del_rows + self.upd_rows
|
|
26
|
+
|
|
27
|
+
def insert_to_update(self) -> 'RowCountStats':
|
|
28
|
+
"""
|
|
29
|
+
Convert insert row count stats to update row count stats.
|
|
30
|
+
This is used when an insert operation is treated as an update.
|
|
31
|
+
"""
|
|
32
|
+
return RowCountStats(
|
|
33
|
+
ins_rows=0,
|
|
34
|
+
del_rows=self.del_rows,
|
|
35
|
+
upd_rows=self.upd_rows + self.ins_rows,
|
|
36
|
+
num_excs=self.num_excs,
|
|
37
|
+
computed_values=self.computed_values,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def __add__(self, other: 'RowCountStats') -> 'RowCountStats':
|
|
41
|
+
"""
|
|
42
|
+
Add the stats from two RowCountStats objects together.
|
|
43
|
+
"""
|
|
44
|
+
return RowCountStats(
|
|
45
|
+
ins_rows=self.ins_rows + other.ins_rows,
|
|
46
|
+
del_rows=self.del_rows + other.del_rows,
|
|
47
|
+
upd_rows=self.upd_rows + other.upd_rows,
|
|
48
|
+
num_excs=self.num_excs + other.num_excs,
|
|
49
|
+
computed_values=self.computed_values + other.computed_values,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class UpdateStatus:
|
|
55
|
+
"""
|
|
56
|
+
Information about changes to table data or table schema
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
updated_cols: list[str] = field(default_factory=list)
|
|
60
|
+
"""Columns that were updated."""
|
|
61
|
+
cols_with_excs: list[str] = field(default_factory=list)
|
|
62
|
+
"""Columns that encountered exceptions."""
|
|
63
|
+
|
|
64
|
+
# stats for the rows affected by the operation
|
|
65
|
+
row_count_stats: RowCountStats = field(default_factory=RowCountStats)
|
|
66
|
+
"""Row count statistics for rows affected by this operation."""
|
|
67
|
+
|
|
68
|
+
# stats for changes cascaded to other tables
|
|
69
|
+
cascade_row_count_stats: RowCountStats = field(default_factory=RowCountStats)
|
|
70
|
+
"""Row count statistics for changes cascaded to other tables."""
|
|
71
|
+
|
|
72
|
+
# stats for the rows affected by the operation in an external store
|
|
73
|
+
ext_row_count_stats: RowCountStats = field(default_factory=RowCountStats)
|
|
74
|
+
"""Row count statistics for rows affected in an external store."""
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def num_rows(self) -> int:
|
|
78
|
+
"""Total number of rows affected (including cascaded changes)."""
|
|
79
|
+
return self.row_count_stats.num_rows + self.cascade_row_count_stats.num_rows
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def num_excs(self) -> int:
|
|
83
|
+
"""Total number of exceptions encountered (including cascaded changes)."""
|
|
84
|
+
return self.row_count_stats.num_excs + self.cascade_row_count_stats.num_excs
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def num_computed_values(self) -> int:
|
|
88
|
+
"""Total number of computed values affected (including cascaded changes)."""
|
|
89
|
+
return self.row_count_stats.computed_values + self.cascade_row_count_stats.computed_values
|
|
90
|
+
|
|
91
|
+
def insert_to_update(self) -> 'UpdateStatus':
|
|
92
|
+
"""
|
|
93
|
+
Convert the update status from an insert operation to an update operation.
|
|
94
|
+
This is used when an insert operation is treated as an update.
|
|
95
|
+
"""
|
|
96
|
+
return UpdateStatus(
|
|
97
|
+
updated_cols=self.updated_cols,
|
|
98
|
+
cols_with_excs=self.cols_with_excs,
|
|
99
|
+
row_count_stats=self.row_count_stats.insert_to_update(),
|
|
100
|
+
cascade_row_count_stats=self.cascade_row_count_stats.insert_to_update(),
|
|
101
|
+
ext_row_count_stats=self.ext_row_count_stats,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def to_cascade(self) -> 'UpdateStatus':
|
|
105
|
+
"""
|
|
106
|
+
Convert the update status to a cascade update status.
|
|
107
|
+
This is used when an operation cascades changes to other tables.
|
|
108
|
+
"""
|
|
109
|
+
return UpdateStatus(
|
|
110
|
+
updated_cols=self.updated_cols,
|
|
111
|
+
cols_with_excs=self.cols_with_excs,
|
|
112
|
+
row_count_stats=RowCountStats(),
|
|
113
|
+
cascade_row_count_stats=self.cascade_row_count_stats + self.row_count_stats,
|
|
114
|
+
ext_row_count_stats=self.ext_row_count_stats,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def __add__(self, other: 'UpdateStatus') -> UpdateStatus:
|
|
118
|
+
"""
|
|
119
|
+
Add the update status from two UpdateStatus objects together.
|
|
120
|
+
"""
|
|
121
|
+
return UpdateStatus(
|
|
122
|
+
updated_cols=list(dict.fromkeys(self.updated_cols + other.updated_cols)),
|
|
123
|
+
cols_with_excs=list(dict.fromkeys(self.cols_with_excs + other.cols_with_excs)),
|
|
124
|
+
row_count_stats=self.row_count_stats + other.row_count_stats,
|
|
125
|
+
cascade_row_count_stats=self.cascade_row_count_stats + other.cascade_row_count_stats,
|
|
126
|
+
ext_row_count_stats=self.ext_row_count_stats + other.ext_row_count_stats,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def insert_msg(self) -> str:
|
|
131
|
+
"""Return a message describing the results of an insert operation."""
|
|
132
|
+
if self.num_excs == 0:
|
|
133
|
+
cols_with_excs_str = ''
|
|
134
|
+
else:
|
|
135
|
+
cols_with_excs_str = (
|
|
136
|
+
f' across {len(self.cols_with_excs)} column{"" if len(self.cols_with_excs) == 1 else "s"}'
|
|
137
|
+
)
|
|
138
|
+
cols_with_excs_str += f' ({", ".join(self.cols_with_excs)})'
|
|
139
|
+
msg = (
|
|
140
|
+
f'Inserted {self.num_rows} row{"" if self.num_rows == 1 else "s"} '
|
|
141
|
+
f'with {self.num_excs} error{"" if self.num_excs == 1 else "s"}{cols_with_excs_str}.'
|
|
142
|
+
)
|
|
143
|
+
return msg
|
|
144
|
+
|
|
145
|
+
@classmethod
|
|
146
|
+
def __cnt_str(cls, cnt: int, item: str) -> str:
|
|
147
|
+
assert cnt > 0
|
|
148
|
+
return f'{cnt} {item}{"" if cnt == 1 else "s"}'
|
|
149
|
+
|
|
150
|
+
def _repr_pretty_(self, p: 'RepresentationPrinter', cycle: bool) -> None:
|
|
151
|
+
messages = []
|
|
152
|
+
# Combine row count stats and cascade row count stats
|
|
153
|
+
stats = self.row_count_stats + self.cascade_row_count_stats
|
|
154
|
+
if stats.ins_rows > 0:
|
|
155
|
+
messages.append(f'{self.__cnt_str(stats.ins_rows, "row")} inserted')
|
|
156
|
+
if stats.del_rows > 0:
|
|
157
|
+
messages.append(f'{self.__cnt_str(stats.del_rows, "row")} deleted')
|
|
158
|
+
if stats.upd_rows > 0:
|
|
159
|
+
messages.append(f'{self.__cnt_str(stats.upd_rows, "row")} updated')
|
|
160
|
+
if stats.computed_values > 0:
|
|
161
|
+
messages.append(f'{self.__cnt_str(stats.computed_values, "value")} computed')
|
|
162
|
+
if stats.num_excs > 0:
|
|
163
|
+
messages.append(self.__cnt_str(stats.num_excs, 'exception'))
|
|
164
|
+
p.text(', '.join(messages) + '.' if len(messages) > 0 else 'No rows affected.')
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def pxt_rows_updated(self) -> int:
|
|
168
|
+
"""
|
|
169
|
+
Returns the number of Pixeltable rows that were updated as a result of the operation.
|
|
170
|
+
"""
|
|
171
|
+
return (self.row_count_stats + self.cascade_row_count_stats).upd_rows
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def external_rows_updated(self) -> int:
|
|
175
|
+
"""Number of rows updated in an external store."""
|
|
176
|
+
return self.ext_row_count_stats.upd_rows
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def external_rows_created(self) -> int:
|
|
180
|
+
"""Number of rows created in an external store."""
|
|
181
|
+
return self.ext_row_count_stats.ins_rows
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def external_rows_deleted(self) -> int:
|
|
185
|
+
"""Number of rows deleted from an external store."""
|
|
186
|
+
return self.ext_row_count_stats.del_rows
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def ext_num_rows(self) -> int:
|
|
190
|
+
"""Total number of rows affected in an external store."""
|
|
191
|
+
return self.ext_row_count_stats.num_rows
|