pixeltable 0.3.7__py3-none-any.whl → 0.3.9__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 (68) hide show
  1. pixeltable/__version__.py +2 -2
  2. pixeltable/catalog/catalog.py +509 -103
  3. pixeltable/catalog/column.py +1 -0
  4. pixeltable/catalog/dir.py +15 -6
  5. pixeltable/catalog/path.py +15 -0
  6. pixeltable/catalog/schema_object.py +7 -12
  7. pixeltable/catalog/table.py +3 -12
  8. pixeltable/catalog/table_version.py +5 -0
  9. pixeltable/catalog/view.py +0 -4
  10. pixeltable/env.py +14 -8
  11. pixeltable/exprs/__init__.py +2 -0
  12. pixeltable/exprs/arithmetic_expr.py +7 -11
  13. pixeltable/exprs/array_slice.py +1 -1
  14. pixeltable/exprs/column_property_ref.py +3 -3
  15. pixeltable/exprs/column_ref.py +5 -6
  16. pixeltable/exprs/comparison.py +2 -5
  17. pixeltable/exprs/compound_predicate.py +4 -4
  18. pixeltable/exprs/expr.py +32 -19
  19. pixeltable/exprs/expr_dict.py +3 -3
  20. pixeltable/exprs/expr_set.py +1 -1
  21. pixeltable/exprs/function_call.py +28 -41
  22. pixeltable/exprs/globals.py +3 -3
  23. pixeltable/exprs/in_predicate.py +1 -1
  24. pixeltable/exprs/inline_expr.py +3 -3
  25. pixeltable/exprs/is_null.py +1 -1
  26. pixeltable/exprs/json_mapper.py +5 -5
  27. pixeltable/exprs/json_path.py +27 -15
  28. pixeltable/exprs/literal.py +1 -1
  29. pixeltable/exprs/method_ref.py +2 -2
  30. pixeltable/exprs/row_builder.py +3 -5
  31. pixeltable/exprs/rowid_ref.py +4 -7
  32. pixeltable/exprs/similarity_expr.py +5 -5
  33. pixeltable/exprs/sql_element_cache.py +1 -1
  34. pixeltable/exprs/type_cast.py +2 -3
  35. pixeltable/exprs/variable.py +2 -2
  36. pixeltable/ext/__init__.py +2 -0
  37. pixeltable/ext/functions/__init__.py +2 -0
  38. pixeltable/ext/functions/yolox.py +3 -3
  39. pixeltable/func/__init__.py +2 -0
  40. pixeltable/func/aggregate_function.py +9 -9
  41. pixeltable/func/callable_function.py +7 -5
  42. pixeltable/func/expr_template_function.py +6 -16
  43. pixeltable/func/function.py +10 -8
  44. pixeltable/func/function_registry.py +1 -3
  45. pixeltable/func/query_template_function.py +8 -24
  46. pixeltable/func/signature.py +23 -22
  47. pixeltable/func/tools.py +3 -3
  48. pixeltable/func/udf.py +5 -3
  49. pixeltable/globals.py +118 -260
  50. pixeltable/share/__init__.py +2 -0
  51. pixeltable/share/packager.py +3 -3
  52. pixeltable/share/publish.py +3 -5
  53. pixeltable/utils/coco.py +4 -4
  54. pixeltable/utils/console_output.py +1 -3
  55. pixeltable/utils/coroutine.py +41 -0
  56. pixeltable/utils/description_helper.py +1 -1
  57. pixeltable/utils/documents.py +3 -3
  58. pixeltable/utils/filecache.py +18 -8
  59. pixeltable/utils/formatter.py +2 -3
  60. pixeltable/utils/media_store.py +1 -1
  61. pixeltable/utils/pytorch.py +1 -1
  62. pixeltable/utils/sql.py +4 -4
  63. pixeltable/utils/transactional_directory.py +2 -1
  64. {pixeltable-0.3.7.dist-info → pixeltable-0.3.9.dist-info}/METADATA +1 -1
  65. {pixeltable-0.3.7.dist-info → pixeltable-0.3.9.dist-info}/RECORD +68 -67
  66. {pixeltable-0.3.7.dist-info → pixeltable-0.3.9.dist-info}/LICENSE +0 -0
  67. {pixeltable-0.3.7.dist-info → pixeltable-0.3.9.dist-info}/WHEEL +0 -0
  68. {pixeltable-0.3.7.dist-info → pixeltable-0.3.9.dist-info}/entry_points.txt +0 -0
@@ -1,8 +1,6 @@
1
- import inspect
2
1
  from typing import Any, Optional, Sequence
3
2
 
4
- import pixeltable
5
- import pixeltable.exceptions as excs
3
+ from pixeltable import exceptions as excs, exprs
6
4
 
7
5
  from .function import Function
8
6
  from .signature import Signature
@@ -15,13 +13,11 @@ class ExprTemplate:
15
13
  `CallableFunction`.)
16
14
  """
17
15
 
18
- expr: 'pixeltable.exprs.Expr'
16
+ expr: 'exprs.Expr'
19
17
  signature: Signature
20
- param_exprs: dict[str, 'pixeltable.exprs.Variable']
21
-
22
- def __init__(self, expr: 'pixeltable.exprs.Expr', signature: Signature):
23
- from pixeltable import exprs
18
+ param_exprs: dict[str, 'exprs.Variable']
24
19
 
20
+ def __init__(self, expr: 'exprs.Expr', signature: Signature):
25
21
  self.expr = expr
26
22
  self.signature = signature
27
23
 
@@ -59,9 +55,7 @@ class ExprTemplateFunction(Function):
59
55
  assert not self.is_polymorphic
60
56
  return self.templates[0]
61
57
 
62
- def instantiate(self, args: Sequence[Any], kwargs: dict[str, Any]) -> 'pixeltable.exprs.Expr':
63
- from pixeltable import exprs
64
-
58
+ def instantiate(self, args: Sequence[Any], kwargs: dict[str, Any]) -> 'exprs.Expr':
65
59
  assert not self.is_polymorphic
66
60
  template = self.template
67
61
  bound_args = self.signature.py_signature.bind(*args, **kwargs).arguments
@@ -86,14 +80,12 @@ class ExprTemplateFunction(Function):
86
80
  return result
87
81
 
88
82
  def _docstring(self) -> Optional[str]:
89
- from pixeltable import exprs
90
-
91
83
  if isinstance(self.templates[0].expr, exprs.FunctionCall):
92
84
  return self.templates[0].expr.fn._docstring()
93
85
  return None
94
86
 
95
87
  def exec(self, args: Sequence[Any], kwargs: dict[str, Any]) -> Any:
96
- from pixeltable import exec, exprs
88
+ from pixeltable import exec
97
89
 
98
90
  assert not self.is_polymorphic
99
91
  expr = self.instantiate(args, kwargs)
@@ -130,7 +122,5 @@ class ExprTemplateFunction(Function):
130
122
  if 'expr' not in d:
131
123
  return super()._from_dict(d)
132
124
  assert 'signature' in d and 'name' in d
133
- import pixeltable.exprs as exprs
134
-
135
125
  template = ExprTemplate(exprs.Expr.from_dict(d['expr']), Signature.from_dict(d['signature']))
136
126
  return cls([template], name=d['name'])
@@ -246,7 +246,7 @@ class Function(ABC):
246
246
  # `None` when any of its non-nullable inputs are `None`.
247
247
  for arg_name, arg in bound_args.items():
248
248
  param = self.signature.parameters[arg_name]
249
- if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
249
+ if param.kind in {inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD}:
250
250
  continue
251
251
  if arg.col_type.nullable and not param.col_type.nullable:
252
252
  return_type = return_type.copy(nullable=True)
@@ -304,13 +304,12 @@ class Function(ABC):
304
304
  callable_args[param.name] = arg
305
305
  else:
306
306
  return None
307
- else:
307
+ elif isinstance(arg, exprs.Literal):
308
308
  # The callable is expecting `param.name` to be a constant Python value. Unpack a Literal if we find
309
309
  # one; otherwise return None.
310
- if isinstance(arg, exprs.Literal):
311
- callable_args[param.name] = arg.val
312
- else:
313
- return None
310
+ callable_args[param.name] = arg.val
311
+ else:
312
+ return None
314
313
 
315
314
  return callable_args
316
315
 
@@ -386,10 +385,10 @@ class Function(ABC):
386
385
  else:
387
386
  var = exprs.Variable(name, param.col_type)
388
387
  bindings[name] = var
389
- if args_ok and param.kind in (
388
+ if args_ok and param.kind in {
390
389
  inspect.Parameter.POSITIONAL_ONLY,
391
390
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
392
- ):
391
+ }:
393
392
  template_args.append(var)
394
393
  else:
395
394
  template_kwargs[name] = var
@@ -436,6 +435,9 @@ class Function(ABC):
436
435
  return False
437
436
  return self.self_path == other.self_path
438
437
 
438
+ def __hash__(self) -> int:
439
+ return hash(self.self_path)
440
+
439
441
  def source(self) -> None:
440
442
  """Print source code"""
441
443
  print('source not available')
@@ -9,9 +9,7 @@ from uuid import UUID
9
9
 
10
10
  import sqlalchemy as sql
11
11
 
12
- import pixeltable.env as env
13
- import pixeltable.exceptions as excs
14
- import pixeltable.type_system as ts
12
+ from pixeltable import env, exceptions as excs, type_system as ts
15
13
  from pixeltable.metadata import schema
16
14
 
17
15
  from .function import Function
@@ -1,13 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from typing import TYPE_CHECKING, Any, Callable, Optional, Sequence, overload
4
+ from typing import TYPE_CHECKING, Any, Callable, Optional, overload
5
5
 
6
- import sqlalchemy as sql
7
-
8
- import pixeltable.exceptions as excs
9
- import pixeltable.type_system as ts
10
- from pixeltable import exprs
6
+ from pixeltable import exprs, type_system as ts
11
7
 
12
8
  from .function import Function
13
9
  from .signature import Signature
@@ -21,8 +17,6 @@ class QueryTemplateFunction(Function):
21
17
 
22
18
  template_df: Optional['DataFrame']
23
19
  self_name: Optional[str]
24
- # conn: Optional[sql.engine.Connection]
25
- defaults: dict[str, exprs.Literal]
26
20
 
27
21
  @classmethod
28
22
  def create(
@@ -50,20 +44,6 @@ class QueryTemplateFunction(Function):
50
44
  self.self_name = name
51
45
  self.template_df = template_df
52
46
 
53
- # if we're running as part of an ongoing update operation, we need to use the same connection, otherwise
54
- # we end up with a deadlock
55
- # TODO: figure out a more general way to make execution state available
56
- # self.conn = None
57
-
58
- # convert defaults to Literals
59
- self.defaults = {} # key: param name, value: default value converted to a Literal
60
- param_types = self.template_df.parameters()
61
- for param in [p for p in sig.parameters.values() if p.has_default()]:
62
- assert param.name in param_types
63
- param_type = param_types[param.name]
64
- literal_default = exprs.Literal(param.default, col_type=param_type)
65
- self.defaults[param.name] = literal_default
66
-
67
47
  def _update_as_overload_resolution(self, signature_idx: int) -> None:
68
48
  pass # only one signature supported for QueryTemplateFunction
69
49
 
@@ -76,7 +56,11 @@ class QueryTemplateFunction(Function):
76
56
  bound_args = self.signature.py_signature.bind(*args, **kwargs).arguments
77
57
  # apply defaults, otherwise we might have Parameters left over
78
58
  bound_args.update(
79
- {param_name: default for param_name, default in self.defaults.items() if param_name not in bound_args}
59
+ {
60
+ param.name: param.default
61
+ for param in self.signature.parameters.values()
62
+ if param.has_default() and param.name not in bound_args
63
+ }
80
64
  )
81
65
  bound_df = self.template_df.bind(bound_args)
82
66
  result = await bound_df._acollect()
@@ -91,7 +75,7 @@ class QueryTemplateFunction(Function):
91
75
  return self.self_name
92
76
 
93
77
  def _as_dict(self) -> dict:
94
- return {'name': self.name, 'signature': self.signatures[0].as_dict(), 'df': self.template_df.as_dict()}
78
+ return {'name': self.name, 'signature': self.signature.as_dict(), 'df': self.template_df.as_dict()}
95
79
 
96
80
  @classmethod
97
81
  def _from_dict(cls, d: dict) -> Function:
@@ -2,10 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
4
  import inspect
5
- import json
6
5
  import logging
7
6
  import typing
8
- from typing import TYPE_CHECKING, Any, Callable, Optional
7
+ from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional
9
8
 
10
9
  import pixeltable.exceptions as excs
11
10
  import pixeltable.type_system as ts
@@ -69,6 +68,9 @@ class Parameter:
69
68
  py_default = self.default.val if self.default is not None else inspect.Parameter.empty
70
69
  return inspect.Parameter(self.name, self.kind, default=py_default)
71
70
 
71
+ def __hash__(self) -> int:
72
+ return hash((self.name, self.col_type, self.kind, self.default, self.is_batched))
73
+
72
74
 
73
75
  T = typing.TypeVar('T')
74
76
  Batch = typing.Annotated[list[T], 'pxt-batch']
@@ -81,7 +83,7 @@ class Signature:
81
83
  - self.is_batched: return type is a Batch[...] type
82
84
  """
83
85
 
84
- SPECIAL_PARAM_NAMES = ['group_by', 'order_by']
86
+ SPECIAL_PARAM_NAMES: ClassVar[list[str]] = ['group_by', 'order_by']
85
87
 
86
88
  def __init__(self, return_type: ts.ColumnType, parameters: list[Parameter], is_batched: bool = False):
87
89
  assert isinstance(return_type, ts.ColumnType)
@@ -135,26 +137,28 @@ class Signature:
135
137
  if (
136
138
  param.kind != other_param.kind
137
139
  or (param.col_type is None) != (other_param.col_type is None) # this can happen if they are varargs
138
- or param.col_type is not None
139
- and not other_param.col_type.is_supertype_of(param.col_type, ignore_nullable=True)
140
+ or (
141
+ param.col_type is not None
142
+ and not other_param.col_type.is_supertype_of(param.col_type, ignore_nullable=True)
143
+ )
140
144
  ):
141
145
  return False
142
146
 
143
147
  # Check (iii)
144
- for other_param in other.required_parameters:
148
+ for other_param in other.required_parameters: # noqa: SIM110
145
149
  if other_param.name not in self.parameters:
146
150
  return False
147
151
 
148
152
  return True
149
153
 
150
154
  def validate_args(self, bound_args: dict[str, Optional['exprs.Expr']], context: str = '') -> None:
151
- if context != '':
155
+ if context:
152
156
  context = f' ({context})'
153
157
 
154
158
  for param_name, arg in bound_args.items():
155
159
  assert param_name in self.parameters
156
160
  param = self.parameters[param_name]
157
- is_var_param = param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
161
+ is_var_param = param.kind in {inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD}
158
162
  if is_var_param:
159
163
  continue
160
164
  assert param.col_type is not None
@@ -191,6 +195,9 @@ class Signature:
191
195
  return False
192
196
  return True
193
197
 
198
+ def __hash__(self) -> int:
199
+ return hash((self.return_type, self.parameters))
200
+
194
201
  def __str__(self) -> str:
195
202
  param_strs: list[str] = []
196
203
  for p in self.parameters.values():
@@ -199,8 +206,8 @@ class Signature:
199
206
  elif p.kind == inspect.Parameter.VAR_KEYWORD:
200
207
  param_strs.append(f'**{p.name}')
201
208
  else:
202
- param_strs.append(f'{p.name}: {str(p.col_type)}')
203
- return f'({", ".join(param_strs)}) -> {str(self.get_return_type())}'
209
+ param_strs.append(f'{p.name}: {p.col_type}')
210
+ return f'({", ".join(param_strs)}) -> {self.get_return_type()}'
204
211
 
205
212
  @classmethod
206
213
  def _infer_type(cls, annotation: Optional[type]) -> tuple[Optional[ts.ColumnType], Optional[bool]]:
@@ -213,7 +220,7 @@ class Signature:
213
220
  type_args = typing.get_args(annotation)
214
221
  if len(type_args) == 2 and type_args[1] == 'pxt-batch':
215
222
  # this is our Batch
216
- assert typing.get_origin(type_args[0]) == list
223
+ assert typing.get_origin(type_args[0]) is list
217
224
  is_batched = True
218
225
  py_type = typing.get_args(type_args[0])[0]
219
226
  if py_type is None:
@@ -246,7 +253,7 @@ class Signature:
246
253
  continue # skip 'self' or 'cls' parameter
247
254
  if param.name in cls.SPECIAL_PARAM_NAMES:
248
255
  raise excs.Error(f'{param.name!r} is a reserved parameter name')
249
- if param.kind == inspect.Parameter.VAR_POSITIONAL or param.kind == inspect.Parameter.VAR_KEYWORD:
256
+ if param.kind in {inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD}:
250
257
  parameters.append(Parameter(param.name, col_type=None, kind=param.kind))
251
258
  continue
252
259
 
@@ -257,11 +264,8 @@ class Signature:
257
264
  param_type = param_types[idx]
258
265
  is_batched = False
259
266
  else:
260
- py_type: Optional[type]
261
- if param.annotation in type_substitutions:
262
- py_type = type_substitutions[param.annotation]
263
- else:
264
- py_type = param.annotation
267
+ # Look up the substitution for param.annotation, defaulting to param.annotation if there is none
268
+ py_type = type_substitutions.get(param.annotation, param.annotation)
265
269
  param_type, is_batched = cls._infer_type(py_type)
266
270
  if param_type is None:
267
271
  raise excs.Error(f'Cannot infer pixeltable type for parameter {param.name!r}')
@@ -297,11 +301,8 @@ class Signature:
297
301
  )
298
302
  sig = inspect.signature(py_fn)
299
303
  if return_type is None:
300
- py_type: Optional[type]
301
- if sig.return_annotation in type_substitutions:
302
- py_type = type_substitutions[sig.return_annotation]
303
- else:
304
- py_type = sig.return_annotation
304
+ # Look up the substitution for sig.return_annotation, defaulting to return_annotation if there is none
305
+ py_type = type_substitutions.get(sig.return_annotation, sig.return_annotation)
305
306
  return_type, return_is_batched = cls._infer_type(py_type)
306
307
  if return_type is None:
307
308
  raise excs.Error('Cannot infer pixeltable return type')
pixeltable/func/tools.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, TypeVar, Union
1
+ from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union
2
2
 
3
3
  import pydantic
4
4
 
@@ -69,7 +69,7 @@ class Tool(pydantic.BaseModel):
69
69
  return _extract_float_tool_arg(kwargs, param_name=param.name)
70
70
  if param.col_type.is_bool_type():
71
71
  return _extract_bool_tool_arg(kwargs, param_name=param.name)
72
- assert False
72
+ raise AssertionError()
73
73
 
74
74
 
75
75
  class ToolChoice(pydantic.BaseModel):
@@ -113,7 +113,7 @@ class Tools(pydantic.BaseModel):
113
113
  )
114
114
  tool_name = tool_obj.name or tool_obj.fn.name
115
115
  except StopIteration:
116
- raise excs.Error(f'That tool is not in the specified list of tools: {tool}')
116
+ raise excs.Error(f'That tool is not in the specified list of tools: {tool}') from None
117
117
  return ToolChoice(auto=auto, required=required, tool=tool_name, parallel_tool_calls=parallel_tool_calls)
118
118
 
119
119
 
pixeltable/func/udf.py CHANGED
@@ -146,7 +146,8 @@ def make_function(
146
146
  raise excs.Error(f'Cannot specify both `is_method` and `is_property` (in function `{function_name}`)')
147
147
  if is_property and len(sig.parameters) != 1:
148
148
  raise excs.Error(
149
- f'`is_property=True` expects a UDF with exactly 1 parameter, but `{function_name}` has {len(sig.parameters)}'
149
+ '`is_property=True` expects a UDF with exactly 1 parameter, but '
150
+ f'`{function_name}` has {len(sig.parameters)}'
150
151
  )
151
152
  if (is_method or is_property) and function_path is None:
152
153
  raise excs.Error('Stored functions cannot be declared using `is_method` or `is_property`')
@@ -205,6 +206,8 @@ def expr_udf(*, param_types: Optional[list[ts.ColumnType]] = None) -> Callable[[
205
206
 
206
207
  def expr_udf(*args: Any, **kwargs: Any) -> Any:
207
208
  def make_expr_template(py_fn: Callable, param_types: Optional[list[ts.ColumnType]]) -> ExprTemplateFunction:
209
+ from pixeltable import exprs
210
+
208
211
  if py_fn.__module__ != '__main__' and py_fn.__name__.isidentifier():
209
212
  # this is a named function in a module
210
213
  function_path = f'{py_fn.__module__}.{py_fn.__qualname__}'
@@ -216,7 +219,6 @@ def expr_udf(*args: Any, **kwargs: Any) -> Any:
216
219
 
217
220
  # construct Signature from the function signature
218
221
  sig = Signature.create(py_fn=py_fn, param_types=param_types, return_type=ts.InvalidType())
219
- import pixeltable.exprs as exprs
220
222
 
221
223
  var_exprs = [exprs.Variable(param.name, param.col_type) for param in sig.parameters.values()]
222
224
  # call the function with the parameter expressions to construct an Expr with parameters
@@ -260,7 +262,7 @@ def from_table(
260
262
  """
261
263
  from pixeltable import exprs
262
264
 
263
- ancestors = [tbl] + tbl._bases
265
+ ancestors = [tbl, *tbl._bases]
264
266
  ancestors.reverse() # We must traverse the ancestors in order from base to derived
265
267
 
266
268
  subst: dict[exprs.Expr, exprs.Expr] = {}