pixeltable 0.2.28__tar.gz → 0.2.30__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.28 → pixeltable-0.2.30}/PKG-INFO +4 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/__init__.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/__version__.py +2 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/__init__.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/dir.py +6 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/globals.py +25 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/named_function.py +4 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/path_dict.py +37 -11
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/schema_object.py +6 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/table.py +96 -19
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/table_version.py +22 -8
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/dataframe.py +201 -3
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/env.py +9 -3
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/expr_eval_node.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/sql_node.py +2 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/function_call.py +134 -29
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/inline_expr.py +22 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/row_builder.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/similarity_expr.py +9 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/__init__.py +1 -0
- pixeltable-0.2.30/pixeltable/func/aggregate_function.py +289 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/callable_function.py +50 -16
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/expr_template_function.py +62 -24
- pixeltable-0.2.30/pixeltable/func/function.py +377 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/function_registry.py +2 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/query_template_function.py +11 -6
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/signature.py +64 -7
- pixeltable-0.2.30/pixeltable/func/tools.py +116 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/udf.py +57 -35
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/__init__.py +2 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/anthropic.py +36 -2
- pixeltable-0.2.30/pixeltable/functions/globals.py +164 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/json.py +3 -8
- pixeltable-0.2.30/pixeltable/functions/math.py +67 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/ollama.py +4 -4
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/openai.py +31 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/timestamp.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/video.py +2 -8
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/vision.py +1 -1
- pixeltable-0.2.30/pixeltable/globals.py +817 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/index/embedding_index.py +44 -24
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/__init__.py +1 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_16.py +2 -1
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_17.py +2 -1
- pixeltable-0.2.30/pixeltable/metadata/converters/convert_23.py +35 -0
- pixeltable-0.2.30/pixeltable/metadata/converters/convert_24.py +47 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/util.py +4 -2
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/notes.py +2 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/schema.py +1 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/type_system.py +192 -48
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pyproject.toml +11 -6
- pixeltable-0.2.28/pixeltable/func/aggregate_function.py +0 -206
- pixeltable-0.2.28/pixeltable/func/function.py +0 -209
- pixeltable-0.2.28/pixeltable/functions/globals.py +0 -144
- pixeltable-0.2.28/pixeltable/globals.py +0 -549
- pixeltable-0.2.28/pixeltable/tool/create_test_db_dump.py +0 -311
- pixeltable-0.2.28/pixeltable/tool/create_test_video.py +0 -81
- pixeltable-0.2.28/pixeltable/tool/doc_plugins/griffe.py +0 -50
- pixeltable-0.2.28/pixeltable/tool/doc_plugins/mkdocstrings.py +0 -6
- pixeltable-0.2.28/pixeltable/tool/doc_plugins/templates/material/udf.html.jinja +0 -135
- pixeltable-0.2.28/pixeltable/tool/embed_udf.py +0 -9
- pixeltable-0.2.28/pixeltable/tool/mypy_plugin.py +0 -55
- {pixeltable-0.2.28 → pixeltable-0.2.30}/LICENSE +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/README.md +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/catalog.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/column.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/insertable_table.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/path.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/table_version_path.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/catalog/view.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exceptions.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/aggregation_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/cache_prefetch_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/component_iteration_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/data_row_batch.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/exec_context.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/exec_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/in_memory_data_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exec/row_update_node.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/arithmetic_expr.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/array_slice.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/column_property_ref.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/column_ref.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/comparison.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/compound_predicate.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/data_row.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/expr.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/expr_dict.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/expr_set.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/globals.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/in_predicate.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/is_null.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/json_mapper.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/json_path.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/literal.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/method_ref.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/object_ref.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/rowid_ref.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/sql_element_cache.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/type_cast.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/exprs/variable.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/ext/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/ext/functions/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/ext/functions/whisperx.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/ext/functions/yolox.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/func/globals.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/audio.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/fireworks.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/gemini.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/huggingface.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/image.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/llama_cpp.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/mistralai.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/replicate.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/string.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/together.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/util.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/functions/whisper.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/index/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/index/base.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/index/btree.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/external_store.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/fiftyone.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/globals.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/hf_datasets.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/label_studio.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/pandas.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/io/parquet.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/base.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/document.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/image.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/string.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/iterators/video.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_10.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_12.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_13.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_14.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_15.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_18.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_19.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_20.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_21.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/metadata/converters/convert_22.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/plan.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/py.typed +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/store.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/__init__.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/arrow.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/coco.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/code.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/description_helper.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/documents.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/filecache.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/formatter.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/http_server.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/media_store.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/pytorch.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/s3.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/pixeltable/utils/sql.py +0 -0
- {pixeltable-0.2.28 → pixeltable-0.2.30}/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.30
|
|
4
4
|
Summary: AI Data Infrastructure: Declarative, Multimodal, and Incremental
|
|
5
5
|
Home-page: https://pixeltable.com/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -29,16 +29,18 @@ Requires-Dist: cloudpickle (>=2.2.1,<3.0.0)
|
|
|
29
29
|
Requires-Dist: ftfy (>=6.2.0,<7.0.0)
|
|
30
30
|
Requires-Dist: jinja2 (>=3.1.3,<4.0.0)
|
|
31
31
|
Requires-Dist: jmespath (>=1.0.1,<2.0.0)
|
|
32
|
+
Requires-Dist: jsonschema (>=4.1.0)
|
|
32
33
|
Requires-Dist: lxml (>=5.0)
|
|
33
34
|
Requires-Dist: more-itertools (>=10.2,<11.0)
|
|
34
35
|
Requires-Dist: numpy (>=1.25,<2.0)
|
|
35
36
|
Requires-Dist: pandas (>=2.0,<3.0)
|
|
36
37
|
Requires-Dist: pgvector (>=0.2.1,<0.3.0)
|
|
37
38
|
Requires-Dist: pillow (>=9.3.0)
|
|
38
|
-
Requires-Dist: pixeltable-pgserver (==0.2.
|
|
39
|
+
Requires-Dist: pixeltable-pgserver (==0.2.9)
|
|
39
40
|
Requires-Dist: psutil (>=5.9.5,<6.0.0)
|
|
40
41
|
Requires-Dist: psycopg[binary] (>=3.1.18)
|
|
41
42
|
Requires-Dist: puremagic (>=1.20)
|
|
43
|
+
Requires-Dist: pydantic (>=2.7.4)
|
|
42
44
|
Requires-Dist: pymupdf (>=1.24.1,<2.0.0)
|
|
43
45
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
44
46
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
@@ -4,7 +4,7 @@ from .exceptions import Error
|
|
|
4
4
|
from .exprs import RELATIVE_PATH_ROOT
|
|
5
5
|
from .func import Aggregator, Function, expr_udf, uda, udf
|
|
6
6
|
from .globals import (array, configure_logging, create_dir, create_snapshot, create_table, create_view, drop_dir,
|
|
7
|
-
drop_table, get_table, init, list_dirs, list_functions, list_tables, move)
|
|
7
|
+
drop_table, get_table, init, list_dirs, list_functions, list_tables, move, tool, tools)
|
|
8
8
|
from .type_system import (Array, ArrayType, Audio, AudioType, Bool, BoolType, ColumnType, Document, DocumentType, Float,
|
|
9
9
|
FloatType, Image, ImageType, Int, IntType, Json, JsonType, Required, String, StringType,
|
|
10
10
|
Timestamp, TimestampType, Video, VideoType)
|
|
@@ -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.30"
|
|
3
|
+
__version_tuple__ = (0, 2, 30)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from .catalog import Catalog
|
|
2
2
|
from .column import Column
|
|
3
3
|
from .dir import Dir
|
|
4
|
-
from .globals import UpdateStatus, is_valid_identifier, is_valid_path, MediaValidation
|
|
4
|
+
from .globals import UpdateStatus, is_valid_identifier, is_valid_path, MediaValidation, IfExistsParam, IfNotExistsParam
|
|
5
5
|
from .insertable_table import InsertableTable
|
|
6
6
|
from .named_function import NamedFunction
|
|
7
7
|
from .path import Path
|
|
@@ -21,6 +21,12 @@ class Dir(SchemaObject):
|
|
|
21
21
|
def _display_name(cls) -> str:
|
|
22
22
|
return 'directory'
|
|
23
23
|
|
|
24
|
+
@property
|
|
25
|
+
def _has_dependents(self) -> bool:
|
|
26
|
+
""" Returns True if this directory has any children. """
|
|
27
|
+
from pixeltable.catalog import Catalog, Path
|
|
28
|
+
return len(Catalog.get().paths.get_children(Path(self._path), child_type=None, recursive=False)) > 0
|
|
29
|
+
|
|
24
30
|
def _move(self, new_name: str, new_dir_id: UUID) -> None:
|
|
25
31
|
super()._move(new_name, new_dir_id)
|
|
26
32
|
with Env.get().engine.begin() as conn:
|
|
@@ -51,6 +51,31 @@ class MediaValidation(enum.Enum):
|
|
|
51
51
|
val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
|
|
52
52
|
raise excs.Error(f'{error_prefix} must be one of: [{val_strs}]')
|
|
53
53
|
|
|
54
|
+
class IfExistsParam(enum.Enum):
|
|
55
|
+
ERROR = 0
|
|
56
|
+
IGNORE = 1
|
|
57
|
+
REPLACE = 2
|
|
58
|
+
REPLACE_FORCE = 3
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def validated(cls, param_val: str, param_name: str) -> IfExistsParam:
|
|
62
|
+
try:
|
|
63
|
+
return cls[param_val.upper()]
|
|
64
|
+
except KeyError:
|
|
65
|
+
val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
|
|
66
|
+
raise excs.Error(f'{param_name} must be one of: [{val_strs}]')
|
|
67
|
+
|
|
68
|
+
class IfNotExistsParam(enum.Enum):
|
|
69
|
+
ERROR = 0
|
|
70
|
+
IGNORE = 1
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def validated(cls, param_val: str, param_name: str) -> IfNotExistsParam:
|
|
74
|
+
try:
|
|
75
|
+
return cls[param_val.upper()]
|
|
76
|
+
except KeyError:
|
|
77
|
+
val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
|
|
78
|
+
raise excs.Error(f'{param_name} must be one of: [{val_strs}]')
|
|
54
79
|
|
|
55
80
|
def is_valid_identifier(name: str) -> bool:
|
|
56
81
|
return name.isidentifier() and not name.startswith('_')
|
|
@@ -25,6 +25,10 @@ class NamedFunction(SchemaObject):
|
|
|
25
25
|
def _display_name(cls) -> str:
|
|
26
26
|
return 'function'
|
|
27
27
|
|
|
28
|
+
@property
|
|
29
|
+
def _has_dependents(self) -> bool:
|
|
30
|
+
return False
|
|
31
|
+
|
|
28
32
|
def _move(self, new_name: str, new_dir_id: UUID) -> None:
|
|
29
33
|
super()._move(new_name, new_dir_id)
|
|
30
34
|
with Env.get().engine.begin() as conn:
|
|
@@ -51,11 +51,41 @@ class PathDict:
|
|
|
51
51
|
record_dir(dir)
|
|
52
52
|
|
|
53
53
|
def _resolve_path(self, path: Path) -> SchemaObject:
|
|
54
|
+
"""Resolve the path to a SchemaObject.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
path: path to resolve
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
SchemaObject at the path.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
Error if path is invalid or does not exist.
|
|
64
|
+
"""
|
|
65
|
+
schema_obj = self.get_object(path)
|
|
66
|
+
if schema_obj is None:
|
|
67
|
+
raise excs.Error(f"No such path: {str(path)}")
|
|
68
|
+
return schema_obj
|
|
69
|
+
|
|
70
|
+
def get_object(self, path: Path) -> Optional[SchemaObject]:
|
|
71
|
+
"""Get the object at the given path, if any.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
path: path to object
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
SchemaObject at the path if it exists, None otherwise.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
Error if path is invalid.
|
|
81
|
+
"""
|
|
54
82
|
if path.is_root:
|
|
55
83
|
return self.root_dir
|
|
56
84
|
dir = self.root_dir
|
|
57
85
|
for i, component in enumerate(path.components):
|
|
58
86
|
if component not in self.dir_contents[dir._id]:
|
|
87
|
+
if i == len(path.components) - 1:
|
|
88
|
+
return None
|
|
59
89
|
raise excs.Error(f'No such path: {".".join(path.components[:i + 1])}')
|
|
60
90
|
schema_obj = self.dir_contents[dir._id][component]
|
|
61
91
|
if i < len(path.components) - 1:
|
|
@@ -112,19 +142,15 @@ class PathDict:
|
|
|
112
142
|
Error if path is invalid or object at path has wrong type
|
|
113
143
|
"""
|
|
114
144
|
# check for existence
|
|
145
|
+
obj = self.get_object(path)
|
|
115
146
|
if expected is not None:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
f'{str(path)} needs to be a {expected._display_name()} but is a {type(schema_obj)._display_name()}')
|
|
120
|
-
if expected is None:
|
|
121
|
-
parent_obj = self._resolve_path(path.parent)
|
|
122
|
-
if not isinstance(parent_obj, Dir):
|
|
147
|
+
if obj is None:
|
|
148
|
+
raise excs.Error(f"No such path: {str(path)}")
|
|
149
|
+
if not isinstance(obj, expected):
|
|
123
150
|
raise excs.Error(
|
|
124
|
-
f'{str(path
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
raise excs.Error(f"{type(obj)._display_name()} '{str(path)}' already exists")
|
|
151
|
+
f'{str(path)} needs to be a {expected._display_name()} but is a {type(obj)._display_name()}')
|
|
152
|
+
if expected is None and obj is not None:
|
|
153
|
+
raise excs.Error(f"{type(obj)._display_name()} '{str(path)}' already exists")
|
|
128
154
|
|
|
129
155
|
def get_children(self, parent: Path, child_type: Optional[type[SchemaObject]], recursive: bool) -> list[Path]:
|
|
130
156
|
dir = self._resolve_path(parent)
|
|
@@ -66,7 +66,13 @@ class SchemaObject:
|
|
|
66
66
|
"""
|
|
67
67
|
pass
|
|
68
68
|
|
|
69
|
+
@property
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def _has_dependents(self) -> bool:
|
|
72
|
+
"""Returns True if this object has dependents (e.g., children, views)"""
|
|
73
|
+
|
|
69
74
|
def _move(self, new_name: str, new_dir_id: UUID) -> None:
|
|
70
75
|
"""Subclasses need to override this to make the change persistent"""
|
|
71
76
|
self.__name = new_name
|
|
72
77
|
self.__dir_id = new_dir_id
|
|
78
|
+
|
|
@@ -25,7 +25,7 @@ from ..exprs import ColumnRef
|
|
|
25
25
|
from ..utils.description_helper import DescriptionHelper
|
|
26
26
|
from ..utils.filecache import FileCache
|
|
27
27
|
from .column import Column
|
|
28
|
-
from .globals import _ROWID_COLUMN_NAME, MediaValidation, UpdateStatus, is_system_column_name, is_valid_identifier
|
|
28
|
+
from .globals import _ROWID_COLUMN_NAME, MediaValidation, UpdateStatus, is_system_column_name, is_valid_identifier, IfNotExistsParam
|
|
29
29
|
from .schema_object import SchemaObject
|
|
30
30
|
from .table_version import TableVersion
|
|
31
31
|
from .table_version_path import TableVersionPath
|
|
@@ -63,6 +63,11 @@ class Table(SchemaObject):
|
|
|
63
63
|
return self._queries[name]
|
|
64
64
|
raise AttributeError(f'Table {self.__table._name!r} has no query with that name: {name!r}')
|
|
65
65
|
|
|
66
|
+
@property
|
|
67
|
+
def _has_dependents(self) -> bool:
|
|
68
|
+
"""Returns True if this table has any dependent views, or snapshots."""
|
|
69
|
+
return len(self._get_views(recursive=False)) > 0
|
|
70
|
+
|
|
66
71
|
def _move(self, new_name: str, new_dir_id: UUID) -> None:
|
|
67
72
|
self._check_is_dropped()
|
|
68
73
|
super()._move(new_name, new_dir_id)
|
|
@@ -184,26 +189,38 @@ class Table(SchemaObject):
|
|
|
184
189
|
return self.__query_scope
|
|
185
190
|
|
|
186
191
|
def select(self, *items: Any, **named_items: Any) -> 'pxt.DataFrame':
|
|
187
|
-
"""
|
|
192
|
+
""" Select columns or expressions from this table.
|
|
193
|
+
|
|
194
|
+
See [`DataFrame.select`][pixeltable.DataFrame.select] for more details.
|
|
195
|
+
"""
|
|
188
196
|
return self._df().select(*items, **named_items)
|
|
189
197
|
|
|
190
198
|
def where(self, pred: 'exprs.Expr') -> 'pxt.DataFrame':
|
|
191
|
-
"""
|
|
199
|
+
"""Filter rows from this table based on the expression.
|
|
200
|
+
|
|
201
|
+
See [`DataFrame.where`][pixeltable.DataFrame.where] for more details.
|
|
202
|
+
"""
|
|
192
203
|
return self._df().where(pred)
|
|
193
204
|
|
|
194
205
|
def join(
|
|
195
206
|
self, other: 'Table', *, on: Optional['exprs.Expr'] = None,
|
|
196
207
|
how: 'pixeltable.plan.JoinType.LiteralType' = 'inner'
|
|
197
208
|
) -> 'pxt.DataFrame':
|
|
198
|
-
"""
|
|
209
|
+
"""Join this table with another table."""
|
|
199
210
|
return self._df().join(other, on=on, how=how)
|
|
200
211
|
|
|
201
212
|
def order_by(self, *items: 'exprs.Expr', asc: bool = True) -> 'pxt.DataFrame':
|
|
202
|
-
"""
|
|
213
|
+
"""Order the rows of this table based on the expression.
|
|
214
|
+
|
|
215
|
+
See [`DataFrame.order_by`][pixeltable.DataFrame.order_by] for more details.
|
|
216
|
+
"""
|
|
203
217
|
return self._df().order_by(*items, asc=asc)
|
|
204
218
|
|
|
205
219
|
def group_by(self, *items: 'exprs.Expr') -> 'pxt.DataFrame':
|
|
206
|
-
"""
|
|
220
|
+
"""Group the rows of this table based on the expression.
|
|
221
|
+
|
|
222
|
+
See [`DataFrame.group_by`][pixeltable.DataFrame.group_by] for more details.
|
|
223
|
+
"""
|
|
207
224
|
return self._df().group_by(*items)
|
|
208
225
|
|
|
209
226
|
def limit(self, n: int) -> 'pxt.DataFrame':
|
|
@@ -695,14 +712,19 @@ class Table(SchemaObject):
|
|
|
695
712
|
if not exists:
|
|
696
713
|
raise excs.Error(f'Unknown column: {col_ref.col.qualified_name}')
|
|
697
714
|
|
|
698
|
-
def drop_column(self, column: Union[str, ColumnRef]) -> None:
|
|
715
|
+
def drop_column(self, column: Union[str, ColumnRef], if_not_exists: Literal['error', 'ignore'] = 'error') -> None:
|
|
699
716
|
"""Drop a column from the table.
|
|
700
717
|
|
|
701
718
|
Args:
|
|
702
719
|
column: The name or reference of the column to drop.
|
|
720
|
+
if_not_exists: Directive for handling a non-existent column. Must be one of the following:
|
|
721
|
+
|
|
722
|
+
- `'error'`: raise an error if the column does not exist.
|
|
723
|
+
- `'ignore'`: do nothing if the column does not exist.
|
|
703
724
|
|
|
704
725
|
Raises:
|
|
705
|
-
Error: If the column does not exist
|
|
726
|
+
Error: If the column does not exist and `if_exists='error'`,
|
|
727
|
+
or if it is referenced by a dependent computed column.
|
|
706
728
|
|
|
707
729
|
Examples:
|
|
708
730
|
Drop the column `col` from the table `my_table` by column name:
|
|
@@ -714,14 +736,32 @@ class Table(SchemaObject):
|
|
|
714
736
|
|
|
715
737
|
>>> tbl = pxt.get_table('my_table')
|
|
716
738
|
... tbl.drop_column(tbl.col)
|
|
739
|
+
|
|
740
|
+
Drop the column `col` from the table `my_table` if it exists, otherwise do nothing:
|
|
741
|
+
|
|
742
|
+
>>> tbl = pxt.get_table('my_table')
|
|
743
|
+
... tbl.drop_col(tbl.col, if_not_exists='ignore')
|
|
717
744
|
"""
|
|
718
745
|
self._check_is_dropped()
|
|
746
|
+
if self._tbl_version_path.is_snapshot():
|
|
747
|
+
raise excs.Error('Cannot drop column from a snapshot.')
|
|
719
748
|
col: Column = None
|
|
749
|
+
_if_not_exists = IfNotExistsParam.validated(if_not_exists, 'if_not_exists')
|
|
720
750
|
if isinstance(column, str):
|
|
721
|
-
self.
|
|
751
|
+
col = self._tbl_version_path.get_column(column, include_bases=False)
|
|
752
|
+
if col is None:
|
|
753
|
+
if _if_not_exists == IfNotExistsParam.ERROR:
|
|
754
|
+
raise excs.Error(f'Column {column!r} unknown')
|
|
755
|
+
assert _if_not_exists == IfNotExistsParam.IGNORE
|
|
756
|
+
return
|
|
722
757
|
col = self._tbl_version.cols_by_name[column]
|
|
723
758
|
else:
|
|
724
|
-
self.
|
|
759
|
+
exists = self._tbl_version_path.has_column(column.col, include_bases=False)
|
|
760
|
+
if not exists:
|
|
761
|
+
if _if_not_exists == IfNotExistsParam.ERROR:
|
|
762
|
+
raise excs.Error(f'Unknown column: {column.col.qualified_name}')
|
|
763
|
+
assert _if_not_exists == IfNotExistsParam.IGNORE
|
|
764
|
+
return
|
|
725
765
|
col = column.col
|
|
726
766
|
|
|
727
767
|
dependent_user_cols = [c for c in col.dependent_cols if c.name is not None]
|
|
@@ -849,7 +889,9 @@ class Table(SchemaObject):
|
|
|
849
889
|
def drop_embedding_index(
|
|
850
890
|
self, *,
|
|
851
891
|
column: Union[str, ColumnRef, None] = None,
|
|
852
|
-
idx_name: Optional[str] = None
|
|
892
|
+
idx_name: Optional[str] = None,
|
|
893
|
+
if_not_exists: Literal['error', 'ignore'] = 'error'
|
|
894
|
+
) -> None:
|
|
853
895
|
"""
|
|
854
896
|
Drop an embedding index from the table. Either a column name or an index name (but not both) must be
|
|
855
897
|
specified. If a column name or reference is specified, it must be a column containing exactly one
|
|
@@ -859,11 +901,20 @@ class Table(SchemaObject):
|
|
|
859
901
|
column: The name of, or reference to, the column from which to drop the index.
|
|
860
902
|
The column must have only one embedding index.
|
|
861
903
|
idx_name: The name of the index to drop.
|
|
904
|
+
if_not_exists: Directive for handling a non-existent index. Must be one of the following:
|
|
905
|
+
|
|
906
|
+
- `'error'`: raise an error if the index does not exist.
|
|
907
|
+
- `'ignore'`: do nothing if the index does not exist.
|
|
908
|
+
|
|
909
|
+
Note that `if_not_exists` parameter is only applicable when an `idx_name` is specified
|
|
910
|
+
and it does not exist, or when `column` is specified and it has no index.
|
|
911
|
+
`if_not_exists` does not apply to non-exisitng column.
|
|
862
912
|
|
|
863
913
|
Raises:
|
|
864
914
|
Error: If `column` is specified, but the column does not exist, or it contains no embedding
|
|
865
|
-
indices or multiple embedding indices.
|
|
866
|
-
Error: If `idx_name` is specified, but the index
|
|
915
|
+
indices and `if_not_exists='error'`, or the column has multiple embedding indices.
|
|
916
|
+
Error: If `idx_name` is specified, but the index is not an embedding index, or
|
|
917
|
+
the index does not exist and `if_not_exists='error'`.
|
|
867
918
|
|
|
868
919
|
Examples:
|
|
869
920
|
Drop the embedding index on the `img` column of the table `my_table` by column name:
|
|
@@ -880,6 +931,9 @@ class Table(SchemaObject):
|
|
|
880
931
|
>>> tbl = pxt.get_table('my_table')
|
|
881
932
|
... tbl.drop_embedding_index(idx_name='idx1')
|
|
882
933
|
|
|
934
|
+
Drop the embedding index `idx1` of the table `my_table` by index name, if it exists, otherwise do nothing:
|
|
935
|
+
>>> tbl = pxt.get_table('my_table')
|
|
936
|
+
... tbl.drop_embedding_index(idx_name='idx1', if_not_exists='ignore')
|
|
883
937
|
"""
|
|
884
938
|
if (column is None) == (idx_name is None):
|
|
885
939
|
raise excs.Error("Exactly one of 'column' or 'idx_name' must be provided")
|
|
@@ -893,12 +947,14 @@ class Table(SchemaObject):
|
|
|
893
947
|
self.__check_column_ref_exists(column, include_bases=True)
|
|
894
948
|
col = column.col
|
|
895
949
|
assert col is not None
|
|
896
|
-
self._drop_index(col=col, idx_name=idx_name, _idx_class=index.EmbeddingIndex)
|
|
950
|
+
self._drop_index(col=col, idx_name=idx_name, _idx_class=index.EmbeddingIndex, if_not_exists=if_not_exists)
|
|
897
951
|
|
|
898
952
|
def drop_index(
|
|
899
953
|
self, *,
|
|
900
954
|
column: Union[str, ColumnRef, None] = None,
|
|
901
|
-
idx_name: Optional[str] = None
|
|
955
|
+
idx_name: Optional[str] = None,
|
|
956
|
+
if_not_exists: Literal['error', 'ignore'] = 'error'
|
|
957
|
+
) -> None:
|
|
902
958
|
"""
|
|
903
959
|
Drop an index from the table. Either a column name or an index name (but not both) must be
|
|
904
960
|
specified. If a column name or reference is specified, it must be a column containing exactly one index;
|
|
@@ -908,6 +964,14 @@ class Table(SchemaObject):
|
|
|
908
964
|
column: The name of, or reference to, the column from which to drop the index.
|
|
909
965
|
The column must have only one embedding index.
|
|
910
966
|
idx_name: The name of the index to drop.
|
|
967
|
+
if_not_exists: Directive for handling a non-existent index. Must be one of the following:
|
|
968
|
+
|
|
969
|
+
- `'error'`: raise an error if the index does not exist.
|
|
970
|
+
- `'ignore'`: do nothing if the index does not exist.
|
|
971
|
+
|
|
972
|
+
Note that `if_not_exists` parameter is only applicable when an `idx_name` is specified
|
|
973
|
+
and it does not exist, or when `column` is specified and it has no index.
|
|
974
|
+
`if_not_exists` does not apply to non-exisitng column.
|
|
911
975
|
|
|
912
976
|
Raises:
|
|
913
977
|
Error: If `column` is specified, but the column does not exist, or it contains no
|
|
@@ -929,6 +993,10 @@ class Table(SchemaObject):
|
|
|
929
993
|
>>> tbl = pxt.get_table('my_table')
|
|
930
994
|
... tbl.drop_index(idx_name='idx1')
|
|
931
995
|
|
|
996
|
+
Drop the index `idx1` of the table `my_table` by index name, if it exists, otherwise do nothing:
|
|
997
|
+
>>> tbl = pxt.get_table('my_table')
|
|
998
|
+
... tbl.drop_index(idx_name='idx1', if_not_exists='ignore')
|
|
999
|
+
|
|
932
1000
|
"""
|
|
933
1001
|
if (column is None) == (idx_name is None):
|
|
934
1002
|
raise excs.Error("Exactly one of 'column' or 'idx_name' must be provided")
|
|
@@ -942,20 +1010,25 @@ class Table(SchemaObject):
|
|
|
942
1010
|
self.__check_column_ref_exists(column, include_bases=True)
|
|
943
1011
|
col = column.col
|
|
944
1012
|
assert col is not None
|
|
945
|
-
self._drop_index(col=col, idx_name=idx_name)
|
|
1013
|
+
self._drop_index(col=col, idx_name=idx_name, if_not_exists=if_not_exists)
|
|
946
1014
|
|
|
947
1015
|
def _drop_index(
|
|
948
1016
|
self, *, col: Optional[Column] = None,
|
|
949
1017
|
idx_name: Optional[str] = None,
|
|
950
|
-
_idx_class: Optional[type[index.IndexBase]] = None
|
|
1018
|
+
_idx_class: Optional[type[index.IndexBase]] = None,
|
|
1019
|
+
if_not_exists: Literal['error', 'ignore'] = 'error'
|
|
951
1020
|
) -> None:
|
|
952
1021
|
if self._tbl_version_path.is_snapshot():
|
|
953
1022
|
raise excs.Error('Cannot drop an index from a snapshot')
|
|
954
1023
|
assert (col is None) != (idx_name is None)
|
|
955
1024
|
|
|
956
1025
|
if idx_name is not None:
|
|
1026
|
+
_if_not_exists = IfNotExistsParam.validated(if_not_exists, 'if_not_exists')
|
|
957
1027
|
if idx_name not in self._tbl_version.idxs_by_name:
|
|
958
|
-
|
|
1028
|
+
if _if_not_exists == IfNotExistsParam.ERROR:
|
|
1029
|
+
raise excs.Error(f'Index {idx_name!r} does not exist')
|
|
1030
|
+
assert _if_not_exists == IfNotExistsParam.IGNORE
|
|
1031
|
+
return
|
|
959
1032
|
idx_id = self._tbl_version.idxs_by_name[idx_name].id
|
|
960
1033
|
else:
|
|
961
1034
|
if col.tbl.id != self._tbl_version.id:
|
|
@@ -965,7 +1038,11 @@ class Table(SchemaObject):
|
|
|
965
1038
|
if _idx_class is not None:
|
|
966
1039
|
idx_info = [info for info in idx_info if isinstance(info.idx, _idx_class)]
|
|
967
1040
|
if len(idx_info) == 0:
|
|
968
|
-
|
|
1041
|
+
_if_not_exists = IfNotExistsParam.validated(if_not_exists, 'if_not_exists')
|
|
1042
|
+
if _if_not_exists == IfNotExistsParam.ERROR:
|
|
1043
|
+
raise excs.Error(f'Column {col.name!r} does not have an index')
|
|
1044
|
+
assert _if_not_exists == IfNotExistsParam.IGNORE
|
|
1045
|
+
return
|
|
969
1046
|
if len(idx_info) > 1:
|
|
970
1047
|
raise excs.Error(f"Column {col.name!r} has multiple indices; specify 'idx_name' instead")
|
|
971
1048
|
idx_id = idx_info[0].id
|
|
@@ -9,6 +9,7 @@ import uuid
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Iterable, Iterator, Literal, Optional
|
|
10
10
|
from uuid import UUID
|
|
11
11
|
|
|
12
|
+
import jsonschema.exceptions
|
|
12
13
|
import sqlalchemy as sql
|
|
13
14
|
import sqlalchemy.orm as orm
|
|
14
15
|
|
|
@@ -173,6 +174,14 @@ class TableVersion:
|
|
|
173
174
|
def __hash__(self) -> int:
|
|
174
175
|
return hash(self.id)
|
|
175
176
|
|
|
177
|
+
def _get_column(self, tbl_id: UUID, col_id: int) -> Column:
|
|
178
|
+
if self.id == tbl_id:
|
|
179
|
+
return self.cols_by_id[col_id]
|
|
180
|
+
else:
|
|
181
|
+
if self.base is None:
|
|
182
|
+
raise excs.Error(f'Unknown table id: {tbl_id}')
|
|
183
|
+
return self.base._get_column(tbl_id, col_id)
|
|
184
|
+
|
|
176
185
|
def create_snapshot_copy(self) -> TableVersion:
|
|
177
186
|
"""Create a snapshot copy of this TableVersion"""
|
|
178
187
|
assert not self.is_snapshot
|
|
@@ -335,7 +344,7 @@ class TableVersion:
|
|
|
335
344
|
# instantiate index object
|
|
336
345
|
cls_name = md.class_fqn.rsplit('.', 1)[-1]
|
|
337
346
|
cls = getattr(index_module, cls_name)
|
|
338
|
-
idx_col = self.
|
|
347
|
+
idx_col = self._get_column(UUID(md.indexed_col_tbl_id), md.indexed_col_id)
|
|
339
348
|
idx = cls.from_dict(idx_col, md.init_args)
|
|
340
349
|
|
|
341
350
|
# fix up the sa column type of the index value and undo columns
|
|
@@ -457,7 +466,8 @@ class TableVersion:
|
|
|
457
466
|
idx_cls = type(idx)
|
|
458
467
|
idx_md = schema.IndexMd(
|
|
459
468
|
id=idx_id, name=idx_name,
|
|
460
|
-
indexed_col_id=col.id,
|
|
469
|
+
indexed_col_id=col.id, indexed_col_tbl_id=str(col.tbl.id),
|
|
470
|
+
index_val_col_id=val_col.id, index_val_undo_col_id=undo_col.id,
|
|
461
471
|
schema_version_add=self.schema_version, schema_version_drop=None,
|
|
462
472
|
class_fqn=idx_cls.__module__ + '.' + idx_cls.__name__, init_args=idx.as_dict())
|
|
463
473
|
idx_info = self.IndexInfo(id=idx_id, name=idx_name, idx=idx, col=col, val_col=val_col, undo_col=undo_col)
|
|
@@ -485,7 +495,10 @@ class TableVersion:
|
|
|
485
495
|
idx_md.schema_version_drop = self.schema_version
|
|
486
496
|
assert idx_md.name in self.idxs_by_name
|
|
487
497
|
idx_info = self.idxs_by_name[idx_md.name]
|
|
498
|
+
# remove this index entry from the active indexes (in memory)
|
|
499
|
+
# and the index metadata (in persistent table metadata)
|
|
488
500
|
del self.idxs_by_name[idx_md.name]
|
|
501
|
+
del self.idx_md[idx_id]
|
|
489
502
|
|
|
490
503
|
with Env.get().engine.begin() as conn:
|
|
491
504
|
self._drop_columns([idx_info.val_col, idx_info.undo_col])
|
|
@@ -819,7 +832,7 @@ class TableVersion:
|
|
|
819
832
|
if error_if_not_exists:
|
|
820
833
|
raise excs.Error(f'batch_update(): {len(unmatched_rows)} row(s) not found')
|
|
821
834
|
if insert_if_not_exists:
|
|
822
|
-
insert_status = self.insert(unmatched_rows, None, print_stats=False, fail_on_exception=False)
|
|
835
|
+
insert_status = self.insert(unmatched_rows, None, conn=conn, print_stats=False, fail_on_exception=False)
|
|
823
836
|
result += insert_status
|
|
824
837
|
return result
|
|
825
838
|
|
|
@@ -846,10 +859,11 @@ class TableVersion:
|
|
|
846
859
|
raise excs.Error(f'Column {col_name} is a primary key column and cannot be updated')
|
|
847
860
|
|
|
848
861
|
# make sure that the value is compatible with the column type
|
|
862
|
+
value_expr: exprs.Expr
|
|
849
863
|
try:
|
|
850
864
|
# check if this is a literal
|
|
851
|
-
value_expr
|
|
852
|
-
except TypeError:
|
|
865
|
+
value_expr = exprs.Literal(val, col_type=col.col_type)
|
|
866
|
+
except (TypeError, jsonschema.exceptions.ValidationError):
|
|
853
867
|
if not allow_exprs:
|
|
854
868
|
raise excs.Error(
|
|
855
869
|
f'Column {col_name}: value {val!r} is not a valid literal for this column '
|
|
@@ -858,11 +872,11 @@ class TableVersion:
|
|
|
858
872
|
value_expr = exprs.Expr.from_object(val)
|
|
859
873
|
if value_expr is None:
|
|
860
874
|
raise excs.Error(f'Column {col_name}: value {val!r} is not a recognized literal or expression')
|
|
861
|
-
if not col.col_type.
|
|
862
|
-
raise excs.Error(
|
|
875
|
+
if not col.col_type.is_supertype_of(value_expr.col_type, ignore_nullable=True):
|
|
876
|
+
raise excs.Error(
|
|
863
877
|
f'Type of value {val!r} ({value_expr.col_type}) is not compatible with the type of column '
|
|
864
878
|
f'{col_name} ({col.col_type})'
|
|
865
|
-
)
|
|
879
|
+
)
|
|
866
880
|
update_targets[col] = value_expr
|
|
867
881
|
|
|
868
882
|
return update_targets
|