pixeltable 0.2.19__tar.gz → 0.2.20__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 (148) hide show
  1. {pixeltable-0.2.19 → pixeltable-0.2.20}/PKG-INFO +11 -3
  2. {pixeltable-0.2.19 → pixeltable-0.2.20}/README.md +9 -2
  3. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/__version__.py +2 -2
  4. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/insertable_table.py +9 -7
  5. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/table.py +18 -4
  6. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/env.py +106 -35
  7. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exceptions.py +7 -4
  8. pixeltable-0.2.20/pixeltable/exec/component_iteration_node.py +100 -0
  9. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/json_path.py +3 -6
  10. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/together.py +24 -10
  11. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/globals.py +2 -0
  12. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/globals.py +1 -1
  13. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/hf_datasets.py +3 -3
  14. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/iterators/document.py +1 -1
  15. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/create_test_db_dump.py +1 -1
  16. pixeltable-0.2.20/pixeltable/utils/filecache.py +242 -0
  17. {pixeltable-0.2.19 → pixeltable-0.2.20}/pyproject.toml +3 -3
  18. pixeltable-0.2.19/pixeltable/exec/component_iteration_node.py +0 -79
  19. pixeltable-0.2.19/pixeltable/utils/filecache.py +0 -195
  20. {pixeltable-0.2.19 → pixeltable-0.2.20}/LICENSE +0 -0
  21. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/__init__.py +0 -0
  22. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/__init__.py +0 -0
  23. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/catalog.py +0 -0
  24. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/column.py +0 -0
  25. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/dir.py +0 -0
  26. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/globals.py +0 -0
  27. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/named_function.py +0 -0
  28. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/path.py +0 -0
  29. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/path_dict.py +0 -0
  30. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/schema_object.py +0 -0
  31. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/table_version.py +0 -0
  32. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/table_version_path.py +0 -0
  33. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/catalog/view.py +0 -0
  34. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/dataframe.py +0 -0
  35. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/__init__.py +0 -0
  36. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/aggregation_node.py +0 -0
  37. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/cache_prefetch_node.py +0 -0
  38. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/data_row_batch.py +0 -0
  39. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/exec_context.py +0 -0
  40. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/exec_node.py +0 -0
  41. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/expr_eval_node.py +0 -0
  42. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/in_memory_data_node.py +0 -0
  43. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/media_validation_node.py +0 -0
  44. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/row_update_node.py +0 -0
  45. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exec/sql_node.py +0 -0
  46. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/__init__.py +0 -0
  47. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/arithmetic_expr.py +0 -0
  48. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/array_slice.py +0 -0
  49. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/column_property_ref.py +0 -0
  50. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/column_ref.py +0 -0
  51. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/comparison.py +0 -0
  52. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/compound_predicate.py +0 -0
  53. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/data_row.py +0 -0
  54. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/expr.py +0 -0
  55. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/expr_set.py +0 -0
  56. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/function_call.py +0 -0
  57. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/globals.py +0 -0
  58. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/in_predicate.py +0 -0
  59. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/inline_expr.py +0 -0
  60. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/is_null.py +0 -0
  61. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/json_mapper.py +0 -0
  62. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/literal.py +0 -0
  63. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/method_ref.py +0 -0
  64. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/object_ref.py +0 -0
  65. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/row_builder.py +0 -0
  66. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/rowid_ref.py +0 -0
  67. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/similarity_expr.py +0 -0
  68. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/sql_element_cache.py +0 -0
  69. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/type_cast.py +0 -0
  70. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/exprs/variable.py +0 -0
  71. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/ext/__init__.py +0 -0
  72. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/ext/functions/__init__.py +0 -0
  73. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/ext/functions/whisperx.py +0 -0
  74. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/ext/functions/yolox.py +0 -0
  75. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/__init__.py +0 -0
  76. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/aggregate_function.py +0 -0
  77. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/callable_function.py +0 -0
  78. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/expr_template_function.py +0 -0
  79. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/function.py +0 -0
  80. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/function_registry.py +0 -0
  81. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/globals.py +0 -0
  82. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/query_template_function.py +0 -0
  83. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/signature.py +0 -0
  84. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/func/udf.py +0 -0
  85. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/__init__.py +0 -0
  86. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/anthropic.py +0 -0
  87. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/audio.py +0 -0
  88. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/fireworks.py +0 -0
  89. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/globals.py +0 -0
  90. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/huggingface.py +0 -0
  91. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/image.py +0 -0
  92. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/json.py +0 -0
  93. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/mistralai.py +0 -0
  94. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/openai.py +0 -0
  95. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/string.py +0 -0
  96. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/timestamp.py +0 -0
  97. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/util.py +0 -0
  98. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/video.py +0 -0
  99. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/vision.py +0 -0
  100. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/functions/whisper.py +0 -0
  101. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/index/__init__.py +0 -0
  102. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/index/base.py +0 -0
  103. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/index/btree.py +0 -0
  104. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/index/embedding_index.py +0 -0
  105. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/__init__.py +0 -0
  106. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/external_store.py +0 -0
  107. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/label_studio.py +0 -0
  108. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/pandas.py +0 -0
  109. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/io/parquet.py +0 -0
  110. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/iterators/__init__.py +0 -0
  111. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/iterators/base.py +0 -0
  112. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/iterators/string.py +0 -0
  113. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/iterators/video.py +0 -0
  114. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/__init__.py +0 -0
  115. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_10.py +0 -0
  116. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_12.py +0 -0
  117. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_13.py +0 -0
  118. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_14.py +0 -0
  119. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_15.py +0 -0
  120. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_16.py +0 -0
  121. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_17.py +0 -0
  122. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_18.py +0 -0
  123. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_19.py +0 -0
  124. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/convert_20.py +0 -0
  125. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/converters/util.py +0 -0
  126. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/notes.py +0 -0
  127. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/metadata/schema.py +0 -0
  128. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/plan.py +0 -0
  129. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/store.py +0 -0
  130. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/create_test_video.py +0 -0
  131. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/doc_plugins/griffe.py +0 -0
  132. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/doc_plugins/mkdocstrings.py +0 -0
  133. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/doc_plugins/templates/material/udf.html.jinja +0 -0
  134. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/tool/embed_udf.py +0 -0
  135. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/type_system.py +0 -0
  136. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/__init__.py +0 -0
  137. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/arrow.py +0 -0
  138. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/coco.py +0 -0
  139. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/code.py +0 -0
  140. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/documents.py +0 -0
  141. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/formatter.py +0 -0
  142. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/help.py +0 -0
  143. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/http_server.py +0 -0
  144. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/media_store.py +0 -0
  145. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/pytorch.py +0 -0
  146. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/s3.py +0 -0
  147. {pixeltable-0.2.19 → pixeltable-0.2.20}/pixeltable/utils/sql.py +0 -0
  148. {pixeltable-0.2.19 → pixeltable-0.2.20}/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.19
3
+ Version: 0.2.20
4
4
  Summary: Pixeltable: The Multimodal AI Data Plane
5
5
  Author: Pixeltable, Inc.
6
6
  Author-email: contact@pixeltable.com
@@ -31,6 +31,7 @@ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
31
31
  Requires-Dist: requests (>=2.31.0,<3.0.0)
32
32
  Requires-Dist: sqlalchemy (>=2.0.23,<3.0.0)
33
33
  Requires-Dist: tenacity (>=8.2,<9.0)
34
+ Requires-Dist: toml (>=0.10)
34
35
  Requires-Dist: tqdm (>=4.64)
35
36
  Description-Content-Type: text/markdown
36
37
 
@@ -46,10 +47,17 @@ Description-Content-Type: text/markdown
46
47
  [![tests status](https://github.com/pixeltable/pixeltable/actions/workflows/nightly.yml/badge.svg)](https://github.com/pixeltable/pixeltable/actions/workflows/nightly.yml)
47
48
  [![PyPI Package](https://img.shields.io/pypi/v/pixeltable?color=darkorange)](https://pypi.org/project/pixeltable/)
48
49
 
49
- [Installation](https://pixeltable.github.io/pixeltable/getting-started/) | [Documentation](https://pixeltable.readme.io/) | [API Reference](https://pixeltable.github.io/pixeltable/) | [Code Samples](https://pixeltable.readme.io/recipes) | [Examples](https://github.com/pixeltable/pixeltable/tree/release/docs/release/tutorials)
50
+ [Installation](https://pixeltable.github.io/pixeltable/getting-started/) | [Documentation](https://pixeltable.readme.io/) | [API Reference](https://pixeltable.github.io/pixeltable/) | [Code Samples](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#-code-samples) | [Computer Vision](https://docs.pixeltable.com/docs/object-detection-in-videos) | [LLM](https://docs.pixeltable.com/docs/document-indexing-and-rag)
50
51
  </div>
51
52
 
52
- Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video). It features built-in versioning, lineage tracking, and incremental updates, enabling users to store, transform, index, and iterate on data for their ML workflows. Data transformations, model inference, and custom logic are embedded as computed columns.
53
+ Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video). It features built-in versioning, lineage tracking, and incremental updates, enabling users to **store**, **transform**, **index**, and **iterate** on data for their ML workflows.
54
+
55
+ Data transformations, model inference, and custom logic are embedded as **computed columns**.
56
+ - **Load/Query all data types**: Interact with [video data](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#import-media-data-into-pixeltable-videos-images-audio) at the [frame level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#text-and-image-similarity-search-on-video-frames-with-embedding-indexes) 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)
57
+ - **Incremental updates for data transformation**: Maintain an [embedding index](https://docs.pixeltable.com/docs/embedding-vector-indexes) colocated with your data
58
+ - **Lazy evaluation and cache management**: Eliminates the need for [manual frame extraction](https://docs.pixeltable.com/docs/object-detection-in-videos)
59
+ - **Integrates with any Python libraries**: Use [built-in and custom functions (UDFs)](https://docs.pixeltable.com/docs/user-defined-functions-udfs) without complex pipelines
60
+ - **Data format agnostic and extensibility**: Access tables as Parquet files, [PyTorch datasets](https://pixeltable.github.io/pixeltable/api/data-frame/#pixeltable.DataFrame.to_pytorch_dataset), or [COCO annotations](https://pixeltable.github.io/pixeltable/api/table/#pixeltable.Table.to_coco_dataset)
53
61
 
54
62
  ## 💾 Installation
55
63
 
@@ -10,10 +10,17 @@
10
10
  [![tests status](https://github.com/pixeltable/pixeltable/actions/workflows/nightly.yml/badge.svg)](https://github.com/pixeltable/pixeltable/actions/workflows/nightly.yml)
11
11
  [![PyPI Package](https://img.shields.io/pypi/v/pixeltable?color=darkorange)](https://pypi.org/project/pixeltable/)
12
12
 
13
- [Installation](https://pixeltable.github.io/pixeltable/getting-started/) | [Documentation](https://pixeltable.readme.io/) | [API Reference](https://pixeltable.github.io/pixeltable/) | [Code Samples](https://pixeltable.readme.io/recipes) | [Examples](https://github.com/pixeltable/pixeltable/tree/release/docs/release/tutorials)
13
+ [Installation](https://pixeltable.github.io/pixeltable/getting-started/) | [Documentation](https://pixeltable.readme.io/) | [API Reference](https://pixeltable.github.io/pixeltable/) | [Code Samples](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#-code-samples) | [Computer Vision](https://docs.pixeltable.com/docs/object-detection-in-videos) | [LLM](https://docs.pixeltable.com/docs/document-indexing-and-rag)
14
14
  </div>
15
15
 
16
- Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video). It features built-in versioning, lineage tracking, and incremental updates, enabling users to store, transform, index, and iterate on data for their ML workflows. Data transformations, model inference, and custom logic are embedded as computed columns.
16
+ Pixeltable is a Python library providing a declarative interface for multimodal data (text, images, audio, video). It features built-in versioning, lineage tracking, and incremental updates, enabling users to **store**, **transform**, **index**, and **iterate** on data for their ML workflows.
17
+
18
+ Data transformations, model inference, and custom logic are embedded as **computed columns**.
19
+ - **Load/Query all data types**: Interact with [video data](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#import-media-data-into-pixeltable-videos-images-audio) at the [frame level](https://github.com/pixeltable/pixeltable?tab=readme-ov-file#text-and-image-similarity-search-on-video-frames-with-embedding-indexes) 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)
20
+ - **Incremental updates for data transformation**: Maintain an [embedding index](https://docs.pixeltable.com/docs/embedding-vector-indexes) colocated with your data
21
+ - **Lazy evaluation and cache management**: Eliminates the need for [manual frame extraction](https://docs.pixeltable.com/docs/object-detection-in-videos)
22
+ - **Integrates with any Python libraries**: Use [built-in and custom functions (UDFs)](https://docs.pixeltable.com/docs/user-defined-functions-udfs) without complex pipelines
23
+ - **Data format agnostic and extensibility**: Access tables as Parquet files, [PyTorch datasets](https://pixeltable.github.io/pixeltable/api/data-frame/#pixeltable.DataFrame.to_pytorch_dataset), or [COCO annotations](https://pixeltable.github.io/pixeltable/api/table/#pixeltable.Table.to_coco_dataset)
17
24
 
18
25
  ## 💾 Installation
19
26
 
@@ -1,3 +1,3 @@
1
1
  # These version placeholders will be replaced during build.
2
- __version__ = "0.2.19"
3
- __version_tuple__ = (0, 2, 19)
2
+ __version__ = "0.2.20"
3
+ __version_tuple__ = (0, 2, 20)
@@ -10,6 +10,7 @@ import pixeltable as pxt
10
10
  import pixeltable.type_system as ts
11
11
  from pixeltable import exceptions as excs
12
12
  from pixeltable.env import Env
13
+ from pixeltable.utils.filecache import FileCache
13
14
 
14
15
  from .catalog import Catalog
15
16
  from .globals import UpdateStatus
@@ -101,21 +102,22 @@ class InsertableTable(Table):
101
102
  if not isinstance(row, dict):
102
103
  raise excs.Error('rows must be a list of dictionaries')
103
104
  self._validate_input_rows(rows)
104
- result = self._tbl_version.insert(rows, None, print_stats=print_stats, fail_on_exception=fail_on_exception)
105
+ status = self._tbl_version.insert(rows, None, print_stats=print_stats, fail_on_exception=fail_on_exception)
105
106
 
106
- if result.num_excs == 0:
107
+ if status.num_excs == 0:
107
108
  cols_with_excs_str = ''
108
109
  else:
109
110
  cols_with_excs_str = \
110
- f' across {len(result.cols_with_excs)} column{"" if len(result.cols_with_excs) == 1 else "s"}'
111
- cols_with_excs_str += f' ({", ".join(result.cols_with_excs)})'
111
+ f' across {len(status.cols_with_excs)} column{"" if len(status.cols_with_excs) == 1 else "s"}'
112
+ cols_with_excs_str += f' ({", ".join(status.cols_with_excs)})'
112
113
  msg = (
113
- f'Inserted {result.num_rows} row{"" if result.num_rows == 1 else "s"} '
114
- f'with {result.num_excs} error{"" if result.num_excs == 1 else "s"}{cols_with_excs_str}.'
114
+ f'Inserted {status.num_rows} row{"" if status.num_rows == 1 else "s"} '
115
+ f'with {status.num_excs} error{"" if status.num_excs == 1 else "s"}{cols_with_excs_str}.'
115
116
  )
116
117
  print(msg)
117
118
  _logger.info(f'InsertableTable {self._name}: {msg}')
118
- return result
119
+ FileCache.get().emit_eviction_warnings()
120
+ return status
119
121
 
120
122
  def _validate_input_rows(self, rows: List[Dict[str, Any]]) -> None:
121
123
  """Verify that the input rows match the table schema"""
@@ -20,6 +20,7 @@ import pixeltable.exprs as exprs
20
20
  import pixeltable.index as index
21
21
  import pixeltable.metadata.schema as schema
22
22
  import pixeltable.type_system as ts
23
+ from pixeltable.utils.filecache import FileCache
23
24
 
24
25
  from .column import Column
25
26
  from .globals import _ROWID_COLUMN_NAME, UpdateStatus, is_system_column_name, is_valid_identifier
@@ -33,7 +34,12 @@ if TYPE_CHECKING:
33
34
  _logger = logging.getLogger('pixeltable')
34
35
 
35
36
  class Table(SchemaObject):
36
- """Base class for table objects (base tables, views, snapshots)."""
37
+ """
38
+ Base class for table objects (base tables, views, snapshots).
39
+
40
+ Every user-invoked operation that runs an ExecNode tree (directly or indirectly) needs to call
41
+ FileCache.emit_eviction_warnings() at the end of the operation.
42
+ """
37
43
 
38
44
  def __init__(self, id: UUID, dir_id: UUID, name: str, tbl_version_path: TableVersionPath):
39
45
  super().__init__(id, name, dir_id)
@@ -374,7 +380,10 @@ class Table(SchemaObject):
374
380
 
375
381
  new_col = self._create_columns({col_name: col_schema})[0]
376
382
  self._verify_column(new_col, set(self._schema.keys()), set(self._query_names))
377
- return self._tbl_version.add_column(new_col, print_stats=print_stats)
383
+ status = self._tbl_version.add_column(new_col, print_stats=print_stats)
384
+ FileCache.get().emit_eviction_warnings()
385
+ return status
386
+
378
387
 
379
388
  @classmethod
380
389
  def _validate_column_spec(cls, name: str, spec: dict[str, Any]) -> None:
@@ -587,6 +596,7 @@ class Table(SchemaObject):
587
596
  idx = EmbeddingIndex(col, metric=metric, string_embed=string_embed, image_embed=image_embed)
588
597
  status = self._tbl_version.add_index(col, idx_name=idx_name, idx=idx)
589
598
  # TODO: how to deal with exceptions here? drop the index and raise?
599
+ FileCache.get().emit_eviction_warnings()
590
600
 
591
601
  def drop_embedding_index(self, *, column_name: Optional[str] = None, idx_name: Optional[str] = None) -> None:
592
602
  """Drop an embedding index from the table.
@@ -732,7 +742,9 @@ class Table(SchemaObject):
732
742
  >>> tbl.update({'int_col': tbl.int_col + 1}, where=tbl.int_col == 0)
733
743
  """
734
744
  self._check_is_dropped()
735
- return self._tbl_version.update(value_spec, where, cascade)
745
+ status = self._tbl_version.update(value_spec, where, cascade)
746
+ FileCache.get().emit_eviction_warnings()
747
+ return status
736
748
 
737
749
  def batch_update(
738
750
  self, rows: Iterable[dict[str, Any]], cascade: bool = True,
@@ -789,9 +801,11 @@ class Table(SchemaObject):
789
801
  missing_cols = pk_col_names - set(col.name for col in col_vals.keys())
790
802
  raise excs.Error(f'Primary key columns ({", ".join(missing_cols)}) missing in {row_spec}')
791
803
  row_updates.append(col_vals)
792
- return self._tbl_version.batch_update(
804
+ status = self._tbl_version.batch_update(
793
805
  row_updates, rowids, error_if_not_exists=if_not_exists == 'error',
794
806
  insert_if_not_exists=if_not_exists == 'insert', cascade=cascade)
807
+ FileCache.get().emit_eviction_warnings()
808
+ return status
795
809
 
796
810
  def delete(self, where: Optional['pixeltable.exprs.Expr'] = None) -> UpdateStatus:
797
811
  """Delete rows in this table.
@@ -8,6 +8,7 @@ import importlib.util
8
8
  import inspect
9
9
  import logging
10
10
  import os
11
+ import shutil
11
12
  import subprocess
12
13
  import sys
13
14
  import threading
@@ -15,12 +16,12 @@ import uuid
15
16
  import warnings
16
17
  from dataclasses import dataclass
17
18
  from pathlib import Path
18
- from typing import TYPE_CHECKING, Any, Callable, Optional
19
+ from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
19
20
  from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
20
21
 
21
22
  import pixeltable_pgserver
22
23
  import sqlalchemy as sql
23
- import yaml
24
+ import toml
24
25
  from tqdm import TqdmWarning
25
26
 
26
27
  import pixeltable.exceptions as excs
@@ -64,7 +65,7 @@ class Env:
64
65
  _log_to_stdout: bool
65
66
  _module_log_level: dict[str, int] # module name -> log level
66
67
  _config_file: Optional[Path]
67
- _config: Optional[dict[str, Any]]
68
+ _config: Optional[Config]
68
69
  _stdout_handler: logging.StreamHandler
69
70
  _initialized: bool
70
71
 
@@ -110,6 +111,7 @@ class Env:
110
111
  self._log_to_stdout = False
111
112
  self._module_log_level = {} # module name -> log level
112
113
 
114
+ # config
113
115
  self._config_file = None
114
116
  self._config = None
115
117
 
@@ -119,7 +121,8 @@ class Env:
119
121
  self._initialized = False
120
122
 
121
123
  @property
122
- def config(self):
124
+ def config(self) -> Config:
125
+ assert self._config is not None
123
126
  return self._config
124
127
 
125
128
  @property
@@ -227,30 +230,13 @@ class Env:
227
230
  home = Path(os.environ.get('PIXELTABLE_HOME', str(Path.home() / '.pixeltable')))
228
231
  assert self._home is None or self._home == home
229
232
  self._home = home
230
- self._config_file = Path(os.environ.get('PIXELTABLE_CONFIG', str(self._home / 'config.yaml')))
233
+ self._config_file = Path(os.environ.get('PIXELTABLE_CONFIG', str(self._home / 'config.toml')))
231
234
  self._media_dir = self._home / 'media'
232
235
  self._file_cache_dir = self._home / 'file_cache'
233
236
  self._dataset_cache_dir = self._home / 'dataset_cache'
234
237
  self._log_dir = self._home / 'logs'
235
238
  self._tmp_dir = self._home / 'tmp'
236
239
 
237
- # Read in the config
238
- if os.path.isfile(self._config_file):
239
- with open(self._config_file, 'r') as stream:
240
- try:
241
- self._config = yaml.safe_load(stream)
242
- except yaml.YAMLError as exc:
243
- self._logger.error(f'Could not read config file: {self._config_file}')
244
- self._config = {}
245
- else:
246
- self._config = {}
247
-
248
- # Disable spurious warnings
249
- warnings.simplefilter('ignore', category=TqdmWarning)
250
- if 'hide_warnings' in self._config and self._config['hide_warnings']:
251
- # Disable more warnings
252
- warnings.simplefilter('ignore', category=UserWarning)
253
-
254
240
  if self._home.exists() and not self._home.is_dir():
255
241
  raise RuntimeError(f'{self._home} is not a directory')
256
242
 
@@ -274,6 +260,22 @@ class Env:
274
260
  if not self._tmp_dir.exists():
275
261
  self._tmp_dir.mkdir()
276
262
 
263
+ # Read in the config
264
+ self._config = Config.from_file(self._config_file)
265
+ self._file_cache_size_g = self._config.get_float_value('file_cache_size_g')
266
+ if self._file_cache_size_g is None:
267
+ raise excs.Error(
268
+ 'pixeltable/file_cache_size_g is missing from configuration\n'
269
+ f'(either add a `file_cache_size_g` entry to the `pixeltable` section of {self._config_file},\n'
270
+ 'or set the PIXELTABLE_FILE_CACHE_SIZE_G environment variable)'
271
+ )
272
+
273
+ # Disable spurious warnings
274
+ warnings.simplefilter('ignore', category=TqdmWarning)
275
+ if self._config.get_bool_value('hide_warnings'):
276
+ # Disable more warnings
277
+ warnings.simplefilter('ignore', category=UserWarning)
278
+
277
279
  # configure _logger to log to a file
278
280
  self._logfilename = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') + '.log'
279
281
  fh = logging.FileHandler(self._log_dir / self._logfilename, mode='w')
@@ -313,7 +315,7 @@ class Env:
313
315
  self._db_server = pixeltable_pgserver.get_server(self._pgdata_dir, cleanup_mode=None)
314
316
  self._db_url = self._db_server.get_uri(database=self._db_name, driver='psycopg')
315
317
 
316
- tz_name = os.environ.get('PXT_TIME_ZONE', self._config.get('pxt_time_zone', None))
318
+ tz_name = self.config.get_string_value('time_zone')
317
319
  if tz_name is not None:
318
320
  # Validate tzname
319
321
  if not isinstance(tz_name, str):
@@ -440,21 +442,18 @@ class Env:
440
442
  if cl.client_obj is not None:
441
443
  return cl.client_obj # Already initialized
442
444
 
443
- # Construct a client. For each client parameter, first check if the parameter is in the environment;
444
- # if not, look in Pixeltable config from `config.yaml`.
445
+ # Construct a client, retrieving each parameter from config.
445
446
 
446
447
  init_kwargs: dict[str, str] = {}
447
448
  for param in cl.param_names:
448
- environ = f'{name.upper()}_{param.upper()}'
449
- if environ in os.environ:
450
- init_kwargs[param] = os.environ[environ]
451
- elif name.lower() in self._config and param in self._config[name.lower()]:
452
- init_kwargs[param] = self._config[name.lower()][param.lower()]
453
- if param not in init_kwargs or init_kwargs[param] == '':
449
+ arg = self._config.get_string_value(param, section=name)
450
+ if arg is not None and len(arg) > 0:
451
+ init_kwargs[param] = arg
452
+ else:
454
453
  raise excs.Error(
455
454
  f'`{name}` client not initialized: parameter `{param}` is not configured.\n'
456
- f'To fix this, specify the `{environ}` environment variable, or put `{param.lower()}` in '
457
- f'the `{name.lower()}` section of $PIXELTABLE_HOME/config.yaml.'
455
+ f'To fix this, specify the `{name.upper()}_{param.upper()}` environment variable, or put `{param.lower()}` in '
456
+ f'the `{name.lower()}` section of $PIXELTABLE_HOME/config.toml.'
458
457
  )
459
458
 
460
459
  cl.client_obj = cl.init_fn(**init_kwargs)
@@ -506,7 +505,6 @@ class Env:
506
505
  self.__register_package('spacy')
507
506
  self.__register_package('tiktoken')
508
507
  self.__register_package('together')
509
- self.__register_package('toml')
510
508
  self.__register_package('torch')
511
509
  self.__register_package('torchvision')
512
510
  self.__register_package('transformers')
@@ -643,7 +641,7 @@ def register_client(name: str) -> Callable:
643
641
  Pixeltable will attempt to load the client parameters from config. For each
644
642
  config parameter:
645
643
  - If an environment variable named MY_CLIENT_API_KEY (for example) is set, use it;
646
- - Otherwise, look for 'api_key' in the 'my_client' section of config.yaml.
644
+ - Otherwise, look for 'api_key' in the 'my_client' section of config.toml.
647
645
 
648
646
  If all config parameters are found, Pixeltable calls the initialization function;
649
647
  otherwise it throws an exception.
@@ -660,6 +658,79 @@ def register_client(name: str) -> Callable:
660
658
  return decorator
661
659
 
662
660
 
661
+ class Config:
662
+ """
663
+ The (global) Pixeltable configuration, as loaded from `config.toml`. Provides methods for retrieving
664
+ configuration values, which can be set in the config file or as environment variables.
665
+ """
666
+ __config: dict[str, Any]
667
+
668
+ T = TypeVar('T')
669
+
670
+ @classmethod
671
+ def from_file(cls, path: Path) -> Config:
672
+ """
673
+ Loads configuration from the specified TOML file. If the file does not exist, it will be
674
+ created and populated with the default configuration.
675
+ """
676
+ if os.path.isfile(path):
677
+ with open(path, 'r') as stream:
678
+ try:
679
+ config_dict = toml.load(stream)
680
+ except Exception as exc:
681
+ raise excs.Error(f'Could not read config file: {str(path)}') from exc
682
+ else:
683
+ config_dict = cls.__create_default_config(path)
684
+ with open(path, 'w') as stream:
685
+ try:
686
+ toml.dump(config_dict, stream)
687
+ except Exception as exc:
688
+ raise excs.Error(f'Could not write config file: {str(path)}') from exc
689
+ logging.getLogger('pixeltable').info(f'Created default config file at: {str(path)}')
690
+ return cls(config_dict)
691
+
692
+ @classmethod
693
+ def __create_default_config(cls, config_path: Path) -> dict[str, Any]:
694
+ free_disk_space_bytes = shutil.disk_usage(config_path.parent).free
695
+ # Default cache size is 1/5 of free disk space
696
+ file_cache_size_g = free_disk_space_bytes / 5 / (1 << 30)
697
+ return {
698
+ 'pixeltable': {
699
+ 'file_cache_size_g': round(file_cache_size_g, 1),
700
+ 'hide_warnings': False,
701
+ }
702
+ }
703
+
704
+ def __init__(self, config: dict[str, Any]) -> None:
705
+ self.__config = config
706
+
707
+ def get_value(self, key: str, expected_type: type[T], section: str = 'pixeltable') -> Optional[T]:
708
+ env_var = f'{section.upper()}_{key.upper()}'
709
+ if env_var in os.environ:
710
+ value = os.environ[env_var]
711
+ elif section in self.__config and key in self.__config[section]:
712
+ value = self.__config[section][key]
713
+ else:
714
+ return None
715
+
716
+ try:
717
+ return expected_type(value) # type: ignore[call-arg]
718
+ except ValueError:
719
+ raise excs.Error(f'Invalid value for configuration parameter {section}.{key}: {value}')
720
+
721
+ def get_string_value(self, key: str, section: str = 'pixeltable') -> Optional[str]:
722
+ return self.get_value(key, str, section)
723
+
724
+ def get_int_value(self, key: str, section: str = 'pixeltable') -> Optional[int]:
725
+ return self.get_value(key, int, section)
726
+
727
+ def get_float_value(self, key: str, section: str = 'pixeltable') -> Optional[float]:
728
+ return self.get_value(key, float, section)
729
+
730
+ def get_bool_value(self, key: str, section: str = 'pixeltable') -> Optional[bool]:
731
+ return self.get_value(key, bool, section)
732
+
733
+
663
734
  _registered_clients: dict[str, ApiClient] = {}
664
735
 
665
736
 
@@ -1,6 +1,9 @@
1
- from typing import List, Any
2
- from types import TracebackType
3
1
  from dataclasses import dataclass
2
+ from types import TracebackType
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ if TYPE_CHECKING:
6
+ from pixeltable import exprs
4
7
 
5
8
 
6
9
  class Error(Exception):
@@ -9,11 +12,11 @@ class Error(Exception):
9
12
 
10
13
  @dataclass
11
14
  class ExprEvalError(Exception):
12
- expr: Any # exprs.Expr, but we're not importing pixeltable.exprs to avoid circular imports
15
+ expr: 'exprs.Expr'
13
16
  expr_msg: str
14
17
  exc: Exception
15
18
  exc_tb: TracebackType
16
- input_vals: List[Any]
19
+ input_vals: list[Any]
17
20
  row_num: int
18
21
 
19
22
 
@@ -0,0 +1,100 @@
1
+ import inspect
2
+ from typing import Iterator, Optional
3
+
4
+ import pixeltable.catalog as catalog
5
+ import pixeltable.exceptions as excs
6
+ import pixeltable.exprs as exprs
7
+
8
+ from .data_row_batch import DataRowBatch
9
+ from .exec_node import ExecNode
10
+
11
+
12
+ class ComponentIterationNode(ExecNode):
13
+ """Expands each row from a base table into one row per component returned by an iterator
14
+
15
+ Returns row batches of OUTPUT_BATCH_SIZE size.
16
+ """
17
+ __OUTPUT_BATCH_SIZE = 1024
18
+
19
+ def __init__(self, view: catalog.TableVersion, input: ExecNode):
20
+ assert view.is_component_view()
21
+ super().__init__(input.row_builder, [], [], input)
22
+ self.view = view
23
+ iterator_args = [view.iterator_args.copy()]
24
+ self.row_builder.set_slot_idxs(iterator_args)
25
+ self.iterator_args = iterator_args[0]
26
+ assert isinstance(self.iterator_args, exprs.InlineDict)
27
+ self.iterator_args_ctx = self.row_builder.create_eval_ctx([self.iterator_args])
28
+ self.iterator_output_schema, self.unstored_column_names = (
29
+ self.view.iterator_cls.output_schema(**self.iterator_args.to_kwargs())
30
+ )
31
+ self.iterator_output_fields = list(self.iterator_output_schema.keys())
32
+ self.iterator_output_cols = {
33
+ field_name: self.view.cols_by_name[field_name] for field_name in self.iterator_output_fields
34
+ }
35
+ # referenced iterator output fields
36
+ self.refd_output_slot_idxs = {
37
+ e.col.name: e.slot_idx for e in self.row_builder.unique_exprs
38
+ if isinstance(e, exprs.ColumnRef) and e.col.name in self.iterator_output_fields
39
+ }
40
+ self.__output: Optional[Iterator[DataRowBatch]] = None
41
+
42
+ def __output_batches(self) -> Iterator[DataRowBatch]:
43
+ output_batch = DataRowBatch(self.view, self.row_builder)
44
+ for input_batch in self.input:
45
+ for input_row in input_batch:
46
+ self.row_builder.eval(input_row, self.iterator_args_ctx)
47
+ iterator_args = input_row[self.iterator_args.slot_idx]
48
+ assert isinstance(iterator_args, dict)
49
+ # We need to ensure that all of the required (non-nullable) parameters of the iterator are
50
+ # specified and are not null. If any of them are null, then we skip this row (i.e., we emit 0
51
+ # output rows for this input row).
52
+ if self.__non_nullable_args_specified(iterator_args):
53
+ iterator = self.view.iterator_cls(**iterator_args)
54
+ for pos, component_dict in enumerate(iterator):
55
+ output_row = output_batch.add_row()
56
+ input_row.copy(output_row)
57
+ # we're expanding the input and need to add the iterator position to the pk
58
+ self.__populate_output_row(output_row, pos, component_dict)
59
+ if len(output_batch) == self.__OUTPUT_BATCH_SIZE:
60
+ yield output_batch
61
+ output_batch = DataRowBatch(self.view, self.row_builder)
62
+
63
+ if len(output_batch) > 0:
64
+ yield output_batch
65
+
66
+ def __non_nullable_args_specified(self, iterator_args: dict) -> bool:
67
+ """
68
+ Returns true if all non-nullable iterator arguments are not `None`.
69
+ """
70
+ input_schema = self.view.iterator_cls.input_schema()
71
+ for arg_name, arg_value in iterator_args.items():
72
+ col_type = input_schema[arg_name]
73
+ if arg_value is None and not col_type.nullable:
74
+ return False
75
+ return True
76
+
77
+ def __populate_output_row(self, output_row: exprs.DataRow, pos: int, component_dict: dict) -> None:
78
+ pk = output_row.pk[:-1] + (pos,) + output_row.pk[-1:]
79
+ output_row.set_pk(pk)
80
+ # verify and copy component_dict fields to their respective slots in output_row
81
+ for field_name, field_val in component_dict.items():
82
+ if field_name not in self.iterator_output_fields:
83
+ raise excs.Error(
84
+ f'Invalid field name {field_name} in output of {self.view.iterator_cls.__name__}')
85
+ if field_name not in self.refd_output_slot_idxs:
86
+ # we can ignore this
87
+ continue
88
+ output_col = self.iterator_output_cols[field_name]
89
+ output_col.col_type.validate_literal(field_val)
90
+ output_row[self.refd_output_slot_idxs[field_name]] = field_val
91
+ if len(component_dict) != len(self.iterator_output_fields):
92
+ missing_fields = set(self.refd_output_slot_idxs.keys()) - set(component_dict.keys())
93
+ raise excs.Error(
94
+ f'Invalid output of {self.view.iterator_cls.__name__}: '
95
+ f'missing fields {", ".join(missing_fields)}')
96
+
97
+ def __next__(self) -> DataRowBatch:
98
+ if self.__output is None:
99
+ self.__output = self.__output_batches()
100
+ return next(self.__output)
@@ -105,12 +105,9 @@ class JsonPath(Expr):
105
105
  return JsonPath(self._anchor, self.path_elements + [name])
106
106
 
107
107
  def __getitem__(self, index: object) -> 'JsonPath':
108
- if isinstance(index, str):
109
- if index != '*':
110
- raise excs.Error(f'Invalid json list index: {index}')
111
- elif not isinstance(index, (int, slice)):
112
- raise excs.Error(f'Invalid json list index: {index}')
113
- return JsonPath(self._anchor, self.path_elements + [index])
108
+ if isinstance(index, (int, slice, str)):
109
+ return JsonPath(self._anchor, self.path_elements + [index])
110
+ raise excs.Error(f'Invalid json list index: {index}')
114
111
 
115
112
  def __rshift__(self, other: object) -> 'JsonMapper':
116
113
  rhs_expr = Expr.from_object(other)
@@ -7,13 +7,15 @@ the [Working with Together AI](https://pixeltable.readme.io/docs/together-ai) tu
7
7
 
8
8
  import base64
9
9
  import io
10
- from typing import TYPE_CHECKING, Callable, Optional
10
+ from typing import TYPE_CHECKING, Callable, Optional, TypeVar
11
11
 
12
12
  import numpy as np
13
13
  import PIL.Image
14
+ import requests
14
15
  import tenacity
15
16
 
16
17
  import pixeltable as pxt
18
+ import pixeltable.exceptions as excs
17
19
  from pixeltable import env
18
20
  from pixeltable.func import Batch
19
21
  from pixeltable.utils.code import local_public_names
@@ -32,7 +34,10 @@ def _together_client() -> 'together.Together':
32
34
  return env.Env.get().get_client('together')
33
35
 
34
36
 
35
- def _retry(fn: Callable) -> Callable:
37
+ T = TypeVar('T')
38
+
39
+
40
+ def _retry(fn: Callable[..., T]) -> Callable[..., T]:
36
41
  import together
37
42
  return tenacity.retry(
38
43
  retry=tenacity.retry_if_exception_type(together.error.RateLimitError),
@@ -249,20 +254,29 @@ def image_generations(
249
254
  The generated image.
250
255
 
251
256
  Examples:
252
- Add a computed column that applies the model `runwayml/stable-diffusion-v1-5`
257
+ Add a computed column that applies the model `stabilityai/stable-diffusion-xl-base-1.0`
253
258
  to an existing Pixeltable column `tbl.prompt` of the table `tbl`:
254
259
 
255
- >>> tbl['response'] = image_generations(tbl.prompt, model='runwayml/stable-diffusion-v1-5')
260
+ >>> tbl['response'] = image_generations(tbl.prompt, model='stabilityai/stable-diffusion-xl-base-1.0')
256
261
  """
257
- # TODO(aaron-siegel): Decompose CPU/GPU ops into separate functions
258
262
  result = _retry(_together_client().images.generate)(
259
263
  prompt=prompt, model=model, steps=steps, seed=seed, height=height, width=width, negative_prompt=negative_prompt
260
264
  )
261
- b64_str = result.data[0].b64_json
262
- b64_bytes = base64.b64decode(b64_str)
263
- img = PIL.Image.open(io.BytesIO(b64_bytes))
264
- img.load()
265
- return img
265
+ if result.data[0].b64_json is not None:
266
+ b64_bytes = base64.b64decode(result.data[0].b64_json)
267
+ img = PIL.Image.open(io.BytesIO(b64_bytes))
268
+ img.load()
269
+ return img
270
+ if result.data[0].url is not None:
271
+ try:
272
+ resp = requests.get(result.data[0].url)
273
+ with io.BytesIO(resp.content) as fp:
274
+ image = PIL.Image.open(fp)
275
+ image.load()
276
+ return image
277
+ except Exception as exc:
278
+ raise excs.Error('Failed to download generated image from together.ai.') from exc
279
+ raise excs.Error('Response does not contain a generated image.')
266
280
 
267
281
 
268
282
  __all__ = local_public_names(__name__)
@@ -16,6 +16,7 @@ from pixeltable.dataframe import DataFrameResultSet
16
16
  from pixeltable.env import Env
17
17
  from pixeltable.iterators import ComponentIterator
18
18
  from pixeltable.metadata import schema
19
+ from pixeltable.utils.filecache import FileCache
19
20
 
20
21
  _logger = logging.getLogger('pixeltable')
21
22
 
@@ -193,6 +194,7 @@ def create_view(
193
194
  )
194
195
  Catalog.get().paths[path] = view
195
196
  _logger.info(f'Created view `{path_str}`.')
197
+ FileCache.get().emit_eviction_warnings()
196
198
  return view
197
199
 
198
200
 
@@ -43,7 +43,7 @@ def create_label_studio_project(
43
43
  The API key and URL for a valid Label Studio server must be specified in Pixeltable config. Either:
44
44
 
45
45
  * Set the `LABEL_STUDIO_API_KEY` and `LABEL_STUDIO_URL` environment variables; or
46
- * Specify `api_key` and `url` fields in the `label-studio` section of `$PIXELTABLE_HOME/config.yaml`.
46
+ * Specify `api_key` and `url` fields in the `label-studio` section of `$PIXELTABLE_HOME/config.toml`.
47
47
 
48
48
  __Requirements:__
49
49