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.

Files changed (132) hide show
  1. {pixeltable-0.2.9 → pixeltable-0.2.11}/PKG-INFO +2 -2
  2. {pixeltable-0.2.9 → pixeltable-0.2.11}/README.md +1 -1
  3. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/__version__.py +2 -2
  4. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/catalog.py +3 -3
  5. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/globals.py +2 -0
  6. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/insertable_table.py +1 -11
  7. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table.py +13 -72
  8. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table_version.py +94 -29
  9. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/table_version_path.py +1 -1
  10. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/view.py +31 -27
  11. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/dataframe.py +32 -115
  12. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/whisper.py +0 -4
  13. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/globals.py +19 -6
  14. pixeltable-0.2.11/pixeltable/utils/formatter.py +234 -0
  15. {pixeltable-0.2.9 → pixeltable-0.2.11}/pyproject.toml +1 -1
  16. {pixeltable-0.2.9 → pixeltable-0.2.11}/LICENSE +0 -0
  17. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/__init__.py +0 -0
  18. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/__init__.py +0 -0
  19. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/column.py +0 -0
  20. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/dir.py +0 -0
  21. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/named_function.py +0 -0
  22. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/path.py +0 -0
  23. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/path_dict.py +0 -0
  24. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/catalog/schema_object.py +0 -0
  25. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/env.py +0 -0
  26. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exceptions.py +0 -0
  27. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/__init__.py +0 -0
  28. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/aggregation_node.py +0 -0
  29. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/cache_prefetch_node.py +0 -0
  30. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/component_iteration_node.py +0 -0
  31. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/data_row_batch.py +0 -0
  32. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/exec_context.py +0 -0
  33. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/exec_node.py +0 -0
  34. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/expr_eval_node.py +0 -0
  35. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/in_memory_data_node.py +0 -0
  36. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/media_validation_node.py +0 -0
  37. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exec/sql_scan_node.py +0 -0
  38. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/__init__.py +0 -0
  39. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/arithmetic_expr.py +0 -0
  40. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/array_slice.py +0 -0
  41. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/column_property_ref.py +0 -0
  42. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/column_ref.py +0 -0
  43. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/comparison.py +0 -0
  44. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/compound_predicate.py +0 -0
  45. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/data_row.py +0 -0
  46. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/expr.py +0 -0
  47. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/expr_set.py +0 -0
  48. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/function_call.py +0 -0
  49. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/globals.py +0 -0
  50. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/image_member_access.py +0 -0
  51. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/in_predicate.py +0 -0
  52. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/inline_array.py +0 -0
  53. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/inline_dict.py +0 -0
  54. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/is_null.py +0 -0
  55. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/json_mapper.py +0 -0
  56. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/json_path.py +0 -0
  57. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/literal.py +0 -0
  58. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/object_ref.py +0 -0
  59. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/predicate.py +0 -0
  60. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/row_builder.py +0 -0
  61. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/rowid_ref.py +0 -0
  62. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/similarity_expr.py +0 -0
  63. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/type_cast.py +0 -0
  64. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/exprs/variable.py +0 -0
  65. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/__init__.py +0 -0
  66. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/functions/whisperx.py +0 -0
  67. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/ext/functions/yolox.py +0 -0
  68. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/__init__.py +0 -0
  69. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/aggregate_function.py +0 -0
  70. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/callable_function.py +0 -0
  71. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/expr_template_function.py +0 -0
  72. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/function.py +0 -0
  73. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/function_registry.py +0 -0
  74. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/globals.py +0 -0
  75. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/query_template_function.py +0 -0
  76. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/signature.py +0 -0
  77. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/func/udf.py +0 -0
  78. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/__init__.py +0 -0
  79. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/eval.py +0 -0
  80. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/fireworks.py +0 -0
  81. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/globals.py +0 -0
  82. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/huggingface.py +0 -0
  83. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/image.py +0 -0
  84. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/openai.py +0 -0
  85. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/string.py +0 -0
  86. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/together.py +0 -0
  87. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/util.py +0 -0
  88. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/functions/video.py +0 -0
  89. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/__init__.py +0 -0
  90. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/base.py +0 -0
  91. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/btree.py +0 -0
  92. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/index/embedding_index.py +0 -0
  93. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/__init__.py +0 -0
  94. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/external_store.py +0 -0
  95. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/globals.py +0 -0
  96. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/hf_datasets.py +0 -0
  97. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/label_studio.py +0 -0
  98. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/pandas.py +0 -0
  99. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/io/parquet.py +0 -0
  100. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/__init__.py +0 -0
  101. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/base.py +0 -0
  102. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/document.py +0 -0
  103. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/string.py +0 -0
  104. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/iterators/video.py +0 -0
  105. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/__init__.py +0 -0
  106. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_10.py +0 -0
  107. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_12.py +0 -0
  108. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_13.py +0 -0
  109. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_14.py +0 -0
  110. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_15.py +0 -0
  111. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/convert_16.py +0 -0
  112. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/converters/util.py +0 -0
  113. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/metadata/schema.py +0 -0
  114. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/plan.py +0 -0
  115. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/store.py +0 -0
  116. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/create_test_db_dump.py +0 -0
  117. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/create_test_video.py +0 -0
  118. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/tool/embed_udf.py +0 -0
  119. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/type_system.py +0 -0
  120. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/__init__.py +0 -0
  121. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/arrow.py +0 -0
  122. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/coco.py +0 -0
  123. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/code.py +0 -0
  124. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/documents.py +0 -0
  125. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/filecache.py +0 -0
  126. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/help.py +0 -0
  127. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/http_server.py +0 -0
  128. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/media_store.py +0 -0
  129. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/pytorch.py +0 -0
  130. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/s3.py +0 -0
  131. {pixeltable-0.2.9 → pixeltable-0.2.11}/pixeltable/utils/sql.py +0 -0
  132. {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.9
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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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"/> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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"/> | [![API](https://img.shields.io/badge/api-reference-blue.svg)](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.9"
3
- __version_tuple__ = (0, 2, 9)
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
- base_tbl = self.tbls[base_path.tbl_version.id]
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, base_tbl,
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[base_tbl._id].append(tbl)
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)
@@ -7,6 +7,8 @@ _logger = logging.getLogger('pixeltable')
7
7
 
8
8
  # name of the position column in a component view
9
9
  POS_COLUMN_NAME = 'pos'
10
+ _ROWID_COLUMN_NAME = '_rowid'
11
+
10
12
 
11
13
  @dataclasses.dataclass
12
14
  class UpdateStatus:
@@ -144,14 +144,4 @@ class InsertableTable(Table):
144
144
 
145
145
  >>> tbl.delete(tbl.a > 5)
146
146
  """
147
- from pixeltable.exprs import Predicate
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 df(self) -> 'pixeltable.dataframe.DataFrame':
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.df().collect()
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.df().show(*args, **kwargs)
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.df().head(*args, **kwargs)
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.df().tail(*args, **kwargs)
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.df().count()
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 = self.__ROWID_COLUMN_NAME in rows[0]
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 self.__ROWID_COLUMN_NAME in row_spec
756
- rowids.append(row_spec[self.__ROWID_COLUMN_NAME])
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
- self, update_targets: dict[Column, 'pixeltable.exprs.Expr'],
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, update_targets, where_clause, cascade)
732
+ return self._update(conn, update_spec, where, cascade)
712
733
 
713
734
  def batch_update(
714
- self, batch: list[dict[Column, 'pixeltable.exprs.Expr']], rowids: list[Tuple[int, ...]],
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
- plan, updated_cols, recomputed_cols = \
791
+
792
+ plan, updated_cols, recomputed_cols = (
781
793
  Planner.create_update_plan(self.path, update_targets, [], where_clause, cascade)
782
- result = self._propagate_update(
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 _propagate_update(
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._propagate_update(
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['pixeltable.exprs.Predicate'] = None) -> UpdateStatus:
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
- analysis_info = Planner.analyze(self, where)
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._delete(analysis_info.sql_where_clause, base_versions=[], conn=conn, timestamp=time.time())
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 _delete(
837
- self, where: Optional['pixeltable.exprs.Predicate'], base_versions: List[Optional[int]],
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._delete(
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 List, Optional, Type, Dict, Set, Any, Iterable
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
- import pixeltable.exceptions as excs
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, base: Table,
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
- self._base = base # keep a reference to the base Table, so that we can keep track of its dependents
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: Table, schema: Dict[str, Any],
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._tbl_version_path):
59
- raise excs.Error(f'Filter cannot be computed in the context of the base {base._name}')
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._tbl_version_path):
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._name}')
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._tbl_version_path) if is_snapshot else base._tbl_version_path
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._id].append(view)
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._base._id].remove(self)
207
+ cat.tbl_dependents[self._base_id].remove(self)
204
208
  del cat.tbl_dependents[self._id]
205
209
 
206
210
  def insert(