pixeltable 0.3.7__tar.gz → 0.3.8__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 (173) hide show
  1. {pixeltable-0.3.7 → pixeltable-0.3.8}/PKG-INFO +1 -1
  2. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/__version__.py +2 -2
  3. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/column.py +1 -0
  4. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/table_version.py +4 -0
  5. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/__init__.py +2 -0
  6. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/arithmetic_expr.py +7 -11
  7. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/array_slice.py +1 -1
  8. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/column_property_ref.py +3 -3
  9. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/column_ref.py +3 -4
  10. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/comparison.py +2 -5
  11. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/compound_predicate.py +4 -4
  12. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/expr.py +11 -17
  13. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/expr_dict.py +3 -3
  14. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/expr_set.py +1 -1
  15. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/function_call.py +27 -37
  16. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/globals.py +3 -3
  17. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/in_predicate.py +1 -1
  18. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/inline_expr.py +3 -3
  19. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/is_null.py +1 -1
  20. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/json_mapper.py +2 -2
  21. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/json_path.py +17 -10
  22. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/literal.py +1 -1
  23. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/method_ref.py +2 -2
  24. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/row_builder.py +3 -5
  25. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/rowid_ref.py +4 -7
  26. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/similarity_expr.py +5 -5
  27. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/sql_element_cache.py +1 -1
  28. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/type_cast.py +2 -3
  29. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/variable.py +2 -2
  30. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/ext/__init__.py +2 -0
  31. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/ext/functions/__init__.py +2 -0
  32. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/ext/functions/yolox.py +3 -3
  33. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/__init__.py +2 -0
  34. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/aggregate_function.py +9 -9
  35. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/callable_function.py +3 -4
  36. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/expr_template_function.py +6 -16
  37. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/function.py +10 -8
  38. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/function_registry.py +1 -3
  39. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/query_template_function.py +2 -6
  40. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/signature.py +23 -22
  41. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/tools.py +3 -3
  42. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/udf.py +5 -3
  43. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/share/__init__.py +2 -0
  44. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/share/packager.py +3 -3
  45. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/share/publish.py +3 -5
  46. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/coco.py +4 -4
  47. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/console_output.py +1 -3
  48. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/description_helper.py +1 -1
  49. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/documents.py +3 -3
  50. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/filecache.py +18 -8
  51. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/formatter.py +2 -3
  52. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/media_store.py +1 -1
  53. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/pytorch.py +1 -1
  54. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/sql.py +4 -4
  55. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/transactional_directory.py +2 -1
  56. {pixeltable-0.3.7 → pixeltable-0.3.8}/pyproject.toml +5 -4
  57. {pixeltable-0.3.7 → pixeltable-0.3.8}/LICENSE +0 -0
  58. {pixeltable-0.3.7 → pixeltable-0.3.8}/README.md +0 -0
  59. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/__init__.py +0 -0
  60. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/__init__.py +0 -0
  61. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/catalog.py +0 -0
  62. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/dir.py +0 -0
  63. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/globals.py +0 -0
  64. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/insertable_table.py +0 -0
  65. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/named_function.py +0 -0
  66. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/path.py +0 -0
  67. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/path_dict.py +0 -0
  68. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/schema_object.py +0 -0
  69. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/table.py +0 -0
  70. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/table_version_handle.py +0 -0
  71. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/table_version_path.py +0 -0
  72. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/catalog/view.py +0 -0
  73. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/config.py +0 -0
  74. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/dataframe.py +0 -0
  75. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/env.py +0 -0
  76. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exceptions.py +0 -0
  77. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/__init__.py +0 -0
  78. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/aggregation_node.py +0 -0
  79. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/cache_prefetch_node.py +0 -0
  80. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/component_iteration_node.py +0 -0
  81. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/data_row_batch.py +0 -0
  82. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/exec_context.py +0 -0
  83. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/exec_node.py +0 -0
  84. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/__init__.py +0 -0
  85. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/evaluators.py +0 -0
  86. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/expr_eval_node.py +0 -0
  87. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/globals.py +0 -0
  88. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/row_buffer.py +0 -0
  89. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/expr_eval/schedulers.py +0 -0
  90. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/in_memory_data_node.py +0 -0
  91. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/row_update_node.py +0 -0
  92. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exec/sql_node.py +0 -0
  93. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/data_row.py +0 -0
  94. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/exprs/object_ref.py +0 -0
  95. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/ext/functions/whisperx.py +0 -0
  96. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/func/globals.py +0 -0
  97. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/__init__.py +0 -0
  98. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/anthropic.py +0 -0
  99. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/audio.py +0 -0
  100. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/deepseek.py +0 -0
  101. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/fireworks.py +0 -0
  102. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/gemini.py +0 -0
  103. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/globals.py +0 -0
  104. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/huggingface.py +0 -0
  105. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/image.py +0 -0
  106. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/json.py +0 -0
  107. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/llama_cpp.py +0 -0
  108. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/math.py +0 -0
  109. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/mistralai.py +0 -0
  110. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/ollama.py +0 -0
  111. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/openai.py +0 -0
  112. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/replicate.py +0 -0
  113. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/string.py +0 -0
  114. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/timestamp.py +0 -0
  115. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/together.py +0 -0
  116. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/util.py +0 -0
  117. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/video.py +0 -0
  118. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/vision.py +0 -0
  119. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/functions/whisper.py +0 -0
  120. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/globals.py +0 -0
  121. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/index/__init__.py +0 -0
  122. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/index/base.py +0 -0
  123. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/index/btree.py +0 -0
  124. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/index/embedding_index.py +0 -0
  125. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/__init__.py +0 -0
  126. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/external_store.py +0 -0
  127. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/fiftyone.py +0 -0
  128. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/globals.py +0 -0
  129. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/hf_datasets.py +0 -0
  130. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/label_studio.py +0 -0
  131. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/pandas.py +0 -0
  132. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/parquet.py +0 -0
  133. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/io/utils.py +0 -0
  134. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/__init__.py +0 -0
  135. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/audio.py +0 -0
  136. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/base.py +0 -0
  137. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/document.py +0 -0
  138. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/image.py +0 -0
  139. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/string.py +0 -0
  140. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/iterators/video.py +0 -0
  141. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/__init__.py +0 -0
  142. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_10.py +0 -0
  143. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_12.py +0 -0
  144. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_13.py +0 -0
  145. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_14.py +0 -0
  146. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_15.py +0 -0
  147. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_16.py +0 -0
  148. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_17.py +0 -0
  149. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_18.py +0 -0
  150. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_19.py +0 -0
  151. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_20.py +0 -0
  152. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_21.py +0 -0
  153. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_22.py +0 -0
  154. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_23.py +0 -0
  155. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_24.py +0 -0
  156. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_25.py +0 -0
  157. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_26.py +0 -0
  158. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_27.py +0 -0
  159. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_28.py +0 -0
  160. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/convert_29.py +0 -0
  161. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/converters/util.py +0 -0
  162. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/notes.py +0 -0
  163. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/metadata/schema.py +0 -0
  164. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/plan.py +0 -0
  165. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/py.typed +0 -0
  166. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/store.py +0 -0
  167. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/type_system.py +0 -0
  168. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/__init__.py +0 -0
  169. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/arrow.py +0 -0
  170. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/code.py +0 -0
  171. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/http_server.py +0 -0
  172. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/iceberg.py +0 -0
  173. {pixeltable-0.3.7 → pixeltable-0.3.8}/pixeltable/utils/s3.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pixeltable
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Summary: AI Data Infrastructure: Declarative, Multimodal, and Incremental
5
5
  License: Apache-2.0
6
6
  Keywords: data-science,machine-learning,database,ai,computer-vision,chatbot,ml,artificial-intelligence,feature-engineering,multimodal,mlops,feature-store,vector-database,llm,genai
@@ -1,3 +1,3 @@
1
1
  # These version placeholders will be replaced during build.
2
- __version__ = '0.3.7'
3
- __version_tuple__ = (0, 3, 7)
2
+ __version__ = '0.3.8'
3
+ __version_tuple__ = (0, 3, 8)
@@ -132,6 +132,7 @@ class Column:
132
132
  from pixeltable import exprs
133
133
 
134
134
  self._value_expr = exprs.Expr.from_dict(self.value_expr_dict)
135
+ self._value_expr.bind_rel_paths()
135
136
  if not self._value_expr.is_valid:
136
137
  message = (
137
138
  dedent(
@@ -177,6 +177,10 @@ class TableVersion:
177
177
  # Init external stores (this needs to happen after the schema is created)
178
178
  self._init_external_stores(tbl_md)
179
179
 
180
+ # Force column metadata to load, in order to surface any invalid metadata now (as warnings)
181
+ for col in self.cols_by_id.values():
182
+ _ = col.value_expr
183
+
180
184
  def __hash__(self) -> int:
181
185
  return hash(self.id)
182
186
 
@@ -1,3 +1,5 @@
1
+ # ruff: noqa: F401
2
+
1
3
  from .arithmetic_expr import ArithmeticExpr
2
4
  from .array_slice import ArraySlice
3
5
  from .column_property_ref import ColumnPropertyRef
@@ -1,12 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Optional, Union
3
+ from typing import Any, Optional
4
4
 
5
5
  import sqlalchemy as sql
6
6
 
7
- import pixeltable.exceptions as excs
8
- import pixeltable.exprs as exprs
9
- import pixeltable.type_system as ts
7
+ from pixeltable import exceptions as excs, type_system as ts
10
8
 
11
9
  from .data_row import DataRow
12
10
  from .expr import Expr
@@ -50,13 +48,13 @@ class ArithmeticExpr(Expr):
50
48
  # add parentheses around operands that are ArithmeticExprs to express precedence
51
49
  op1_str = f'({self._op1})' if isinstance(self._op1, ArithmeticExpr) else str(self._op1)
52
50
  op2_str = f'({self._op2})' if isinstance(self._op2, ArithmeticExpr) else str(self._op2)
53
- return f'{op1_str} {str(self.operator)} {op2_str}'
51
+ return f'{op1_str} {self.operator} {op2_str}'
54
52
 
55
53
  def _equals(self, other: ArithmeticExpr) -> bool:
56
54
  return self.operator == other.operator
57
55
 
58
56
  def _id_attrs(self) -> list[tuple[str, Any]]:
59
- return super()._id_attrs() + [('operator', self.operator.value)]
57
+ return [*super()._id_attrs(), ('operator', self.operator.value)]
60
58
 
61
59
  def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
62
60
  assert self.col_type.is_int_type() or self.col_type.is_float_type() or self.col_type.is_json_type()
@@ -95,7 +93,7 @@ class ArithmeticExpr(Expr):
95
93
  return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
96
94
  if self.col_type.is_float_type():
97
95
  return sql.sql.expression.cast(sql.func.floor(left / nullif), self.col_type.to_sa_type())
98
- assert False
96
+ raise AssertionError()
99
97
 
100
98
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
101
99
  op1_val = data_row[self._op1.slot_idx]
@@ -113,9 +111,7 @@ class ArithmeticExpr(Expr):
113
111
 
114
112
  data_row[self.slot_idx] = self.eval_nullable(op1_val, op2_val)
115
113
 
116
- def eval_nullable(
117
- self, op1_val: Union[int, float, None], op2_val: Union[int, float, None]
118
- ) -> Union[int, float, None]:
114
+ def eval_nullable(self, op1_val: Optional[float], op2_val: Optional[float]) -> Optional[float]:
119
115
  """
120
116
  Return the result of evaluating the expression on two nullable int/float operands,
121
117
  None is interpreted as SQL NULL
@@ -124,7 +120,7 @@ class ArithmeticExpr(Expr):
124
120
  return None
125
121
  return self.eval_non_null(op1_val, op2_val)
126
122
 
127
- def eval_non_null(self, op1_val: Union[int, float], op2_val: Union[int, float]) -> Union[int, float]:
123
+ def eval_non_null(self, op1_val: float, op2_val: float) -> float:
128
124
  """
129
125
  Return the result of evaluating the expression on two int/float operands
130
126
  """
@@ -41,7 +41,7 @@ class ArraySlice(Expr):
41
41
  return self.index == other.index
42
42
 
43
43
  def _id_attrs(self) -> list[tuple[str, Any]]:
44
- return super()._id_attrs() + [('index', self.index)]
44
+ return [*super()._id_attrs(), ('index', self.index)]
45
45
 
46
46
  def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
47
47
  return None
@@ -40,7 +40,7 @@ class ColumnPropertyRef(Expr):
40
40
  return self.prop == other.prop
41
41
 
42
42
  def _id_attrs(self) -> list[tuple[str, Any]]:
43
- return super()._id_attrs() + [('prop', self.prop.value)]
43
+ return [*super()._id_attrs(), ('prop', self.prop.value)]
44
44
 
45
45
  @property
46
46
  def _col_ref(self) -> ColumnRef:
@@ -52,7 +52,7 @@ class ColumnPropertyRef(Expr):
52
52
  return f'{self._col_ref}.{self.prop.name.lower()}'
53
53
 
54
54
  def is_error_prop(self) -> bool:
55
- return self.prop == self.Property.ERRORTYPE or self.prop == self.Property.ERRORMSG
55
+ return self.prop in {self.Property.ERRORTYPE, self.Property.ERRORMSG}
56
56
 
57
57
  def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
58
58
  if not self._col_ref.col.is_stored:
@@ -95,7 +95,7 @@ class ColumnPropertyRef(Expr):
95
95
  else:
96
96
  data_row[self.slot_idx] = str(exc)
97
97
  else:
98
- assert False
98
+ raise AssertionError()
99
99
 
100
100
  def _as_dict(self) -> dict:
101
101
  return {'prop': self.prop.value, **super()._as_dict()}
@@ -6,9 +6,7 @@ from uuid import UUID
6
6
  import sqlalchemy as sql
7
7
 
8
8
  import pixeltable as pxt
9
- import pixeltable.catalog as catalog
10
- import pixeltable.exceptions as excs
11
- import pixeltable.iterators as iters
9
+ from pixeltable import catalog, exceptions as excs, iterators as iters
12
10
 
13
11
  from ..utils.description_helper import DescriptionHelper
14
12
  from .data_row import DataRow
@@ -84,7 +82,8 @@ class ColumnRef(Expr):
84
82
  assert len(self.iter_arg_ctx.target_slot_idxs) == 1 # a single inline dict
85
83
 
86
84
  def _id_attrs(self) -> list[tuple[str, Any]]:
87
- return super()._id_attrs() + [
85
+ return [
86
+ *super()._id_attrs(),
88
87
  ('tbl_id', self.col.tbl.id),
89
88
  ('col_id', self.col.id),
90
89
  ('perform_validation', self.perform_validation),
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional
3
+ from typing import Any, Optional
4
4
 
5
5
  import sqlalchemy as sql
6
6
 
@@ -15,9 +15,6 @@ from .literal import Literal
15
15
  from .row_builder import RowBuilder
16
16
  from .sql_element_cache import SqlElementCache
17
17
 
18
- if TYPE_CHECKING:
19
- from pixeltable import index
20
-
21
18
 
22
19
  class Comparison(Expr):
23
20
  is_search_arg_comparison: bool
@@ -62,7 +59,7 @@ class Comparison(Expr):
62
59
  return self.operator == other.operator
63
60
 
64
61
  def _id_attrs(self) -> list[tuple[str, Any]]:
65
- return super()._id_attrs() + [('operator', self.operator.value)]
62
+ return [*super()._id_attrs(), ('operator', self.operator.value)]
66
63
 
67
64
  @property
68
65
  def _op1(self) -> Expr:
@@ -5,7 +5,7 @@ from typing import Any, Callable, Optional
5
5
 
6
6
  import sqlalchemy as sql
7
7
 
8
- import pixeltable.type_system as ts
8
+ from pixeltable import type_system as ts
9
9
 
10
10
  from .data_row import DataRow
11
11
  from .expr import Expr
@@ -58,10 +58,10 @@ class CompoundPredicate(Expr):
58
58
  return self.operator == other.operator
59
59
 
60
60
  def _id_attrs(self) -> list[tuple[str, Any]]:
61
- return super()._id_attrs() + [('operator', self.operator.value)]
61
+ return [*super()._id_attrs(), ('operator', self.operator.value)]
62
62
 
63
63
  def split_conjuncts(self, condition: Callable[[Expr], bool]) -> tuple[list[Expr], Optional[Expr]]:
64
- if self.operator == LogicalOperator.OR or self.operator == LogicalOperator.NOT:
64
+ if self.operator in {LogicalOperator.OR, LogicalOperator.NOT}:
65
65
  return super().split_conjuncts(condition)
66
66
  matches = [op for op in self.components if condition(op)]
67
67
  non_matches = [op for op in self.components if not condition(op)]
@@ -83,7 +83,7 @@ class CompoundPredicate(Expr):
83
83
  if self.operator == LogicalOperator.NOT:
84
84
  data_row[self.slot_idx] = not data_row[self.components[0].slot_idx]
85
85
  else:
86
- val = True if self.operator == LogicalOperator.AND else False
86
+ val = self.operator == LogicalOperator.AND
87
87
  op_function = operator.and_ if self.operator == LogicalOperator.AND else operator.or_
88
88
  for op in self.components:
89
89
  val = op_function(val, data_row[op.slot_idx])
@@ -129,7 +129,7 @@ class Expr(abc.ABC):
129
129
  """
130
130
  Subclass-specific comparison. Implemented as a function because __eq__() is needed to construct Comparisons.
131
131
  """
132
- if type(self) != type(other):
132
+ if type(self) is not type(other):
133
133
  return False
134
134
  if len(self.components) != len(other.components):
135
135
  return False
@@ -171,10 +171,7 @@ class Expr(abc.ABC):
171
171
  def list_equals(cls, a: list[Expr], b: list[Expr]) -> bool:
172
172
  if len(a) != len(b):
173
173
  return False
174
- for i in range(len(a)):
175
- if not a[i].equals(b[i]):
176
- return False
177
- return True
174
+ return all(a[i].equals(b[i]) for i in range(len(a)))
178
175
 
179
176
  def copy(self) -> Expr:
180
177
  """
@@ -216,9 +213,9 @@ class Expr(abc.ABC):
216
213
  return new.copy()
217
214
  for i in range(len(self.components)):
218
215
  self.components[i] = self.components[i].substitute(spec)
219
- self = self.maybe_literal()
220
- self.id = self._create_id()
221
- return self
216
+ result = self.maybe_literal()
217
+ result.id = result._create_id()
218
+ return result
222
219
 
223
220
  @classmethod
224
221
  def list_substitute(cls, expr_list: list[Expr], spec: dict[Expr, Expr]) -> None:
@@ -253,10 +250,7 @@ class Expr(abc.ABC):
253
250
  from .column_ref import ColumnRef
254
251
 
255
252
  col_refs = self.subexprs(ColumnRef)
256
- for col_ref in col_refs:
257
- if not any(tbl.has_column(col_ref.col) for tbl in tbls):
258
- return False
259
- return True
253
+ return all(any(tbl.has_column(col_ref.col) for tbl in tbls) for col_ref in col_refs)
260
254
 
261
255
  def retarget(self, tbl: catalog.TableVersionPath) -> Self:
262
256
  """Retarget ColumnRefs in this expr to the specific TableVersions in tbl."""
@@ -370,7 +364,7 @@ class Expr(abc.ABC):
370
364
 
371
365
  @classmethod
372
366
  def all_tbl_ids(cls, exprs_: Iterable[Expr]) -> set[UUID]:
373
- return set(tbl_id for e in exprs_ for tbl_id in e.tbl_ids())
367
+ return {tbl_id for e in exprs_ for tbl_id in e.tbl_ids()}
374
368
 
375
369
  @classmethod
376
370
  def get_refd_columns(cls, expr_dict: dict[str, Any]) -> list[catalog.Column]:
@@ -489,7 +483,7 @@ class Expr(abc.ABC):
489
483
  return {'_classname': self.__class__.__name__, **self._as_dict()}
490
484
 
491
485
  @classmethod
492
- def as_dict_list(self, expr_list: list[Expr]) -> list[dict]:
486
+ def as_dict_list(cls, expr_list: list[Expr]) -> list[dict]:
493
487
  return [e.as_dict() for e in expr_list]
494
488
 
495
489
  def _as_dict(self) -> dict:
@@ -520,7 +514,7 @@ class Expr(abc.ABC):
520
514
 
521
515
  @classmethod
522
516
  def _from_dict(cls, d: dict, components: list[Expr]) -> Self:
523
- assert False, 'not implemented'
517
+ raise AssertionError('not implemented')
524
518
 
525
519
  def isin(self, value_set: Any) -> 'exprs.InPredicate':
526
520
  from .in_predicate import InPredicate
@@ -792,13 +786,13 @@ class Expr(abc.ABC):
792
786
  first_param = next(params_iter) if len(params) >= 1 else None
793
787
  second_param = next(params_iter) if len(params) >= 2 else None
794
788
  # Check that fn has at least one positional parameter
795
- if len(params) == 0 or first_param.kind in (inspect.Parameter.KEYWORD_ONLY, inspect.Parameter.VAR_KEYWORD):
789
+ if len(params) == 0 or first_param.kind in {inspect.Parameter.KEYWORD_ONLY, inspect.Parameter.VAR_KEYWORD}:
796
790
  raise excs.Error(f'Function `{fn.__name__}` has no positional parameters.')
797
791
  # Check that fn has at most one required parameter, i.e., its second parameter
798
792
  # has no default and is not a varargs
799
793
  if (
800
794
  len(params) >= 2
801
- and second_param.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
795
+ and second_param.kind not in {inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD}
802
796
  and second_param.default is inspect.Parameter.empty
803
797
  ):
804
798
  raise excs.Error(f'Function `{fn.__name__}` has multiple required parameters.')
@@ -1,9 +1,9 @@
1
1
  from typing import Generic, Iterable, Iterator, Optional, TypeVar
2
2
 
3
- T = TypeVar('T')
4
-
5
3
  from .expr import Expr
6
4
 
5
+ T = TypeVar('T')
6
+
7
7
 
8
8
  class ExprDict(Generic[T]):
9
9
  """
@@ -47,7 +47,7 @@ class ExprDict(Generic[T]):
47
47
  self._data.clear()
48
48
 
49
49
  def keys(self) -> Iterator[Expr]:
50
- return self.__iter__()
50
+ return iter(self)
51
51
 
52
52
  def values(self) -> Iterator[T]:
53
53
  return (value for _, value in self._data.values())
@@ -46,7 +46,7 @@ class ExprSet(Generic[T]):
46
46
 
47
47
  def __getitem__(self, index: object) -> Optional[T]:
48
48
  """Indexed lookup by slot_idx or Expr.id."""
49
- assert isinstance(index, int) or isinstance(index, Expr)
49
+ assert isinstance(index, (int, Expr))
50
50
  if isinstance(index, int):
51
51
  # return expr with matching slot_idx
52
52
  return self.exprs_by_idx.get(index)
@@ -3,16 +3,12 @@ from __future__ import annotations
3
3
  import inspect
4
4
  import logging
5
5
  import sys
6
- import warnings
7
6
  from textwrap import dedent
8
7
  from typing import Any, Optional, Sequence, Union
9
8
 
10
9
  import sqlalchemy as sql
11
10
 
12
- import pixeltable.catalog as catalog
13
- import pixeltable.exceptions as excs
14
- import pixeltable.func as func
15
- import pixeltable.type_system as ts
11
+ from pixeltable import catalog, exceptions as excs, func, type_system as ts
16
12
 
17
13
  from .data_row import DataRow
18
14
  from .expr import Expr
@@ -156,22 +152,18 @@ class FunctionCall(Expr):
156
152
  return self.fn.name
157
153
 
158
154
  def _equals(self, other: FunctionCall) -> bool:
159
- if self.fn != other.fn:
160
- return False
161
- if self.arg_idxs != other.arg_idxs:
162
- return False
163
- if self.kwarg_idxs != other.kwarg_idxs:
164
- return False
165
- if self.group_by_start_idx != other.group_by_start_idx:
166
- return False
167
- if self.group_by_stop_idx != other.group_by_stop_idx:
168
- return False
169
- if self.order_by_start_idx != other.order_by_start_idx:
170
- return False
171
- return True
155
+ return (
156
+ self.fn == other.fn
157
+ and self.arg_idxs == other.arg_idxs
158
+ and self.kwarg_idxs == other.kwarg_idxs
159
+ and self.group_by_start_idx == other.group_by_start_idx
160
+ and self.group_by_stop_idx == other.group_by_stop_idx
161
+ and self.order_by_start_idx == other.order_by_start_idx
162
+ )
172
163
 
173
164
  def _id_attrs(self) -> list[tuple[str, Any]]:
174
- return super()._id_attrs() + [
165
+ return [
166
+ *super()._id_attrs(),
175
167
  ('fn', id(self.fn)), # use the function pointer, not the fqn, which isn't set for lambdas
176
168
  ('args', self.arg_idxs),
177
169
  ('kwargs', self.kwarg_idxs),
@@ -192,12 +184,12 @@ class FunctionCall(Expr):
192
184
  if self.is_method_call:
193
185
  return f'{self.components[0]}.{self.fn.name}({self._print_args(1, inline)})'
194
186
  else:
195
- fn_name = self.fn.display_name if self.fn.display_name != '' else 'anonymous_fn'
187
+ fn_name = self.fn.display_name or 'anonymous_fn'
196
188
  return f'{fn_name}({self._print_args()})'
197
189
 
198
190
  def _print_args(self, start_idx: int = 0, inline: bool = True) -> str:
199
191
  arg_strs = [str(self.components[idx]) for idx in self.arg_idxs[start_idx:]]
200
- arg_strs.extend([f'{param_name}={str(self.components[idx])}' for param_name, idx in self.kwarg_idxs.items()])
192
+ arg_strs.extend([f'{param_name}={self.components[idx]}' for param_name, idx in self.kwarg_idxs.items()])
201
193
  if len(self.order_by) > 0:
202
194
  assert isinstance(self.fn, func.AggregateFunction)
203
195
  if self.fn.requires_order_by:
@@ -297,7 +289,7 @@ class FunctionCall(Expr):
297
289
  if (
298
290
  val is None
299
291
  and parameters_by_pos[idx].kind
300
- in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
292
+ in {inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD}
301
293
  and not parameters_by_pos[idx].col_type.nullable
302
294
  ):
303
295
  return None
@@ -310,7 +302,7 @@ class FunctionCall(Expr):
310
302
  if (
311
303
  val is None
312
304
  and parameters[param_name].kind
313
- in (inspect.Parameter.KEYWORD_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
305
+ in {inspect.Parameter.KEYWORD_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD}
314
306
  and not parameters[param_name].col_type.nullable
315
307
  ):
316
308
  return None
@@ -466,20 +458,18 @@ class FunctionCall(Expr):
466
458
  # the call_return_type that we just inferred (which matches the deserialization behavior prior to
467
459
  # version 25).
468
460
  return_type = call_return_type
469
- else:
470
- # There is a return_type stored in metadata (schema version >= 25).
471
- # Check that the stored return_type of the UDF call matches the column type of the FunctionCall, and
472
- # fail-fast if it doesn't (otherwise we risk getting downstream database errors).
473
- if not return_type.is_supertype_of(call_return_type, ignore_nullable=True):
474
- validation_error = dedent(
475
- f"""
476
- The return type stored in the database for a UDF call to {fn.self_path!r} no longer
477
- matches its return type as currently defined in the code. This probably means that the
478
- code for {fn.self_path!r} has changed in a backward-incompatible way.
479
- Return type of UDF call in the database: {return_type}
480
- Return type of UDF as currently defined in code: {call_return_type}
481
- """
482
- ).strip()
461
+ elif not return_type.is_supertype_of(call_return_type, ignore_nullable=True):
462
+ # There is a return_type stored in metadata (schema version >= 25),
463
+ # and the stored return_type of the UDF call doesn't match the column type of the FunctionCall.
464
+ validation_error = dedent(
465
+ f"""
466
+ The return type stored in the database for a UDF call to {fn.self_path!r} no longer
467
+ matches its return type as currently defined in the code. This probably means that the
468
+ code for {fn.self_path!r} has changed in a backward-incompatible way.
469
+ Return type of UDF call in the database: {return_type}
470
+ Return type of UDF as currently defined in code: {call_return_type}
471
+ """
472
+ ).strip()
483
473
 
484
474
  fn_call = cls(
485
475
  resolved_fn,
@@ -36,7 +36,7 @@ class ComparisonOperator(enum.Enum):
36
36
  return '>'
37
37
  if self == self.GE:
38
38
  return '>='
39
- assert False
39
+ raise AssertionError()
40
40
 
41
41
  def reverse(self) -> ComparisonOperator:
42
42
  if self == self.LT:
@@ -62,7 +62,7 @@ class LogicalOperator(enum.Enum):
62
62
  return '|'
63
63
  if self == self.NOT:
64
64
  return '~'
65
- assert False
65
+ raise AssertionError()
66
66
 
67
67
 
68
68
  class ArithmeticOperator(enum.Enum):
@@ -86,4 +86,4 @@ class ArithmeticOperator(enum.Enum):
86
86
  return '%'
87
87
  if self == self.FLOORDIV:
88
88
  return '//'
89
- assert False
89
+ raise AssertionError()
@@ -71,7 +71,7 @@ class InPredicate(Expr):
71
71
  return self.value_list == other.value_list
72
72
 
73
73
  def _id_attrs(self) -> list[tuple[str, Any]]:
74
- return super()._id_attrs() + [('value_list', self.value_list)]
74
+ return [*super()._id_attrs(), ('value_list', self.value_list)]
75
75
 
76
76
  def sql_expr(self, sql_elements: SqlElementCache) -> Optional[sql.ColumnElement]:
77
77
  lhs_sql_exprs = sql_elements.get(self.components[0])
@@ -131,7 +131,7 @@ class InlineList(Expr):
131
131
  def as_literal(self) -> Optional[Literal]:
132
132
  if not all(isinstance(comp, Literal) for comp in self.components):
133
133
  return None
134
- return Literal(list(c.as_literal().val for c in self.components), self.col_type)
134
+ return Literal([c.as_literal().val for c in self.components], self.col_type)
135
135
 
136
136
 
137
137
  class InlineDict(Expr):
@@ -166,7 +166,7 @@ class InlineDict(Expr):
166
166
  self.id = self._create_id()
167
167
 
168
168
  def __repr__(self) -> str:
169
- item_strs = list(f"'{key}': {str(expr)}" for key, expr in zip(self.keys, self.components))
169
+ item_strs = [f"'{key}': {expr}" for key, expr in zip(self.keys, self.components)]
170
170
  return '{' + ', '.join(item_strs) + '}'
171
171
 
172
172
  def _equals(self, other: InlineDict) -> bool:
@@ -174,7 +174,7 @@ class InlineDict(Expr):
174
174
  return self.keys == other.keys
175
175
 
176
176
  def _id_attrs(self) -> list[tuple[str, Any]]:
177
- return super()._id_attrs() + [('keys', self.keys)]
177
+ return [*super()._id_attrs(), ('keys', self.keys)]
178
178
 
179
179
  def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
180
180
  return None
@@ -19,7 +19,7 @@ class IsNull(Expr):
19
19
  self.id = self._create_id()
20
20
 
21
21
  def __repr__(self) -> str:
22
- return f'{str(self.components[0])} == None'
22
+ return f'{self.components[0]} == None'
23
23
 
24
24
  def _equals(self, other: IsNull) -> bool:
25
25
  return True
@@ -81,12 +81,12 @@ class JsonMapper(Expr):
81
81
  """
82
82
  We override equals() because we need to avoid comparing our scope anchor.
83
83
  """
84
- if type(self) != type(other):
84
+ if type(self) is not type(other):
85
85
  return False
86
86
  return self._src_expr.equals(other._src_expr) and self._target_expr.equals(other._target_expr)
87
87
 
88
88
  def __repr__(self) -> str:
89
- return f'{str(self._src_expr)} >> {str(self._target_expr)}'
89
+ return f'{self._src_expr} >> {self._target_expr}'
90
90
 
91
91
  @property
92
92
  def _src_expr(self) -> Expr:
@@ -6,14 +6,13 @@ import jmespath
6
6
  import sqlalchemy as sql
7
7
 
8
8
  import pixeltable as pxt
9
- import pixeltable.catalog as catalog
10
- import pixeltable.exceptions as excs
11
- import pixeltable.type_system as ts
9
+ from pixeltable import catalog, exceptions as excs, type_system as ts
12
10
 
13
11
  from .data_row import DataRow
14
12
  from .expr import Expr
15
13
  from .globals import print_slice
16
14
  from .json_mapper import JsonMapper
15
+ from .object_ref import ObjectRef
17
16
  from .row_builder import RowBuilder
18
17
  from .sql_element_cache import SqlElementCache
19
18
 
@@ -50,8 +49,16 @@ class JsonPath(Expr):
50
49
  return f'{anchor_str}{"." if isinstance(self.path_elements[0], str) else ""}{self._json_path()}'
51
50
 
52
51
  def _as_dict(self) -> dict:
52
+ assert len(self.components) <= 1
53
+ components_dict: dict[str, Any]
54
+ if len(self.components) == 0 or isinstance(self.components[0], ObjectRef):
55
+ # If the anchor is an ObjectRef, it means this JsonPath is a bound relative path. We store it as a relative
56
+ # path, *not* a bound path (which has no meaning in the dict).
57
+ components_dict = {}
58
+ else:
59
+ components_dict = super()._as_dict()
53
60
  path_elements = [[el.start, el.stop, el.step] if isinstance(el, slice) else el for el in self.path_elements]
54
- return {'path_elements': path_elements, 'scope_idx': self.scope_idx, **super()._as_dict()}
61
+ return {'path_elements': path_elements, 'scope_idx': self.scope_idx, **components_dict}
55
62
 
56
63
  @classmethod
57
64
  def _from_dict(cls, d: dict, components: list[Expr]) -> JsonPath:
@@ -84,18 +91,18 @@ class JsonPath(Expr):
84
91
  Construct a relative path that references an ancestor of the immediately enclosing JsonMapper.
85
92
  """
86
93
  if not self.is_relative_path():
87
- raise excs.Error(f'() for an absolute path is invalid')
94
+ raise excs.Error('() for an absolute path is invalid')
88
95
  if len(args) != 1 or not isinstance(args[0], int) or args[0] >= 0:
89
- raise excs.Error(f'R() requires a negative index')
96
+ raise excs.Error('R() requires a negative index')
90
97
  return JsonPath(None, [], args[0])
91
98
 
92
99
  def __getattr__(self, name: str) -> 'JsonPath':
93
100
  assert isinstance(name, str)
94
- return JsonPath(self._anchor, self.path_elements + [name])
101
+ return JsonPath(self._anchor, [*self.path_elements, name])
95
102
 
96
103
  def __getitem__(self, index: object) -> 'JsonPath':
97
104
  if isinstance(index, (int, slice, str)):
98
- return JsonPath(self._anchor, self.path_elements + [index])
105
+ return JsonPath(self._anchor, [*self.path_elements, index])
99
106
  raise excs.Error(f'Invalid json list index: {index}')
100
107
 
101
108
  def __rshift__(self, other: object) -> 'JsonMapper':
@@ -120,7 +127,7 @@ class JsonPath(Expr):
120
127
 
121
128
  clean_name = ''.join(map(cleanup_char, ret_name))
122
129
  clean_name = clean_name.lstrip('_') # remove leading underscore
123
- if clean_name == '':
130
+ if not clean_name: # Replace '' with None
124
131
  clean_name = None
125
132
 
126
133
  assert clean_name is None or catalog.is_valid_identifier(clean_name)
@@ -130,7 +137,7 @@ class JsonPath(Expr):
130
137
  return self.path_elements == other.path_elements
131
138
 
132
139
  def _id_attrs(self) -> list[tuple[str, Any]]:
133
- return super()._id_attrs() + [('path_elements', self.path_elements)]
140
+ return [*super()._id_attrs(), ('path_elements', self.path_elements)]
134
141
 
135
142
  def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
136
143
  """
@@ -62,7 +62,7 @@ class Literal(Expr):
62
62
  return self.val == other.val
63
63
 
64
64
  def _id_attrs(self) -> list[tuple[str, Any]]:
65
- return super()._id_attrs() + [('val', self.val)]
65
+ return [*super()._id_attrs(), ('val', self.val)]
66
66
 
67
67
  def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
68
68
  # Return a sql object so that constants can participate in SQL expressions
@@ -53,13 +53,13 @@ class MethodRef(Expr):
53
53
  return self.base_expr.id == other.base_expr.id and self.method_name == other.method_name
54
54
 
55
55
  def _id_attrs(self) -> list[tuple[str, Any]]:
56
- return super()._id_attrs() + [('method_name', self.method_name)]
56
+ return [*super()._id_attrs(), ('method_name', self.method_name)]
57
57
 
58
58
  def sql_expr(self, _: SqlElementCache) -> Optional[sql.ColumnElement]:
59
59
  return None
60
60
 
61
61
  def eval(self, data_row: DataRow, row_builder: RowBuilder) -> None:
62
- assert False, 'MethodRef cannot be evaluated directly'
62
+ raise AssertionError('MethodRef cannot be evaluated directly')
63
63
 
64
64
  def __repr__(self) -> str:
65
65
  return f'{self.base_expr}.{self.method_name}'