pixeltable 0.3.2__tar.gz → 0.3.3__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 (165) hide show
  1. {pixeltable-0.3.2 → pixeltable-0.3.3}/PKG-INFO +6 -8
  2. {pixeltable-0.3.2 → pixeltable-0.3.3}/README.md +5 -7
  3. pixeltable-0.3.3/pixeltable/__init__.py +78 -0
  4. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/__version__.py +2 -2
  5. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/__init__.py +1 -1
  6. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/catalog.py +50 -27
  7. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/column.py +27 -11
  8. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/dir.py +6 -4
  9. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/globals.py +8 -1
  10. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/insertable_table.py +22 -12
  11. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/named_function.py +10 -6
  12. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/path.py +3 -2
  13. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/path_dict.py +8 -6
  14. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/schema_object.py +2 -1
  15. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/table.py +121 -101
  16. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/table_version.py +291 -142
  17. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/table_version_path.py +8 -5
  18. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/catalog/view.py +67 -26
  19. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/dataframe.py +102 -72
  20. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/env.py +20 -21
  21. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/__init__.py +2 -2
  22. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/aggregation_node.py +10 -4
  23. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/cache_prefetch_node.py +5 -3
  24. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/component_iteration_node.py +9 -8
  25. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/data_row_batch.py +21 -10
  26. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/exec_context.py +10 -3
  27. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/exec_node.py +23 -12
  28. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/evaluators.py +13 -7
  29. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/expr_eval_node.py +24 -15
  30. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/globals.py +30 -7
  31. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/row_buffer.py +5 -6
  32. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/schedulers.py +151 -31
  33. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/in_memory_data_node.py +8 -7
  34. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/row_update_node.py +15 -5
  35. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/sql_node.py +56 -27
  36. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/__init__.py +2 -2
  37. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/arithmetic_expr.py +57 -26
  38. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/column_property_ref.py +2 -1
  39. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/column_ref.py +20 -15
  40. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/comparison.py +6 -2
  41. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/compound_predicate.py +1 -3
  42. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/expr.py +101 -72
  43. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/expr_dict.py +2 -1
  44. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/expr_set.py +3 -1
  45. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/function_call.py +39 -41
  46. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/globals.py +1 -0
  47. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/in_predicate.py +2 -2
  48. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/inline_expr.py +20 -17
  49. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/json_mapper.py +4 -2
  50. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/json_path.py +12 -18
  51. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/literal.py +5 -9
  52. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/method_ref.py +1 -0
  53. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/row_builder.py +32 -17
  54. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/rowid_ref.py +14 -5
  55. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/similarity_expr.py +11 -6
  56. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/sql_element_cache.py +1 -1
  57. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/type_cast.py +24 -9
  58. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/ext/__init__.py +1 -0
  59. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/ext/functions/__init__.py +1 -0
  60. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/ext/functions/whisperx.py +2 -2
  61. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/ext/functions/yolox.py +11 -11
  62. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/aggregate_function.py +17 -13
  63. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/callable_function.py +6 -6
  64. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/expr_template_function.py +15 -14
  65. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/function.py +16 -16
  66. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/function_registry.py +11 -8
  67. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/globals.py +4 -2
  68. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/query_template_function.py +12 -13
  69. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/signature.py +18 -9
  70. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/tools.py +10 -17
  71. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/udf.py +106 -11
  72. pixeltable-0.3.3/pixeltable/functions/__init__.py +30 -0
  73. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/anthropic.py +16 -12
  74. pixeltable-0.3.3/pixeltable/functions/fireworks.py +132 -0
  75. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/gemini.py +13 -3
  76. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/globals.py +18 -6
  77. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/huggingface.py +20 -38
  78. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/image.py +7 -3
  79. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/json.py +1 -0
  80. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/llama_cpp.py +1 -4
  81. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/mistralai.py +31 -20
  82. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/ollama.py +4 -18
  83. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/openai.py +201 -108
  84. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/replicate.py +11 -10
  85. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/string.py +70 -7
  86. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/timestamp.py +21 -8
  87. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/together.py +66 -52
  88. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/video.py +1 -0
  89. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/vision.py +14 -11
  90. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/whisper.py +2 -1
  91. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/globals.py +60 -26
  92. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/index/btree.py +5 -3
  93. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/index/embedding_index.py +15 -14
  94. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/__init__.py +1 -1
  95. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/external_store.py +30 -25
  96. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/fiftyone.py +6 -14
  97. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/globals.py +33 -27
  98. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/hf_datasets.py +2 -1
  99. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/label_studio.py +77 -68
  100. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/pandas.py +33 -9
  101. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/io/parquet.py +9 -12
  102. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/__init__.py +1 -0
  103. pixeltable-0.3.3/pixeltable/iterators/audio.py +205 -0
  104. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/document.py +19 -8
  105. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/image.py +6 -24
  106. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/string.py +3 -6
  107. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/video.py +1 -7
  108. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/__init__.py +7 -1
  109. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_10.py +2 -2
  110. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_15.py +1 -5
  111. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_16.py +2 -4
  112. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_17.py +2 -4
  113. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_18.py +2 -4
  114. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_19.py +2 -5
  115. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_20.py +1 -4
  116. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_21.py +4 -6
  117. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_22.py +1 -0
  118. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_23.py +5 -5
  119. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_24.py +12 -13
  120. pixeltable-0.3.3/pixeltable/metadata/converters/convert_26.py +23 -0
  121. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/util.py +3 -4
  122. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/notes.py +1 -0
  123. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/schema.py +13 -2
  124. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/plan.py +173 -98
  125. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/store.py +42 -26
  126. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/type_system.py +62 -54
  127. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/arrow.py +1 -2
  128. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/coco.py +16 -17
  129. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/console_output.py +6 -3
  130. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/description_helper.py +7 -7
  131. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/documents.py +3 -1
  132. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/filecache.py +12 -7
  133. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/http_server.py +9 -8
  134. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/media_store.py +2 -1
  135. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/pytorch.py +11 -14
  136. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/s3.py +1 -0
  137. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/sql.py +1 -0
  138. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/transactional_directory.py +2 -2
  139. {pixeltable-0.3.2 → pixeltable-0.3.3}/pyproject.toml +10 -2
  140. pixeltable-0.3.2/pixeltable/__init__.py +0 -25
  141. pixeltable-0.3.2/pixeltable/functions/__init__.py +0 -11
  142. pixeltable-0.3.2/pixeltable/functions/fireworks.py +0 -74
  143. {pixeltable-0.3.2 → pixeltable-0.3.3}/LICENSE +0 -0
  144. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exceptions.py +0 -0
  145. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exec/expr_eval/__init__.py +0 -0
  146. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/array_slice.py +1 -1
  147. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/data_row.py +2 -2
  148. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/is_null.py +0 -0
  149. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/object_ref.py +1 -1
  150. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/exprs/variable.py +0 -0
  151. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/func/__init__.py +0 -0
  152. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/audio.py +0 -0
  153. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/math.py +0 -0
  154. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/functions/util.py +0 -0
  155. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/index/__init__.py +1 -1
  156. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/index/base.py +0 -0
  157. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/iterators/base.py +0 -0
  158. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_12.py +0 -0
  159. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_13.py +0 -0
  160. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_14.py +0 -0
  161. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/metadata/converters/convert_25.py +0 -0
  162. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/py.typed +0 -0
  163. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/__init__.py +0 -0
  164. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/code.py +1 -1
  165. {pixeltable-0.3.2 → pixeltable-0.3.3}/pixeltable/utils/formatter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pixeltable
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: AI Data Infrastructure: Declarative, Multimodal, and Incremental
5
5
  Home-page: https://pixeltable.com/
6
6
  License: Apache-2.0
@@ -60,7 +60,7 @@ Description-Content-Type: text/markdown
60
60
  alt="Pixeltable" width="50%" />
61
61
  <br></br>
62
62
 
63
- <h2>AI Data Infrastructure Declarative, Multimodal, and Incremental</h2>
63
+ <h2>Build Multimodal AI Apps with Declarative Data Infrastructure</h2>
64
64
 
65
65
  [![License](https://img.shields.io/badge/License-Apache%202.0-0530AD.svg)](https://opensource.org/licenses/Apache-2.0)
66
66
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pixeltable?logo=python&logoColor=white&)
@@ -82,17 +82,15 @@ Description-Content-Type: text/markdown
82
82
  [LLM](https://docs.pixeltable.com/docs/document-indexing-and-rag)
83
83
  </div>
84
84
 
85
- Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video).
86
- It features built-in versioning, lineage tracking, and incremental updates, enabling users to **store**, **transform**,
87
- **index**, and **iterate** on data for their ML workflows.
85
+ Pixeltable is a declarative data infrastructure for building multimodal AI applications, enabling incremental storage, transformation, indexing, and orchestration of your data.
88
86
 
89
- Data transformations, model inference, and custom logic are embedded as **computed columns**.
87
+ Consider it your unified foundation for computer vision, LLMs, and multimodal AI development - where complex data operations become simple tables and computed columns, including but not limited to:
90
88
 
91
- - **Load/Query all data types**: Interact with
89
+ - **Work with all your data**: Interact with
92
90
  [video data](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#import-media-data-into-pixeltable-videos-images-audio)
93
91
  at the [frame level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#text-and-image-similarity-search-on-video-frames-with-embedding-indexes)
94
92
  and documents at the [chunk level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#automate-data-operations-with-views-eg-split-documents-into-chunks)
95
- - **Incremental updates for data transformation**: Maintain an
93
+ - **Incremental updates**: Maintain an
96
94
  [embedding index](https://docs.pixeltable.com/docs/embedding-vector-indexes) colocated with your data
97
95
  - **Lazy evaluation and cache management**: Eliminates the need for
98
96
  [manual frame extraction](https://docs.pixeltable.com/docs/object-detection-in-videos)
@@ -3,7 +3,7 @@
3
3
  alt="Pixeltable" width="50%" />
4
4
  <br></br>
5
5
 
6
- <h2>AI Data Infrastructure Declarative, Multimodal, and Incremental</h2>
6
+ <h2>Build Multimodal AI Apps with Declarative Data Infrastructure</h2>
7
7
 
8
8
  [![License](https://img.shields.io/badge/License-Apache%202.0-0530AD.svg)](https://opensource.org/licenses/Apache-2.0)
9
9
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pixeltable?logo=python&logoColor=white&)
@@ -25,17 +25,15 @@
25
25
  [LLM](https://docs.pixeltable.com/docs/document-indexing-and-rag)
26
26
  </div>
27
27
 
28
- Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video).
29
- It features built-in versioning, lineage tracking, and incremental updates, enabling users to **store**, **transform**,
30
- **index**, and **iterate** on data for their ML workflows.
28
+ Pixeltable is a declarative data infrastructure for building multimodal AI applications, enabling incremental storage, transformation, indexing, and orchestration of your data.
31
29
 
32
- Data transformations, model inference, and custom logic are embedded as **computed columns**.
30
+ Consider it your unified foundation for computer vision, LLMs, and multimodal AI development - where complex data operations become simple tables and computed columns, including but not limited to:
33
31
 
34
- - **Load/Query all data types**: Interact with
32
+ - **Work with all your data**: Interact with
35
33
  [video data](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#import-media-data-into-pixeltable-videos-images-audio)
36
34
  at the [frame level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#text-and-image-similarity-search-on-video-frames-with-embedding-indexes)
37
35
  and documents at the [chunk level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#automate-data-operations-with-views-eg-split-documents-into-chunks)
38
- - **Incremental updates for data transformation**: Maintain an
36
+ - **Incremental updates**: Maintain an
39
37
  [embedding index](https://docs.pixeltable.com/docs/embedding-vector-indexes) colocated with your data
40
38
  - **Lazy evaluation and cache management**: Eliminates the need for
41
39
  [manual frame extraction](https://docs.pixeltable.com/docs/object-detection-in-videos)
@@ -0,0 +1,78 @@
1
+ from .__version__ import __version__, __version_tuple__
2
+ from .catalog import Column, InsertableTable, Table, UpdateStatus, View
3
+ from .dataframe import DataFrame
4
+ from .exceptions import Error
5
+ from .exprs import RELATIVE_PATH_ROOT
6
+ from .func import Aggregator, Function, expr_udf, query, uda, udf
7
+ from .globals import (
8
+ array,
9
+ configure_logging,
10
+ create_dir,
11
+ create_snapshot,
12
+ create_table,
13
+ create_view,
14
+ drop_dir,
15
+ drop_table,
16
+ get_table,
17
+ init,
18
+ list_dirs,
19
+ list_functions,
20
+ list_tables,
21
+ move,
22
+ tool,
23
+ tools,
24
+ )
25
+ from .type_system import (
26
+ Array,
27
+ ArrayType,
28
+ Audio,
29
+ AudioType,
30
+ Bool,
31
+ BoolType,
32
+ ColumnType,
33
+ Document,
34
+ DocumentType,
35
+ Float,
36
+ FloatType,
37
+ Image,
38
+ ImageType,
39
+ Int,
40
+ IntType,
41
+ Json,
42
+ JsonType,
43
+ Required,
44
+ String,
45
+ StringType,
46
+ Timestamp,
47
+ TimestampType,
48
+ Video,
49
+ VideoType,
50
+ )
51
+
52
+ # This import must go last to avoid circular imports.
53
+ from . import ext, functions, io, iterators # isort: skip
54
+
55
+ # This is the safest / most maintainable way to construct __all__: start with the default and "blacklist"
56
+ # stuff that we don't want in there. (Using a "whitelist" is considerably harder to maintain.)
57
+
58
+ __default_dir = set(symbol for symbol in dir() if not symbol.startswith('_'))
59
+ __removed_symbols = {
60
+ 'catalog',
61
+ 'dataframe',
62
+ 'env',
63
+ 'exceptions',
64
+ 'exec',
65
+ 'exprs',
66
+ 'func',
67
+ 'globals',
68
+ 'index',
69
+ 'metadata',
70
+ 'plan',
71
+ 'type_system',
72
+ 'utils',
73
+ }
74
+ __all__ = sorted(list(__default_dir - __removed_symbols))
75
+
76
+
77
+ def __dir__():
78
+ return __all__
@@ -1,3 +1,3 @@
1
1
  # These version placeholders will be replaced during build.
2
- __version__ = "0.3.2"
3
- __version_tuple__ = (0, 3, 2)
2
+ __version__ = '0.3.3'
3
+ __version_tuple__ = (0, 3, 3)
@@ -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, IfExistsParam, IfNotExistsParam
4
+ from .globals import IfExistsParam, IfNotExistsParam, MediaValidation, UpdateStatus, is_valid_identifier, is_valid_path
5
5
  from .insertable_table import InsertableTable
6
6
  from .named_function import NamedFunction
7
7
  from .path import Path
@@ -8,18 +8,22 @@ from uuid import UUID
8
8
  import sqlalchemy as sql
9
9
  import sqlalchemy.orm as orm
10
10
 
11
+ import pixeltable.metadata.schema as schema
12
+
13
+ from .path_dict import PathDict
14
+ from .table import Table
11
15
  from .table_version import TableVersion
12
16
  from .table_version_path import TableVersionPath
13
- from .table import Table
14
- from .path_dict import PathDict
15
17
 
16
- import pixeltable.env as env
17
- import pixeltable.metadata.schema as schema
18
+ # This import must go last to avoid circular imports.
19
+ import pixeltable.env as env # isort: skip
18
20
 
19
21
  _logger = logging.getLogger('pixeltable')
20
22
 
23
+
21
24
  class Catalog:
22
25
  """A repository of catalog objects"""
26
+
23
27
  _instance: Optional[Catalog] = None
24
28
 
25
29
  @classmethod
@@ -28,7 +32,7 @@ class Catalog:
28
32
  cls._instance = cls()
29
33
  with orm.Session(env.Env.get().engine, future=True) as session:
30
34
  cls._instance._load_table_versions(session)
31
- #cls._instance._load_functions(session)
35
+ # cls._instance._load_functions(session)
32
36
  return cls._instance
33
37
 
34
38
  @classmethod
@@ -62,17 +66,24 @@ class Catalog:
62
66
  _logger.info(f'Initialized catalog')
63
67
 
64
68
  def _load_snapshot_version(
65
- self, tbl_id: UUID, version: int, base: Optional[TableVersion], session: orm.Session
69
+ self, tbl_id: UUID, version: int, base: Optional[TableVersion], session: orm.Session
66
70
  ) -> TableVersion:
67
- q = session.query(schema.Table, schema.TableSchemaVersion) \
68
- .select_from(schema.Table) \
69
- .join(schema.TableVersion) \
70
- .join(schema.TableSchemaVersion) \
71
- .where(schema.Table.id == tbl_id) \
72
- .where(sql.text(f"({schema.TableVersion.__table__}.md->>'version')::int = {version}")) \
73
- .where(sql.text((
74
- f"({schema.TableVersion.__table__}.md->>'schema_version')::int = "
75
- f"{schema.TableSchemaVersion.__table__}.{schema.TableSchemaVersion.schema_version.name}")))
71
+ q = (
72
+ session.query(schema.Table, schema.TableSchemaVersion)
73
+ .select_from(schema.Table)
74
+ .join(schema.TableVersion)
75
+ .join(schema.TableSchemaVersion)
76
+ .where(schema.Table.id == tbl_id)
77
+ .where(sql.text(f"({schema.TableVersion.__table__}.md->>'version')::int = {version}"))
78
+ .where(
79
+ sql.text(
80
+ (
81
+ f"({schema.TableVersion.__table__}.md->>'schema_version')::int = "
82
+ f'{schema.TableSchemaVersion.__table__}.{schema.TableSchemaVersion.schema_version.name}'
83
+ )
84
+ )
85
+ )
86
+ )
76
87
  tbl_record, schema_version_record = q.one()
77
88
  tbl_md = schema.md_from_dict(schema.TableMd, tbl_record.md)
78
89
  schema_version_md = schema.md_from_dict(schema.TableSchemaVersionMd, schema_version_record.md)
@@ -86,15 +97,22 @@ class Catalog:
86
97
 
87
98
  # load tables/views;
88
99
  # do this in ascending order of creation ts so that we can resolve base references in one pass
89
- q = session.query(schema.Table, schema.TableSchemaVersion) \
90
- .select_from(schema.Table) \
91
- .join(schema.TableVersion) \
92
- .join(schema.TableSchemaVersion) \
93
- .where(sql.text(f"({schema.TableVersion.__table__}.md->>'version')::int = 0")) \
94
- .where(sql.text((
95
- f"({schema.Table.__table__}.md->>'current_schema_version')::int = "
96
- f"{schema.TableSchemaVersion.__table__}.{schema.TableSchemaVersion.schema_version.name}"))) \
100
+ q = (
101
+ session.query(schema.Table, schema.TableSchemaVersion)
102
+ .select_from(schema.Table)
103
+ .join(schema.TableVersion)
104
+ .join(schema.TableSchemaVersion)
105
+ .where(sql.text(f"({schema.TableVersion.__table__}.md->>'version')::int = 0"))
106
+ .where(
107
+ sql.text(
108
+ (
109
+ f"({schema.Table.__table__}.md->>'current_schema_version')::int = "
110
+ f'{schema.TableSchemaVersion.__table__}.{schema.TableSchemaVersion.schema_version.name}'
111
+ )
112
+ )
113
+ )
97
114
  .order_by(sql.text(f"({schema.TableVersion.__table__}.md->>'created_at')::float"))
115
+ )
98
116
 
99
117
  for tbl_record, schema_version_record in q.all():
100
118
  tbl_md = schema.md_from_dict(schema.TableMd, tbl_record.md)
@@ -129,14 +147,19 @@ class Catalog:
129
147
  view_path = base_path
130
148
  else:
131
149
  tbl_version = TableVersion(
132
- tbl_record.id, tbl_md, tbl_md.current_version, schema_version_md, is_snapshot=is_snapshot,
150
+ tbl_record.id,
151
+ tbl_md,
152
+ tbl_md.current_version,
153
+ schema_version_md,
154
+ is_snapshot=is_snapshot,
133
155
  base=base_path.tbl_version if is_snapshot else None,
134
- base_path=base_path if not is_snapshot else None)
156
+ base_path=base_path if not is_snapshot else None,
157
+ )
135
158
  view_path = TableVersionPath(tbl_version, base=base_path)
136
159
 
137
160
  tbl: Table = View(
138
- tbl_record.id, tbl_record.dir_id, tbl_md.name, view_path, base_tbl_id,
139
- snapshot_only=snapshot_only)
161
+ tbl_record.id, tbl_record.dir_id, tbl_md.name, view_path, base_tbl_id, snapshot_only=snapshot_only
162
+ )
140
163
  self.tbl_dependents[base_tbl_id].append(tbl)
141
164
 
142
165
  else:
@@ -8,7 +8,8 @@ import sqlalchemy as sql
8
8
  import pixeltable.exceptions as excs
9
9
  import pixeltable.type_system as ts
10
10
  from pixeltable import exprs
11
- from .globals import is_valid_identifier, MediaValidation
11
+
12
+ from .globals import MediaValidation, is_valid_identifier
12
13
 
13
14
  if TYPE_CHECKING:
14
15
  from .table_version import TableVersion
@@ -22,6 +23,7 @@ class Column:
22
23
  A Column contains all the metadata necessary for executing queries and updates against a particular version of a
23
24
  table/view.
24
25
  """
26
+
25
27
  name: str
26
28
  id: Optional[int]
27
29
  col_type: ts.ColumnType
@@ -41,12 +43,19 @@ class Column:
41
43
  tbl: Optional[TableVersion]
42
44
 
43
45
  def __init__(
44
- self, name: Optional[str], col_type: Optional[ts.ColumnType] = None,
45
- computed_with: Optional[exprs.Expr] = None,
46
- is_pk: bool = False, stored: bool = True, media_validation: Optional[MediaValidation] = None,
47
- col_id: Optional[int] = None, schema_version_add: Optional[int] = None,
48
- schema_version_drop: Optional[int] = None, sa_col_type: Optional[sql.sqltypes.TypeEngine] = None,
49
- records_errors: Optional[bool] = None, value_expr_dict: Optional[dict[str, Any]] = None,
46
+ self,
47
+ name: Optional[str],
48
+ col_type: Optional[ts.ColumnType] = None,
49
+ computed_with: Optional[exprs.Expr] = None,
50
+ is_pk: bool = False,
51
+ stored: bool = True,
52
+ media_validation: Optional[MediaValidation] = None,
53
+ col_id: Optional[int] = None,
54
+ schema_version_add: Optional[int] = None,
55
+ schema_version_drop: Optional[int] = None,
56
+ sa_col_type: Optional[sql.sqltypes.TypeEngine] = None,
57
+ records_errors: Optional[bool] = None,
58
+ value_expr_dict: Optional[dict[str, Any]] = None,
50
59
  ):
51
60
  """Column constructor.
52
61
 
@@ -81,7 +90,8 @@ class Column:
81
90
  if value_expr is None:
82
91
  raise excs.Error(
83
92
  f'Column {name}: computed_with needs to be a valid Pixeltable expression, '
84
- f'but it is a {type(computed_with)}')
93
+ f'but it is a {type(computed_with)}'
94
+ )
85
95
  else:
86
96
  self._value_expr = value_expr.copy()
87
97
  self.col_type = self._value_expr.col_type
@@ -117,6 +127,7 @@ class Column:
117
127
  # catalog has been fully loaded; that way, we encounter bugs in the serialization/deserialization logic earlier
118
128
  if self.value_expr_dict is not None and self._value_expr is None:
119
129
  from pixeltable import exprs
130
+
120
131
  self._value_expr = exprs.Expr.from_dict(self.value_expr_dict)
121
132
  return self._value_expr
122
133
 
@@ -129,12 +140,14 @@ class Column:
129
140
  if self.stored == False and self.is_computed and self.has_window_fn_call():
130
141
  raise excs.Error(
131
142
  f'Column {self.name}: stored={self.stored} not supported for columns computed with window functions:'
132
- f'\n{self.value_expr}')
143
+ f'\n{self.value_expr}'
144
+ )
133
145
 
134
146
  def has_window_fn_call(self) -> bool:
135
147
  if self.value_expr is None:
136
148
  return False
137
149
  from pixeltable import exprs
150
+
138
151
  l = list(self.value_expr.subexprs(filter=lambda e: isinstance(e, exprs.FunctionCall) and e.is_window_fn_call))
139
152
  return len(l) > 0
140
153
 
@@ -177,6 +190,7 @@ class Column:
177
190
  If this is a computed col and the top-level expr is a function call, print the source, if possible.
178
191
  """
179
192
  from pixeltable import exprs
193
+
180
194
  if self.value_expr is None or not isinstance(self.value_expr, exprs.FunctionCall):
181
195
  return
182
196
  self.value_expr.fn.source()
@@ -188,8 +202,10 @@ class Column:
188
202
  assert self.is_stored
189
203
  # all storage columns are nullable (we deal with null errors in Pixeltable directly)
190
204
  self.sa_col = sql.Column(
191
- self.store_name(), self.col_type.to_sa_type() if self.sa_col_type is None else self.sa_col_type,
192
- nullable=True)
205
+ self.store_name(),
206
+ self.col_type.to_sa_type() if self.sa_col_type is None else self.sa_col_type,
207
+ nullable=True,
208
+ )
193
209
  if self.is_computed or self.col_type.is_media_type():
194
210
  self.sa_errormsg_col = sql.Column(self.errormsg_store_name(), ts.StringType().to_sa_type(), nullable=True)
195
211
  self.sa_errortype_col = sql.Column(self.errortype_store_name(), ts.StringType().to_sa_type(), nullable=True)
@@ -6,13 +6,14 @@ from uuid import UUID
6
6
 
7
7
  import sqlalchemy as sql
8
8
 
9
- from .schema_object import SchemaObject
10
9
  from pixeltable.env import Env
11
10
  from pixeltable.metadata import schema
12
11
 
12
+ from .schema_object import SchemaObject
13
13
 
14
14
  _logger = logging.getLogger('pixeltable')
15
15
 
16
+
16
17
  class Dir(SchemaObject):
17
18
  def __init__(self, id: UUID, parent_id: UUID, name: str):
18
19
  super().__init__(id, name, parent_id)
@@ -23,8 +24,9 @@ class Dir(SchemaObject):
23
24
 
24
25
  @property
25
26
  def _has_dependents(self) -> bool:
26
- """ Returns True if this directory has any children. """
27
+ """Returns True if this directory has any children."""
27
28
  from pixeltable.catalog import Catalog, Path
29
+
28
30
  return len(Catalog.get().paths.get_children(Path(self._path), child_type=None, recursive=False)) > 0
29
31
 
30
32
  def _move(self, new_name: str, new_dir_id: UUID) -> None:
@@ -34,5 +36,5 @@ class Dir(SchemaObject):
34
36
  conn.execute(
35
37
  sql.update(schema.Dir.__table__)
36
38
  .values({schema.Dir.parent_id: self._dir_id, schema.Dir.md: dataclasses.asdict(dir_md)})
37
- .where(schema.Dir.id == self._id))
38
-
39
+ .where(schema.Dir.id == self._id)
40
+ )
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+
2
3
  import dataclasses
3
4
  import enum
4
5
  import itertools
@@ -23,6 +24,7 @@ class UpdateStatus:
23
24
  """
24
25
  Information about updates that resulted from a table operation.
25
26
  """
27
+
26
28
  num_rows: int = 0
27
29
  # TODO: disambiguate what this means: # of slots computed or # of columns computed?
28
30
  num_computed_values: int = 0
@@ -51,6 +53,7 @@ class MediaValidation(enum.Enum):
51
53
  val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
52
54
  raise excs.Error(f'{error_prefix} must be one of: [{val_strs}]')
53
55
 
56
+
54
57
  class IfExistsParam(enum.Enum):
55
58
  ERROR = 0
56
59
  IGNORE = 1
@@ -65,6 +68,7 @@ class IfExistsParam(enum.Enum):
65
68
  val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
66
69
  raise excs.Error(f'{param_name} must be one of: [{val_strs}]')
67
70
 
71
+
68
72
  class IfNotExistsParam(enum.Enum):
69
73
  ERROR = 0
70
74
  IGNORE = 1
@@ -77,10 +81,12 @@ class IfNotExistsParam(enum.Enum):
77
81
  val_strs = ', '.join(f'{s.lower()!r}' for s in cls.__members__.keys())
78
82
  raise excs.Error(f'{param_name} must be one of: [{val_strs}]')
79
83
 
84
+
80
85
  def is_valid_identifier(name: str) -> bool:
81
86
  return name.isidentifier() and not name.startswith('_')
82
87
 
83
- def is_valid_path(path: str, empty_is_valid : bool) -> bool:
88
+
89
+ def is_valid_path(path: str, empty_is_valid: bool) -> bool:
84
90
  if path == '':
85
91
  return empty_is_valid
86
92
 
@@ -89,6 +95,7 @@ def is_valid_path(path: str, empty_is_valid : bool) -> bool:
89
95
  return False
90
96
  return True
91
97
 
98
+
92
99
  def is_system_column_name(name: str) -> bool:
93
100
  from pixeltable.catalog import InsertableTable, View
94
101
 
@@ -35,8 +35,15 @@ class InsertableTable(Table):
35
35
  # MODULE-LOCAL, NOT PUBLIC
36
36
  @classmethod
37
37
  def _create(
38
- cls, dir_id: UUID, name: str, schema: dict[str, ts.ColumnType], df: Optional[pxt.DataFrame],
39
- primary_key: list[str], num_retained_versions: int, comment: str, media_validation: MediaValidation
38
+ cls,
39
+ dir_id: UUID,
40
+ name: str,
41
+ schema: dict[str, ts.ColumnType],
42
+ df: Optional[pxt.DataFrame],
43
+ primary_key: list[str],
44
+ num_retained_versions: int,
45
+ comment: str,
46
+ media_validation: MediaValidation,
40
47
  ) -> InsertableTable:
41
48
  columns = cls._create_columns(schema)
42
49
  cls._verify_schema(columns)
@@ -51,8 +58,14 @@ class InsertableTable(Table):
51
58
 
52
59
  with orm.Session(Env.get().engine, future=True) as session:
53
60
  _, tbl_version = TableVersion.create(
54
- session, dir_id, name, columns, num_retained_versions=num_retained_versions, comment=comment,
55
- media_validation=media_validation)
61
+ session,
62
+ dir_id,
63
+ name,
64
+ columns,
65
+ num_retained_versions=num_retained_versions,
66
+ comment=comment,
67
+ media_validation=media_validation,
68
+ )
56
69
  tbl = cls(dir_id, tbl_version)
57
70
  # TODO We need to commit before doing the insertion, in order to avoid a primary key (version) collision
58
71
  # when the table metadata gets updated. Once we have a notion of user-defined transactions in
@@ -84,16 +97,12 @@ class InsertableTable(Table):
84
97
  /,
85
98
  *,
86
99
  print_stats: bool = False,
87
- on_error: Literal['abort', 'ignore'] = 'abort'
100
+ on_error: Literal['abort', 'ignore'] = 'abort',
88
101
  ) -> UpdateStatus: ...
89
102
 
90
103
  @overload
91
104
  def insert(
92
- self,
93
- *,
94
- print_stats: bool = False,
95
- on_error: Literal['abort', 'ignore'] = 'abort',
96
- **kwargs: Any
105
+ self, *, print_stats: bool = False, on_error: Literal['abort', 'ignore'] = 'abort', **kwargs: Any
97
106
  ) -> UpdateStatus: ...
98
107
 
99
108
  def insert( # type: ignore[misc]
@@ -103,7 +112,7 @@ class InsertableTable(Table):
103
112
  *,
104
113
  print_stats: bool = False,
105
114
  on_error: Literal['abort', 'ignore'] = 'abort',
106
- **kwargs: Any
115
+ **kwargs: Any,
107
116
  ) -> UpdateStatus:
108
117
  if rows is None:
109
118
  rows = [kwargs]
@@ -127,8 +136,9 @@ class InsertableTable(Table):
127
136
  if status.num_excs == 0:
128
137
  cols_with_excs_str = ''
129
138
  else:
130
- cols_with_excs_str = \
139
+ cols_with_excs_str = (
131
140
  f' across {len(status.cols_with_excs)} column{"" if len(status.cols_with_excs) == 1 else "s"}'
141
+ )
132
142
  cols_with_excs_str += f' ({", ".join(status.cols_with_excs)})'
133
143
  msg = (
134
144
  f'Inserted {status.num_rows} row{"" if status.num_rows == 1 else "s"} '
@@ -6,18 +6,20 @@ from uuid import UUID
6
6
 
7
7
  import sqlalchemy as sql
8
8
 
9
- from .schema_object import SchemaObject
10
9
  from pixeltable.env import Env
11
10
  from pixeltable.metadata import schema
12
11
 
12
+ from .schema_object import SchemaObject
13
13
 
14
14
  _logger = logging.getLogger('pixeltable')
15
15
 
16
+
16
17
  class NamedFunction(SchemaObject):
17
18
  """
18
19
  Contains references to functions that are named and have a path.
19
20
  The Function itself is stored in the FunctionRegistry.
20
21
  """
22
+
21
23
  def __init__(self, id: UUID, dir_id: UUID, name: str):
22
24
  super().__init__(id, name, dir_id)
23
25
 
@@ -32,9 +34,11 @@ class NamedFunction(SchemaObject):
32
34
  def _move(self, new_name: str, new_dir_id: UUID) -> None:
33
35
  super()._move(new_name, new_dir_id)
34
36
  with Env.get().engine.begin() as conn:
35
- stmt = sql.text((
36
- f"UPDATE {schema.Function.__table__} "
37
- f"SET {schema.Function.dir_id.name} = :new_dir_id, {schema.Function.md.name}['name'] = :new_name "
38
- f"WHERE {schema.Function.id.name} = :id"))
37
+ stmt = sql.text(
38
+ (
39
+ f'UPDATE {schema.Function.__table__} '
40
+ f"SET {schema.Function.dir_id.name} = :new_dir_id, {schema.Function.md.name}['name'] = :new_name "
41
+ f'WHERE {schema.Function.id.name} = :id'
42
+ )
43
+ )
39
44
  conn.execute(stmt, {'new_dir_id': new_dir_id, 'new_name': json.dumps(new_name), 'id': self._id})
40
-
@@ -3,10 +3,12 @@ from __future__ import annotations
3
3
  import logging
4
4
 
5
5
  from pixeltable import exceptions as excs
6
+
6
7
  from .globals import is_valid_path
7
8
 
8
9
  _logger = logging.getLogger('pixeltable')
9
10
 
11
+
10
12
  class Path:
11
13
  def __init__(self, path: str, empty_is_valid: bool = False):
12
14
  if not is_valid_path(path, empty_is_valid):
@@ -50,9 +52,8 @@ class Path:
50
52
  return False
51
53
  if self.is_root and (other.len == 1 or not is_parent):
52
54
  return True
53
- is_prefix = self.components == other.components[:self.len]
55
+ is_prefix = self.components == other.components[: self.len]
54
56
  return is_prefix and (self.len == (other.len - 1) or not is_parent)
55
57
 
56
58
  def __str__(self) -> str:
57
59
  return '.'.join(self.components)
58
-
@@ -17,8 +17,10 @@ from .schema_object import SchemaObject
17
17
 
18
18
  _logger = logging.getLogger('pixeltable')
19
19
 
20
+
20
21
  class PathDict:
21
22
  """Keep track of all paths in a Db instance"""
23
+
22
24
  def __init__(self):
23
25
  self.dir_contents: dict[UUID, dict[str, SchemaObject]] = {}
24
26
  self.schema_objs: dict[UUID, SchemaObject] = {}
@@ -64,7 +66,7 @@ class PathDict:
64
66
  """
65
67
  schema_obj = self.get_object(path)
66
68
  if schema_obj is None:
67
- raise excs.Error(f"No such path: {str(path)}")
69
+ raise excs.Error(f'No such path: {str(path)}')
68
70
  return schema_obj
69
71
 
70
72
  def get_object(self, path: Path) -> Optional[SchemaObject]:
@@ -86,11 +88,11 @@ class PathDict:
86
88
  if component not in self.dir_contents[dir._id]:
87
89
  if i == len(path.components) - 1:
88
90
  return None
89
- raise excs.Error(f'No such path: {".".join(path.components[:i + 1])}')
91
+ raise excs.Error(f'No such path: {".".join(path.components[: i + 1])}')
90
92
  schema_obj = self.dir_contents[dir._id][component]
91
93
  if i < len(path.components) - 1:
92
94
  if not isinstance(schema_obj, Dir):
93
- raise excs.Error(f'Not a directory: {".".join(path.components[:i + 1])}')
95
+ raise excs.Error(f'Not a directory: {".".join(path.components[: i + 1])}')
94
96
  dir = schema_obj
95
97
  return schema_obj
96
98
 
@@ -145,10 +147,11 @@ class PathDict:
145
147
  obj = self.get_object(path)
146
148
  if expected is not None:
147
149
  if obj is None:
148
- raise excs.Error(f"No such path: {str(path)}")
150
+ raise excs.Error(f'No such path: {str(path)}')
149
151
  if not isinstance(obj, expected):
150
152
  raise excs.Error(
151
- f'{str(path)} needs to be a {expected._display_name()} but is a {type(obj)._display_name()}')
153
+ f'{str(path)} needs to be a {expected._display_name()} but is a {type(obj)._display_name()}'
154
+ )
152
155
  if expected is None and obj is not None:
153
156
  raise excs.Error(f"{type(obj)._display_name()} '{str(path)}' already exists")
154
157
 
@@ -164,4 +167,3 @@ class PathDict:
164
167
  for dir in [obj for obj in self.dir_contents[dir._id].values() if isinstance(obj, Dir)]:
165
168
  result.extend(self.get_children(copy.copy(parent).append(dir._name), child_type, recursive))
166
169
  return result
167
-