pixeltable 0.4.17__py3-none-any.whl → 0.4.19__py3-none-any.whl

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 (153) hide show
  1. pixeltable/__init__.py +1 -1
  2. pixeltable/_version.py +1 -0
  3. pixeltable/catalog/catalog.py +144 -118
  4. pixeltable/catalog/column.py +104 -115
  5. pixeltable/catalog/globals.py +1 -2
  6. pixeltable/catalog/insertable_table.py +44 -49
  7. pixeltable/catalog/path.py +3 -4
  8. pixeltable/catalog/schema_object.py +4 -4
  9. pixeltable/catalog/table.py +139 -124
  10. pixeltable/catalog/table_metadata.py +6 -6
  11. pixeltable/catalog/table_version.py +315 -246
  12. pixeltable/catalog/table_version_handle.py +4 -4
  13. pixeltable/catalog/table_version_path.py +9 -10
  14. pixeltable/catalog/tbl_ops.py +9 -3
  15. pixeltable/catalog/view.py +34 -28
  16. pixeltable/config.py +14 -10
  17. pixeltable/dataframe.py +69 -78
  18. pixeltable/env.py +78 -64
  19. pixeltable/exec/aggregation_node.py +6 -6
  20. pixeltable/exec/cache_prefetch_node.py +10 -10
  21. pixeltable/exec/data_row_batch.py +3 -3
  22. pixeltable/exec/exec_context.py +16 -4
  23. pixeltable/exec/exec_node.py +5 -5
  24. pixeltable/exec/expr_eval/evaluators.py +6 -6
  25. pixeltable/exec/expr_eval/expr_eval_node.py +8 -7
  26. pixeltable/exec/expr_eval/globals.py +6 -6
  27. pixeltable/exec/expr_eval/row_buffer.py +1 -2
  28. pixeltable/exec/expr_eval/schedulers.py +11 -11
  29. pixeltable/exec/in_memory_data_node.py +2 -2
  30. pixeltable/exec/object_store_save_node.py +14 -17
  31. pixeltable/exec/sql_node.py +28 -27
  32. pixeltable/exprs/arithmetic_expr.py +4 -4
  33. pixeltable/exprs/array_slice.py +2 -2
  34. pixeltable/exprs/column_property_ref.py +3 -3
  35. pixeltable/exprs/column_ref.py +61 -74
  36. pixeltable/exprs/comparison.py +5 -5
  37. pixeltable/exprs/compound_predicate.py +3 -3
  38. pixeltable/exprs/data_row.py +12 -12
  39. pixeltable/exprs/expr.py +41 -31
  40. pixeltable/exprs/expr_dict.py +3 -3
  41. pixeltable/exprs/expr_set.py +3 -3
  42. pixeltable/exprs/function_call.py +14 -14
  43. pixeltable/exprs/in_predicate.py +4 -4
  44. pixeltable/exprs/inline_expr.py +8 -8
  45. pixeltable/exprs/is_null.py +1 -3
  46. pixeltable/exprs/json_mapper.py +8 -8
  47. pixeltable/exprs/json_path.py +6 -6
  48. pixeltable/exprs/literal.py +5 -5
  49. pixeltable/exprs/method_ref.py +2 -2
  50. pixeltable/exprs/object_ref.py +2 -2
  51. pixeltable/exprs/row_builder.py +14 -14
  52. pixeltable/exprs/rowid_ref.py +8 -8
  53. pixeltable/exprs/similarity_expr.py +50 -25
  54. pixeltable/exprs/sql_element_cache.py +4 -4
  55. pixeltable/exprs/string_op.py +2 -2
  56. pixeltable/exprs/type_cast.py +3 -5
  57. pixeltable/func/aggregate_function.py +8 -8
  58. pixeltable/func/callable_function.py +9 -9
  59. pixeltable/func/expr_template_function.py +3 -3
  60. pixeltable/func/function.py +15 -17
  61. pixeltable/func/function_registry.py +6 -7
  62. pixeltable/func/globals.py +2 -3
  63. pixeltable/func/mcp.py +2 -2
  64. pixeltable/func/query_template_function.py +16 -16
  65. pixeltable/func/signature.py +14 -14
  66. pixeltable/func/tools.py +11 -11
  67. pixeltable/func/udf.py +16 -18
  68. pixeltable/functions/__init__.py +1 -0
  69. pixeltable/functions/anthropic.py +7 -7
  70. pixeltable/functions/audio.py +76 -0
  71. pixeltable/functions/bedrock.py +6 -6
  72. pixeltable/functions/deepseek.py +4 -4
  73. pixeltable/functions/fireworks.py +2 -2
  74. pixeltable/functions/gemini.py +6 -6
  75. pixeltable/functions/globals.py +12 -12
  76. pixeltable/functions/groq.py +4 -4
  77. pixeltable/functions/huggingface.py +1033 -6
  78. pixeltable/functions/image.py +7 -10
  79. pixeltable/functions/llama_cpp.py +7 -7
  80. pixeltable/functions/math.py +2 -3
  81. pixeltable/functions/mistralai.py +3 -3
  82. pixeltable/functions/ollama.py +9 -9
  83. pixeltable/functions/openai.py +21 -21
  84. pixeltable/functions/openrouter.py +7 -7
  85. pixeltable/functions/string.py +21 -28
  86. pixeltable/functions/timestamp.py +7 -8
  87. pixeltable/functions/together.py +4 -6
  88. pixeltable/functions/twelvelabs.py +92 -0
  89. pixeltable/functions/video.py +36 -31
  90. pixeltable/functions/vision.py +6 -6
  91. pixeltable/functions/whisper.py +7 -7
  92. pixeltable/functions/whisperx.py +16 -16
  93. pixeltable/globals.py +75 -40
  94. pixeltable/index/base.py +12 -8
  95. pixeltable/index/btree.py +19 -22
  96. pixeltable/index/embedding_index.py +30 -39
  97. pixeltable/io/datarows.py +3 -3
  98. pixeltable/io/external_store.py +13 -16
  99. pixeltable/io/fiftyone.py +5 -5
  100. pixeltable/io/globals.py +5 -5
  101. pixeltable/io/hf_datasets.py +4 -4
  102. pixeltable/io/label_studio.py +12 -12
  103. pixeltable/io/pandas.py +6 -6
  104. pixeltable/io/parquet.py +2 -2
  105. pixeltable/io/table_data_conduit.py +12 -12
  106. pixeltable/io/utils.py +2 -2
  107. pixeltable/iterators/audio.py +2 -2
  108. pixeltable/iterators/document.py +88 -57
  109. pixeltable/iterators/video.py +66 -37
  110. pixeltable/metadata/converters/convert_18.py +2 -2
  111. pixeltable/metadata/converters/convert_19.py +2 -2
  112. pixeltable/metadata/converters/convert_20.py +2 -2
  113. pixeltable/metadata/converters/convert_21.py +2 -2
  114. pixeltable/metadata/converters/convert_22.py +2 -2
  115. pixeltable/metadata/converters/convert_24.py +2 -2
  116. pixeltable/metadata/converters/convert_25.py +2 -2
  117. pixeltable/metadata/converters/convert_26.py +2 -2
  118. pixeltable/metadata/converters/convert_29.py +4 -4
  119. pixeltable/metadata/converters/convert_34.py +2 -2
  120. pixeltable/metadata/converters/convert_36.py +2 -2
  121. pixeltable/metadata/converters/convert_38.py +2 -2
  122. pixeltable/metadata/converters/convert_39.py +1 -2
  123. pixeltable/metadata/converters/util.py +11 -13
  124. pixeltable/metadata/schema.py +22 -21
  125. pixeltable/metadata/utils.py +2 -6
  126. pixeltable/mypy/mypy_plugin.py +5 -5
  127. pixeltable/plan.py +32 -34
  128. pixeltable/share/packager.py +7 -7
  129. pixeltable/share/publish.py +3 -3
  130. pixeltable/store.py +126 -41
  131. pixeltable/type_system.py +43 -46
  132. pixeltable/utils/__init__.py +1 -2
  133. pixeltable/utils/arrow.py +4 -4
  134. pixeltable/utils/av.py +74 -38
  135. pixeltable/utils/azure_store.py +305 -0
  136. pixeltable/utils/code.py +1 -2
  137. pixeltable/utils/dbms.py +15 -19
  138. pixeltable/utils/description_helper.py +2 -3
  139. pixeltable/utils/documents.py +5 -6
  140. pixeltable/utils/exception_handler.py +2 -2
  141. pixeltable/utils/filecache.py +5 -5
  142. pixeltable/utils/formatter.py +4 -6
  143. pixeltable/utils/gcs_store.py +9 -9
  144. pixeltable/utils/local_store.py +17 -17
  145. pixeltable/utils/object_stores.py +59 -43
  146. pixeltable/utils/s3_store.py +35 -30
  147. {pixeltable-0.4.17.dist-info → pixeltable-0.4.19.dist-info}/METADATA +4 -4
  148. pixeltable-0.4.19.dist-info/RECORD +213 -0
  149. pixeltable/__version__.py +0 -3
  150. pixeltable-0.4.17.dist-info/RECORD +0 -211
  151. {pixeltable-0.4.17.dist-info → pixeltable-0.4.19.dist-info}/WHEEL +0 -0
  152. {pixeltable-0.4.17.dist-info → pixeltable-0.4.19.dist-info}/entry_points.txt +0 -0
  153. {pixeltable-0.4.17.dist-info → pixeltable-0.4.19.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import logging
4
4
  from dataclasses import dataclass
5
- from typing import TYPE_CHECKING, Optional
5
+ from typing import TYPE_CHECKING
6
6
  from uuid import UUID
7
7
 
8
8
  from pixeltable import exceptions as excs
@@ -21,10 +21,10 @@ class TableVersionHandle:
21
21
  """
22
22
 
23
23
  id: UUID
24
- effective_version: Optional[int]
25
- _tbl_version: Optional[TableVersion]
24
+ effective_version: int | None
25
+ _tbl_version: TableVersion | None
26
26
 
27
- def __init__(self, tbl_id: UUID, effective_version: Optional[int], tbl_version: Optional[TableVersion] = None):
27
+ def __init__(self, tbl_id: UUID, effective_version: int | None, tbl_version: TableVersion | None = None):
28
28
  self.id = tbl_id
29
29
  self.effective_version = effective_version
30
30
  self._tbl_version = tbl_version
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from typing import Optional
5
4
  from uuid import UUID
6
5
 
7
6
  from pixeltable.env import Env
@@ -39,10 +38,10 @@ class TableVersionPath:
39
38
  """
40
39
 
41
40
  tbl_version: TableVersionHandle
42
- base: Optional[TableVersionPath]
43
- _cached_tbl_version: Optional[TableVersion]
41
+ base: TableVersionPath | None
42
+ _cached_tbl_version: TableVersion | None
44
43
 
45
- def __init__(self, tbl_version: TableVersionHandle, base: Optional[TableVersionPath] = None):
44
+ def __init__(self, tbl_version: TableVersionHandle, base: TableVersionPath | None = None):
46
45
  assert tbl_version is not None
47
46
  self.tbl_version = tbl_version
48
47
  self.base = base
@@ -51,7 +50,7 @@ class TableVersionPath:
51
50
  @classmethod
52
51
  def from_md(cls, path: schema.TableVersionPath) -> TableVersionPath:
53
52
  assert len(path) > 0
54
- result: Optional[TableVersionPath] = None
53
+ result: TableVersionPath | None = None
55
54
  for tbl_id_str, effective_version in path[::-1]:
56
55
  tbl_id = UUID(tbl_id_str)
57
56
  result = TableVersionPath(TableVersionHandle(tbl_id, effective_version), base=result)
@@ -156,7 +155,7 @@ class TableVersionPath:
156
155
  return []
157
156
  return self.base.get_tbl_versions()
158
157
 
159
- def find_tbl_version(self, id: UUID) -> Optional[TableVersionHandle]:
158
+ def find_tbl_version(self, id: UUID) -> TableVersionHandle | None:
160
159
  """Return the matching TableVersion in the chain of TableVersions, starting with this one"""
161
160
  if self.tbl_version.id == id:
162
161
  return self.tbl_version
@@ -184,7 +183,7 @@ class TableVersionPath:
184
183
  cols = self.columns()
185
184
  return {col.id: col for col in cols}
186
185
 
187
- def get_column(self, name: str) -> Optional[Column]:
186
+ def get_column(self, name: str) -> Column | None:
188
187
  """Return the column with the given name, or None if not found"""
189
188
  self.refresh_cached_md()
190
189
  col = self._cached_tbl_version.cols_by_name.get(name)
@@ -197,12 +196,12 @@ class TableVersionPath:
197
196
 
198
197
  def has_column(self, col: Column) -> bool:
199
198
  """Return True if this table has the given column."""
200
- assert col.tbl is not None
199
+ assert col.get_tbl() is not None
201
200
  self.refresh_cached_md()
202
201
 
203
202
  if (
204
- col.tbl.id == self.tbl_version.id
205
- and col.tbl.effective_version == self.tbl_version.effective_version
203
+ col.get_tbl().id == self.tbl_version.id
204
+ and col.get_tbl().effective_version == self.tbl_version.effective_version
206
205
  and col.id in self._cached_tbl_version.cols_by_id
207
206
  ):
208
207
  # the column is visible in this table version
@@ -5,7 +5,7 @@
5
5
  # TableVersion
6
6
 
7
7
  import dataclasses
8
- from typing import Any, Optional
8
+ from typing import Any
9
9
 
10
10
 
11
11
  @dataclasses.dataclass
@@ -13,6 +13,11 @@ class CreateStoreTableOp:
13
13
  pass
14
14
 
15
15
 
16
+ @dataclasses.dataclass
17
+ class CreateIndexOp:
18
+ idx_id: int
19
+
20
+
16
21
  @dataclasses.dataclass
17
22
  class LoadViewOp:
18
23
  view_path: dict[str, Any] # needed to create the view load plan
@@ -40,5 +45,6 @@ class TableOp:
40
45
  num_ops: int # total number of ops forming the update operation
41
46
  needs_xact: bool # if True, op must be run as part of a transaction
42
47
 
43
- create_store_table_op: Optional[CreateStoreTableOp] = None
44
- load_view_op: Optional[LoadViewOp] = None
48
+ create_store_table_op: CreateStoreTableOp | None = None
49
+ create_index_op: CreateIndexOp | None = None
50
+ load_view_op: LoadViewOp | None = None
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import inspect
4
4
  import logging
5
- from typing import TYPE_CHECKING, Any, List, Literal, Optional
5
+ from typing import TYPE_CHECKING, Any, List, Literal
6
6
  from uuid import UUID
7
7
 
8
8
  import pixeltable.exceptions as excs
@@ -11,10 +11,6 @@ import pixeltable.type_system as ts
11
11
  from pixeltable import catalog, exprs, func
12
12
  from pixeltable.iterators import ComponentIterator
13
13
 
14
- if TYPE_CHECKING:
15
- from pixeltable.plan import SampleClause
16
-
17
-
18
14
  from .column import Column
19
15
  from .globals import _POS_COLUMN_NAME, MediaValidation
20
16
  from .table import Table
@@ -27,6 +23,7 @@ from .update_status import UpdateStatus
27
23
  if TYPE_CHECKING:
28
24
  from pixeltable.catalog.table import TableMetadata
29
25
  from pixeltable.globals import TableDataSource
26
+ from pixeltable.plan import SampleClause
30
27
 
31
28
  _logger = logging.getLogger('pixeltable')
32
29
 
@@ -56,7 +53,7 @@ class View(Table):
56
53
  return 'table'
57
54
 
58
55
  @classmethod
59
- def select_list_to_additional_columns(cls, select_list: list[tuple[exprs.Expr, Optional[str]]]) -> dict[str, dict]:
56
+ def select_list_to_additional_columns(cls, select_list: list[tuple[exprs.Expr, str | None]]) -> dict[str, dict]:
60
57
  """Returns a list of columns in the same format as the additional_columns parameter of View.create.
61
58
  The source is the list of expressions from a select() statement on a DataFrame.
62
59
  If the column is a ColumnRef, to a base table column, it is marked to not be stored.sy
@@ -76,17 +73,18 @@ class View(Table):
76
73
  dir_id: UUID,
77
74
  name: str,
78
75
  base: TableVersionPath,
79
- select_list: Optional[list[tuple[exprs.Expr, Optional[str]]]],
76
+ select_list: list[tuple[exprs.Expr, str | None]] | None,
80
77
  additional_columns: dict[str, Any],
81
- predicate: Optional['exprs.Expr'],
82
- sample_clause: Optional['SampleClause'],
78
+ predicate: 'exprs.Expr' | None,
79
+ sample_clause: 'SampleClause' | None,
83
80
  is_snapshot: bool,
81
+ create_default_idxs: bool,
84
82
  num_retained_versions: int,
85
83
  comment: str,
86
84
  media_validation: MediaValidation,
87
- iterator_cls: Optional[type[ComponentIterator]],
88
- iterator_args: Optional[dict],
89
- ) -> tuple[TableVersionMd, Optional[list[TableOp]]]:
85
+ iterator_cls: type[ComponentIterator] | None,
86
+ iterator_args: dict | None,
87
+ ) -> tuple[TableVersionMd, list[TableOp] | None]:
90
88
  from pixeltable.plan import SampleClause
91
89
 
92
90
  # Convert select_list to more additional_columns if present
@@ -103,7 +101,7 @@ class View(Table):
103
101
  # verify that filters can be evaluated in the context of the base
104
102
  if predicate is not None:
105
103
  if not predicate.is_bound_by([base]):
106
- raise excs.Error(f'Filter cannot be computed in the context of the base {base.tbl_name()}')
104
+ raise excs.Error(f'View filter cannot be computed in the context of the base table {base.tbl_name()!r}')
107
105
  # create a copy that we can modify and store
108
106
  predicate = predicate.copy()
109
107
  if sample_clause is not None:
@@ -111,7 +109,9 @@ class View(Table):
111
109
  if sample_clause.stratify_exprs is not None and not all(
112
110
  stratify_expr.is_bound_by([base]) for stratify_expr in sample_clause.stratify_exprs
113
111
  ):
114
- raise excs.Error(f'Sample clause cannot be computed in the context of the base {base.tbl_name()}')
112
+ raise excs.Error(
113
+ f'View sample clause cannot be computed in the context of the base table {base.tbl_name()!r}'
114
+ )
115
115
  # create a copy that we can modify and store
116
116
  sc = sample_clause
117
117
  sample_clause = SampleClause(
@@ -125,8 +125,8 @@ class View(Table):
125
125
  # make sure that the value can be computed in the context of the base
126
126
  if col.value_expr is not None and not col.value_expr.is_bound_by([base]):
127
127
  raise excs.Error(
128
- f'Column {col.name}: value expression cannot be computed in the context of the '
129
- f'base {base.tbl_name()}'
128
+ f'Column {col.name!r}: Value expression cannot be computed in the context of the '
129
+ f'base table {base.tbl_name()!r}'
130
130
  )
131
131
 
132
132
  if iterator_cls is not None:
@@ -153,18 +153,18 @@ class View(Table):
153
153
  sig = func.Signature(ts.InvalidType(), params)
154
154
 
155
155
  expr_args = {k: exprs.Expr.from_object(v) for k, v in bound_args.items()}
156
- sig.validate_args(expr_args, context=f'in iterator {iterator_cls.__name__!r}')
156
+ sig.validate_args(expr_args, context=f'in iterator of type `{iterator_cls.__name__}`')
157
157
  literal_args = {k: v.val if isinstance(v, exprs.Literal) else v for k, v in expr_args.items()}
158
158
 
159
159
  # prepend pos and output_schema columns to cols:
160
160
  # a component view exposes the pos column of its rowid;
161
161
  # we create that column here, so it gets assigned a column id;
162
162
  # stored=False: it is not stored separately (it's already stored as part of the rowid)
163
- iterator_cols = [Column(_POS_COLUMN_NAME, ts.IntType(), stored=False)]
163
+ iterator_cols = [Column(_POS_COLUMN_NAME, ts.IntType(), is_iterator_col=True, stored=False)]
164
164
  output_dict, unstored_cols = iterator_cls.output_schema(**literal_args)
165
165
  iterator_cols.extend(
166
166
  [
167
- Column(col_name, col_type, stored=col_name not in unstored_cols)
167
+ Column(col_name, col_type, is_iterator_col=True, stored=col_name not in unstored_cols)
168
168
  for col_name, col_type in output_dict.items()
169
169
  ]
170
170
  )
@@ -206,7 +206,13 @@ class View(Table):
206
206
  )
207
207
 
208
208
  md = TableVersion.create_initial_md(
209
- name, columns, num_retained_versions, comment, media_validation=media_validation, view_md=view_md
209
+ name,
210
+ columns,
211
+ num_retained_versions,
212
+ comment,
213
+ media_validation=media_validation,
214
+ view_md=view_md,
215
+ create_default_idxs=create_default_idxs,
210
216
  )
211
217
  if md.tbl_md.is_pure_snapshot:
212
218
  # this is purely a snapshot: no store table to create or load
@@ -230,7 +236,7 @@ class View(Table):
230
236
  def _verify_column(cls, col: Column) -> None:
231
237
  # make sure that columns are nullable or have a default
232
238
  if not col.col_type.nullable and not col.is_computed:
233
- raise excs.Error(f'Column {col.name}: non-computed columns in views must be nullable')
239
+ raise excs.Error(f'Column {col.name!r}: Non-computed columns in views must be nullable')
234
240
  super()._verify_column(col)
235
241
 
236
242
  @classmethod
@@ -282,22 +288,22 @@ class View(Table):
282
288
 
283
289
  def insert(
284
290
  self,
285
- source: Optional[TableDataSource] = None,
291
+ source: TableDataSource | None = None,
286
292
  /,
287
293
  *,
288
- source_format: Optional[Literal['csv', 'excel', 'parquet', 'json']] = None,
289
- schema_overrides: Optional[dict[str, ts.ColumnType]] = None,
294
+ source_format: Literal['csv', 'excel', 'parquet', 'json'] | None = None,
295
+ schema_overrides: dict[str, ts.ColumnType] | None = None,
290
296
  on_error: Literal['abort', 'ignore'] = 'abort',
291
297
  print_stats: bool = False,
292
298
  **kwargs: Any,
293
299
  ) -> UpdateStatus:
294
300
  raise excs.Error(f'{self._display_str()}: Cannot insert into a {self._display_name()}.')
295
301
 
296
- def delete(self, where: Optional[exprs.Expr] = None) -> UpdateStatus:
302
+ def delete(self, where: exprs.Expr | None = None) -> UpdateStatus:
297
303
  raise excs.Error(f'{self._display_str()}: Cannot delete from a {self._display_name()}.')
298
304
 
299
305
  @property
300
- def _base_tbl_id(self) -> Optional[UUID]:
306
+ def _base_tbl_id(self) -> UUID | None:
301
307
  if self._tbl_version_path.tbl_id != self._id:
302
308
  # _tbl_version_path represents a different schema object from this one. This can only happen if this is a
303
309
  # named pure snapshot.
@@ -306,14 +312,14 @@ class View(Table):
306
312
  return None
307
313
  return self._tbl_version_path.base.tbl_id
308
314
 
309
- def _get_base_table(self) -> Optional['Table']:
315
+ def _get_base_table(self) -> 'Table' | None:
310
316
  """Returns None if there is no base table, or if the base table is hidden."""
311
317
  base_tbl_id = self._base_tbl_id
312
318
  with catalog.Catalog.get().begin_xact(tbl_id=base_tbl_id, for_write=False):
313
319
  return catalog.Catalog.get().get_table_by_id(base_tbl_id)
314
320
 
315
321
  @property
316
- def _effective_base_versions(self) -> list[Optional[int]]:
322
+ def _effective_base_versions(self) -> list[int | None]:
317
323
  effective_versions = [tv.effective_version for tv in self._tbl_version_path.get_tbl_versions()]
318
324
  if self._snapshot_only and not self._is_anonymous_snapshot():
319
325
  return effective_versions # Named pure snapshot
pixeltable/config.py CHANGED
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  import shutil
6
6
  from pathlib import Path
7
- from typing import Any, ClassVar, Optional, TypeVar
7
+ from typing import Any, ClassVar, TypeVar
8
8
 
9
9
  import toml
10
10
 
@@ -21,7 +21,7 @@ class Config:
21
21
  configuration values, which can be set in the config file or as environment variables.
22
22
  """
23
23
 
24
- __instance: ClassVar[Optional[Config]] = None
24
+ __instance: ClassVar[Config | None] = None
25
25
 
26
26
  __home: Path
27
27
  __config_file: Path
@@ -110,7 +110,7 @@ class Config:
110
110
  return os.environ[env_var]
111
111
  return default
112
112
 
113
- def get_value(self, key: str, expected_type: type[T], section: str = 'pixeltable') -> Optional[T]:
113
+ def get_value(self, key: str, expected_type: type[T], section: str = 'pixeltable') -> T | None:
114
114
  value: Any = self.lookup_env(section, key) # Try to get from environment first
115
115
  # Next try the config file
116
116
  if value is None:
@@ -131,22 +131,22 @@ class Config:
131
131
  try:
132
132
  if expected_type is bool and isinstance(value, str):
133
133
  if value.lower() not in ('true', 'false'):
134
- raise excs.Error(f'Invalid value for configuration parameter {section}.{key}: {value}')
134
+ raise excs.Error(f"Invalid value for configuration parameter '{section}.{key}': {value}")
135
135
  return value.lower() == 'true' # type: ignore[return-value]
136
136
  return expected_type(value) # type: ignore[call-arg]
137
137
  except (ValueError, TypeError) as exc:
138
- raise excs.Error(f'Invalid value for configuration parameter {section}.{key}: {value}') from exc
138
+ raise excs.Error(f"Invalid value for configuration parameter '{section}.{key}': {value}") from exc
139
139
 
140
- def get_string_value(self, key: str, section: str = 'pixeltable') -> Optional[str]:
140
+ def get_string_value(self, key: str, section: str = 'pixeltable') -> str | None:
141
141
  return self.get_value(key, str, section)
142
142
 
143
- def get_int_value(self, key: str, section: str = 'pixeltable') -> Optional[int]:
143
+ def get_int_value(self, key: str, section: str = 'pixeltable') -> int | None:
144
144
  return self.get_value(key, int, section)
145
145
 
146
- def get_float_value(self, key: str, section: str = 'pixeltable') -> Optional[float]:
146
+ def get_float_value(self, key: str, section: str = 'pixeltable') -> float | None:
147
147
  return self.get_value(key, float, section)
148
148
 
149
- def get_bool_value(self, key: str, section: str = 'pixeltable') -> Optional[bool]:
149
+ def get_bool_value(self, key: str, section: str = 'pixeltable') -> bool | None:
150
150
  return self.get_value(key, bool, section)
151
151
 
152
152
 
@@ -161,18 +161,21 @@ KNOWN_CONFIG_OPTIONS = {
161
161
  'hide_warnings': 'Hide warnings from the console',
162
162
  'verbosity': 'Verbosity level for console output',
163
163
  'api_key': 'API key for Pixeltable cloud',
164
+ 'input_media_dest': 'Default destination URI for input media data',
165
+ 'output_media_dest': 'Default destination URI for output (computed) media data',
164
166
  'r2_profile': 'AWS config profile name used to access R2 storage',
165
167
  's3_profile': 'AWS config profile name used to access S3 storage',
166
168
  'b2_profile': 'S3-compatible profile name used to access Backblaze B2 storage',
167
169
  },
168
170
  'anthropic': {'api_key': 'Anthropic API key'},
171
+ 'azure': {'storage_account_name': 'Azure storage account name', 'storage_account_key': 'Azure storage account key'},
169
172
  'bedrock': {'api_key': 'AWS Bedrock API key'},
170
173
  'deepseek': {'api_key': 'Deepseek API key', 'rate_limit': 'Rate limit for Deepseek API requests'},
171
174
  'fireworks': {'api_key': 'Fireworks API key', 'rate_limit': 'Rate limit for Fireworks API requests'},
175
+ 'twelvelabs': {'api_key': 'TwelveLabs API key', 'rate_limit': 'Rate limit for TwelveLabs API requests'},
172
176
  'gemini': {'api_key': 'Gemini API key', 'rate_limits': 'Per-model rate limits for Gemini API requests'},
173
177
  'hf': {'auth_token': 'Hugging Face access token'},
174
178
  'imagen': {'rate_limits': 'Per-model rate limits for Imagen API requests'},
175
- 'veo': {'rate_limits': 'Per-model rate limits for Veo API requests'},
176
179
  'groq': {'api_key': 'Groq API key', 'rate_limit': 'Rate limit for Groq API requests'},
177
180
  'label_studio': {'api_key': 'Label Studio API key', 'url': 'Label Studio server URL'},
178
181
  'mistral': {'api_key': 'Mistral API key', 'rate_limit': 'Rate limit for Mistral API requests'},
@@ -193,6 +196,7 @@ KNOWN_CONFIG_OPTIONS = {
193
196
  'api_key': 'Together API key',
194
197
  'rate_limits': 'Per-model category rate limits for Together API requests',
195
198
  },
199
+ 'veo': {'rate_limits': 'Per-model rate limits for Veo API requests'},
196
200
  'pypi': {'api_key': 'PyPI API key (for internal use only)'},
197
201
  }
198
202