pixeltable 0.3.2__py3-none-any.whl → 0.3.3__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 (147) hide show
  1. pixeltable/__init__.py +64 -11
  2. pixeltable/__version__.py +2 -2
  3. pixeltable/catalog/__init__.py +1 -1
  4. pixeltable/catalog/catalog.py +50 -27
  5. pixeltable/catalog/column.py +27 -11
  6. pixeltable/catalog/dir.py +6 -4
  7. pixeltable/catalog/globals.py +8 -1
  8. pixeltable/catalog/insertable_table.py +22 -12
  9. pixeltable/catalog/named_function.py +10 -6
  10. pixeltable/catalog/path.py +3 -2
  11. pixeltable/catalog/path_dict.py +8 -6
  12. pixeltable/catalog/schema_object.py +2 -1
  13. pixeltable/catalog/table.py +121 -101
  14. pixeltable/catalog/table_version.py +291 -142
  15. pixeltable/catalog/table_version_path.py +8 -5
  16. pixeltable/catalog/view.py +67 -26
  17. pixeltable/dataframe.py +102 -72
  18. pixeltable/env.py +20 -21
  19. pixeltable/exec/__init__.py +2 -2
  20. pixeltable/exec/aggregation_node.py +10 -4
  21. pixeltable/exec/cache_prefetch_node.py +5 -3
  22. pixeltable/exec/component_iteration_node.py +9 -8
  23. pixeltable/exec/data_row_batch.py +21 -10
  24. pixeltable/exec/exec_context.py +10 -3
  25. pixeltable/exec/exec_node.py +23 -12
  26. pixeltable/exec/expr_eval/evaluators.py +13 -7
  27. pixeltable/exec/expr_eval/expr_eval_node.py +24 -15
  28. pixeltable/exec/expr_eval/globals.py +30 -7
  29. pixeltable/exec/expr_eval/row_buffer.py +5 -6
  30. pixeltable/exec/expr_eval/schedulers.py +151 -31
  31. pixeltable/exec/in_memory_data_node.py +8 -7
  32. pixeltable/exec/row_update_node.py +15 -5
  33. pixeltable/exec/sql_node.py +56 -27
  34. pixeltable/exprs/__init__.py +2 -2
  35. pixeltable/exprs/arithmetic_expr.py +57 -26
  36. pixeltable/exprs/array_slice.py +1 -1
  37. pixeltable/exprs/column_property_ref.py +2 -1
  38. pixeltable/exprs/column_ref.py +20 -15
  39. pixeltable/exprs/comparison.py +6 -2
  40. pixeltable/exprs/compound_predicate.py +1 -3
  41. pixeltable/exprs/data_row.py +2 -2
  42. pixeltable/exprs/expr.py +101 -72
  43. pixeltable/exprs/expr_dict.py +2 -1
  44. pixeltable/exprs/expr_set.py +3 -1
  45. pixeltable/exprs/function_call.py +39 -41
  46. pixeltable/exprs/globals.py +1 -0
  47. pixeltable/exprs/in_predicate.py +2 -2
  48. pixeltable/exprs/inline_expr.py +20 -17
  49. pixeltable/exprs/json_mapper.py +4 -2
  50. pixeltable/exprs/json_path.py +12 -18
  51. pixeltable/exprs/literal.py +5 -9
  52. pixeltable/exprs/method_ref.py +1 -0
  53. pixeltable/exprs/object_ref.py +1 -1
  54. pixeltable/exprs/row_builder.py +32 -17
  55. pixeltable/exprs/rowid_ref.py +14 -5
  56. pixeltable/exprs/similarity_expr.py +11 -6
  57. pixeltable/exprs/sql_element_cache.py +1 -1
  58. pixeltable/exprs/type_cast.py +24 -9
  59. pixeltable/ext/__init__.py +1 -0
  60. pixeltable/ext/functions/__init__.py +1 -0
  61. pixeltable/ext/functions/whisperx.py +2 -2
  62. pixeltable/ext/functions/yolox.py +11 -11
  63. pixeltable/func/aggregate_function.py +17 -13
  64. pixeltable/func/callable_function.py +6 -6
  65. pixeltable/func/expr_template_function.py +15 -14
  66. pixeltable/func/function.py +16 -16
  67. pixeltable/func/function_registry.py +11 -8
  68. pixeltable/func/globals.py +4 -2
  69. pixeltable/func/query_template_function.py +12 -13
  70. pixeltable/func/signature.py +18 -9
  71. pixeltable/func/tools.py +10 -17
  72. pixeltable/func/udf.py +106 -11
  73. pixeltable/functions/__init__.py +21 -2
  74. pixeltable/functions/anthropic.py +16 -12
  75. pixeltable/functions/fireworks.py +63 -5
  76. pixeltable/functions/gemini.py +13 -3
  77. pixeltable/functions/globals.py +18 -6
  78. pixeltable/functions/huggingface.py +20 -38
  79. pixeltable/functions/image.py +7 -3
  80. pixeltable/functions/json.py +1 -0
  81. pixeltable/functions/llama_cpp.py +1 -4
  82. pixeltable/functions/mistralai.py +31 -20
  83. pixeltable/functions/ollama.py +4 -18
  84. pixeltable/functions/openai.py +201 -108
  85. pixeltable/functions/replicate.py +11 -10
  86. pixeltable/functions/string.py +70 -7
  87. pixeltable/functions/timestamp.py +21 -8
  88. pixeltable/functions/together.py +66 -52
  89. pixeltable/functions/video.py +1 -0
  90. pixeltable/functions/vision.py +14 -11
  91. pixeltable/functions/whisper.py +2 -1
  92. pixeltable/globals.py +60 -26
  93. pixeltable/index/__init__.py +1 -1
  94. pixeltable/index/btree.py +5 -3
  95. pixeltable/index/embedding_index.py +15 -14
  96. pixeltable/io/__init__.py +1 -1
  97. pixeltable/io/external_store.py +30 -25
  98. pixeltable/io/fiftyone.py +6 -14
  99. pixeltable/io/globals.py +33 -27
  100. pixeltable/io/hf_datasets.py +2 -1
  101. pixeltable/io/label_studio.py +77 -68
  102. pixeltable/io/pandas.py +33 -9
  103. pixeltable/io/parquet.py +9 -12
  104. pixeltable/iterators/__init__.py +1 -0
  105. pixeltable/iterators/audio.py +205 -0
  106. pixeltable/iterators/document.py +19 -8
  107. pixeltable/iterators/image.py +6 -24
  108. pixeltable/iterators/string.py +3 -6
  109. pixeltable/iterators/video.py +1 -7
  110. pixeltable/metadata/__init__.py +7 -1
  111. pixeltable/metadata/converters/convert_10.py +2 -2
  112. pixeltable/metadata/converters/convert_15.py +1 -5
  113. pixeltable/metadata/converters/convert_16.py +2 -4
  114. pixeltable/metadata/converters/convert_17.py +2 -4
  115. pixeltable/metadata/converters/convert_18.py +2 -4
  116. pixeltable/metadata/converters/convert_19.py +2 -5
  117. pixeltable/metadata/converters/convert_20.py +1 -4
  118. pixeltable/metadata/converters/convert_21.py +4 -6
  119. pixeltable/metadata/converters/convert_22.py +1 -0
  120. pixeltable/metadata/converters/convert_23.py +5 -5
  121. pixeltable/metadata/converters/convert_24.py +12 -13
  122. pixeltable/metadata/converters/convert_26.py +23 -0
  123. pixeltable/metadata/converters/util.py +3 -4
  124. pixeltable/metadata/notes.py +1 -0
  125. pixeltable/metadata/schema.py +13 -2
  126. pixeltable/plan.py +173 -98
  127. pixeltable/store.py +42 -26
  128. pixeltable/type_system.py +62 -54
  129. pixeltable/utils/arrow.py +1 -2
  130. pixeltable/utils/coco.py +16 -17
  131. pixeltable/utils/code.py +1 -1
  132. pixeltable/utils/console_output.py +6 -3
  133. pixeltable/utils/description_helper.py +7 -7
  134. pixeltable/utils/documents.py +3 -1
  135. pixeltable/utils/filecache.py +12 -7
  136. pixeltable/utils/http_server.py +9 -8
  137. pixeltable/utils/media_store.py +2 -1
  138. pixeltable/utils/pytorch.py +11 -14
  139. pixeltable/utils/s3.py +1 -0
  140. pixeltable/utils/sql.py +1 -0
  141. pixeltable/utils/transactional_directory.py +2 -2
  142. {pixeltable-0.3.2.dist-info → pixeltable-0.3.3.dist-info}/METADATA +6 -8
  143. pixeltable-0.3.3.dist-info/RECORD +163 -0
  144. pixeltable-0.3.2.dist-info/RECORD +0 -161
  145. {pixeltable-0.3.2.dist-info → pixeltable-0.3.3.dist-info}/LICENSE +0 -0
  146. {pixeltable-0.3.2.dist-info → pixeltable-0.3.3.dist-info}/WHEEL +0 -0
  147. {pixeltable-0.3.2.dist-info → pixeltable-0.3.3.dist-info}/entry_points.txt +0 -0
@@ -9,6 +9,7 @@ from .expr import Expr
9
9
  from .expr_dict import ExprDict
10
10
  from .expr_set import ExprSet
11
11
  from .function_call import FunctionCall
12
+ from .globals import ArithmeticOperator, ComparisonOperator, LogicalOperator
12
13
  from .in_predicate import InPredicate
13
14
  from .inline_expr import InlineArray, InlineDict, InlineList
14
15
  from .is_null import IsNull
@@ -17,10 +18,9 @@ from .json_path import RELATIVE_PATH_ROOT, JsonPath
17
18
  from .literal import Literal
18
19
  from .method_ref import MethodRef
19
20
  from .object_ref import ObjectRef
20
- from .row_builder import RowBuilder, ColumnSlotIdx, ExecProfile
21
+ from .row_builder import ColumnSlotIdx, ExecProfile, RowBuilder
21
22
  from .rowid_ref import RowidRef
22
23
  from .similarity_expr import SimilarityExpr
23
24
  from .sql_element_cache import SqlElementCache
24
25
  from .type_cast import TypeCast
25
26
  from .variable import Variable
26
- from .globals import ComparisonOperator, LogicalOperator, ArithmeticOperator
@@ -1,15 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Optional
3
+ from typing import Any, Optional, Union
4
4
 
5
5
  import sqlalchemy as sql
6
6
 
7
7
  import pixeltable.exceptions as excs
8
+ import pixeltable.exprs as exprs
8
9
  import pixeltable.type_system as ts
9
10
 
10
11
  from .data_row import DataRow
11
12
  from .expr import Expr
12
13
  from .globals import ArithmeticOperator
14
+ from .literal import Literal
13
15
  from .row_builder import RowBuilder
14
16
  from .sql_element_cache import SqlElementCache
15
17
 
@@ -18,6 +20,7 @@ class ArithmeticExpr(Expr):
18
20
  """
19
21
  Allows arithmetic exprs on json paths
20
22
  """
23
+
21
24
  def __init__(self, operator: ArithmeticOperator, op1: Expr, op2: Expr):
22
25
  if op1.col_type.is_json_type() or op2.col_type.is_json_type() or operator == ArithmeticOperator.DIV:
23
26
  # we assume it's a float
@@ -35,6 +38,14 @@ class ArithmeticExpr(Expr):
35
38
 
36
39
  self.id = self._create_id()
37
40
 
41
+ @property
42
+ def _op1(self) -> Expr:
43
+ return self.components[0]
44
+
45
+ @property
46
+ def _op2(self) -> Expr:
47
+ return self.components[1]
48
+
38
49
  def __repr__(self) -> str:
39
50
  # add parentheses around operands that are ArithmeticExprs to express precedence
40
51
  op1_str = f'({self._op1})' if isinstance(self._op1, ArithmeticExpr) else str(self._op1)
@@ -47,14 +58,6 @@ class ArithmeticExpr(Expr):
47
58
  def _id_attrs(self) -> list[tuple[str, Any]]:
48
59
  return super()._id_attrs() + [('operator', self.operator.value)]
49
60
 
50
- @property
51
- def _op1(self) -> Expr:
52
- return self.components[0]
53
-
54
- @property
55
- def _op2(self) -> Expr:
56
- return self.components[1]
57
-
58
61
  def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
59
62
  assert self.col_type.is_int_type() or self.col_type.is_float_type() or self.col_type.is_json_type()
60
63
  left = sql_elements.get(self._op1)
@@ -73,7 +76,7 @@ class ArithmeticExpr(Expr):
73
76
  # TODO: Should we cast the NULLs to NaNs when they are retrieved back into Python?
74
77
  nullif = sql.sql.func.nullif(right, 0)
75
78
  # We have to cast to a `float`, or else we'll get a `Decimal`
76
- return sql.sql.expression.cast(left / nullif, sql.Float)
79
+ return sql.sql.expression.cast(left / nullif, self.col_type.to_sa_type())
77
80
  if self.operator == ArithmeticOperator.MOD:
78
81
  if self.col_type.is_int_type():
79
82
  nullif = sql.sql.func.nullif(right, 0)
@@ -89,9 +92,9 @@ class ArithmeticExpr(Expr):
89
92
  # mimic the behavior of Python's // operator.
90
93
  nullif = sql.sql.func.nullif(right, 0)
91
94
  if self.col_type.is_int_type():
92
- return sql.sql.expression.cast(sql.func.floor(left / nullif), sql.Integer)
95
+ return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
93
96
  if self.col_type.is_float_type():
94
- return sql.sql.expression.cast(sql.func.floor(left / nullif), sql.Float)
97
+ return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
95
98
  assert False
96
99
 
97
100
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
@@ -99,30 +102,58 @@ class ArithmeticExpr(Expr):
99
102
  op2_val = data_row[self._op2.slot_idx]
100
103
 
101
104
  # if one or both columns is JsonTyped, we need a dynamic check that they are numeric
102
- if self._op1.col_type.is_json_type() and not isinstance(op1_val, int) and not isinstance(op1_val, float):
105
+ if self._op1.col_type.is_json_type() and op1_val is not None and not isinstance(op1_val, (int, float)):
103
106
  raise excs.Error(
104
- f'{self.operator} requires numeric type, but {self._op1} has type {type(op1_val).__name__}')
105
- if self._op2.col_type.is_json_type() and not isinstance(op2_val, int) and not isinstance(op2_val, float):
107
+ f'{self.operator} requires numeric types, but {self._op1} has type {type(op1_val).__name__}'
108
+ )
109
+ if self._op2.col_type.is_json_type() and op2_val is not None and not isinstance(op2_val, (int, float)):
106
110
  raise excs.Error(
107
- f'{self.operator} requires numeric type, but {self._op2} has type {type(op2_val).__name__}')
108
-
109
- # if either operand is None, always return None
111
+ f'{self.operator} requires numeric types, but {self._op2} has type {type(op2_val).__name__}'
112
+ )
113
+
114
+ data_row[self.slot_idx] = self.eval_nullable(op1_val, op2_val)
115
+
116
+ def eval_nullable(
117
+ self, op1_val: Union[int, float, None], op2_val: Union[int, float, None]
118
+ ) -> Union[int, float, None]:
119
+ """
120
+ Return the result of evaluating the expression on two nullable int/float operands,
121
+ None is interpreted as SQL NULL
122
+ """
110
123
  if op1_val is None or op2_val is None:
111
- data_row[self.slot_idx] = None
112
- return
124
+ return None
125
+ return self.eval_non_null(op1_val, op2_val)
113
126
 
127
+ def eval_non_null(self, op1_val: Union[int, float], op2_val: Union[int, float]) -> Union[int, float]:
128
+ """
129
+ Return the result of evaluating the expression on two int/float operands
130
+ """
114
131
  if self.operator == ArithmeticOperator.ADD:
115
- data_row[self.slot_idx] = op1_val + op2_val
132
+ return op1_val + op2_val
116
133
  elif self.operator == ArithmeticOperator.SUB:
117
- data_row[self.slot_idx] = op1_val - op2_val
134
+ return op1_val - op2_val
118
135
  elif self.operator == ArithmeticOperator.MUL:
119
- data_row[self.slot_idx] = op1_val * op2_val
136
+ return op1_val * op2_val
120
137
  elif self.operator == ArithmeticOperator.DIV:
121
- data_row[self.slot_idx] = op1_val / op2_val
138
+ return op1_val / op2_val
122
139
  elif self.operator == ArithmeticOperator.MOD:
123
- data_row[self.slot_idx] = op1_val % op2_val
140
+ return op1_val % op2_val
124
141
  elif self.operator == ArithmeticOperator.FLOORDIV:
125
- data_row[self.slot_idx] = op1_val // op2_val
142
+ return op1_val // op2_val
143
+
144
+ def as_literal(self) -> Optional[Literal]:
145
+ op1_lit = self._op1.as_literal()
146
+ if op1_lit is None:
147
+ return None
148
+ op2_lit = self._op2.as_literal()
149
+ if op2_lit is None:
150
+ return None
151
+ op1_val = op1_lit.val
152
+ assert op1_lit.col_type.is_numeric_type() or op1_val is None
153
+ op2_val = op2_lit.val
154
+ assert op2_lit.col_type.is_numeric_type() or op2_val is None
155
+
156
+ return Literal(self.eval_nullable(op1_val, op2_val), self.col_type) # type: ignore[arg-type]
126
157
 
127
158
  def _as_dict(self) -> dict:
128
159
  return {'operator': self.operator.value, **super()._as_dict()}
@@ -15,6 +15,7 @@ class ArraySlice(Expr):
15
15
  """
16
16
  Slice operation on an array, eg, t.array_col[:, 1:2].
17
17
  """
18
+
18
19
  def __init__(self, arr: Expr, index: tuple[Union[int, slice], ...]):
19
20
  assert arr.col_type.is_array_type()
20
21
  # determine result type
@@ -68,4 +69,3 @@ class ArraySlice(Expr):
68
69
  else:
69
70
  index.append(el)
70
71
  return cls(components[0], tuple(index))
71
-
@@ -7,6 +7,7 @@ import sqlalchemy as sql
7
7
 
8
8
  import pixeltable.type_system as ts
9
9
  from pixeltable import catalog
10
+
10
11
  from .column_ref import ColumnRef
11
12
  from .data_row import DataRow
12
13
  from .expr import Expr
@@ -19,6 +20,7 @@ class ColumnPropertyRef(Expr):
19
20
 
20
21
  The properties themselves are type-specific and may or may not need to reference the underlying column data.
21
22
  """
23
+
22
24
  class Property(enum.Enum):
23
25
  ERRORTYPE = 0
24
26
  ERRORMSG = 1
@@ -103,4 +105,3 @@ class ColumnPropertyRef(Expr):
103
105
  assert 'prop' in d
104
106
  assert isinstance(components[0], ColumnRef)
105
107
  return cls(components[0], cls.Property(d['prop']))
106
-
@@ -51,8 +51,9 @@ class ColumnRef(Expr):
51
51
  super().__init__(col.col_type)
52
52
  assert col.tbl is not None
53
53
  self.col = col
54
- self.is_unstored_iter_col = \
54
+ self.is_unstored_iter_col = (
55
55
  col.tbl.is_component_view() and col.tbl.is_iterator_column(col) and not col.is_stored
56
+ )
56
57
  self.iter_arg_ctx = None
57
58
  # number of rowid columns in the base table
58
59
  self.base_rowid_len = col.tbl.base.num_rowid_columns() if self.is_unstored_iter_col else 0
@@ -83,10 +84,11 @@ class ColumnRef(Expr):
83
84
  assert len(self.iter_arg_ctx.target_slot_idxs) == 1 # a single inline dict
84
85
 
85
86
  def _id_attrs(self) -> list[tuple[str, Any]]:
86
- return (
87
- super()._id_attrs()
88
- + [('tbl_id', self.col.tbl.id), ('col_id', self.col.id), ('perform_validation', self.perform_validation)]
89
- )
87
+ return super()._id_attrs() + [
88
+ ('tbl_id', self.col.tbl.id),
89
+ ('col_id', self.col.id),
90
+ ('perform_validation', self.perform_validation),
91
+ ]
90
92
 
91
93
  # override
92
94
  def _retarget(self, tbl_versions: dict[UUID, catalog.TableVersion]) -> ColumnRef:
@@ -99,14 +101,18 @@ class ColumnRef(Expr):
99
101
  from .column_property_ref import ColumnPropertyRef
100
102
 
101
103
  # resolve column properties
102
- if name == ColumnPropertyRef.Property.ERRORTYPE.name.lower() \
103
- or name == ColumnPropertyRef.Property.ERRORMSG.name.lower():
104
+ if (
105
+ name == ColumnPropertyRef.Property.ERRORTYPE.name.lower()
106
+ or name == ColumnPropertyRef.Property.ERRORMSG.name.lower()
107
+ ):
104
108
  property_is_present = self.col.is_stored and (self.col.is_computed or self.col_type.is_media_type())
105
109
  if not property_is_present:
106
110
  raise excs.Error(f'{name} only valid for a stored computed or media column: {self}')
107
111
  return ColumnPropertyRef(self, ColumnPropertyRef.Property[name.upper()])
108
- if name == ColumnPropertyRef.Property.FILEURL.name.lower() \
109
- or name == ColumnPropertyRef.Property.LOCALPATH.name.lower():
112
+ if (
113
+ name == ColumnPropertyRef.Property.FILEURL.name.lower()
114
+ or name == ColumnPropertyRef.Property.LOCALPATH.name.lower()
115
+ ):
110
116
  if not self.col.col_type.is_media_type():
111
117
  raise excs.Error(f'{name} only valid for image/video/audio/document columns: {self}')
112
118
  if self.col.is_computed and not self.col.is_stored:
@@ -115,12 +121,14 @@ class ColumnRef(Expr):
115
121
 
116
122
  if self.col_type.is_json_type():
117
123
  from .json_path import JsonPath
124
+
118
125
  return JsonPath(self, [name])
119
126
 
120
127
  return super().__getattr__(name)
121
128
 
122
129
  def similarity(self, item: Any, *, idx: Optional[str] = None) -> Expr:
123
130
  from .similarity_expr import SimilarityExpr
131
+
124
132
  return SimilarityExpr(self, item, idx_name=idx)
125
133
 
126
134
  def default_column_name(self) -> Optional[str]:
@@ -206,11 +214,11 @@ class ColumnRef(Expr):
206
214
  return
207
215
 
208
216
  # if this is a new base row, we need to instantiate a new iterator
209
- if self.base_rowid != data_row.pk[:self.base_rowid_len]:
217
+ if self.base_rowid != data_row.pk[: self.base_rowid_len]:
210
218
  row_builder.eval(data_row, self.iter_arg_ctx)
211
219
  iterator_args = data_row[self.iter_arg_ctx.target_slot_idxs[0]]
212
220
  self.iterator = self.col.tbl.iterator_cls(**iterator_args)
213
- self.base_rowid = data_row.pk[:self.base_rowid_len]
221
+ self.base_rowid = data_row.pk[: self.base_rowid_len]
214
222
  self.iterator.set_pos(data_row.pk[self.pos_idx])
215
223
  res = next(self.iterator)
216
224
  data_row[self.slot_idx] = res[self.col.name]
@@ -224,7 +232,7 @@ class ColumnRef(Expr):
224
232
  'tbl_id': str(tbl.id),
225
233
  'tbl_version': version,
226
234
  'col_id': self.col.id,
227
- 'perform_validation': self.perform_validation
235
+ 'perform_validation': self.perform_validation,
228
236
  }
229
237
 
230
238
  @classmethod
@@ -240,6 +248,3 @@ class ColumnRef(Expr):
240
248
  col = cls.get_column(d)
241
249
  perform_validation = d['perform_validation']
242
250
  return cls(col, perform_validation=perform_validation)
243
-
244
- def is_constant(self) -> bool:
245
- return False
@@ -39,8 +39,12 @@ class Comparison(Expr):
39
39
  self.components = [op1, op2]
40
40
 
41
41
  import pixeltable.index as index
42
- if self.is_search_arg_comparison and self._op2.col_type.is_string_type() \
43
- and len(self._op2.val) >= index.BtreeIndex.MAX_STRING_LEN:
42
+
43
+ if (
44
+ self.is_search_arg_comparison
45
+ and self._op2.col_type.is_string_type()
46
+ and len(self._op2.val) >= index.BtreeIndex.MAX_STRING_LEN
47
+ ):
44
48
  # we can't use an index for this after all
45
49
  raise excs.Error(
46
50
  f'String literal too long for comparison against indexed column {self._op1.col.name!r} '
@@ -60,8 +60,7 @@ class CompoundPredicate(Expr):
60
60
  def _id_attrs(self) -> list[tuple[str, Any]]:
61
61
  return super()._id_attrs() + [('operator', self.operator.value)]
62
62
 
63
- def split_conjuncts(
64
- self, condition: Callable[[Expr], bool]) -> tuple[list[Expr], Optional[Expr]]:
63
+ def split_conjuncts(self, condition: Callable[[Expr], bool]) -> tuple[list[Expr], Optional[Expr]]:
65
64
  if self.operator == LogicalOperator.OR or self.operator == LogicalOperator.NOT:
66
65
  return super().split_conjuncts(condition)
67
66
  matches = [op for op in self.components if condition(op)]
@@ -97,4 +96,3 @@ class CompoundPredicate(Expr):
97
96
  def _from_dict(cls, d: dict, components: list[Expr]) -> CompoundPredicate:
98
97
  assert 'operator' in d
99
98
  return cls(LogicalOperator(d['operator']), components)
100
-
@@ -6,10 +6,10 @@ import urllib.parse
6
6
  import urllib.request
7
7
  from typing import Any, Optional
8
8
 
9
- import PIL
10
- import PIL.Image
11
9
  import numpy as np
12
10
  import pgvector.sqlalchemy # type: ignore[import-untyped]
11
+ import PIL
12
+ import PIL.Image
13
13
  import sqlalchemy as sql
14
14
 
15
15
  from pixeltable import env