pixeltable 0.3.14__py3-none-any.whl → 0.5.7__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.
Files changed (220) hide show
  1. pixeltable/__init__.py +42 -8
  2. pixeltable/{dataframe.py → _query.py} +470 -206
  3. pixeltable/_version.py +1 -0
  4. pixeltable/catalog/__init__.py +5 -4
  5. pixeltable/catalog/catalog.py +1785 -432
  6. pixeltable/catalog/column.py +190 -113
  7. pixeltable/catalog/dir.py +2 -4
  8. pixeltable/catalog/globals.py +19 -46
  9. pixeltable/catalog/insertable_table.py +191 -98
  10. pixeltable/catalog/path.py +63 -23
  11. pixeltable/catalog/schema_object.py +11 -15
  12. pixeltable/catalog/table.py +843 -436
  13. pixeltable/catalog/table_metadata.py +103 -0
  14. pixeltable/catalog/table_version.py +978 -657
  15. pixeltable/catalog/table_version_handle.py +72 -16
  16. pixeltable/catalog/table_version_path.py +112 -43
  17. pixeltable/catalog/tbl_ops.py +53 -0
  18. pixeltable/catalog/update_status.py +191 -0
  19. pixeltable/catalog/view.py +134 -90
  20. pixeltable/config.py +134 -22
  21. pixeltable/env.py +471 -157
  22. pixeltable/exceptions.py +6 -0
  23. pixeltable/exec/__init__.py +4 -1
  24. pixeltable/exec/aggregation_node.py +7 -8
  25. pixeltable/exec/cache_prefetch_node.py +83 -110
  26. pixeltable/exec/cell_materialization_node.py +268 -0
  27. pixeltable/exec/cell_reconstruction_node.py +168 -0
  28. pixeltable/exec/component_iteration_node.py +4 -3
  29. pixeltable/exec/data_row_batch.py +8 -65
  30. pixeltable/exec/exec_context.py +16 -4
  31. pixeltable/exec/exec_node.py +13 -36
  32. pixeltable/exec/expr_eval/evaluators.py +11 -7
  33. pixeltable/exec/expr_eval/expr_eval_node.py +27 -12
  34. pixeltable/exec/expr_eval/globals.py +8 -5
  35. pixeltable/exec/expr_eval/row_buffer.py +1 -2
  36. pixeltable/exec/expr_eval/schedulers.py +106 -56
  37. pixeltable/exec/globals.py +35 -0
  38. pixeltable/exec/in_memory_data_node.py +19 -19
  39. pixeltable/exec/object_store_save_node.py +293 -0
  40. pixeltable/exec/row_update_node.py +16 -9
  41. pixeltable/exec/sql_node.py +351 -84
  42. pixeltable/exprs/__init__.py +1 -1
  43. pixeltable/exprs/arithmetic_expr.py +27 -22
  44. pixeltable/exprs/array_slice.py +3 -3
  45. pixeltable/exprs/column_property_ref.py +36 -23
  46. pixeltable/exprs/column_ref.py +213 -89
  47. pixeltable/exprs/comparison.py +5 -5
  48. pixeltable/exprs/compound_predicate.py +5 -4
  49. pixeltable/exprs/data_row.py +164 -54
  50. pixeltable/exprs/expr.py +70 -44
  51. pixeltable/exprs/expr_dict.py +3 -3
  52. pixeltable/exprs/expr_set.py +17 -10
  53. pixeltable/exprs/function_call.py +100 -40
  54. pixeltable/exprs/globals.py +2 -2
  55. pixeltable/exprs/in_predicate.py +4 -4
  56. pixeltable/exprs/inline_expr.py +18 -32
  57. pixeltable/exprs/is_null.py +7 -3
  58. pixeltable/exprs/json_mapper.py +8 -8
  59. pixeltable/exprs/json_path.py +56 -22
  60. pixeltable/exprs/literal.py +27 -5
  61. pixeltable/exprs/method_ref.py +2 -2
  62. pixeltable/exprs/object_ref.py +2 -2
  63. pixeltable/exprs/row_builder.py +167 -67
  64. pixeltable/exprs/rowid_ref.py +25 -10
  65. pixeltable/exprs/similarity_expr.py +58 -40
  66. pixeltable/exprs/sql_element_cache.py +4 -4
  67. pixeltable/exprs/string_op.py +5 -5
  68. pixeltable/exprs/type_cast.py +3 -5
  69. pixeltable/func/__init__.py +1 -0
  70. pixeltable/func/aggregate_function.py +8 -8
  71. pixeltable/func/callable_function.py +9 -9
  72. pixeltable/func/expr_template_function.py +17 -11
  73. pixeltable/func/function.py +18 -20
  74. pixeltable/func/function_registry.py +6 -7
  75. pixeltable/func/globals.py +2 -3
  76. pixeltable/func/mcp.py +74 -0
  77. pixeltable/func/query_template_function.py +29 -27
  78. pixeltable/func/signature.py +46 -19
  79. pixeltable/func/tools.py +31 -13
  80. pixeltable/func/udf.py +18 -20
  81. pixeltable/functions/__init__.py +16 -0
  82. pixeltable/functions/anthropic.py +123 -77
  83. pixeltable/functions/audio.py +147 -10
  84. pixeltable/functions/bedrock.py +13 -6
  85. pixeltable/functions/date.py +7 -4
  86. pixeltable/functions/deepseek.py +35 -43
  87. pixeltable/functions/document.py +81 -0
  88. pixeltable/functions/fal.py +76 -0
  89. pixeltable/functions/fireworks.py +11 -20
  90. pixeltable/functions/gemini.py +195 -39
  91. pixeltable/functions/globals.py +142 -14
  92. pixeltable/functions/groq.py +108 -0
  93. pixeltable/functions/huggingface.py +1056 -24
  94. pixeltable/functions/image.py +115 -57
  95. pixeltable/functions/json.py +1 -1
  96. pixeltable/functions/llama_cpp.py +28 -13
  97. pixeltable/functions/math.py +67 -5
  98. pixeltable/functions/mistralai.py +18 -55
  99. pixeltable/functions/net.py +70 -0
  100. pixeltable/functions/ollama.py +20 -13
  101. pixeltable/functions/openai.py +240 -226
  102. pixeltable/functions/openrouter.py +143 -0
  103. pixeltable/functions/replicate.py +4 -4
  104. pixeltable/functions/reve.py +250 -0
  105. pixeltable/functions/string.py +239 -69
  106. pixeltable/functions/timestamp.py +16 -16
  107. pixeltable/functions/together.py +24 -84
  108. pixeltable/functions/twelvelabs.py +188 -0
  109. pixeltable/functions/util.py +6 -1
  110. pixeltable/functions/uuid.py +30 -0
  111. pixeltable/functions/video.py +1515 -107
  112. pixeltable/functions/vision.py +8 -8
  113. pixeltable/functions/voyageai.py +289 -0
  114. pixeltable/functions/whisper.py +16 -8
  115. pixeltable/functions/whisperx.py +179 -0
  116. pixeltable/{ext/functions → functions}/yolox.py +2 -4
  117. pixeltable/globals.py +362 -115
  118. pixeltable/index/base.py +17 -21
  119. pixeltable/index/btree.py +28 -22
  120. pixeltable/index/embedding_index.py +100 -118
  121. pixeltable/io/__init__.py +4 -2
  122. pixeltable/io/datarows.py +8 -7
  123. pixeltable/io/external_store.py +56 -105
  124. pixeltable/io/fiftyone.py +13 -13
  125. pixeltable/io/globals.py +31 -30
  126. pixeltable/io/hf_datasets.py +61 -16
  127. pixeltable/io/label_studio.py +74 -70
  128. pixeltable/io/lancedb.py +3 -0
  129. pixeltable/io/pandas.py +21 -12
  130. pixeltable/io/parquet.py +25 -105
  131. pixeltable/io/table_data_conduit.py +250 -123
  132. pixeltable/io/utils.py +4 -4
  133. pixeltable/iterators/__init__.py +2 -1
  134. pixeltable/iterators/audio.py +26 -25
  135. pixeltable/iterators/base.py +9 -3
  136. pixeltable/iterators/document.py +112 -78
  137. pixeltable/iterators/image.py +12 -15
  138. pixeltable/iterators/string.py +11 -4
  139. pixeltable/iterators/video.py +523 -120
  140. pixeltable/metadata/__init__.py +14 -3
  141. pixeltable/metadata/converters/convert_13.py +2 -2
  142. pixeltable/metadata/converters/convert_18.py +2 -2
  143. pixeltable/metadata/converters/convert_19.py +2 -2
  144. pixeltable/metadata/converters/convert_20.py +2 -2
  145. pixeltable/metadata/converters/convert_21.py +2 -2
  146. pixeltable/metadata/converters/convert_22.py +2 -2
  147. pixeltable/metadata/converters/convert_24.py +2 -2
  148. pixeltable/metadata/converters/convert_25.py +2 -2
  149. pixeltable/metadata/converters/convert_26.py +2 -2
  150. pixeltable/metadata/converters/convert_29.py +4 -4
  151. pixeltable/metadata/converters/convert_30.py +34 -21
  152. pixeltable/metadata/converters/convert_34.py +2 -2
  153. pixeltable/metadata/converters/convert_35.py +9 -0
  154. pixeltable/metadata/converters/convert_36.py +38 -0
  155. pixeltable/metadata/converters/convert_37.py +15 -0
  156. pixeltable/metadata/converters/convert_38.py +39 -0
  157. pixeltable/metadata/converters/convert_39.py +124 -0
  158. pixeltable/metadata/converters/convert_40.py +73 -0
  159. pixeltable/metadata/converters/convert_41.py +12 -0
  160. pixeltable/metadata/converters/convert_42.py +9 -0
  161. pixeltable/metadata/converters/convert_43.py +44 -0
  162. pixeltable/metadata/converters/util.py +20 -31
  163. pixeltable/metadata/notes.py +9 -0
  164. pixeltable/metadata/schema.py +140 -53
  165. pixeltable/metadata/utils.py +74 -0
  166. pixeltable/mypy/__init__.py +3 -0
  167. pixeltable/mypy/mypy_plugin.py +123 -0
  168. pixeltable/plan.py +382 -115
  169. pixeltable/share/__init__.py +1 -1
  170. pixeltable/share/packager.py +547 -83
  171. pixeltable/share/protocol/__init__.py +33 -0
  172. pixeltable/share/protocol/common.py +165 -0
  173. pixeltable/share/protocol/operation_types.py +33 -0
  174. pixeltable/share/protocol/replica.py +119 -0
  175. pixeltable/share/publish.py +257 -59
  176. pixeltable/store.py +311 -194
  177. pixeltable/type_system.py +373 -211
  178. pixeltable/utils/__init__.py +2 -3
  179. pixeltable/utils/arrow.py +131 -17
  180. pixeltable/utils/av.py +298 -0
  181. pixeltable/utils/azure_store.py +346 -0
  182. pixeltable/utils/coco.py +6 -6
  183. pixeltable/utils/code.py +3 -3
  184. pixeltable/utils/console_output.py +4 -1
  185. pixeltable/utils/coroutine.py +6 -23
  186. pixeltable/utils/dbms.py +32 -6
  187. pixeltable/utils/description_helper.py +4 -5
  188. pixeltable/utils/documents.py +7 -18
  189. pixeltable/utils/exception_handler.py +7 -30
  190. pixeltable/utils/filecache.py +6 -6
  191. pixeltable/utils/formatter.py +86 -48
  192. pixeltable/utils/gcs_store.py +295 -0
  193. pixeltable/utils/http.py +133 -0
  194. pixeltable/utils/http_server.py +2 -3
  195. pixeltable/utils/iceberg.py +1 -2
  196. pixeltable/utils/image.py +17 -0
  197. pixeltable/utils/lancedb.py +90 -0
  198. pixeltable/utils/local_store.py +322 -0
  199. pixeltable/utils/misc.py +5 -0
  200. pixeltable/utils/object_stores.py +573 -0
  201. pixeltable/utils/pydantic.py +60 -0
  202. pixeltable/utils/pytorch.py +5 -6
  203. pixeltable/utils/s3_store.py +527 -0
  204. pixeltable/utils/sql.py +26 -0
  205. pixeltable/utils/system.py +30 -0
  206. pixeltable-0.5.7.dist-info/METADATA +579 -0
  207. pixeltable-0.5.7.dist-info/RECORD +227 -0
  208. {pixeltable-0.3.14.dist-info → pixeltable-0.5.7.dist-info}/WHEEL +1 -1
  209. pixeltable-0.5.7.dist-info/entry_points.txt +2 -0
  210. pixeltable/__version__.py +0 -3
  211. pixeltable/catalog/named_function.py +0 -40
  212. pixeltable/ext/__init__.py +0 -17
  213. pixeltable/ext/functions/__init__.py +0 -11
  214. pixeltable/ext/functions/whisperx.py +0 -77
  215. pixeltable/utils/media_store.py +0 -77
  216. pixeltable/utils/s3.py +0 -17
  217. pixeltable-0.3.14.dist-info/METADATA +0 -434
  218. pixeltable-0.3.14.dist-info/RECORD +0 -186
  219. pixeltable-0.3.14.dist-info/entry_points.txt +0 -3
  220. {pixeltable-0.3.14.dist-info → pixeltable-0.5.7.dist-info/licenses}/LICENSE +0 -0
@@ -1,10 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Optional
3
+ from typing import Any
4
4
 
5
5
  import sqlalchemy as sql
6
6
 
7
- from pixeltable import exceptions as excs, type_system as ts
7
+ from pixeltable import env, exceptions as excs, type_system as ts
8
8
 
9
9
  from .data_row import DataRow
10
10
  from .expr import Expr
@@ -58,29 +58,36 @@ class ArithmeticExpr(Expr):
58
58
  def _id_attrs(self) -> list[tuple[str, Any]]:
59
59
  return [*super()._id_attrs(), ('operator', self.operator.value)]
60
60
 
61
- def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
61
+ def sql_expr(self, sql_elements: SqlElementCache) -> sql.ColumnElement | None:
62
62
  assert self.col_type.is_int_type() or self.col_type.is_float_type() or self.col_type.is_json_type()
63
63
  left = sql_elements.get(self._op1)
64
64
  right = sql_elements.get(self._op2)
65
65
  if left is None or right is None:
66
66
  return None
67
- if self.operator == ArithmeticOperator.ADD:
68
- return left + right
69
- if self.operator == ArithmeticOperator.SUB:
70
- return left - right
71
- if self.operator == ArithmeticOperator.MUL:
72
- return left * right
67
+ if self.operator in (ArithmeticOperator.ADD, ArithmeticOperator.SUB, ArithmeticOperator.MUL):
68
+ if env.Env.get().is_using_cockroachdb and self._op1.col_type != self._op2.col_type:
69
+ if self._op1.col_type != self.col_type:
70
+ left = sql.cast(left, self.col_type.to_sa_type())
71
+ if self._op2.col_type != self.col_type:
72
+ right = sql.cast(right, self.col_type.to_sa_type())
73
+ if self.operator == ArithmeticOperator.ADD:
74
+ return left + right
75
+ if self.operator == ArithmeticOperator.SUB:
76
+ return left - right
77
+ if self.operator == ArithmeticOperator.MUL:
78
+ return left * right
73
79
  if self.operator == ArithmeticOperator.DIV:
74
80
  assert self.col_type.is_float_type()
75
- # Avoid DivisionByZero: if right is 0, make this a NULL
81
+ # Avoid division by zero errors by converting any zero divisor to NULL.
76
82
  # TODO: Should we cast the NULLs to NaNs when they are retrieved back into Python?
77
- nullif = sql.sql.func.nullif(right, 0)
78
- # We have to cast to a `float`, or else we'll get a `Decimal`
79
- return sql.sql.expression.cast(left / nullif, self.col_type.to_sa_type())
83
+ # These casts cause the computation to take place in float units, rather than DECIMAL.
84
+ nullif = sql.cast(sql.func.nullif(right, 0), self.col_type.to_sa_type())
85
+ return sql.cast(left, self.col_type.to_sa_type()) / nullif
80
86
  if self.operator == ArithmeticOperator.MOD:
81
87
  if self.col_type.is_int_type():
82
- nullif = sql.sql.func.nullif(right, 0)
83
- return left % nullif
88
+ # Avoid division by zero errors by converting any zero divisor to NULL.
89
+ nullif1 = sql.cast(sql.func.nullif(right, 0), self.col_type.to_sa_type())
90
+ return left % nullif1
84
91
  if self.col_type.is_float_type():
85
92
  # Postgres does not support modulus for floats
86
93
  return None
@@ -90,11 +97,9 @@ class ArithmeticExpr(Expr):
90
97
  # We need the behavior to be consistent, so that expressions will evaluate the same way
91
98
  # whether or not their operands can be translated to SQL. These SQL clauses should
92
99
  # mimic the behavior of Python's // operator.
93
- nullif = sql.sql.func.nullif(right, 0)
94
- if self.col_type.is_int_type():
95
- return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
96
- if self.col_type.is_float_type():
97
- return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
100
+ # Avoid division by zero errors by converting any zero divisor to NULL.
101
+ nullif = sql.cast(sql.func.nullif(right, 0), self.col_type.to_sa_type())
102
+ return sql.func.floor(sql.cast(left, self.col_type.to_sa_type()) / nullif)
98
103
  raise AssertionError()
99
104
 
100
105
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
@@ -113,7 +118,7 @@ class ArithmeticExpr(Expr):
113
118
 
114
119
  data_row[self.slot_idx] = self.eval_nullable(op1_val, op2_val)
115
120
 
116
- def eval_nullable(self, op1_val: Optional[float], op2_val: Optional[float]) -> Optional[float]:
121
+ def eval_nullable(self, op1_val: float | None, op2_val: float | None) -> float | None:
117
122
  """
118
123
  Return the result of evaluating the expression on two nullable int/float operands,
119
124
  None is interpreted as SQL NULL
@@ -139,7 +144,7 @@ class ArithmeticExpr(Expr):
139
144
  elif self.operator == ArithmeticOperator.FLOORDIV:
140
145
  return op1_val // op2_val
141
146
 
142
- def as_literal(self) -> Optional[Literal]:
147
+ def as_literal(self) -> Literal | None:
143
148
  op1_lit = self._op1.as_literal()
144
149
  if op1_lit is None:
145
150
  return None
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Optional, Union
3
+ from typing import Any
4
4
 
5
5
  import sqlalchemy as sql
6
6
 
@@ -16,7 +16,7 @@ class ArraySlice(Expr):
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
+ def __init__(self, arr: Expr, index: tuple[int | slice, ...]):
20
20
  assert arr.col_type.is_array_type()
21
21
  # determine result type
22
22
  super().__init__(arr.col_type)
@@ -43,7 +43,7 @@ class ArraySlice(Expr):
43
43
  def _id_attrs(self) -> list[tuple[str, Any]]:
44
44
  return [*super()._id_attrs(), ('index', self.index)]
45
45
 
46
- def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
46
+ def sql_expr(self, _: SqlElementCache) -> sql.ColumnElement | None:
47
47
  return None
48
48
 
49
49
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import enum
4
- from typing import Any, Optional
4
+ from typing import Any
5
5
 
6
6
  import sqlalchemy as sql
7
7
 
@@ -26,6 +26,7 @@ class ColumnPropertyRef(Expr):
26
26
  ERRORMSG = 1
27
27
  FILEURL = 2
28
28
  LOCALPATH = 3
29
+ CELLMD = 4 # JSON metadata for the cell, e.g. errortype, errormsg for media columns
29
30
 
30
31
  def __init__(self, col_ref: ColumnRef, prop: Property):
31
32
  super().__init__(ts.StringType(nullable=True))
@@ -33,7 +34,7 @@ class ColumnPropertyRef(Expr):
33
34
  self.prop = prop
34
35
  self.id = self._create_id()
35
36
 
36
- def default_column_name(self) -> Optional[str]:
37
+ def default_column_name(self) -> str | None:
37
38
  return str(self).replace('.', '_')
38
39
 
39
40
  def _equals(self, other: ColumnPropertyRef) -> bool:
@@ -43,57 +44,69 @@ class ColumnPropertyRef(Expr):
43
44
  return [*super()._id_attrs(), ('prop', self.prop.value)]
44
45
 
45
46
  @property
46
- def _col_ref(self) -> ColumnRef:
47
+ def col_ref(self) -> ColumnRef:
47
48
  col_ref = self.components[0]
48
49
  assert isinstance(col_ref, ColumnRef)
49
50
  return col_ref
50
51
 
51
52
  def __repr__(self) -> str:
52
- return f'{self._col_ref}.{self.prop.name.lower()}'
53
+ return f'{self.col_ref}.{self.prop.name.lower()}'
53
54
 
54
- def is_error_prop(self) -> bool:
55
- return self.prop in (self.Property.ERRORTYPE, self.Property.ERRORMSG)
55
+ def is_cellmd_prop(self) -> bool:
56
+ return self.prop in (self.Property.ERRORTYPE, self.Property.ERRORMSG, self.Property.CELLMD)
56
57
 
57
- def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
58
- if not self._col_ref.col.is_stored:
58
+ def sql_expr(self, sql_elements: SqlElementCache) -> sql.ColumnElement | None:
59
+ if not self.col_ref.col_handle.get().is_stored:
59
60
  return None
61
+ col = self.col_ref.col_handle.get()
60
62
 
61
63
  # the errortype/-msg properties of a read-validated media column need to be extracted from the DataRow
62
64
  if (
63
- self._col_ref.col.col_type.is_media_type()
64
- and self._col_ref.col.media_validation == catalog.MediaValidation.ON_READ
65
- and self.is_error_prop()
65
+ col.col_type.is_media_type()
66
+ and col.media_validation == catalog.MediaValidation.ON_READ
67
+ and self.is_cellmd_prop()
66
68
  ):
67
69
  return None
68
70
 
69
71
  if self.prop == self.Property.ERRORTYPE:
70
- assert self._col_ref.col.sa_errortype_col is not None
71
- return self._col_ref.col.sa_errortype_col
72
+ return col.sa_cellmd_col.op('->>')('errortype')
72
73
  if self.prop == self.Property.ERRORMSG:
73
- assert self._col_ref.col.sa_errormsg_col is not None
74
- return self._col_ref.col.sa_errormsg_col
74
+ return col.sa_cellmd_col.op('->>')('errormsg')
75
+ if self.prop == self.Property.CELLMD:
76
+ assert col.sa_cellmd_col is not None
77
+ return col.sa_cellmd_col
75
78
  if self.prop == self.Property.FILEURL:
76
79
  # the file url is stored as the column value
77
- return sql_elements.get(self._col_ref)
80
+ return sql_elements.get(self.col_ref)
78
81
  return None
79
82
 
83
+ @classmethod
84
+ def create_cellmd_exc(cls, exc: Exception) -> dict[str, str]:
85
+ """Create a cellmd value from an exception."""
86
+ return {'errortype': type(exc).__name__, 'errormsg': str(exc)}
87
+
80
88
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
81
89
  if self.prop == self.Property.FILEURL:
82
- assert data_row.has_val[self._col_ref.slot_idx]
83
- data_row[self.slot_idx] = data_row.file_urls[self._col_ref.slot_idx]
90
+ assert data_row.has_val[self.col_ref.slot_idx]
91
+ data_row[self.slot_idx] = data_row.file_urls[self.col_ref.slot_idx]
84
92
  return
85
93
  elif self.prop == self.Property.LOCALPATH:
86
- assert data_row.has_val[self._col_ref.slot_idx]
87
- data_row[self.slot_idx] = data_row.file_paths[self._col_ref.slot_idx]
94
+ assert data_row.has_val[self.col_ref.slot_idx]
95
+ data_row[self.slot_idx] = data_row.file_paths[self.col_ref.slot_idx]
88
96
  return
89
- elif self.is_error_prop():
90
- exc = data_row.get_exc(self._col_ref.slot_idx)
97
+ elif self.is_cellmd_prop():
98
+ exc = data_row.get_exc(self.col_ref.slot_idx)
91
99
  if exc is None:
92
100
  data_row[self.slot_idx] = None
93
101
  elif self.prop == self.Property.ERRORTYPE:
94
102
  data_row[self.slot_idx] = type(exc).__name__
95
- else:
103
+ elif self.prop == self.Property.ERRORMSG:
96
104
  data_row[self.slot_idx] = str(exc)
105
+ elif self.prop == self.Property.CELLMD:
106
+ data_row[self.slot_idx] = self.create_cellmd_exc(exc)
107
+ else:
108
+ raise AssertionError(f'Unknown property {self.prop}')
109
+ return
97
110
  else:
98
111
  raise AssertionError()
99
112