pixeltable 0.4.19__py3-none-any.whl → 0.4.20__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 (36) hide show
  1. pixeltable/_version.py +1 -1
  2. pixeltable/catalog/catalog.py +76 -50
  3. pixeltable/catalog/column.py +29 -16
  4. pixeltable/catalog/insertable_table.py +2 -2
  5. pixeltable/catalog/path.py +4 -10
  6. pixeltable/catalog/table.py +51 -0
  7. pixeltable/catalog/table_version.py +40 -7
  8. pixeltable/catalog/view.py +2 -2
  9. pixeltable/config.py +1 -0
  10. pixeltable/env.py +2 -0
  11. pixeltable/exprs/column_ref.py +2 -1
  12. pixeltable/functions/__init__.py +1 -0
  13. pixeltable/functions/image.py +2 -8
  14. pixeltable/functions/reve.py +250 -0
  15. pixeltable/functions/video.py +534 -1
  16. pixeltable/globals.py +2 -1
  17. pixeltable/index/base.py +5 -18
  18. pixeltable/index/btree.py +6 -2
  19. pixeltable/index/embedding_index.py +4 -4
  20. pixeltable/metadata/schema.py +7 -32
  21. pixeltable/share/__init__.py +1 -1
  22. pixeltable/share/packager.py +22 -18
  23. pixeltable/share/protocol/__init__.py +34 -0
  24. pixeltable/share/protocol/common.py +170 -0
  25. pixeltable/share/protocol/operation_types.py +33 -0
  26. pixeltable/share/protocol/replica.py +109 -0
  27. pixeltable/share/publish.py +90 -56
  28. pixeltable/store.py +11 -15
  29. pixeltable/utils/av.py +87 -1
  30. pixeltable/utils/dbms.py +15 -11
  31. pixeltable/utils/image.py +10 -0
  32. {pixeltable-0.4.19.dist-info → pixeltable-0.4.20.dist-info}/METADATA +2 -1
  33. {pixeltable-0.4.19.dist-info → pixeltable-0.4.20.dist-info}/RECORD +36 -31
  34. {pixeltable-0.4.19.dist-info → pixeltable-0.4.20.dist-info}/WHEEL +0 -0
  35. {pixeltable-0.4.19.dist-info → pixeltable-0.4.20.dist-info}/entry_points.txt +0 -0
  36. {pixeltable-0.4.19.dist-info → pixeltable-0.4.20.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,11 @@
1
+ import dataclasses
2
+ import json
1
3
  import os
2
4
  import sys
3
5
  import urllib.parse
4
6
  import urllib.request
5
7
  from pathlib import Path
6
- from typing import Literal
8
+ from typing import Any, Literal
7
9
 
8
10
  import requests
9
11
  from requests.adapters import HTTPAdapter
@@ -12,11 +14,23 @@ from urllib3.util.retry import Retry
12
14
 
13
15
  import pixeltable as pxt
14
16
  from pixeltable import exceptions as excs
17
+ from pixeltable.catalog import Catalog
15
18
  from pixeltable.env import Env
16
19
  from pixeltable.utils import sha256sum
17
20
  from pixeltable.utils.local_store import TempStore
18
21
 
19
22
  from .packager import TablePackager, TableRestorer
23
+ from .protocol import PxtUri
24
+ from .protocol.replica import (
25
+ DeleteRequest,
26
+ DeleteResponse,
27
+ FinalizeRequest,
28
+ FinalizeResponse,
29
+ PublishRequest,
30
+ PublishResponse,
31
+ ReplicateRequest,
32
+ ReplicateResponse,
33
+ )
20
34
 
21
35
  # These URLs are abstracted out for now, but will be replaced with actual (hard-coded) URLs once the
22
36
  # pixeltable.com URLs are available.
@@ -27,24 +41,31 @@ PIXELTABLE_API_URL = os.environ.get('PIXELTABLE_API_URL', 'https://internal-api.
27
41
  def push_replica(
28
42
  dest_tbl_uri: str, src_tbl: pxt.Table, bucket: str | None = None, access: Literal['public', 'private'] = 'private'
29
43
  ) -> str:
30
- packager = TablePackager(
31
- src_tbl, additional_md={'table_uri': dest_tbl_uri, 'bucket_name': bucket, 'is_public': access == 'public'}
44
+ packager = TablePackager(src_tbl)
45
+
46
+ # Create the publish request using packager's bundle_md
47
+ publish_request = PublishRequest(
48
+ table_uri=PxtUri(uri=dest_tbl_uri),
49
+ pxt_version=packager.bundle_md['pxt_version'],
50
+ pxt_md_version=packager.bundle_md['pxt_md_version'],
51
+ md=packager.bundle_md['md'],
52
+ bucket_name=bucket,
53
+ is_public=access == 'public',
32
54
  )
33
- request_json = packager.md | {'operation_type': 'publish_snapshot'}
34
- response = requests.post(PIXELTABLE_API_URL, json=request_json, headers=_api_headers())
55
+
56
+ response = requests.post(PIXELTABLE_API_URL, data=publish_request.model_dump_json(), headers=_api_headers())
35
57
  if response.status_code != 200:
36
- raise excs.Error(f'Error publishing snapshot: {response.text}')
37
- response_json = response.json()
38
- if not isinstance(response_json, dict):
39
- raise excs.Error(f'Error publishing snapshot: unexpected response from server.\n{response_json}')
40
- upload_id = response_json['upload_id']
41
- destination_uri = response_json['destination_uri']
58
+ raise excs.Error(f'Error publishing {src_tbl._display_name()}: {response.text}')
59
+ publish_response = PublishResponse.model_validate(response.json())
60
+
61
+ upload_id = publish_response.upload_id
62
+ destination_uri = publish_response.destination_uri
42
63
 
43
- Env.get().console_logger.info(f"Creating a snapshot of '{src_tbl._path()}' at: {dest_tbl_uri}")
64
+ Env.get().console_logger.info(f"Creating a replica of '{src_tbl._path()}' at: {dest_tbl_uri}")
44
65
 
45
66
  bundle = packager.package()
46
67
 
47
- parsed_location = urllib.parse.urlparse(destination_uri)
68
+ parsed_location = urllib.parse.urlparse(str(destination_uri))
48
69
  if parsed_location.scheme == 's3':
49
70
  _upload_bundle_to_s3(bundle, parsed_location)
50
71
  elif parsed_location.scheme == 'https':
@@ -52,30 +73,32 @@ def push_replica(
52
73
  else:
53
74
  raise excs.Error(f'Unsupported destination: {destination_uri}')
54
75
 
55
- Env.get().console_logger.info('Finalizing snapshot ...')
56
-
57
- finalize_request_json = {
58
- 'table_uri': dest_tbl_uri,
59
- 'operation_type': 'finalize_snapshot',
60
- 'upload_id': upload_id,
61
- 'datafile': bundle.name,
62
- 'size': bundle.stat().st_size,
63
- 'sha256': sha256sum(bundle), # Generate our own SHA for independent verification
64
- 'rows': packager.md['row_count'], # TODO rename rows to row_count once cloud side changes are complete
65
- 'preview_header': packager.md['preview_header'],
66
- 'preview_data': packager.md['preview_data'],
67
- }
68
- # TODO: Use Pydantic for validation
69
- finalize_response = requests.post(PIXELTABLE_API_URL, json=finalize_request_json, headers=_api_headers())
70
- if finalize_response.status_code != 200:
71
- raise excs.Error(f'Error finalizing snapshot: {finalize_response.text}')
72
- finalize_response_json = finalize_response.json()
73
- if not isinstance(finalize_response_json, dict) or 'confirmed_table_uri' not in finalize_response_json:
74
- raise excs.Error(f'Error finalizing snapshot: unexpected response from server.\n{finalize_response_json}')
75
-
76
- confirmed_tbl_uri = finalize_response_json['confirmed_table_uri']
77
- Env.get().console_logger.info(f'The published snapshot is now available at: {confirmed_tbl_uri}')
78
- return confirmed_tbl_uri
76
+ Env.get().console_logger.info('Finalizing replica ...')
77
+ # Use preview data from packager's bundle_md (set during package())
78
+ finalize_request = FinalizeRequest(
79
+ table_uri=PxtUri(uri=dest_tbl_uri),
80
+ upload_id=upload_id,
81
+ datafile=bundle.name,
82
+ size=bundle.stat().st_size,
83
+ sha256=sha256sum(bundle), # Generate our own SHA for independent verification
84
+ row_count=packager.bundle_md['row_count'],
85
+ preview_header=packager.bundle_md['preview_header'],
86
+ preview_data=packager.bundle_md['preview_data'],
87
+ )
88
+ finalize_response_json = requests.post(
89
+ PIXELTABLE_API_URL, data=finalize_request.model_dump_json(), headers=_api_headers()
90
+ )
91
+ if finalize_response_json.status_code != 200:
92
+ raise excs.Error(f'Error finalizing {src_tbl._display_name()}: {finalize_response_json.text}')
93
+
94
+ finalize_response = FinalizeResponse.model_validate(finalize_response_json.json())
95
+ confirmed_tbl_uri = finalize_response.confirmed_table_uri
96
+ Env.get().console_logger.info(f'The published table is now available at: {confirmed_tbl_uri}')
97
+
98
+ with Catalog.get().begin_xact(tbl_id=src_tbl._tbl_version_path.tbl_id, for_write=True):
99
+ src_tbl._tbl_version_path.tbl_version.get().update_pxt_uri(str(confirmed_tbl_uri))
100
+
101
+ return str(confirmed_tbl_uri)
79
102
 
80
103
 
81
104
  def _upload_bundle_to_s3(bundle: Path, parsed_location: urllib.parse.ParseResult) -> None:
@@ -83,7 +106,7 @@ def _upload_bundle_to_s3(bundle: Path, parsed_location: urllib.parse.ParseResult
83
106
  remote_dir = Path(urllib.parse.unquote(urllib.request.url2pathname(parsed_location.path)))
84
107
  remote_path = str(remote_dir / bundle.name)[1:] # Remove initial /
85
108
 
86
- Env.get().console_logger.info(f'Uploading snapshot to: {bucket}:{remote_path}')
109
+ Env.get().console_logger.info(f'Uploading replica to: {bucket}:{remote_path}')
87
110
 
88
111
  s3_client = Env.get().get_client('s3')
89
112
 
@@ -105,17 +128,14 @@ def _upload_bundle_to_s3(bundle: Path, parsed_location: urllib.parse.ParseResult
105
128
 
106
129
 
107
130
  def pull_replica(dest_path: str, src_tbl_uri: str) -> pxt.Table:
108
- clone_request_json = {'operation_type': 'clone_snapshot', 'table_uri': src_tbl_uri}
109
- response = requests.post(PIXELTABLE_API_URL, json=clone_request_json, headers=_api_headers())
131
+ clone_request = ReplicateRequest(table_uri=PxtUri(src_tbl_uri))
132
+ response = requests.post(PIXELTABLE_API_URL, data=clone_request.model_dump_json(), headers=_api_headers())
110
133
  if response.status_code != 200:
111
- raise excs.Error(f'Error cloning snapshot: {response.text}')
112
- response_json = response.json()
113
- if not isinstance(response_json, dict) or 'table_uri' not in response_json:
114
- raise excs.Error(f'Error cloning shapshot: unexpected response from server.\n{response_json}')
115
-
116
- primary_tbl_additional_md = response_json['md']['tables'][0]['table_md']['additional_md']
117
- bundle_uri = response_json['destination_uri']
118
- bundle_filename = primary_tbl_additional_md['datafile']
134
+ raise excs.Error(f'Error cloning replica: {response.text}')
135
+ clone_response = ReplicateResponse.model_validate(response.json())
136
+ primary_version_additional_md = clone_response.md[0].version_md.additional_md
137
+ bundle_uri = str(clone_response.destination_uri)
138
+ bundle_filename = primary_version_additional_md['cloud']['datafile']
119
139
  parsed_location = urllib.parse.urlparse(bundle_uri)
120
140
  if parsed_location.scheme == 's3':
121
141
  bundle_path = _download_bundle_from_s3(parsed_location, bundle_filename)
@@ -124,8 +144,13 @@ def pull_replica(dest_path: str, src_tbl_uri: str) -> pxt.Table:
124
144
  _download_from_presigned_url(url=parsed_location.geturl(), output_path=bundle_path)
125
145
  else:
126
146
  raise excs.Error(f'Unexpected response from server: unsupported bundle uri: {bundle_uri}')
147
+ # Set pxt_uri in the table metadata; use table_uri from ReplicateResponse
148
+ clone_response.md[0].tbl_md.additional_md['pxt_uri'] = str(clone_response.table_uri)
149
+ md_list = [dataclasses.asdict(md) for md in clone_response.md]
150
+ restorer = TableRestorer(
151
+ dest_path, {'pxt_version': pxt.__version__, 'pxt_md_version': clone_response.pxt_md_version, 'md': md_list}
152
+ )
127
153
 
128
- restorer = TableRestorer(dest_path, response_json)
129
154
  tbl = restorer.restore(bundle_path)
130
155
  Env.get().console_logger.info(f'Created local replica {tbl._path()!r} from URI: {src_tbl_uri}')
131
156
  return tbl
@@ -136,7 +161,7 @@ def _download_bundle_from_s3(parsed_location: urllib.parse.ParseResult, bundle_f
136
161
  remote_dir = Path(urllib.parse.unquote(urllib.request.url2pathname(parsed_location.path)))
137
162
  remote_path = str(remote_dir / bundle_filename)[1:] # Remove initial /
138
163
 
139
- Env.get().console_logger.info(f'Downloading snapshot from: {bucket}:{remote_path}')
164
+ Env.get().console_logger.info(f'Downloading replica from: {bucket}:{remote_path}')
140
165
 
141
166
  s3_client = Env.get().get_client('s3')
142
167
 
@@ -254,15 +279,24 @@ def _download_from_presigned_url(
254
279
  session.close()
255
280
 
256
281
 
257
- def delete_replica(dest_path: str) -> None:
282
+ def delete_replica(dest_path: str, version: int | None = None) -> None:
258
283
  """Delete cloud replica"""
259
- delete_request_json = {'operation_type': 'delete_snapshot', 'table_uri': dest_path}
260
- response = requests.post(PIXELTABLE_API_URL, json=delete_request_json, headers=_api_headers())
284
+ delete_request = DeleteRequest(table_uri=PxtUri(uri=dest_path), version=version)
285
+ response = requests.post(PIXELTABLE_API_URL, data=delete_request.model_dump_json(), headers=_api_headers())
261
286
  if response.status_code != 200:
262
287
  raise excs.Error(f'Error deleting replica: {response.text}')
263
- response_json = response.json()
264
- if not isinstance(response_json, dict) or 'table_uri' not in response_json:
265
- raise excs.Error(f'Error deleting replica: unexpected response from server.\n{response_json}')
288
+ DeleteResponse.model_validate(response.json())
289
+ Env.get().console_logger.info(f'Deleted replica at: {dest_path}')
290
+
291
+
292
+ def list_table_versions(table_uri: str) -> list[dict[str, Any]]:
293
+ """List versions for a remote table."""
294
+ request_json = {'operation_type': 'list_table_versions', 'table_uri': {'uri': table_uri}}
295
+ response = requests.post(PIXELTABLE_API_URL, data=json.dumps(request_json), headers=_api_headers())
296
+ if response.status_code != 200:
297
+ raise excs.Error(f'Error listing table versions: {response.text}')
298
+ response_data = response.json()
299
+ return response_data.get('versions', [])
266
300
 
267
301
 
268
302
  def _api_headers() -> dict[str, str]:
pixeltable/store.py CHANGED
@@ -113,11 +113,6 @@ class StoreBase:
113
113
  idx_name = f'vmax_idx_{tbl_version.id.hex}'
114
114
  idxs.append(sql.Index(idx_name, self.v_max_col, postgresql_using=Env.get().dbms.version_index_type))
115
115
 
116
- # we only capture indices visible in this version
117
- for idx_info in tbl_version.idxs.values():
118
- idx = idx_info.idx.sa_index(tbl_version._store_idx_name(idx_info.id), idx_info.val_col)
119
- idxs.append(idx)
120
-
121
116
  self.sa_tbl = sql.Table(self._storage_name(), self.sa_md, *all_cols, *idxs)
122
117
  # _logger.debug(f'created sa tbl for {tbl_version.id!s} (sa_tbl={id(self.sa_tbl):x}, tv={id(tbl_version):x})')
123
118
 
@@ -152,7 +147,7 @@ class StoreBase:
152
147
  while True:
153
148
  with Env.get().begin_xact(for_write=True) as conn:
154
149
  try:
155
- if wait_for_table:
150
+ if wait_for_table and not Env.get().is_using_cockroachdb:
156
151
  # Try to lock the table to make sure that it exists. This needs to run in the same transaction
157
152
  # as 'stmt' to avoid a race condition.
158
153
  # TODO: adapt this for CockroachDB
@@ -215,19 +210,20 @@ class StoreBase:
215
210
  # TODO: do we also need to ensure that these columns are now visible (ie, is there another potential race
216
211
  # condition here?)
217
212
 
218
- # ensure that all visible indices exist by running Create Index If Not Exists
219
- for index in self.sa_tbl.indexes:
220
- create_stmt = sql.schema.CreateIndex(index, if_not_exists=True).compile(dialect=postgres_dialect)
221
- self._exec_if_not_exists(str(create_stmt), wait_for_table=True)
213
+ # ensure that all system indices exist by running Create Index If Not Exists
214
+ for idx in self.sa_tbl.indexes:
215
+ create_idx_stmt = sql.schema.CreateIndex(idx, if_not_exists=True).compile(dialect=postgres_dialect)
216
+ self._exec_if_not_exists(str(create_idx_stmt), wait_for_table=True)
217
+
218
+ # ensure that all visible non-system indices exist by running appropriate create statements
219
+ for id in self.tbl_version.get().idxs:
220
+ self.create_index(id)
222
221
 
223
222
  def create_index(self, idx_id: int) -> None:
224
223
  """Create If Not Exists for this index"""
225
224
  idx_info = self.tbl_version.get().idxs[idx_id]
226
- sa_idx = idx_info.idx.sa_index(self.tbl_version.get()._store_idx_name(idx_id), idx_info.val_col)
227
- conn = Env.get().conn
228
- stmt = sql.schema.CreateIndex(sa_idx, if_not_exists=True).compile(conn)
229
- create_stmt = str(stmt)
230
- self._exec_if_not_exists(create_stmt, wait_for_table=True)
225
+ stmt = idx_info.idx.sa_create_stmt(self.tbl_version.get()._store_idx_name(idx_id), idx_info.val_col.sa_col)
226
+ self._exec_if_not_exists(str(stmt), wait_for_table=True)
231
227
 
232
228
  def validate(self) -> None:
233
229
  """Validate store table against self.table_version"""
pixeltable/utils/av.py CHANGED
@@ -1,7 +1,15 @@
1
- from typing import Any
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from fractions import Fraction
5
+ from pathlib import Path
6
+ from types import TracebackType
7
+ from typing import Any, Iterator
2
8
 
3
9
  import av
4
10
  import av.stream
11
+ import PIL.Image
12
+ from typing_extensions import Self
5
13
 
6
14
  from pixeltable.env import Env
7
15
 
@@ -210,3 +218,81 @@ def ffmpeg_segment_cmd(
210
218
  ]
211
219
  )
212
220
  return cmd
221
+
222
+
223
+ class VideoFrames:
224
+ """
225
+ Context manager for iterating over video frames at a specified frame rate.
226
+
227
+ Args:
228
+ path: Path to the video file
229
+ fps: Number of frames to extract per second. If None or 0.0, extracts all frames.
230
+ """
231
+
232
+ path: Path
233
+ fps: float
234
+ container: av.container.input.InputContainer | None
235
+ video_framerate: Fraction | None
236
+ video_time_base: Fraction | None
237
+ video_start_time: int | None
238
+
239
+ @dataclass
240
+ class Item:
241
+ frame_idx: int
242
+ pts: int
243
+ dts: int
244
+ time: float
245
+ is_corrupt: bool
246
+ key_frame: bool
247
+ pict_type: int
248
+ interlaced_frame: bool
249
+ frame: PIL.Image.Image
250
+
251
+ def __init__(self, path: Path, fps: float | None = None) -> None:
252
+ self.path = path
253
+ self.fps = 0.0 if fps is None else fps
254
+ self.container = None
255
+ self.video_framerate = None
256
+ self.video_time_base = None
257
+ self.video_start_time = None
258
+
259
+ def __enter__(self) -> Self:
260
+ self.container = av.open(self.path)
261
+ stream = self.container.streams.video[0]
262
+ self.video_framerate = stream.average_rate
263
+ self.video_time_base = stream.time_base
264
+ self.video_start_time = stream.start_time or 0
265
+ return self
266
+
267
+ def __exit__(
268
+ self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
269
+ ) -> None:
270
+ # Clean up
271
+ if self.container:
272
+ self.container.close()
273
+
274
+ def __iter__(self) -> Iterator[Item]:
275
+ num_returned = 0
276
+ frame_idx = -1
277
+ while True:
278
+ try:
279
+ frame = next(self.container.decode(video=0))
280
+ except (StopIteration, EOFError):
281
+ return
282
+
283
+ frame_idx += 1
284
+ if self.fps == 0.0 or (num_returned <= frame.time * self.fps):
285
+ img = frame.to_image()
286
+ assert isinstance(img, PIL.Image.Image)
287
+ yield VideoFrames.Item(
288
+ frame_idx=frame_idx,
289
+ pts=frame.pts,
290
+ dts=frame.dts,
291
+ time=frame.time,
292
+ is_corrupt=frame.is_corrupt,
293
+ key_frame=frame.key_frame,
294
+ pict_type=frame.pict_type,
295
+ interlaced_frame=frame.interlaced_frame,
296
+ frame=img,
297
+ )
298
+ num_returned += 1
pixeltable/utils/dbms.py CHANGED
@@ -29,7 +29,9 @@ class Dbms(abc.ABC):
29
29
  def default_system_db_url(self) -> str: ...
30
30
 
31
31
  @abc.abstractmethod
32
- def sa_vector_index(self, store_index_name: str, sa_value_col: sql.schema.Column, metric: str) -> sql.Index: ...
32
+ def create_vector_index_stmt(
33
+ self, store_index_name: str, sa_value_col: sql.Column, metric: str
34
+ ) -> sql.Compiled: ...
33
35
 
34
36
 
35
37
  class PostgresqlDbms(Dbms):
@@ -50,14 +52,17 @@ class PostgresqlDbms(Dbms):
50
52
  a = self.db_url.set(database='postgres').render_as_string(hide_password=False)
51
53
  return a
52
54
 
53
- def sa_vector_index(self, store_index_name: str, sa_value_col: sql.schema.Column, metric: str) -> sql.Index:
54
- return sql.Index(
55
+ def create_vector_index_stmt(self, store_index_name: str, sa_value_col: sql.Column, metric: str) -> sql.Compiled:
56
+ from sqlalchemy.dialects import postgresql
57
+
58
+ sa_idx = sql.Index(
55
59
  store_index_name,
56
60
  sa_value_col,
57
61
  postgresql_using='hnsw',
58
62
  postgresql_with={'m': 16, 'ef_construction': 64},
59
63
  postgresql_ops={sa_value_col.name: metric},
60
64
  )
65
+ return sql.schema.CreateIndex(sa_idx, if_not_exists=True).compile(dialect=postgresql.dialect())
61
66
 
62
67
 
63
68
  class CockroachDbms(Dbms):
@@ -77,12 +82,11 @@ class CockroachDbms(Dbms):
77
82
  def default_system_db_url(self) -> str:
78
83
  return self.db_url.set(database='defaultdb').render_as_string(hide_password=False)
79
84
 
80
- def sa_vector_index(self, store_index_name: str, sa_value_col: sql.schema.Column, metric: str) -> sql.Index:
81
- # TODO: can the Create Index statement be generated via sqlalchemy?
82
- # if not, change this method to create_vector_index_stmt(...) -> str
83
- # original code:
84
- # create_index_sql = sql.text(
85
- # f"""CREATE VECTOR INDEX {store_index_name} ON {sa_value_col.table.name}
86
- # ({sa_value_col.name} {metric})"""
87
- # )
85
+ def sa_vector_index(self, store_index_name: str, sa_value_col: sql.schema.Column, metric: str) -> sql.Index | None:
88
86
  return None
87
+
88
+ def create_vector_index_stmt(self, store_index_name: str, sa_value_col: sql.Column, metric: str) -> sql.Compiled:
89
+ return sql.text(
90
+ f'CREATE VECTOR INDEX IF NOT EXISTS {store_index_name} ON {sa_value_col.table.name}'
91
+ f'({sa_value_col.name} {metric})'
92
+ ).compile()
pixeltable/utils/image.py CHANGED
@@ -1,3 +1,6 @@
1
+ import base64
2
+ from io import BytesIO
3
+
1
4
  import PIL.Image
2
5
 
3
6
 
@@ -5,3 +8,10 @@ def default_format(img: PIL.Image.Image) -> str:
5
8
  # Default to JPEG unless the image has a transparency layer (which isn't supported by JPEG).
6
9
  # In that case, use WebP instead.
7
10
  return 'webp' if img.has_transparency_data else 'jpeg'
11
+
12
+
13
+ def to_base64(image: PIL.Image.Image, format: str | None = None) -> str:
14
+ buffer = BytesIO()
15
+ image.save(buffer, format=format or image.format)
16
+ image_bytes = buffer.getvalue()
17
+ return base64.b64encode(image_bytes).decode('utf-8')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixeltable
3
- Version: 0.4.19
3
+ Version: 0.4.20
4
4
  Summary: AI Data Infrastructure: Declarative, Multimodal, and Incremental
5
5
  Project-URL: homepage, https://pixeltable.com/
6
6
  Project-URL: repository, https://github.com/pixeltable/pixeltable
@@ -23,6 +23,7 @@ Classifier: Topic :: Database
23
23
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
25
  Requires-Python: >=3.10
26
+ Requires-Dist: aiohttp>=3.9
26
27
  Requires-Dist: av>=10.0.0
27
28
  Requires-Dist: beautifulsoup4>=4.10
28
29
  Requires-Dist: cloudpickle>=2.2.1
@@ -1,31 +1,31 @@
1
1
  pixeltable/__init__.py,sha256=_glawKwHDw5Jjzfe2ef-SRS1EQFacpPMnyqvQdh06PU,1694
2
- pixeltable/_version.py,sha256=TwNthYFJ3cvr1GNovf5xvDz3dOYECHGY2FIfhuJJ0eA,28
3
- pixeltable/config.py,sha256=hL65z9Qu8GHJTPMLojjEKFVrMq8vIXJ5qRSRqIWMUCs,9300
2
+ pixeltable/_version.py,sha256=Dkb1PPzwEu0CDGosx47xImseE4rUuAWjBcXPheH0q1E,28
3
+ pixeltable/config.py,sha256=aVYorLvk1Z4zUBPOlmWfXsubkxubIueL9R_klngtFw0,9413
4
4
  pixeltable/dataframe.py,sha256=CuyO0XydUqAIBu8vht79gMfZCGLNr5ClQUJKV9IPAFQ,64779
5
- pixeltable/env.py,sha256=9OAHydT83PUvqc9AzDc_vFo9IcgZl_KwjjE2HYeB2j0,47483
5
+ pixeltable/env.py,sha256=BdKRoy58cUl2zC7foFqLmIpUVmPZhkC2ibork-irMTs,47570
6
6
  pixeltable/exceptions.py,sha256=Gm8d3TL2iiv6Pj2DLd29wp_j41qNBhxXL9iTQnL4Nk4,1116
7
- pixeltable/globals.py,sha256=V7hLJrqvs5Khu_Gn7sky0qxh7T_j4kp41EHqD7EjErA,42621
7
+ pixeltable/globals.py,sha256=42yXgYF6tR5_F-GEea8Ov0N8AuFBwW0VMtUg1reNieY,42690
8
8
  pixeltable/plan.py,sha256=SuVT6cY7nsJXYOwcyyCfWpcorWSU6vv56dBs_03QJ3w,54078
9
9
  pixeltable/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- pixeltable/store.py,sha256=YPncPGA1VoA_wxGBnsCXtbt_QLI7g0N6FQiIReVU4qg,27700
10
+ pixeltable/store.py,sha256=Dz9N85DISVZlX1gLf3x_sWVdP-j9DBaUURMv55kuEmI,27552
11
11
  pixeltable/type_system.py,sha256=mhks0nbY4JtBHuLssGr5JCPRVXWyZUy6nmsOpqBX4cI,56143
12
12
  pixeltable/catalog/__init__.py,sha256=GL0MLxqCBHlhKWqhC3e9B4kwTazagTOiqBHHRjyWbTg,726
13
- pixeltable/catalog/catalog.py,sha256=nUOwlJC4AYDJKmGW3K7W4ivnvqCM5dKhm3iLOr1kUn0,104885
14
- pixeltable/catalog/column.py,sha256=xv2SJLgtQAz2SfcBxP2g0YprUsigfmEF-s78fJizobQ,13415
13
+ pixeltable/catalog/catalog.py,sha256=GYx6tuk5EY0MvUQRkyf4sRtf11qXgn0RortIWc8V0BY,105782
14
+ pixeltable/catalog/column.py,sha256=ttNGZbmbnDmWiIOIbpESPRWYFomtVqKxwQhHyaNFasA,13955
15
15
  pixeltable/catalog/dir.py,sha256=VYTscPlKR6XhupPTXlJ8txAHxS5GSpPJ3LIleDJagVQ,2047
16
16
  pixeltable/catalog/globals.py,sha256=EGlqpgmw5rhzfQC4MTKVYpdxXStFSz0J4LKxAXXXS3k,2617
17
- pixeltable/catalog/insertable_table.py,sha256=sce35OAs-S6hkCqAZz5Fmw7jQQeOzn49Z8t4aqlQDJo,13287
17
+ pixeltable/catalog/insertable_table.py,sha256=W83qtX8dN3NWLr9Nm75QadM7tZ83wBbIcz3cklVdUWY,13303
18
18
  pixeltable/catalog/named_function.py,sha256=vZ-j7P4HugWh9OmUzBMwyRYvO3tQn9jWyJz_1stPavU,1210
19
- pixeltable/catalog/path.py,sha256=FmcL8drXZShYi7BKtDQQdNjdzXTVQJ7rkzEf0Qf3fFI,3743
19
+ pixeltable/catalog/path.py,sha256=gPq_ezwDEU-7dxGE3-kEiKTwvZz0JwzoLy9rSgtHouc,3558
20
20
  pixeltable/catalog/schema_object.py,sha256=Xzax_sGpvHw7mPi-srOBYFrcOv-4MT_KXrN2y8_qwGc,1766
21
- pixeltable/catalog/table.py,sha256=VkWx_N7C-WhHReBnVAatbUv7dJHEt6rv2WFYpQ-faJ0,81766
21
+ pixeltable/catalog/table.py,sha256=pkKNBTFrrU4Dj5DWVrt0mFrW6FadLgDXWwqTMq0Visc,84007
22
22
  pixeltable/catalog/table_metadata.py,sha256=MV79FWMbZy238XsjR8pY0ROsSSPqXQHERry7mf-ds9E,3737
23
- pixeltable/catalog/table_version.py,sha256=784ZQWa736UPgo4VNnxpYJn9nY8evxhBOcyh_fPoZHE,70446
23
+ pixeltable/catalog/table_version.py,sha256=kECvsW46-08Wv42tL7oAo22dkkjKDhJ0zr0YDvhITd8,71850
24
24
  pixeltable/catalog/table_version_handle.py,sha256=KP3-AnHP9LANpMzaP7P2E-HY7E33sMJfkOAz36S5kkg,3710
25
25
  pixeltable/catalog/table_version_path.py,sha256=_imZieXYDrHR1VcDdjm6Bu2u5DFRgb85AegBeVXeiiY,9209
26
26
  pixeltable/catalog/tbl_ops.py,sha256=2B8D6nwPAr6wEcMbDaEiMOjbvsAOXIGMcZ0qKRGrS2E,1240
27
27
  pixeltable/catalog/update_status.py,sha256=jeRy7WUZ80l4gPY1c5vYcxT1F82nL5KphNrSKKfOdk8,7667
28
- pixeltable/catalog/view.py,sha256=GTd1AAN1ngxMZ5jpEcfx9l_vs6LF7qNt744KexC8rUU,15863
28
+ pixeltable/catalog/view.py,sha256=KwZzEYZMD0mqZLA-ZzfDtRauK6MpdTKGE6oh96kuZVk,15879
29
29
  pixeltable/exec/__init__.py,sha256=UQ32v0MbLF3vFx6MZLuZKfrqNVoihJFhsYzWOChX1go,704
30
30
  pixeltable/exec/aggregation_node.py,sha256=nERkQI7XdqxT0hXle3NMQowGD3KWQ80qnEGmIS8G-RM,4376
31
31
  pixeltable/exec/cache_prefetch_node.py,sha256=Wud39ykEju5Hk7gld0M2D-EQ9JWar6xm6xLqjn6smzI,10860
@@ -50,7 +50,7 @@ pixeltable/exprs/__init__.py,sha256=u8z3gv-uHt2Bz0F7heRPOVNa1r2OD1qqUDXnwEdSmlM,
50
50
  pixeltable/exprs/arithmetic_expr.py,sha256=fBfFb5xBKHxQlIbkUeQe4TubpJOHmU6YT0-spBcKwzw,7876
51
51
  pixeltable/exprs/array_slice.py,sha256=yf8pl_QICCxjKBhweLHJGkHmjji90sQO4cd1e2heMZ0,2154
52
52
  pixeltable/exprs/column_property_ref.py,sha256=ke9DnXygBKhhFRSmGcGjGjOADCcGCz82ctvjTsKHmbo,4396
53
- pixeltable/exprs/column_ref.py,sha256=WivoiimzpaqCVE8HH4BeWhCud9vfMSIfM5K_wppzOsc,14424
53
+ pixeltable/exprs/column_ref.py,sha256=XKDYDbwz_vrBNTL5abJ2QTFz911tyGPAJXnFcY6eQUg,14477
54
54
  pixeltable/exprs/comparison.py,sha256=kk35PjlvEEUW4PwaY-ZEd4uTCr3IoDA2vf8_yUKKPRw,5135
55
55
  pixeltable/exprs/compound_predicate.py,sha256=plm-VILYFH5tDtxI5bPrnTcSRrrvQSfUYFOzSYpw-PY,3847
56
56
  pixeltable/exprs/data_row.py,sha256=I55mhg9WM2ZBUyMukMyXQUS6cz1FLpF6d6oa08Nn98A,14354
@@ -86,7 +86,7 @@ pixeltable/func/query_template_function.py,sha256=H5-Y1wZsbiCEPjetb8HAeuU13fz9da
86
86
  pixeltable/func/signature.py,sha256=ZaE1j1lyg4LGzymn-UEF5PYJqtW_5kqi0DSj0laZEks,14933
87
87
  pixeltable/func/tools.py,sha256=cPHy2c5UxfyThe-1C94_hfOlDZUgSdCr-wJPh_ZHaZw,6022
88
88
  pixeltable/func/udf.py,sha256=61pgEARxd36wtKQDw2EIow87vVBj9-tEkAbT84VQwE0,13167
89
- pixeltable/functions/__init__.py,sha256=KeWGaC8CDTFX7666vpbhhb37EORsTvBbGR-r4k0ypxE,645
89
+ pixeltable/functions/__init__.py,sha256=9SwvQFkeOexDhMH63QZIlDmeex2OjmmQ-IUxvsl4Ncg,655
90
90
  pixeltable/functions/anthropic.py,sha256=K3gIqmtuhnHhbSVnDvVE1ZNoKqj_TLmBHLTTWGn0Suk,10782
91
91
  pixeltable/functions/audio.py,sha256=h9JqgwQKoFO9MDhJofYO32idmA4dzLnnCrWjY1Aw820,4747
92
92
  pixeltable/functions/bedrock.py,sha256=MXULfnd2ZguOaUrKpaAzJRTx6tF-iPAaFYiYHogz5iI,4386
@@ -97,7 +97,7 @@ pixeltable/functions/gemini.py,sha256=ZIq92RwJeXFAcdQqEA3gXdrMs3h99E-bpFqCIlNwOR
97
97
  pixeltable/functions/globals.py,sha256=4x0S_eyWDuC-Hw-9tVXcLPwP1Gkwxr50AurtpQmHXGw,5057
98
98
  pixeltable/functions/groq.py,sha256=WvAitBpqopaSpXFeNaivxiozTglMcaNRVV-KKxE2UQA,3586
99
99
  pixeltable/functions/huggingface.py,sha256=wft4Z2K-wNT1J3NVFBu_5YHfo4WpeSvBqCxfwKfn49g,59945
100
- pixeltable/functions/image.py,sha256=OjKhyMfyRNZEBWTsQ5EWg84pHxFRwZql-rCsscczg7I,13910
100
+ pixeltable/functions/image.py,sha256=LyfO5-oyT8X4yJqVEbfVsWL5OzUyBiWnhfOk4LpXj24,13806
101
101
  pixeltable/functions/json.py,sha256=d7-AvwytUQtQYF_JnWJkptT_Yq0NgMpWfVk-m3U6qTY,807
102
102
  pixeltable/functions/llama_cpp.py,sha256=i7_3sJZve59sU9KZVDzqO-VtCEZ0d6sXOmgvKcQOZNk,4290
103
103
  pixeltable/functions/math.py,sha256=JSd4cIWYEL9um2gLbEqYkJmVa6BEK6FrilIZROzKD_w,4966
@@ -106,20 +106,21 @@ pixeltable/functions/ollama.py,sha256=aO1OD8h9kB6Y8wdPC8Ha9mmQiSN5R_MmPuJAe_KjhK
106
106
  pixeltable/functions/openai.py,sha256=OfvpEQlSIP5GeUY_jUcA5DBc0w7uBPw5fTP58FDkFQQ,28926
107
107
  pixeltable/functions/openrouter.py,sha256=M7_HUJhhQSXSXynyR6RFHlOt4oxCawChAOT-EKszmFQ,4654
108
108
  pixeltable/functions/replicate.py,sha256=sPvRGr0j0kCDc6Vz3mPUioFflApijukvZWJJUO2bqIQ,2429
109
+ pixeltable/functions/reve.py,sha256=FHq32vwC_Du5DcKbf4XzEIO2F0P2crBjf4ENM58OUrI,9885
109
110
  pixeltable/functions/string.py,sha256=8wQJiS8Xu3RJJZ6uaMvwSbT4yqREj8Seqdtg9nczvqY,25243
110
111
  pixeltable/functions/timestamp.py,sha256=_BRSBwY-moykqUBLDMJRMnH8iCcueuSVZdJE0uQyYHU,9094
111
112
  pixeltable/functions/together.py,sha256=NdKJbndfjHkZTKNyh_1S2F8773fegXQErkOKJrNfi_s,8817
112
113
  pixeltable/functions/twelvelabs.py,sha256=-hHiLwd9boqv7ieQRlU_iAN9jC9V0_Dz__91LQhK9zc,2938
113
114
  pixeltable/functions/util.py,sha256=uQNkyBSkTVMe1wbUI2Q0nz-mM3qPVTF86yK8c9OFIcE,954
114
- pixeltable/functions/video.py,sha256=MYoecuuGYxFHfZB59rdZgPm0EeoaenAfo27GzwO5v9k,35170
115
+ pixeltable/functions/video.py,sha256=55HhdoSYrDhAvKoKZNGw4RckkxjNng7eNiqmo5JDsZg,58006
115
116
  pixeltable/functions/vision.py,sha256=7LYDKaNLy8bR7jBfelUmESA-laB79kB16qboayZaQHs,15355
116
117
  pixeltable/functions/whisper.py,sha256=UeSH3J7GUc5hgcD6pSQMDVqbYaCHI_7efuiayMBBE8Y,3075
117
118
  pixeltable/functions/whisperx.py,sha256=FtSVNK9L_5MMD9s-deUPww9PJhHd8WQOnxbu911QAAA,7669
118
119
  pixeltable/functions/yolox.py,sha256=IXTE-1NDY7cQp94UDFu0wZjMMcTociUZc4GgEOcNU3I,3559
119
120
  pixeltable/index/__init__.py,sha256=97aFuxiP_oz1ldn5iq8IWApkOV8XG6ZIBW5-9rkS0vM,122
120
- pixeltable/index/base.py,sha256=1Ez4MJgrqtc0vdlLMtG3UZ76PSUjJ0ft7KUuRqrQHeg,1842
121
- pixeltable/index/btree.py,sha256=n4opR5Kj1BEqI9fBXMzSTjsfpdBtP3Lt92co1xqi9c8,2393
122
- pixeltable/index/embedding_index.py,sha256=zo1gdwjqnbUp1y3zkf2IeuWit-Q-psYmcpBUTp8HTGc,11373
121
+ pixeltable/index/base.py,sha256=sJBGrp4dIh6eB0TA7glj4vuHnlOEJcRXWJE3CO0S4Ww,1676
122
+ pixeltable/index/btree.py,sha256=8RtDW4rJ7f_CUPuTRZlZ35i9U5MowuQhSLE06SCHRZ4,2608
123
+ pixeltable/index/embedding_index.py,sha256=qLHYVR8TY_EFEABIFjHe3RxUV0-H3omjLuvzg7kPZm8,11382
123
124
  pixeltable/io/__init__.py,sha256=k8jlxi2IB_yA8yYTk9lf7qyuayxUbvs9xDuZcO77sFY,716
124
125
  pixeltable/io/datarows.py,sha256=okkRRYValloF4Ax1tEI0auqqYsTXO_OOaWhvidNAnK4,6138
125
126
  pixeltable/io/external_store.py,sha256=qCtnN2fvB5N3wtaN62PYYt52euU-Mnz3IeDDJ7JfVEY,14742
@@ -141,7 +142,7 @@ pixeltable/iterators/string.py,sha256=URj5edWp-CsorjN_8nnfWGvtIFs_Zh4VPm6htlJbFk
141
142
  pixeltable/iterators/video.py,sha256=62_smE_YlMY6FSC5xhYnUVXLl7JUCKlk9UptrvMuz_o,21551
142
143
  pixeltable/metadata/__init__.py,sha256=8ytwPwl2GkaS8JaBLneqT8jxxRDbsKaO52bRip8SpcI,3289
143
144
  pixeltable/metadata/notes.py,sha256=heoQFFkn_vo-vPO6K2_6gcE2LpL8Ca_2wjsUNcN7_0E,1598
144
- pixeltable/metadata/schema.py,sha256=qR6vKKwClSqfyDAUKKZmVIgtYZHGirdp7Dma4KivYBI,13808
145
+ pixeltable/metadata/schema.py,sha256=uQ5SqifIqidR1QIRbbCEOMxpB5Br1sbVu-Uatq6oPEA,12855
145
146
  pixeltable/metadata/utils.py,sha256=ocun76zdpgoj1BHROQNZZXxhQ_aQwmuKfXRM2iSmTxY,2630
146
147
  pixeltable/metadata/converters/convert_10.py,sha256=myYIo1DyccnsQUxDKG6mafnU5ge_EhZpHg_pesKBoK4,708
147
148
  pixeltable/metadata/converters/convert_12.py,sha256=Ci-qyZW1gqci-8wnjeOB5afdq7KTuN-hVSV9OqSPx8g,162
@@ -176,18 +177,22 @@ pixeltable/metadata/converters/convert_40.py,sha256=qtsbIGv_YcMKswsSam2PBsspIl0m
176
177
  pixeltable/metadata/converters/util.py,sha256=fZxlSMLKpl3ZcjPYHkCXWauM3RuCjUKS4HRQ1ru0uWI,7671
177
178
  pixeltable/mypy/__init__.py,sha256=cD_oHXClR_bDM8qVNIfaOAgRhQjPfcWvLcinz79ua6o,54
178
179
  pixeltable/mypy/mypy_plugin.py,sha256=_eV2PtFDLUztb-QlysdEmF4qzVDALEQkH8aapbLYqy4,5438
179
- pixeltable/share/__init__.py,sha256=PTX1mw61Ss4acEOI-sUlu0HaoVsosLqwDfh0ldn8Hkg,84
180
- pixeltable/share/packager.py,sha256=SD9ictoaXw-zLZQ-jEvg4sY86zwHZKveTnyJzT_mzaE,38509
181
- pixeltable/share/publish.py,sha256=xFxSg5pu-z5ULtWOeyzO0KQNcTjepguVKhdukqclKOY,10883
180
+ pixeltable/share/__init__.py,sha256=5NafGEUosRUQW61lj2dq4O3NAj8EehT9iK81mvh7Kis,105
181
+ pixeltable/share/packager.py,sha256=3UKTC9u2M0_aLAbz6rsL8nkO5kAtD45tAiEbfyTswcg,38837
182
+ pixeltable/share/publish.py,sha256=0u-Wcy_1VOwkVwcJV9oBKAzgznnlQnxZxforJWBoPuE,11903
183
+ pixeltable/share/protocol/__init__.py,sha256=IS51n0-RYDy5ET2d2Y17Agevr8TYbKN8xRWiV_TJ1MQ,786
184
+ pixeltable/share/protocol/common.py,sha256=qJjlk9NJKgb85JKCdTloPvSlBVFNFs5xRY5slT90T3s,6082
185
+ pixeltable/share/protocol/operation_types.py,sha256=yr0id4nsihUaGnb2gS9HQ0sG9mIGSmllCzqgdreyGeg,959
186
+ pixeltable/share/protocol/replica.py,sha256=6Z6oLPC8o9hQtQrGV4x7wG3DwahsTd8PV15w0byM524,3283
182
187
  pixeltable/utils/__init__.py,sha256=DWylt_1U2PzSK047uiIhWcjykG19UtqXBey_f_TKUzM,1697
183
188
  pixeltable/utils/arrow.py,sha256=W48Rg5glpP7cdPblymY88HWuqpzLDb-vU-ohyJycnoc,10316
184
- pixeltable/utils/av.py,sha256=mtcguRdTiXKgHMHar_n3bkvdE448zqABlQ9tbrfSvlw,6790
189
+ pixeltable/utils/av.py,sha256=rj-ksxiW-88dHjBZ5J3a49iaHDNlzfP9B199ka97OX0,9442
185
190
  pixeltable/utils/azure_store.py,sha256=rGseJ1N71SFo4LjoRXwnv7LMAnK_6zUZxhzH2nL7xA0,12716
186
191
  pixeltable/utils/coco.py,sha256=Y1DWVYguZD4VhKyf7JruYfHWvhkJLq39fzbiSm5cdyY,7304
187
192
  pixeltable/utils/code.py,sha256=1WdqqWIG6_L0Ye1eWiJi9Jrb0v1XINKUy7V9esYh3oE,1249
188
193
  pixeltable/utils/console_output.py,sha256=Xodh5K3bI_2WsL6ySTVHXM7S3FZKi7RLwIqFIxip-mg,1232
189
194
  pixeltable/utils/coroutine.py,sha256=d87kLlkVIZq2u0kTE7kJ5Tc_yjEkdGi5sXAuxjLLxXY,896
190
- pixeltable/utils/dbms.py,sha256=WgPitGjA1f3r7lgy7OOK8DNBdWQ1f2TiG8-DMofz7_A,3033
195
+ pixeltable/utils/dbms.py,sha256=IibwfOlQlOwJA99EPsXLUV_JhOydzeElOm5dawuOl7Y,3165
191
196
  pixeltable/utils/description_helper.py,sha256=kqNduYCN6a68q3zPyyfU9_CXDiuB28AGBSqcznubefs,3690
192
197
  pixeltable/utils/documents.py,sha256=vYwr6yyNsSIS7VHXVL3kop7i9nLVRIO6MFnXzjU_rTU,3062
193
198
  pixeltable/utils/exception_handler.py,sha256=KW-m5uzv42sH9l6zfwgnDLaiR5sSwvq3JTOdlCwfX0w,1450
@@ -196,7 +201,7 @@ pixeltable/utils/formatter.py,sha256=uEbEAC-d72dKf18RXxQerPLRnjVJMKL5vNIRt5CJz_I
196
201
  pixeltable/utils/gcs_store.py,sha256=L4AKuB_t2ACpu9dRhK0rZWc7ouzyhdb_Aclq1vBS_oU,11351
197
202
  pixeltable/utils/http_server.py,sha256=6khOAtpVj1lDIm9Dx8VIECLm87cFEp4IFbAg8T92A2o,2441
198
203
  pixeltable/utils/iceberg.py,sha256=COeNqqy5RRMkDGLS8CTnaUeAccG10x2fwP3e1veuqIA,522
199
- pixeltable/utils/image.py,sha256=3KwtA106LT0pxtPV8EiCvpkfeNBVpjfvzkoC5PBOD74,262
204
+ pixeltable/utils/image.py,sha256=xQNyfylvPnDnmJrHQI9URzzbieIpq5qyK7QLod_hezU,545
200
205
  pixeltable/utils/lancedb.py,sha256=Otr-t47YACRo0Cq9-FyelcUuan1Kgs4gxCOpLOckj3s,2988
201
206
  pixeltable/utils/local_store.py,sha256=pBhlJw3jkMXsoT-ND5k1TvFkUpAElMQbPWbHV9kaa3M,13480
202
207
  pixeltable/utils/misc.py,sha256=HxTAxPVrZGtPPDGefXzzprYlT8TGiZa4mZkfHNsfdWs,137
@@ -206,8 +211,8 @@ pixeltable/utils/pytorch.py,sha256=77x2g4N6dkfYvqbxjYi_rBRiNnMMZAb2cNtBw0hOCHg,3
206
211
  pixeltable/utils/s3_store.py,sha256=rpUrgMbrI06AE2TnQTODjkspo9OutOX6knCeTrShhXA,16657
207
212
  pixeltable/utils/sql.py,sha256=Sa4Lh-VGe8GToU5W7DRiWf2lMl9B6saPqemiT0ZdHEc,806
208
213
  pixeltable/utils/transactional_directory.py,sha256=OFKmu90oP7KwBAljwjnzP_w8euGdAXob3y4Nx9SCNHA,1357
209
- pixeltable-0.4.19.dist-info/METADATA,sha256=48rO91oPMrBigGCL_Ve82z7ojIHz6n7L2KdEz6ipefw,25521
210
- pixeltable-0.4.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
211
- pixeltable-0.4.19.dist-info/entry_points.txt,sha256=rrKugZmxDtGnXCnEQ5UJMaaSYY7-g1cLjUZ4W1moIhM,98
212
- pixeltable-0.4.19.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
213
- pixeltable-0.4.19.dist-info/RECORD,,
214
+ pixeltable-0.4.20.dist-info/METADATA,sha256=Q36F-nXu5Tqd3na65Tq8whGnxzbQ1Yy_j4LaQlyI6qs,25549
215
+ pixeltable-0.4.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
216
+ pixeltable-0.4.20.dist-info/entry_points.txt,sha256=rrKugZmxDtGnXCnEQ5UJMaaSYY7-g1cLjUZ4W1moIhM,98
217
+ pixeltable-0.4.20.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
218
+ pixeltable-0.4.20.dist-info/RECORD,,