pixeltable 0.2.9__tar.gz → 0.2.11__tar.gz
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-0.2.9 → pixeltable-0.2.11}/PKG-INFO +2 -2
- {pixeltable-0.2.9 → pixeltable-0.2.11}/README.md +1 -1
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/__version__.py +2 -2
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/catalog.py +3 -3
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/globals.py +2 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/insertable_table.py +1 -11
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table.py +13 -72
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table_version.py +94 -29
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table_version_path.py +1 -1
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/view.py +31 -27
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/dataframe.py +32 -115
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/whisper.py +0 -4
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/globals.py +19 -6
- pixeltable-0.2.11/pixeltable/utils/formatter.py +234 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pyproject.toml +1 -1
- {pixeltable-0.2.9 → pixeltable-0.2.11}/LICENSE +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/column.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/dir.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/named_function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/path.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/path_dict.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/schema_object.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/env.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exceptions.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/aggregation_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/cache_prefetch_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/component_iteration_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/data_row_batch.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/exec_context.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/exec_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/expr_eval_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/in_memory_data_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/media_validation_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/sql_scan_node.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/arithmetic_expr.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/array_slice.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/column_property_ref.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/column_ref.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/comparison.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/compound_predicate.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/data_row.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/expr.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/expr_set.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/function_call.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/globals.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/image_member_access.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/in_predicate.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/inline_array.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/inline_dict.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/is_null.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/json_mapper.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/json_path.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/literal.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/object_ref.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/predicate.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/row_builder.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/rowid_ref.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/similarity_expr.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/type_cast.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/variable.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/functions/whisperx.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/functions/yolox.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/aggregate_function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/callable_function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/expr_template_function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/function_registry.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/globals.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/query_template_function.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/signature.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/udf.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/eval.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/fireworks.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/globals.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/huggingface.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/image.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/openai.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/string.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/together.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/util.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/video.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/base.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/btree.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/embedding_index.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/external_store.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/globals.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/hf_datasets.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/label_studio.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/pandas.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/parquet.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/base.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/document.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/string.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/video.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_10.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_12.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_13.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_14.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_15.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_16.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/util.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/schema.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/plan.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/store.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/create_test_db_dump.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/create_test_video.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/embed_udf.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/type_system.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/__init__.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/arrow.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/coco.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/code.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/documents.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/filecache.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/help.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/http_server.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/media_store.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/pytorch.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/s3.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/sql.py +0 -0
- {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/transactional_directory.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pixeltable
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.11
|
|
4
4
|
Summary: Pixeltable: The Multimodal AI Data Plane
|
|
5
5
|
Author: Marcel Kornacker
|
|
6
6
|
Author-email: marcelk@gmail.com
|
|
@@ -75,7 +75,7 @@ Learn how to create tables, populate them with data, and enhance them with built
|
|
|
75
75
|
|
|
76
76
|
| Topic | Notebook | API |
|
|
77
77
|
|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|
|
78
|
-
| Get Started | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/tutorials/pixeltable-basics.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/pixeltable/) |
|
|
78
|
+
| Get Started | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/pixeltable-basics.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/pixeltable/) |
|
|
79
79
|
| User-Defined Functions (UDFs) | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/howto/udfs-in-pixeltable.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/iterators/document-splitter/) |
|
|
80
80
|
| Comparing Object Detection Models | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/object-detection-in-videos.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api-cheat-sheet/#frame-extraction-for-video-data) |
|
|
81
81
|
| Experimenting with Chunking (RAG) | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/rag-operations.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> | [](https://pixeltable.github.io/pixeltable/api/iterators/document-splitter/) |
|
|
@@ -38,7 +38,7 @@ Learn how to create tables, populate them with data, and enhance them with built
|
|
|
38
38
|
|
|
39
39
|
| Topic | Notebook | API |
|
|
40
40
|
|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|
|
41
|
-
| Get Started | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/tutorials/pixeltable-basics.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/pixeltable/) |
|
|
41
|
+
| Get Started | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/pixeltable-basics.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/pixeltable/) |
|
|
42
42
|
| User-Defined Functions (UDFs) | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/howto/udfs-in-pixeltable.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api/iterators/document-splitter/) |
|
|
43
43
|
| Comparing Object Detection Models | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/object-detection-in-videos.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> </a> | [](https://pixeltable.github.io/pixeltable/api-cheat-sheet/#frame-extraction-for-video-data) |
|
|
44
44
|
| Experimenting with Chunking (RAG) | <a target="_blank" href="https://colab.research.google.com/github/pixeltable/pixeltable/blob/master/docs/release/tutorials/rag-operations.ipynb"> <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> | [](https://pixeltable.github.io/pixeltable/api/iterators/document-splitter/) |
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# These version placeholders will be replaced during build.
|
|
2
|
-
__version__ = "0.2.
|
|
3
|
-
__version_tuple__ = (0, 2,
|
|
2
|
+
__version__ = "0.2.11"
|
|
3
|
+
__version_tuple__ = (0, 2, 11)
|
|
@@ -120,7 +120,7 @@ class Catalog:
|
|
|
120
120
|
base = base_version
|
|
121
121
|
assert base_path is not None
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
base_tbl_id = base_path.tbl_id()
|
|
124
124
|
is_snapshot = view_md is not None and view_md.is_snapshot
|
|
125
125
|
snapshot_only = is_snapshot and view_md.predicate is None and len(schema_version_md.columns) == 0
|
|
126
126
|
if snapshot_only:
|
|
@@ -134,9 +134,9 @@ class Catalog:
|
|
|
134
134
|
view_path = TableVersionPath(tbl_version, base=base_path)
|
|
135
135
|
|
|
136
136
|
tbl = View(
|
|
137
|
-
tbl_record.id, tbl_record.dir_id, tbl_md.name, view_path,
|
|
137
|
+
tbl_record.id, tbl_record.dir_id, tbl_md.name, view_path, base_tbl_id,
|
|
138
138
|
snapshot_only=snapshot_only)
|
|
139
|
-
self.tbl_dependents[
|
|
139
|
+
self.tbl_dependents[base_tbl_id].append(tbl)
|
|
140
140
|
|
|
141
141
|
else:
|
|
142
142
|
tbl_version = TableVersion(tbl_record.id, tbl_md, tbl_md.current_version, schema_version_md)
|
|
@@ -144,14 +144,4 @@ class InsertableTable(Table):
|
|
|
144
144
|
|
|
145
145
|
>>> tbl.delete(tbl.a > 5)
|
|
146
146
|
"""
|
|
147
|
-
|
|
148
|
-
from pixeltable.plan import Planner
|
|
149
|
-
if where is not None:
|
|
150
|
-
if not isinstance(where, Predicate):
|
|
151
|
-
raise excs.Error(f"'where' argument must be a Predicate, got {type(where)}")
|
|
152
|
-
analysis_info = Planner.analyze(self._tbl_version_path, where)
|
|
153
|
-
# for now we require that the updated rows can be identified via SQL, rather than via a Python filter
|
|
154
|
-
if analysis_info.filter is not None:
|
|
155
|
-
raise excs.Error(f'Filter {analysis_info.filter} not expressible in SQL')
|
|
156
|
-
|
|
157
|
-
return self.tbl_version.delete(where)
|
|
147
|
+
return self._tbl_version.delete(where=where)
|
|
@@ -19,7 +19,7 @@ import pixeltable.index as index
|
|
|
19
19
|
import pixeltable.metadata.schema as schema
|
|
20
20
|
import pixeltable.type_system as ts
|
|
21
21
|
from .column import Column
|
|
22
|
-
from .globals import is_valid_identifier, is_system_column_name, UpdateStatus
|
|
22
|
+
from .globals import _ROWID_COLUMN_NAME, is_valid_identifier, is_system_column_name, UpdateStatus
|
|
23
23
|
from .schema_object import SchemaObject
|
|
24
24
|
from .table_version import TableVersion
|
|
25
25
|
from .table_version_path import TableVersionPath
|
|
@@ -29,8 +29,6 @@ _logger = logging.getLogger('pixeltable')
|
|
|
29
29
|
class Table(SchemaObject):
|
|
30
30
|
"""Base class for all tabular SchemaObjects."""
|
|
31
31
|
|
|
32
|
-
__ROWID_COLUMN_NAME = '_rowid'
|
|
33
|
-
|
|
34
32
|
def __init__(self, id: UUID, dir_id: UUID, name: str, tbl_version_path: TableVersionPath):
|
|
35
33
|
super().__init__(id, name, dir_id)
|
|
36
34
|
self._is_dropped = False
|
|
@@ -93,7 +91,7 @@ class Table(SchemaObject):
|
|
|
93
91
|
else:
|
|
94
92
|
return catalog.Catalog.get().tbl_dependents[self._get_id()]
|
|
95
93
|
|
|
96
|
-
def
|
|
94
|
+
def _df(self) -> 'pixeltable.dataframe.DataFrame':
|
|
97
95
|
"""Return a DataFrame for this table.
|
|
98
96
|
"""
|
|
99
97
|
# local import: avoid circular imports
|
|
@@ -132,30 +130,30 @@ class Table(SchemaObject):
|
|
|
132
130
|
|
|
133
131
|
def collect(self) -> 'pixeltable.dataframe.DataFrameResultSet':
|
|
134
132
|
"""Return rows from this table."""
|
|
135
|
-
return self.
|
|
133
|
+
return self._df().collect()
|
|
136
134
|
|
|
137
135
|
def show(
|
|
138
136
|
self, *args, **kwargs
|
|
139
137
|
) -> 'pixeltable.dataframe.DataFrameResultSet':
|
|
140
138
|
"""Return rows from this table.
|
|
141
139
|
"""
|
|
142
|
-
return self.
|
|
140
|
+
return self._df().show(*args, **kwargs)
|
|
143
141
|
|
|
144
142
|
def head(
|
|
145
143
|
self, *args, **kwargs
|
|
146
144
|
) -> 'pixeltable.dataframe.DataFrameResultSet':
|
|
147
145
|
"""Return the first n rows inserted into this table."""
|
|
148
|
-
return self.
|
|
146
|
+
return self._df().head(*args, **kwargs)
|
|
149
147
|
|
|
150
148
|
def tail(
|
|
151
149
|
self, *args, **kwargs
|
|
152
150
|
) -> 'pixeltable.dataframe.DataFrameResultSet':
|
|
153
151
|
"""Return the last n rows inserted into this table."""
|
|
154
|
-
return self.
|
|
152
|
+
return self._df().tail(*args, **kwargs)
|
|
155
153
|
|
|
156
154
|
def count(self) -> int:
|
|
157
155
|
"""Return the number of rows in this table."""
|
|
158
|
-
return self.
|
|
156
|
+
return self._df().count()
|
|
159
157
|
|
|
160
158
|
def column_names(self) -> list[str]:
|
|
161
159
|
"""Return the names of the columns in this table."""
|
|
@@ -706,21 +704,8 @@ class Table(SchemaObject):
|
|
|
706
704
|
|
|
707
705
|
>>> tbl.update({'int_col': tbl.int_col + 1}, where=tbl.int_col == 0)
|
|
708
706
|
"""
|
|
709
|
-
if self._tbl_version_path.is_snapshot():
|
|
710
|
-
raise excs.Error('Cannot update a snapshot')
|
|
711
707
|
self._check_is_dropped()
|
|
712
|
-
|
|
713
|
-
update_spec = self._validate_update_spec(value_spec, allow_pk=False, allow_exprs=True)
|
|
714
|
-
from pixeltable.plan import Planner
|
|
715
|
-
if where is not None:
|
|
716
|
-
if not isinstance(where, exprs.Predicate):
|
|
717
|
-
raise excs.Error(f"'where' argument must be a Predicate, got {type(where)}")
|
|
718
|
-
analysis_info = Planner.analyze(self._tbl_version_path, where)
|
|
719
|
-
# for now we require that the updated rows can be identified via SQL, rather than via a Python filter
|
|
720
|
-
if analysis_info.filter is not None:
|
|
721
|
-
raise excs.Error(f'Filter {analysis_info.filter} not expressible in SQL')
|
|
722
|
-
|
|
723
|
-
return self._tbl_version.update(update_spec, where, cascade)
|
|
708
|
+
return self._tbl_version.update(value_spec, where, cascade)
|
|
724
709
|
|
|
725
710
|
def batch_update(self, rows: Iterable[dict[str, Any]], cascade: bool = True) -> UpdateStatus:
|
|
726
711
|
"""Update rows in this table.
|
|
@@ -738,22 +723,23 @@ class Table(SchemaObject):
|
|
|
738
723
|
if self._tbl_version_path.is_snapshot():
|
|
739
724
|
raise excs.Error('Cannot update a snapshot')
|
|
740
725
|
self._check_is_dropped()
|
|
726
|
+
rows = list(rows)
|
|
741
727
|
|
|
742
728
|
row_updates: list[dict[Column, exprs.Expr]] = []
|
|
743
729
|
pk_col_names = set(c.name for c in self._tbl_version.primary_key_columns())
|
|
744
730
|
|
|
745
731
|
# pseudo-column _rowid: contains the rowid of the row to update and can be used instead of the primary key
|
|
746
|
-
has_rowid =
|
|
732
|
+
has_rowid = _ROWID_COLUMN_NAME in rows[0]
|
|
747
733
|
rowids: list[Tuple[int, ...]] = []
|
|
748
734
|
if len(pk_col_names) == 0 and not has_rowid:
|
|
749
735
|
raise excs.Error('Table must have primary key for batch update')
|
|
750
736
|
|
|
751
737
|
for row_spec in rows:
|
|
752
|
-
col_vals = self._validate_update_spec(row_spec, allow_pk=not has_rowid, allow_exprs=False)
|
|
738
|
+
col_vals = self._tbl_version._validate_update_spec(row_spec, allow_pk=not has_rowid, allow_exprs=False)
|
|
753
739
|
if has_rowid:
|
|
754
740
|
# we expect the _rowid column to be present for each row
|
|
755
|
-
assert
|
|
756
|
-
rowids.append(row_spec[
|
|
741
|
+
assert _ROWID_COLUMN_NAME in row_spec
|
|
742
|
+
rowids.append(row_spec[_ROWID_COLUMN_NAME])
|
|
757
743
|
else:
|
|
758
744
|
col_names = set(col.name for col in col_vals.keys())
|
|
759
745
|
if any(pk_col_name not in col_names for pk_col_name in pk_col_names):
|
|
@@ -762,51 +748,6 @@ class Table(SchemaObject):
|
|
|
762
748
|
row_updates.append(col_vals)
|
|
763
749
|
return self._tbl_version.batch_update(row_updates, rowids, cascade)
|
|
764
750
|
|
|
765
|
-
def _validate_update_spec(
|
|
766
|
-
self, value_spec: dict[str, Any], allow_pk: bool, allow_exprs: bool
|
|
767
|
-
) -> dict[Column, 'pixeltable.exprs.Expr']:
|
|
768
|
-
from pixeltable import exprs
|
|
769
|
-
update_targets: dict[Column, exprs.Expr] = {}
|
|
770
|
-
for col_name, val in value_spec.items():
|
|
771
|
-
if not isinstance(col_name, str):
|
|
772
|
-
raise excs.Error(f'Update specification: dict key must be column name, got {col_name!r}')
|
|
773
|
-
if col_name == self.__ROWID_COLUMN_NAME:
|
|
774
|
-
# ignore pseudo-column _rowid
|
|
775
|
-
continue
|
|
776
|
-
col = self._tbl_version_path.get_column(col_name, include_bases=False)
|
|
777
|
-
if col is None:
|
|
778
|
-
# TODO: return more informative error if this is trying to update a base column
|
|
779
|
-
raise excs.Error(f'Column {col_name} unknown')
|
|
780
|
-
if col.is_computed:
|
|
781
|
-
raise excs.Error(f'Column {col_name} is computed and cannot be updated')
|
|
782
|
-
if col.is_pk and not allow_pk:
|
|
783
|
-
raise excs.Error(f'Column {col_name} is a primary key column and cannot be updated')
|
|
784
|
-
if col.col_type.is_media_type():
|
|
785
|
-
raise excs.Error(f'Column {col_name} has type image/video/audio/document and cannot be updated')
|
|
786
|
-
|
|
787
|
-
# make sure that the value is compatible with the column type
|
|
788
|
-
try:
|
|
789
|
-
# check if this is a literal
|
|
790
|
-
value_expr = exprs.Literal(val, col_type=col.col_type)
|
|
791
|
-
except TypeError:
|
|
792
|
-
if not allow_exprs:
|
|
793
|
-
raise excs.Error(
|
|
794
|
-
f'Column {col_name}: value {val!r} is not a valid literal for this column '
|
|
795
|
-
f'(expected {col.col_type})')
|
|
796
|
-
# it's not a literal, let's try to create an expr from it
|
|
797
|
-
value_expr = exprs.Expr.from_object(val)
|
|
798
|
-
if value_expr is None:
|
|
799
|
-
raise excs.Error(f'Column {col_name}: value {val!r} is not a recognized literal or expression')
|
|
800
|
-
if not col.col_type.matches(value_expr.col_type):
|
|
801
|
-
raise excs.Error((
|
|
802
|
-
f'Type of value {val!r} ({value_expr.col_type}) is not compatible with the type of column '
|
|
803
|
-
f'{col_name} ({col.col_type})'
|
|
804
|
-
))
|
|
805
|
-
update_targets[col] = value_expr
|
|
806
|
-
|
|
807
|
-
return update_targets
|
|
808
|
-
|
|
809
|
-
@abc.abstractmethod
|
|
810
751
|
def delete(self, where: Optional['pixeltable.exprs.Predicate'] = None) -> UpdateStatus:
|
|
811
752
|
"""Delete rows in this table.
|
|
812
753
|
|
|
@@ -5,29 +5,31 @@ import importlib
|
|
|
5
5
|
import inspect
|
|
6
6
|
import logging
|
|
7
7
|
import time
|
|
8
|
-
from typing import Optional, List, Dict, Any, Tuple, Type, Set, Iterable
|
|
9
8
|
import uuid
|
|
9
|
+
from typing import Optional, List, Dict, Any, Tuple, Type, Iterable
|
|
10
10
|
from uuid import UUID
|
|
11
11
|
|
|
12
12
|
import sqlalchemy as sql
|
|
13
13
|
import sqlalchemy.orm as orm
|
|
14
14
|
|
|
15
15
|
import pixeltable
|
|
16
|
-
import pixeltable.func as func
|
|
17
|
-
import pixeltable.type_system as ts
|
|
18
16
|
import pixeltable.exceptions as excs
|
|
17
|
+
import pixeltable.exprs as exprs
|
|
18
|
+
import pixeltable.func as func
|
|
19
19
|
import pixeltable.index as index
|
|
20
|
+
import pixeltable.type_system as ts
|
|
20
21
|
from pixeltable.env import Env
|
|
21
22
|
from pixeltable.iterators import ComponentIterator
|
|
22
23
|
from pixeltable.metadata import schema
|
|
23
24
|
from pixeltable.utils.filecache import FileCache
|
|
24
25
|
from pixeltable.utils.media_store import MediaStore
|
|
25
26
|
from .column import Column
|
|
26
|
-
from .globals import UpdateStatus, POS_COLUMN_NAME, is_valid_identifier
|
|
27
|
+
from .globals import UpdateStatus, POS_COLUMN_NAME, is_valid_identifier, _ROWID_COLUMN_NAME
|
|
27
28
|
from ..func.globals import resolve_symbol
|
|
28
29
|
|
|
29
30
|
_logger = logging.getLogger('pixeltable')
|
|
30
31
|
|
|
32
|
+
|
|
31
33
|
class TableVersion:
|
|
32
34
|
"""
|
|
33
35
|
TableVersion represents a particular version of a table/view along with its physical representation:
|
|
@@ -243,7 +245,6 @@ class TableVersion:
|
|
|
243
245
|
def _init_cols(self, tbl_md: schema.TableMd, schema_version_md: schema.TableSchemaVersionMd) -> None:
|
|
244
246
|
"""Initialize self.cols with the columns visible in our effective version"""
|
|
245
247
|
import pixeltable.exprs as exprs
|
|
246
|
-
from pixeltable.catalog import Catalog
|
|
247
248
|
|
|
248
249
|
self.cols = []
|
|
249
250
|
self.cols_by_name = {}
|
|
@@ -704,15 +705,34 @@ class TableVersion:
|
|
|
704
705
|
return result
|
|
705
706
|
|
|
706
707
|
def update(
|
|
707
|
-
|
|
708
|
-
where_clause: Optional['pixeltable.exprs.Predicate'] = None, cascade: bool = True
|
|
708
|
+
self, value_spec: dict[str, Any], where: Optional['exprs.Predicate'] = None, cascade: bool = True
|
|
709
709
|
) -> UpdateStatus:
|
|
710
|
+
"""Update rows in this TableVersionPath.
|
|
711
|
+
Args:
|
|
712
|
+
value_spec: a list of (column, value) pairs specifying the columns to update and their new values.
|
|
713
|
+
where: a Predicate to filter rows to update.
|
|
714
|
+
cascade: if True, also update all computed columns that transitively depend on the updated columns,
|
|
715
|
+
including within views.
|
|
716
|
+
"""
|
|
717
|
+
if self.is_snapshot:
|
|
718
|
+
raise excs.Error('Cannot update a snapshot')
|
|
719
|
+
|
|
720
|
+
from pixeltable.plan import Planner
|
|
721
|
+
|
|
722
|
+
update_spec = self._validate_update_spec(value_spec, allow_pk=False, allow_exprs=True)
|
|
723
|
+
if where is not None:
|
|
724
|
+
if not isinstance(where, exprs.Predicate):
|
|
725
|
+
raise excs.Error(f"'where' argument must be a Predicate, got {type(where)}")
|
|
726
|
+
analysis_info = Planner.analyze(self.path, where)
|
|
727
|
+
# for now we require that the updated rows can be identified via SQL, rather than via a Python filter
|
|
728
|
+
if analysis_info.filter is not None:
|
|
729
|
+
raise excs.Error(f'Filter {analysis_info.filter} not expressible in SQL')
|
|
730
|
+
|
|
710
731
|
with Env.get().engine.begin() as conn:
|
|
711
|
-
return self._update(conn,
|
|
732
|
+
return self._update(conn, update_spec, where, cascade)
|
|
712
733
|
|
|
713
734
|
def batch_update(
|
|
714
|
-
self, batch: list[dict[Column, '
|
|
715
|
-
cascade: bool = True
|
|
735
|
+
self, batch: list[dict[Column, 'exprs.Expr']], rowids: list[tuple[int, ...]], cascade: bool = True
|
|
716
736
|
) -> UpdateStatus:
|
|
717
737
|
"""Update rows in batch.
|
|
718
738
|
Args:
|
|
@@ -721,7 +741,6 @@ class TableVersion:
|
|
|
721
741
|
"""
|
|
722
742
|
# if we do lookups of rowids, we must have one for each row in the batch
|
|
723
743
|
assert len(rowids) == 0 or len(rowids) == len(batch)
|
|
724
|
-
import pixeltable.exprs as exprs
|
|
725
744
|
result_status = UpdateStatus()
|
|
726
745
|
cols_with_excs: set[str] = set()
|
|
727
746
|
updated_cols: set[str] = set()
|
|
@@ -768,24 +787,61 @@ class TableVersion:
|
|
|
768
787
|
where_clause: Optional['pixeltable.exprs.Predicate'] = None, cascade: bool = True,
|
|
769
788
|
show_progress: bool = True
|
|
770
789
|
) -> UpdateStatus:
|
|
771
|
-
"""Update rows in this table.
|
|
772
|
-
Args:
|
|
773
|
-
update_targets: a list of (column, value) pairs specifying the columns to update and their new values.
|
|
774
|
-
where_clause: a Predicate to filter rows to update.
|
|
775
|
-
cascade: if True, also update all computed columns that transitively depend on the updated columns,
|
|
776
|
-
including within views.
|
|
777
|
-
"""
|
|
778
|
-
assert not self.is_snapshot
|
|
779
790
|
from pixeltable.plan import Planner
|
|
780
|
-
|
|
791
|
+
|
|
792
|
+
plan, updated_cols, recomputed_cols = (
|
|
781
793
|
Planner.create_update_plan(self.path, update_targets, [], where_clause, cascade)
|
|
782
|
-
|
|
794
|
+
)
|
|
795
|
+
result = self.propagate_update(
|
|
783
796
|
plan, where_clause.sql_expr() if where_clause is not None else None, recomputed_cols,
|
|
784
797
|
base_versions=[], conn=conn, timestamp=time.time(), cascade=cascade, show_progress=show_progress)
|
|
785
798
|
result.updated_cols = updated_cols
|
|
786
799
|
return result
|
|
787
800
|
|
|
788
|
-
def
|
|
801
|
+
def _validate_update_spec(
|
|
802
|
+
self, value_spec: dict[str, Any], allow_pk: bool, allow_exprs: bool
|
|
803
|
+
) -> dict[Column, 'exprs.Expr']:
|
|
804
|
+
update_targets: dict[Column, exprs.Expr] = {}
|
|
805
|
+
for col_name, val in value_spec.items():
|
|
806
|
+
if not isinstance(col_name, str):
|
|
807
|
+
raise excs.Error(f'Update specification: dict key must be column name, got {col_name!r}')
|
|
808
|
+
if col_name == _ROWID_COLUMN_NAME:
|
|
809
|
+
# ignore pseudo-column _rowid
|
|
810
|
+
continue
|
|
811
|
+
col = self.path.get_column(col_name, include_bases=False)
|
|
812
|
+
if col is None:
|
|
813
|
+
# TODO: return more informative error if this is trying to update a base column
|
|
814
|
+
raise excs.Error(f'Column {col_name} unknown')
|
|
815
|
+
if col.is_computed:
|
|
816
|
+
raise excs.Error(f'Column {col_name} is computed and cannot be updated')
|
|
817
|
+
if col.is_pk and not allow_pk:
|
|
818
|
+
raise excs.Error(f'Column {col_name} is a primary key column and cannot be updated')
|
|
819
|
+
if col.col_type.is_media_type():
|
|
820
|
+
raise excs.Error(f'Column {col_name} has type image/video/audio/document and cannot be updated')
|
|
821
|
+
|
|
822
|
+
# make sure that the value is compatible with the column type
|
|
823
|
+
try:
|
|
824
|
+
# check if this is a literal
|
|
825
|
+
value_expr = exprs.Literal(val, col_type=col.col_type)
|
|
826
|
+
except TypeError:
|
|
827
|
+
if not allow_exprs:
|
|
828
|
+
raise excs.Error(
|
|
829
|
+
f'Column {col_name}: value {val!r} is not a valid literal for this column '
|
|
830
|
+
f'(expected {col.col_type})')
|
|
831
|
+
# it's not a literal, let's try to create an expr from it
|
|
832
|
+
value_expr = exprs.Expr.from_object(val)
|
|
833
|
+
if value_expr is None:
|
|
834
|
+
raise excs.Error(f'Column {col_name}: value {val!r} is not a recognized literal or expression')
|
|
835
|
+
if not col.col_type.matches(value_expr.col_type):
|
|
836
|
+
raise excs.Error((
|
|
837
|
+
f'Type of value {val!r} ({value_expr.col_type}) is not compatible with the type of column '
|
|
838
|
+
f'{col_name} ({col.col_type})'
|
|
839
|
+
))
|
|
840
|
+
update_targets[col] = value_expr
|
|
841
|
+
|
|
842
|
+
return update_targets
|
|
843
|
+
|
|
844
|
+
def propagate_update(
|
|
789
845
|
self, plan: Optional[exec.ExecNode], where_clause: Optional[sql.ClauseElement],
|
|
790
846
|
recomputed_view_cols: List[Column], base_versions: List[Optional[int]], conn: sql.engine.Connection,
|
|
791
847
|
timestamp: float, cascade: bool, show_progress: bool = True
|
|
@@ -810,7 +866,7 @@ class TableVersion:
|
|
|
810
866
|
if len(recomputed_cols) > 0:
|
|
811
867
|
from pixeltable.plan import Planner
|
|
812
868
|
plan = Planner.create_view_update_plan(view.path, recompute_targets=recomputed_cols)
|
|
813
|
-
status = view.
|
|
869
|
+
status = view.propagate_update(
|
|
814
870
|
plan, None, recomputed_view_cols, base_versions=base_versions, conn=conn, timestamp=timestamp, cascade=True)
|
|
815
871
|
result.num_rows += status.num_rows
|
|
816
872
|
result.num_excs += status.num_excs
|
|
@@ -819,22 +875,31 @@ class TableVersion:
|
|
|
819
875
|
result.cols_with_excs = list(dict.fromkeys(result.cols_with_excs).keys()) # remove duplicates
|
|
820
876
|
return result
|
|
821
877
|
|
|
822
|
-
def delete(self, where: Optional['
|
|
878
|
+
def delete(self, where: Optional['exprs.Predicate'] = None) -> UpdateStatus:
|
|
823
879
|
"""Delete rows in this table.
|
|
824
880
|
Args:
|
|
825
881
|
where: a Predicate to filter rows to delete.
|
|
826
882
|
"""
|
|
827
883
|
assert self.is_insertable()
|
|
884
|
+
from pixeltable.exprs import Predicate
|
|
828
885
|
from pixeltable.plan import Planner
|
|
829
|
-
|
|
886
|
+
if where is not None:
|
|
887
|
+
if not isinstance(where, Predicate):
|
|
888
|
+
raise excs.Error(f"'where' argument must be a Predicate, got {type(where)}")
|
|
889
|
+
analysis_info = Planner.analyze(self.path, where)
|
|
890
|
+
# for now we require that the updated rows can be identified via SQL, rather than via a Python filter
|
|
891
|
+
if analysis_info.filter is not None:
|
|
892
|
+
raise excs.Error(f'Filter {analysis_info.filter} not expressible in SQL')
|
|
893
|
+
|
|
894
|
+
analysis_info = Planner.analyze(self.path, where)
|
|
830
895
|
with Env.get().engine.begin() as conn:
|
|
831
|
-
num_rows = self.
|
|
896
|
+
num_rows = self.propagate_delete(analysis_info.sql_where_clause, base_versions=[], conn=conn, timestamp=time.time())
|
|
832
897
|
|
|
833
898
|
status = UpdateStatus(num_rows=num_rows)
|
|
834
899
|
return status
|
|
835
900
|
|
|
836
|
-
def
|
|
837
|
-
self, where: Optional['
|
|
901
|
+
def propagate_delete(
|
|
902
|
+
self, where: Optional['exprs.Predicate'], base_versions: List[Optional[int]],
|
|
838
903
|
conn: sql.engine.Connection, timestamp: float) -> int:
|
|
839
904
|
"""Delete rows in this table and propagate to views.
|
|
840
905
|
Args:
|
|
@@ -853,7 +918,7 @@ class TableVersion:
|
|
|
853
918
|
else:
|
|
854
919
|
pass
|
|
855
920
|
for view in self.mutable_views:
|
|
856
|
-
num_rows += view.
|
|
921
|
+
num_rows += view.propagate_delete(
|
|
857
922
|
where=None, base_versions=[self.version] + base_versions, conn=conn, timestamp=timestamp)
|
|
858
923
|
return num_rows
|
|
859
924
|
|
|
@@ -5,13 +5,13 @@ from typing import Optional, Union
|
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
7
|
import pixeltable
|
|
8
|
-
import pixeltable.catalog as catalog
|
|
9
8
|
from .column import Column
|
|
10
9
|
from .globals import POS_COLUMN_NAME
|
|
11
10
|
from .table_version import TableVersion
|
|
12
11
|
|
|
13
12
|
_logger = logging.getLogger('pixeltable')
|
|
14
13
|
|
|
14
|
+
|
|
15
15
|
class TableVersionPath:
|
|
16
16
|
"""
|
|
17
17
|
A TableVersionPath represents the sequence of TableVersions from a base table to a particular view:
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
2
4
|
import logging
|
|
3
|
-
from typing import
|
|
5
|
+
from typing import Optional, Type, Dict, Set, Any, Iterable, TYPE_CHECKING
|
|
4
6
|
from uuid import UUID
|
|
5
|
-
import inspect
|
|
6
7
|
|
|
7
8
|
import sqlalchemy.orm as orm
|
|
8
9
|
|
|
9
|
-
from .table import Table
|
|
10
|
-
from .table_version import TableVersion
|
|
11
|
-
from .table_version_path import TableVersionPath
|
|
12
|
-
from .column import Column
|
|
13
|
-
from .catalog import Catalog
|
|
14
|
-
from .globals import POS_COLUMN_NAME, UpdateStatus
|
|
15
|
-
from pixeltable.env import Env
|
|
16
|
-
from pixeltable.iterators import ComponentIterator
|
|
17
|
-
from pixeltable.exceptions import Error
|
|
18
|
-
import pixeltable.func as func
|
|
19
|
-
import pixeltable.type_system as ts
|
|
20
10
|
import pixeltable.catalog as catalog
|
|
11
|
+
import pixeltable.exceptions as excs
|
|
12
|
+
import pixeltable.func as func
|
|
21
13
|
import pixeltable.metadata.schema as md_schema
|
|
14
|
+
from pixeltable.env import Env
|
|
15
|
+
from pixeltable.exceptions import Error
|
|
16
|
+
from pixeltable.iterators import ComponentIterator
|
|
22
17
|
from pixeltable.type_system import InvalidType, IntType
|
|
23
|
-
|
|
18
|
+
from .catalog import Catalog
|
|
19
|
+
from .column import Column
|
|
20
|
+
from .globals import POS_COLUMN_NAME, UpdateStatus
|
|
21
|
+
from .table import Table
|
|
22
|
+
from .table_version import TableVersion
|
|
23
|
+
from .table_version_path import TableVersionPath
|
|
24
24
|
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
import pixeltable as pxt
|
|
25
27
|
|
|
26
28
|
_logger = logging.getLogger('pixeltable')
|
|
27
29
|
|
|
30
|
+
|
|
28
31
|
class View(Table):
|
|
29
32
|
"""A `Table` that presents a virtual view of another table (or view).
|
|
30
33
|
|
|
@@ -34,10 +37,11 @@ class View(Table):
|
|
|
34
37
|
is simply a reference to a specific set of base versions.
|
|
35
38
|
"""
|
|
36
39
|
def __init__(
|
|
37
|
-
self, id: UUID, dir_id: UUID, name: str, tbl_version_path: TableVersionPath,
|
|
40
|
+
self, id: UUID, dir_id: UUID, name: str, tbl_version_path: TableVersionPath, base_id: UUID,
|
|
38
41
|
snapshot_only: bool):
|
|
39
42
|
super().__init__(id, dir_id, name, tbl_version_path)
|
|
40
|
-
|
|
43
|
+
assert base_id in catalog.Catalog.get().tbl_dependents
|
|
44
|
+
self._base_id = base_id # keep a reference to the base Table ID, so that we can keep track of its dependents
|
|
41
45
|
self._snapshot_only = snapshot_only
|
|
42
46
|
|
|
43
47
|
@classmethod
|
|
@@ -46,8 +50,8 @@ class View(Table):
|
|
|
46
50
|
|
|
47
51
|
@classmethod
|
|
48
52
|
def create(
|
|
49
|
-
cls, dir_id: UUID, name: str, base:
|
|
50
|
-
predicate: 'exprs.Predicate', is_snapshot: bool, num_retained_versions: int, comment: str,
|
|
53
|
+
cls, dir_id: UUID, name: str, base: TableVersionPath, schema: Dict[str, Any],
|
|
54
|
+
predicate: 'pxt.exprs.Predicate', is_snapshot: bool, num_retained_versions: int, comment: str,
|
|
51
55
|
iterator_cls: Optional[Type[ComponentIterator]], iterator_args: Optional[Dict]
|
|
52
56
|
) -> View:
|
|
53
57
|
columns = cls._create_columns(schema)
|
|
@@ -55,8 +59,8 @@ class View(Table):
|
|
|
55
59
|
|
|
56
60
|
# verify that filter can be evaluated in the context of the base
|
|
57
61
|
if predicate is not None:
|
|
58
|
-
if not predicate.is_bound_by(base
|
|
59
|
-
raise excs.Error(f'Filter cannot be computed in the context of the base {base.
|
|
62
|
+
if not predicate.is_bound_by(base):
|
|
63
|
+
raise excs.Error(f'Filter cannot be computed in the context of the base {base.tbl_name()}')
|
|
60
64
|
# create a copy that we can modify and store
|
|
61
65
|
predicate = predicate.copy()
|
|
62
66
|
|
|
@@ -65,9 +69,9 @@ class View(Table):
|
|
|
65
69
|
if not col.is_computed:
|
|
66
70
|
continue
|
|
67
71
|
# make sure that the value can be computed in the context of the base
|
|
68
|
-
if col.value_expr is not None and not col.value_expr.is_bound_by(base
|
|
72
|
+
if col.value_expr is not None and not col.value_expr.is_bound_by(base):
|
|
69
73
|
raise excs.Error(
|
|
70
|
-
f'Column {col.name}: value expression cannot be computed in the context of the base {base.
|
|
74
|
+
f'Column {col.name}: value expression cannot be computed in the context of the base {base.tbl_name()}')
|
|
71
75
|
|
|
72
76
|
if iterator_cls is not None:
|
|
73
77
|
assert iterator_args is not None
|
|
@@ -114,7 +118,7 @@ class View(Table):
|
|
|
114
118
|
iterator_args_expr = InlineDict(iterator_args) if iterator_args is not None else None
|
|
115
119
|
iterator_class_fqn = f'{iterator_cls.__module__}.{iterator_cls.__name__}' if iterator_cls is not None \
|
|
116
120
|
else None
|
|
117
|
-
base_version_path = cls._get_snapshot_path(base
|
|
121
|
+
base_version_path = cls._get_snapshot_path(base) if is_snapshot else base
|
|
118
122
|
base_versions = [
|
|
119
123
|
(tbl_version.id.hex, tbl_version.version if is_snapshot or tbl_version.is_snapshot else None)
|
|
120
124
|
for tbl_version in base_version_path.get_tbl_versions()
|
|
@@ -139,11 +143,11 @@ class View(Table):
|
|
|
139
143
|
session, dir_id, name, columns, num_retained_versions, comment, base_path=base_version_path, view_md=view_md)
|
|
140
144
|
if tbl_version is None:
|
|
141
145
|
# this is purely a snapshot: we use the base's tbl version path
|
|
142
|
-
view = cls(id, dir_id, name, base_version_path, base, snapshot_only=True)
|
|
146
|
+
view = cls(id, dir_id, name, base_version_path, base.tbl_id(), snapshot_only=True)
|
|
143
147
|
_logger.info(f'created snapshot {name}')
|
|
144
148
|
else:
|
|
145
149
|
view = cls(
|
|
146
|
-
id, dir_id, name, TableVersionPath(tbl_version, base=base_version_path), base,
|
|
150
|
+
id, dir_id, name, TableVersionPath(tbl_version, base=base_version_path), base.tbl_id(),
|
|
147
151
|
snapshot_only=False)
|
|
148
152
|
_logger.info(f'Created view `{name}`, id={tbl_version.id}')
|
|
149
153
|
|
|
@@ -156,7 +160,7 @@ class View(Table):
|
|
|
156
160
|
session.commit()
|
|
157
161
|
cat = Catalog.get()
|
|
158
162
|
cat.tbl_dependents[view._id] = []
|
|
159
|
-
cat.tbl_dependents[base.
|
|
163
|
+
cat.tbl_dependents[base.tbl_id()].append(view)
|
|
160
164
|
cat.tbls[view._id] = view
|
|
161
165
|
return view
|
|
162
166
|
|
|
@@ -200,7 +204,7 @@ class View(Table):
|
|
|
200
204
|
del cat.tbls[self._id]
|
|
201
205
|
else:
|
|
202
206
|
super()._drop()
|
|
203
|
-
cat.tbl_dependents[self.
|
|
207
|
+
cat.tbl_dependents[self._base_id].remove(self)
|
|
204
208
|
del cat.tbl_dependents[self._id]
|
|
205
209
|
|
|
206
210
|
def insert(
|