pixeltable 0.4.5__py3-none-any.whl → 0.4.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pixeltable might be problematic. Click here for more details.

Files changed (55) hide show
  1. pixeltable/__init__.py +4 -2
  2. pixeltable/__version__.py +2 -2
  3. pixeltable/catalog/__init__.py +1 -1
  4. pixeltable/catalog/catalog.py +3 -3
  5. pixeltable/catalog/column.py +49 -0
  6. pixeltable/catalog/insertable_table.py +0 -7
  7. pixeltable/catalog/schema_object.py +1 -14
  8. pixeltable/catalog/table.py +139 -53
  9. pixeltable/catalog/table_version.py +30 -138
  10. pixeltable/catalog/view.py +2 -1
  11. pixeltable/dataframe.py +2 -3
  12. pixeltable/env.py +43 -5
  13. pixeltable/exec/expr_eval/expr_eval_node.py +2 -2
  14. pixeltable/exec/expr_eval/schedulers.py +36 -15
  15. pixeltable/exprs/array_slice.py +2 -2
  16. pixeltable/exprs/data_row.py +13 -0
  17. pixeltable/exprs/expr.py +9 -9
  18. pixeltable/exprs/function_call.py +2 -2
  19. pixeltable/exprs/globals.py +1 -2
  20. pixeltable/exprs/json_path.py +3 -3
  21. pixeltable/exprs/row_builder.py +14 -16
  22. pixeltable/exprs/string_op.py +3 -3
  23. pixeltable/func/query_template_function.py +2 -2
  24. pixeltable/func/signature.py +30 -3
  25. pixeltable/func/tools.py +2 -2
  26. pixeltable/functions/anthropic.py +75 -25
  27. pixeltable/functions/globals.py +2 -2
  28. pixeltable/functions/llama_cpp.py +9 -1
  29. pixeltable/functions/openai.py +74 -54
  30. pixeltable/functions/video.py +54 -1
  31. pixeltable/functions/vision.py +2 -2
  32. pixeltable/globals.py +74 -12
  33. pixeltable/io/datarows.py +3 -3
  34. pixeltable/io/fiftyone.py +4 -4
  35. pixeltable/io/globals.py +3 -3
  36. pixeltable/io/hf_datasets.py +4 -4
  37. pixeltable/io/pandas.py +6 -6
  38. pixeltable/io/parquet.py +3 -3
  39. pixeltable/io/table_data_conduit.py +2 -2
  40. pixeltable/io/utils.py +2 -2
  41. pixeltable/iterators/document.py +2 -2
  42. pixeltable/iterators/video.py +49 -9
  43. pixeltable/share/packager.py +45 -36
  44. pixeltable/store.py +5 -25
  45. pixeltable/type_system.py +5 -8
  46. pixeltable/utils/__init__.py +2 -2
  47. pixeltable/utils/arrow.py +5 -5
  48. pixeltable/utils/description_helper.py +3 -3
  49. pixeltable/utils/iceberg.py +1 -2
  50. {pixeltable-0.4.5.dist-info → pixeltable-0.4.7.dist-info}/METADATA +109 -59
  51. {pixeltable-0.4.5.dist-info → pixeltable-0.4.7.dist-info}/RECORD +64 -64
  52. {pixeltable-0.4.5.dist-info → pixeltable-0.4.7.dist-info}/WHEEL +1 -1
  53. pixeltable-0.4.7.dist-info/entry_points.txt +2 -0
  54. pixeltable-0.4.5.dist-info/entry_points.txt +0 -3
  55. {pixeltable-0.4.5.dist-info → pixeltable-0.4.7.dist-info/licenses}/LICENSE +0 -0
pixeltable/__init__.py CHANGED
@@ -1,11 +1,12 @@
1
1
  # ruff: noqa: F401
2
2
 
3
3
  from .__version__ import __version__, __version_tuple__
4
- from .catalog import Column, InsertableTable, Table, UpdateStatus, View
4
+ from .catalog import Column, ColumnMetadata, IndexMetadata, InsertableTable, Table, TableMetadata, UpdateStatus, View
5
5
  from .dataframe import DataFrame
6
6
  from .exceptions import Error, ExprEvalError, PixeltableWarning
7
- from .func import Aggregator, Function, expr_udf, mcp_udfs, query, retrieval_udf, uda, udf
7
+ from .func import Aggregator, Function, Tool, ToolChoice, Tools, expr_udf, mcp_udfs, query, retrieval_udf, uda, udf
8
8
  from .globals import (
9
+ DirContents,
9
10
  array,
10
11
  configure_logging,
11
12
  create_dir,
@@ -15,6 +16,7 @@ from .globals import (
15
16
  create_view,
16
17
  drop_dir,
17
18
  drop_table,
19
+ get_dir_contents,
18
20
  get_table,
19
21
  init,
20
22
  list_dirs,
pixeltable/__version__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # These version placeholders will be replaced during build.
2
- __version__ = '0.4.5'
3
- __version_tuple__ = (0, 4, 5)
2
+ __version__ = '0.0.0'
3
+ __version_tuple__ = (0, 0, 0)
@@ -8,7 +8,7 @@ from .insertable_table import InsertableTable
8
8
  from .named_function import NamedFunction
9
9
  from .path import Path
10
10
  from .schema_object import SchemaObject
11
- from .table import Table
11
+ from .table import ColumnMetadata, IndexMetadata, Table, TableMetadata
12
12
  from .table_version import TableVersion
13
13
  from .table_version_handle import ColumnHandle, TableVersionHandle
14
14
  from .table_version_path import TableVersionPath
@@ -103,7 +103,7 @@ def retry_loop(
103
103
  except PendingTableOpsError as e:
104
104
  Env.get().console_logger.debug(f'retry_loop(): finalizing pending ops for {e.tbl_id}')
105
105
  Catalog.get()._finalize_pending_ops(e.tbl_id)
106
- except sql.exc.DBAPIError as e:
106
+ except (sql.exc.DBAPIError, sql.exc.OperationalError) as e:
107
107
  # TODO: what other exceptions should we be looking for?
108
108
  if isinstance(e.orig, (psycopg.errors.SerializationFailure, psycopg.errors.LockNotAvailable)):
109
109
  if num_retries < _MAX_RETRIES or _MAX_RETRIES == -1:
@@ -356,7 +356,7 @@ class Catalog:
356
356
  # raise to abort the transaction
357
357
  raise
358
358
 
359
- except sql.exc.DBAPIError as e:
359
+ except (sql.exc.DBAPIError, sql.exc.OperationalError) as e:
360
360
  has_exc = True
361
361
  if isinstance(
362
362
  e.orig, (psycopg.errors.SerializationFailure, psycopg.errors.LockNotAvailable)
@@ -380,7 +380,7 @@ class Catalog:
380
380
  # we got this exception after getting the initial table locks and therefore need to abort
381
381
  raise
382
382
 
383
- except sql.exc.DBAPIError as e:
383
+ except (sql.exc.DBAPIError, sql.exc.OperationalError) as e:
384
384
  has_exc = True
385
385
  # we got some db error during the actual operation (not just while trying to get locks on the metadata
386
386
  # records): we convert these into Errors, if asked to do so, and abort
@@ -10,6 +10,7 @@ import sqlalchemy as sql
10
10
  import pixeltable.exceptions as excs
11
11
  import pixeltable.type_system as ts
12
12
  from pixeltable import exprs
13
+ from pixeltable.metadata import schema
13
14
 
14
15
  from .globals import MediaValidation, is_valid_identifier
15
16
 
@@ -126,6 +127,54 @@ class Column:
126
127
  # computed cols also have storage columns for the exception string and type
127
128
  self.sa_cellmd_col = None
128
129
 
130
+ def to_md(self, pos: Optional[int] = None) -> tuple[schema.ColumnMd, Optional[schema.SchemaColumn]]:
131
+ """Returns the Column and optional SchemaColumn metadata for this Column."""
132
+ assert self.is_pk is not None
133
+ col_md = schema.ColumnMd(
134
+ id=self.id,
135
+ col_type=self.col_type.as_dict(),
136
+ is_pk=self.is_pk,
137
+ schema_version_add=self.schema_version_add,
138
+ schema_version_drop=self.schema_version_drop,
139
+ value_expr=self.value_expr.as_dict() if self.value_expr is not None else None,
140
+ stored=self.stored,
141
+ )
142
+ if pos is None:
143
+ return col_md, None
144
+ assert self.name is not None, 'Column name must be set for user-facing columns'
145
+ sch_md = schema.SchemaColumn(
146
+ name=self.name,
147
+ pos=pos,
148
+ media_validation=self._media_validation.name.lower() if self._media_validation is not None else None,
149
+ )
150
+ return col_md, sch_md
151
+
152
+ @classmethod
153
+ def from_md(
154
+ cls, col_md: schema.ColumnMd, tbl: TableVersion, schema_col_md: Optional[schema.SchemaColumn]
155
+ ) -> Column:
156
+ """Create a Column from a ColumnMd."""
157
+ assert col_md.id is not None
158
+ col_name = schema_col_md.name if schema_col_md is not None else None
159
+ media_val = (
160
+ MediaValidation[schema_col_md.media_validation.upper()]
161
+ if schema_col_md is not None and schema_col_md.media_validation is not None
162
+ else None
163
+ )
164
+ col = cls(
165
+ col_id=col_md.id,
166
+ name=col_name,
167
+ col_type=ts.ColumnType.from_dict(col_md.col_type),
168
+ is_pk=col_md.is_pk,
169
+ stored=col_md.stored,
170
+ media_validation=media_val,
171
+ schema_version_add=col_md.schema_version_add,
172
+ schema_version_drop=col_md.schema_version_drop,
173
+ value_expr_dict=col_md.value_expr,
174
+ tbl=tbl,
175
+ )
176
+ return col
177
+
129
178
  def init_value_expr(self) -> None:
130
179
  from pixeltable import exprs
131
180
 
@@ -105,13 +105,6 @@ class InsertableTable(Table):
105
105
  Env.get().console_logger.info(f'Created table {name!r}.')
106
106
  return tbl
107
107
 
108
- def _get_metadata(self) -> dict[str, Any]:
109
- md = super()._get_metadata()
110
- md['base'] = None
111
- md['is_view'] = False
112
- md['is_snapshot'] = False
113
- return md
114
-
115
108
  @overload
116
109
  def insert(
117
110
  self,
@@ -1,5 +1,5 @@
1
1
  from abc import abstractmethod
2
- from typing import TYPE_CHECKING, Any, Optional
2
+ from typing import TYPE_CHECKING, Optional
3
3
  from uuid import UUID
4
4
 
5
5
  if TYPE_CHECKING:
@@ -41,19 +41,6 @@ class SchemaObject:
41
41
  path = Catalog.get().get_dir_path(self._dir_id)
42
42
  return str(path.append(self._name))
43
43
 
44
- def get_metadata(self) -> dict[str, Any]:
45
- """Returns metadata associated with this schema object."""
46
- from pixeltable.catalog import retry_loop
47
-
48
- @retry_loop(for_write=False)
49
- def op() -> dict[str, Any]:
50
- return self._get_metadata()
51
-
52
- return op()
53
-
54
- def _get_metadata(self) -> dict[str, Any]:
55
- return {'name': self._name, 'path': self._path()}
56
-
57
44
  @abstractmethod
58
45
  def _display_name(self) -> str:
59
46
  """
@@ -6,7 +6,7 @@ import json
6
6
  import logging
7
7
  from keyword import iskeyword as is_python_keyword
8
8
  from pathlib import Path
9
- from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Literal, Optional, Union, overload
9
+ from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Literal, Optional, TypedDict, overload
10
10
 
11
11
  from typing import _GenericAlias # type: ignore[attr-defined] # isort: skip
12
12
  import datetime
@@ -80,49 +80,70 @@ class Table(SchemaObject):
80
80
  conn.execute(stmt, {'new_dir_id': new_dir_id, 'new_name': json.dumps(new_name), 'id': self._id})
81
81
 
82
82
  # this is duplicated from SchemaObject so that our API docs show the docstring for Table
83
- def get_metadata(self) -> dict[str, Any]:
83
+ def get_metadata(self) -> 'TableMetadata':
84
84
  """
85
85
  Retrieves metadata associated with this table.
86
86
 
87
87
  Returns:
88
- A dictionary containing the metadata, in the following format:
89
-
90
- ```python
91
- {
92
- 'name': 'my_table',
93
- 'path': 'my_dir.my_subdir.my_table',
94
- 'base': None, # If this is a view or snapshot, will contain the name of its base table
95
- 'schema': {
96
- 'col1': StringType(),
97
- 'col2': IntType(),
98
- },
99
- 'is_replica': False,
100
- 'version': 22,
101
- 'version_created': datetime.datetime(...),
102
- 'schema_version': 1,
103
- 'comment': '',
104
- 'num_retained_versions': 10,
105
- 'is_view': False,
106
- 'is_snapshot': False,
107
- 'media_validation': 'on_write',
108
- }
109
- ```
88
+ A [TableMetadata][pixeltable.TableMetadata] instance containing this table's metadata.
110
89
  """
111
- return super().get_metadata()
112
-
113
- def _get_metadata(self) -> dict[str, Any]:
114
- md = super()._get_metadata()
115
- md['schema'] = self._get_schema()
116
- md['is_replica'] = self._tbl_version_path.is_replica()
117
- md['version'] = self._get_version()
118
- md['version_created'] = datetime.datetime.fromtimestamp(
119
- self._tbl_version_path.tbl_version.get().created_at, tz=datetime.timezone.utc
90
+ from pixeltable.catalog import retry_loop
91
+
92
+ @retry_loop(for_write=False)
93
+ def op() -> 'TableMetadata':
94
+ return self._get_metadata()
95
+
96
+ return op()
97
+
98
+ def _get_metadata(self) -> 'TableMetadata':
99
+ columns = self._tbl_version_path.columns()
100
+ column_info: dict[str, ColumnMetadata] = {}
101
+ for col in columns:
102
+ column_info[col.name] = ColumnMetadata(
103
+ name=col.name,
104
+ type_=col.col_type._to_str(as_schema=True),
105
+ version_added=col.schema_version_add,
106
+ is_stored=col.is_stored,
107
+ is_primary_key=col.is_pk,
108
+ media_validation=col.media_validation.name.lower() if col.media_validation is not None else None, # type: ignore[typeddict-item]
109
+ computed_with=col.value_expr.display_str(inline=False) if col.value_expr is not None else None,
110
+ )
111
+ # Pure snapshots have no indices
112
+ indices = self._tbl_version.get().idxs_by_name.values() if self._tbl_version is not None else {}
113
+ index_info: dict[str, IndexMetadata] = {}
114
+ for info in indices:
115
+ if isinstance(info.idx, index.EmbeddingIndex):
116
+ embeddings: list[str] = []
117
+ if info.idx.string_embed is not None:
118
+ embeddings.append(str(info.idx.string_embed))
119
+ if info.idx.image_embed is not None:
120
+ embeddings.append(str(info.idx.image_embed))
121
+ index_info[info.name] = IndexMetadata(
122
+ name=info.name,
123
+ columns=[info.col.name],
124
+ index_type='embedding',
125
+ parameters=EmbeddingIndexParams(
126
+ metric=info.idx.metric.name.lower(), # type: ignore[typeddict-item]
127
+ embeddings=embeddings,
128
+ ),
129
+ )
130
+ return TableMetadata(
131
+ name=self._name,
132
+ path=self._path(),
133
+ columns=column_info,
134
+ indices=index_info,
135
+ is_replica=self._tbl_version_path.is_replica(),
136
+ is_view=False,
137
+ is_snapshot=False,
138
+ version=self._get_version(),
139
+ version_created=datetime.datetime.fromtimestamp(
140
+ self._tbl_version_path.tbl_version.get().created_at, tz=datetime.timezone.utc
141
+ ),
142
+ schema_version=self._tbl_version_path.schema_version(),
143
+ comment=self._get_comment(),
144
+ media_validation=self._get_media_validation().name.lower(), # type: ignore[typeddict-item]
145
+ base=None,
120
146
  )
121
- md['schema_version'] = self._tbl_version_path.schema_version()
122
- md['comment'] = self._get_comment()
123
- md['num_retained_versions'] = self._get_num_retained_versions()
124
- md['media_validation'] = self._get_media_validation().name.lower()
125
- return md
126
147
 
127
148
  def _get_version(self) -> int:
128
149
  """Return the version of this table. Used by tests to ascertain version changes."""
@@ -455,7 +476,7 @@ class Table(SchemaObject):
455
476
 
456
477
  def add_columns(
457
478
  self,
458
- schema: dict[str, Union[ts.ColumnType, builtins.type, _GenericAlias]],
479
+ schema: dict[str, ts.ColumnType | builtins.type | _GenericAlias],
459
480
  if_exists: Literal['error', 'ignore', 'replace', 'replace_force'] = 'error',
460
481
  ) -> UpdateStatus:
461
482
  """
@@ -529,7 +550,7 @@ class Table(SchemaObject):
529
550
  self,
530
551
  *,
531
552
  if_exists: Literal['error', 'ignore', 'replace', 'replace_force'] = 'error',
532
- **kwargs: Union[ts.ColumnType, builtins.type, _GenericAlias, exprs.Expr],
553
+ **kwargs: ts.ColumnType | builtins.type | _GenericAlias | exprs.Expr,
533
554
  ) -> UpdateStatus:
534
555
  """
535
556
  Adds an ordinary (non-computed) column to the table.
@@ -774,7 +795,7 @@ class Table(SchemaObject):
774
795
  cls._verify_column(col)
775
796
  column_names.add(col.name)
776
797
 
777
- def drop_column(self, column: Union[str, ColumnRef], if_not_exists: Literal['error', 'ignore'] = 'error') -> None:
798
+ def drop_column(self, column: str | ColumnRef, if_not_exists: Literal['error', 'ignore'] = 'error') -> None:
778
799
  """Drop a column from the table.
779
800
 
780
801
  Args:
@@ -896,7 +917,7 @@ class Table(SchemaObject):
896
917
 
897
918
  def add_embedding_index(
898
919
  self,
899
- column: Union[str, ColumnRef],
920
+ column: str | ColumnRef,
900
921
  *,
901
922
  idx_name: Optional[str] = None,
902
923
  embedding: Optional[pxt.Function] = None,
@@ -1023,7 +1044,7 @@ class Table(SchemaObject):
1023
1044
  def drop_embedding_index(
1024
1045
  self,
1025
1046
  *,
1026
- column: Union[str, ColumnRef, None] = None,
1047
+ column: str | ColumnRef | None = None,
1027
1048
  idx_name: Optional[str] = None,
1028
1049
  if_not_exists: Literal['error', 'ignore'] = 'error',
1029
1050
  ) -> None:
@@ -1083,7 +1104,7 @@ class Table(SchemaObject):
1083
1104
 
1084
1105
  self._drop_index(col=col, idx_name=idx_name, _idx_class=index.EmbeddingIndex, if_not_exists=if_not_exists)
1085
1106
 
1086
- def _resolve_column_parameter(self, column: Union[str, ColumnRef]) -> Column:
1107
+ def _resolve_column_parameter(self, column: str | ColumnRef) -> Column:
1087
1108
  """Resolve a column parameter to a Column object"""
1088
1109
  col: Column = None
1089
1110
  if isinstance(column, str):
@@ -1102,7 +1123,7 @@ class Table(SchemaObject):
1102
1123
  def drop_index(
1103
1124
  self,
1104
1125
  *,
1105
- column: Union[str, ColumnRef, None] = None,
1126
+ column: str | ColumnRef | None = None,
1106
1127
  idx_name: Optional[str] = None,
1107
1128
  if_not_exists: Literal['error', 'ignore'] = 'error',
1108
1129
  ) -> None:
@@ -1421,7 +1442,7 @@ class Table(SchemaObject):
1421
1442
  return result
1422
1443
 
1423
1444
  def recompute_columns(
1424
- self, *columns: Union[str, ColumnRef], errors_only: bool = False, cascade: bool = True
1445
+ self, *columns: str | ColumnRef, errors_only: bool = False, cascade: bool = True
1425
1446
  ) -> UpdateStatus:
1426
1447
  """Recompute the values in one or more computed columns of this table.
1427
1448
 
@@ -1533,11 +1554,7 @@ class Table(SchemaObject):
1533
1554
  env.Env.get().console_logger.info(f'Linked external store `{store.name}` to table `{self._name}`.')
1534
1555
 
1535
1556
  def unlink_external_stores(
1536
- self,
1537
- stores: Optional[str | list[str]] = None,
1538
- *,
1539
- delete_external_data: bool = False,
1540
- ignore_errors: bool = False,
1557
+ self, stores: str | list[str] | None = None, *, delete_external_data: bool = False, ignore_errors: bool = False
1541
1558
  ) -> None:
1542
1559
  """
1543
1560
  Unlinks this table's external stores.
@@ -1579,7 +1596,7 @@ class Table(SchemaObject):
1579
1596
  env.Env.get().console_logger.info(f'Unlinked external store from table `{self._name}`: {store_str}')
1580
1597
 
1581
1598
  def sync(
1582
- self, stores: Optional[str | list[str]] = None, *, export_data: bool = True, import_data: bool = True
1599
+ self, stores: str | list[str] | None = None, *, export_data: bool = True, import_data: bool = True
1583
1600
  ) -> UpdateStatus:
1584
1601
  """
1585
1602
  Synchronizes this table with its linked external stores.
@@ -1657,7 +1674,7 @@ class Table(SchemaObject):
1657
1674
  from pixeltable.catalog import Catalog
1658
1675
 
1659
1676
  if n is None:
1660
- n = 1000_000_000
1677
+ n = 1_000_000_000
1661
1678
  if not isinstance(n, int) or n < 1:
1662
1679
  raise excs.Error(f'Invalid value for n: {n}')
1663
1680
 
@@ -1709,3 +1726,72 @@ class Table(SchemaObject):
1709
1726
  raise excs.Error(f'{self._display_str()}: Cannot {op_descr} a snapshot.')
1710
1727
  if self._tbl_version_path.is_replica():
1711
1728
  raise excs.Error(f'{self._display_str()}: Cannot {op_descr} a {self._display_name()}.')
1729
+
1730
+
1731
+ class ColumnMetadata(TypedDict):
1732
+ """Metadata for a column of a Pixeltable table."""
1733
+
1734
+ name: str
1735
+ """The name of the column."""
1736
+ type_: str
1737
+ """The type specifier of the column."""
1738
+ version_added: int
1739
+ """The table version when this column was added."""
1740
+ is_stored: bool
1741
+ """`True` if this is a stored column; `False` if it is dynamically computed."""
1742
+ is_primary_key: bool
1743
+ """`True` if this column is part of the table's primary key."""
1744
+ media_validation: Optional[Literal['on_read', 'on_write']]
1745
+ """The media validation policy for this column."""
1746
+ computed_with: Optional[str]
1747
+ """Expression used to compute this column; `None` if this is not a computed column."""
1748
+
1749
+
1750
+ class IndexMetadata(TypedDict):
1751
+ """Metadata for a column of a Pixeltable table."""
1752
+
1753
+ name: str
1754
+ """The name of the index."""
1755
+ columns: list[str]
1756
+ """The table columns that are indexed."""
1757
+ index_type: Literal['embedding']
1758
+ """The type of index (currently only `'embedding'` is supported, but others will be added in the future)."""
1759
+ parameters: EmbeddingIndexParams
1760
+
1761
+
1762
+ class EmbeddingIndexParams(TypedDict):
1763
+ metric: Literal['cosine', 'ip', 'l2']
1764
+ """Index metric."""
1765
+ embeddings: list[str]
1766
+ """List of embeddings defined for this index."""
1767
+
1768
+
1769
+ class TableMetadata(TypedDict):
1770
+ """Metadata for a Pixeltable table."""
1771
+
1772
+ name: str
1773
+ """The name of the table (ex: `'my_table'`)."""
1774
+ path: str
1775
+ """The full path of the table (ex: `'my_dir.my_subdir.my_table'`)."""
1776
+ columns: dict[str, ColumnMetadata]
1777
+ """Column metadata for all of the visible columns of the table."""
1778
+ indices: dict[str, IndexMetadata]
1779
+ """Index metadata for all of the indices of the table."""
1780
+ is_replica: bool
1781
+ """`True` if this table is a replica of another (shared) table."""
1782
+ is_view: bool
1783
+ """`True` if this table is a view."""
1784
+ is_snapshot: bool
1785
+ """`True` if this table is a snapshot."""
1786
+ version: int
1787
+ """The current version of the table."""
1788
+ version_created: datetime.datetime
1789
+ """The timestamp when this table version was created."""
1790
+ schema_version: int
1791
+ """The current schema version of the table."""
1792
+ comment: Optional[str]
1793
+ """User-provided table comment, if one exists."""
1794
+ media_validation: Literal['on_read', 'on_write']
1795
+ """The media validation policy for this table."""
1796
+ base: Optional[str]
1797
+ """If this table is a view or snapshot, the full path of its base table; otherwise `None`."""