Skip to main content

Lifecycle

new

Table.new(
    name: str,
    description: Optional[str] = None,
    columns: Optional[list[ColumnSpec]] = None,
) -> Table
Create a new table. Pass columns to seed the schema in one call; omit it to start empty and add columns later with add_column / add_columns. Parameters
name
str
required
Display name of the table.
description
Optional[str]
default:"None"
Free-text description shown in the platform UI.
columns
Optional[list[ColumnSpec]]
default:"None"
Initial column schema. See ColumnSpec.
Returns
returns
Table
The new Table instance.

fetch

Table.fetch(
    id: Optional[str] = None,
    name: Optional[str] = None,
    username: Optional[str] = None,
    org_name: Optional[str] = None,
) -> Table
Fetch by id or name. Exactly one is required. username and org_name scope name-fetches to a specific owner.

list

Table.list(limit: int = 20, offset: int = 0) -> list[Table]
Paginated list of the tables visible to the API key’s org.

update

Table.update(name: Optional[str] = None) -> Table
Rename the table. Mutates self and returns it.

duplicate

Table.duplicate(new_name: Optional[str] = None) -> Table
Server-side copy of the table (schema + rows). Pass new_name to set the duplicate’s name; otherwise the server auto-generates one.

delete

Table.delete() -> None
Permanently delete the table.

Column schema

add_column

Table.add_column(
    name: str,
    format: ColumnFormat,
    generation: Optional[ColumnGenerator] = None,
    display_name: Optional[str] = None,
    required: bool = False,
    default: Any = None,
) -> Column
Add a single column. format is one of the ColumnFormat variants. generation binds the column to a PipelineGenerator or AgentGenerator — see ColumnGenerator.

add_columns

Table.add_columns(
    columns: list[ColumnSpec] | dict[str, str],
) -> list[Column]
Add multiple columns in one call. Accepts either a list of ColumnSpec (recommended) or a shorthand {name: kind_string} dict for quick smoke tests.
# Shorthand
t.add_columns({"vendor": "string", "amount": "int", "status": "string"})

# Typed
t.add_columns([
    ColumnSpec(name="vendor", format=StringFormat()),
    ColumnSpec(name="amount", format=NumberFormat(number_kind=NumberKind.FLOAT)),
])

rename_column

Table.rename_column(name: str, new_name: str) -> None

delete_column

Table.delete_column(name: str) -> None

update_column

Table.update_column(
    name: str,
    format: ColumnFormat,
    *,
    display_name: Optional[str] = None,
) -> Column
Change a column’s format and/or display_name. Existing cell values must be coercible to the new format.

list_columns

Table.list_columns() -> list[Column]
Returns the current column descriptors. table.columns exposes the same list as an attribute.

Row CRUD

read_rows returns one page (about 1,000 rows by default). To iterate over every matching row in a larger table, use scroll / ascroll instead — same filters and columns arguments, but it pages through the whole result set for you.

insert_row

Table.insert_row(values: dict[str, Any]) -> None
Insert a single row. Keys are column names; values are coerced via the column format. Returns None — use insert_rows when you need the inserted count, or follow up with read_rows(filters=...) to inspect.

insert_rows

Table.insert_rows(rows: list[dict[str, Any]]) -> InsertRowsResult
Bulk insert. Returns an InsertRowsResult with success and rows_inserted.
If rows have different shapes (different rows omit different columns), bulk insert can fail. Fall back to one insert_row call per row that’s missing columns the others have — your dense rows can still go through insert_rows.

read_rows

Table.read_rows(
    filters: Optional[CompoundFilter] = None,
    columns: Optional[list[str]] = None,
) -> RowsPage
Read rows that match filters. Pass columns to project only specific column names. Returns a RowsPage with rows and a total count. Capped at one page (~1,000 rows by default) — use scroll to iterate past that.

update_rows

Table.update_rows(values: dict[str, Any], filters: CompoundFilter) -> int
Apply a partial update to every row matched by filters. filters is required to prevent accidental table-wide updates. Returns the number of rows touched. If you really do want to clear the table, call clear instead.

delete_rows

Table.delete_rows(filters: CompoundFilter) -> int
Delete every row matched by filters. filters is required.

clear

Table.clear() -> None
Drop every row in the table while keeping the schema. Use this instead of delete_rows when you genuinely want to empty the table.

scroll

Table.scroll(
    page_size: int = 200,
    filters: Optional[CompoundFilter] = None,
    columns: Optional[list[str]] = None,
) -> Iterator[RowsPage]
Iterate over all matching rows in fixed-size pages. The iterator stops cleanly at the last page; no trailing empty page is yielded when the row count is a multiple of page_size.
for chunk in t.scroll(page_size=500):
    process(chunk["rows"])

Running generators

A column with a PipelineGenerator or AgentGenerator attached gets its cells filled by table.run(columns=[...]). Without generator columns, run is a no-op.

run

Table.run(
    columns: list[str],
    filters: Optional[CompoundFilter] = None,
) -> TableRunTask
Start filling the named generator columns. Returns a TableRunTask — poll via run_status(task_id) or block via run_and_wait. filters scopes which rows are updated.

run_status

Table.run_status(task_id: str) -> TableRunTask

run_and_wait

Table.run_and_wait(
    columns: list[str],
    filters: Optional[CompoundFilter] = None,
    timeout: float = 600.0,
    poll_interval: float = 1.0,
) -> TableRunTask
Blocking variant of run. Raises TableRunTimeout on timeout, TableRunFailed if the task ends in FAILED.

Aggregation

aggregate

Table.aggregate(
    aggregations: list[tuple[str, AggregationType]],
    filters: Optional[CompoundFilter] = None,
) -> AggregationResult
Compute one or more aggregations over the rows matched by filters. Each (column, AggregationType) pair returns one value. See AggregationType for the 21 supported functions (SUM, AVERAGE, MEDIAN, MIN, MAX, RANGE, STANDARD_DEVIATION, UNIQUE, EARLIEST_DATE, …).
The result map is keyed by column name, so passing two aggregations on the same column in a single call will only return one of them. Issue one aggregate(...) call per (column, type) pair when you need multiple aggregations on the same column.

Import / export

import_file

Table.import_file(
    file: str | Path | bytes,
    column_mapping: Optional[dict[str, str]] = None,
    custom_headers: Optional[list[str]] = None,
    format: ImportFormat = ImportFormat.AUTO,
) -> TableImportTask
Bulk-load rows from a CSV or XLSX file. column_mapping maps file-column names to table-column names. custom_headers lets you supply headers when the file has none. format defaults to AUTO (sniff by extension).

import_file_status

Table.import_file_status(task_id: str) -> TableImportTask

import_file_and_wait

Table.import_file_and_wait(
    file: str | Path | bytes,
    column_mapping: Optional[dict[str, str]] = None,
    custom_headers: Optional[list[str]] = None,
    format: ImportFormat = ImportFormat.AUTO,
    timeout: float = 600.0,
    poll_interval: float = 1.0,
) -> TableImportTask
Blocking variant. Raises TableImportTimeout / TableImportFailed.

export

Table.export(
    format: ExportFormat = ExportFormat.CSV,
    filters: Optional[CompoundFilter] = None,
) -> TableExportResult
Synchronous export to CSV or Excel. For small exports the server returns the file bytes inline as content. For large exports the server streams to object storage and content is empty — use s3_key (and s3_url if provided) to fetch the file.

Queries

raw_query

Table.raw_query(query: str) -> list[Row]
Run a raw SQL SELECT against the underlying table. Returns a list of Row.

nl_query

Table.nl_query(query: str) -> NlQueryResult
Server-side natural-language → SQL. Returns an NlQueryResult with an answer and the intermediate dataframes.

Serialization

to_dict

Table.to_dict() -> dict[str, Any]
Return the table as a plain dict.

Types

ColumnSpec

ColumnSpec(
    name: str,
    format: ColumnFormat,
    display_name: Optional[str] = None,
    generation: Optional[ColumnGenerator] = None,
    required: bool = False,
    default: Optional[Any] = None,
)
Input shape for Table.add_column[s] and Table.new(columns=...). Pairs a column name with a typed ColumnFormat and an optional ColumnGenerator.

Column

Returned by list_columns() / table.columns.
FieldTypeNotes
namestrColumn name (used as the dict key in row values)
kindColumnKindThe resolved column kind
display_nameOptional[str]UI label
requiredboolWhether the column rejects nulls on insert
rawOptional[dict]The full server-side descriptor

ColumnFormat

A column’s format is one of the variants below. Each variant carries a kind literal identifying it.

StringFormat

StringFormat(kind="string")

BoolFormat

BoolFormat(kind="bool")

NumberFormat

NumberFormat(
    kind="number",
    number_kind: NumberKind = NumberKind.FLOAT,
    decimals: Optional[int] = None,
    separator: Optional[str] = None,
    symbol: Optional[str] = None,       # currency symbol
    abbreviation: Optional[str] = None, # "K" / "M" / "B" / ""
)

TimestampFormat

TimestampFormat(
    kind="timestamp",
    format: str = "yyyy-MM-dd HH:mm",
    display_timezone: bool = False,
)

SingleSelectFormat / MultiSelectFormat

SingleSelectFormat(kind="single_select", options=[SelectOption(...)])
MultiSelectFormat(kind="multi_select",   options=[SelectOption(...)])

SelectOption

SelectOption(id: str, label: str, color: Optional[str] = None)

FileFormat / AudioFormat / ImageFormat

FileFormat(kind="file")
AudioFormat(kind="audio")
ImageFormat(kind="image")

KnowledgeBaseFormat

KnowledgeBaseFormat(kind="knowledge_base")

ListOfFilesFormat / ListOfStringsFormat

ListOfFilesFormat(kind="list_of_files")
ListOfStringsFormat(kind="list_of_strings")

ColumnGenerator

Two variants today: PipelineGenerator and AgentGenerator. Attach one to ColumnSpec.generation to make a column AI-filled.

PipelineGenerator

PipelineGenerator(
    kind="pipeline",
    pipeline: Pipeline,
    input_mapping: dict[str, str] = {},
    output_name: str,
    auto_execute: bool = False,
)
Fills a cell by running the bound Pipeline once per row.
  • input_mappingkeys are pipeline input names, values are table-column names. For each row, the engine reads the value of the named column and passes it into the matching pipeline input. Example: {"vendor_name": "vendor", "raw_notes": "notes"} sends the row’s vendor value to the vendor_name input and the notes value to raw_notes.
  • output_name — which pipeline output to write into the cell.
  • auto_execute=True — the engine fires the pipeline as new rows arrive instead of waiting for an explicit table.run(...).

AgentGenerator

AgentGenerator(
    kind="agent",
    agent: Agent,
    instructions: str,
    auto_execute: bool = False,
    knowledge_base: Optional[KnowledgeBase] = None,
    input_mapping: dict[str, str] = {},
)
Fills a cell by sending the row through an Agent.
  • instructions — the per-cell prompt template the agent runs against each row.
  • input_mappingkeys are agent input names, values are table-column names. For each row, the engine reads the value of the named column and passes it into the matching agent input.
  • knowledge_base (optional) — gives the agent retrieval context for the cell.
  • auto_execute=True — the engine fires the agent as new rows arrive instead of waiting for an explicit table.run(...).

CompoundFilter

CompoundFilter(
    groups: list[FilterGroup] = [],
    group_logical_operator: RelationalOperator = RelationalOperator.AND,
)
The top-level filter shape consumed by every query verb. Groups join via group_logical_operator; within each FilterGroup, conditions join via that group’s logical_operator. Builders
MethodWhat it does
CompoundFilter.of(*conditions, logical_operator=AND)Shorthand for a single-group filter
.order_by(column, desc=False)Add a sort key (chainable for multi-key sort)
.group_sort_by(column, desc=False)Sort the groups themselves
.paginate(limit, offset=0)Add a limit / offset pair
All builders return a new CompoundFilter (the dataclass is frozen).

FilterGroup

FilterGroup(
    conditions: list[FilterCondition],
    logical_operator: RelationalOperator = RelationalOperator.AND,
)

FilterCondition

FilterCondition(field: str, operator: TableFilterOperator, value: Any)
A single leaf condition: “the value of column field should satisfy operator against value”. value is the Python value for that column — bool, int, float, str, datetime, list, or None — and the SDK encodes it for the wire.

TableFilterOperator

The 13 operators you can pass to a FilterCondition, grouped by what they do. Equality and set membership
OperatorMatches a row when the column value…
EQ…equals value.
NEQ…does not equal value. Rows where the column is NULL are included — NEQ treats a missing value as “not literally equal”.
IS_IN…is one of the entries in the list value (e.g. IS_IN ["EU", "US"]).
IS_NOT_IN…is not in the list, and is not NULL.
FilterCondition("region", TableFilterOperator.EQ, "EU")
FilterCondition("region", TableFilterOperator.IS_IN, ["EU", "US"])
Ordering (numbers and timestamps)
OperatorMatches when the value is…
GT…strictly greater than value.
GTE…greater than or equal.
LT…strictly less than value.
LTE…less than or equal.
FilterCondition("priority", TableFilterOperator.GT, 5)
FilterCondition("created_at", TableFilterOperator.LTE, datetime(2026, 1, 1))
Text
OperatorMatches when the string column…
CONTAINS…contains value as a substring. Case-insensitive — searching for "a" matches "Acme".
DOES_NOT_CONTAIN…does not contain value. Case-insensitive.
FilterCondition("vendor", TableFilterOperator.CONTAINS, "acme")
Missing data
OperatorMatches when the value…
IS_EMPTY…is NULL. Pass None as the value.
IS_NOT_EMPTY…is set to anything.
FilterCondition("region", TableFilterOperator.IS_EMPTY, None)
Files
OperatorMatches when…
FILENAMES_CONTAIN…a file column holds a file whose filename contains value as a substring.
FilterCondition("attachment", TableFilterOperator.FILENAMES_CONTAIN, "invoice")

RelationalOperator

RelationalOperator.AND
RelationalOperator.OR

OrderByDirection

OrderByDirection.ASC
OrderByDirection.DESC

AggregationType

21 functions covering counts, percentages, numeric reductions, boolean truth-counts, and timestamp ranges:
GroupMembers
CountsEMPTY, FILLED, UNIQUE (+ PERCENT_*)
NumericSUM, MEDIAN, AVERAGE, MIN, MAX, RANGE, STANDARD_DEVIATION
BooleanTRUE_COUNT, FALSE_COUNT (+ PERCENT_*)
TimestampEARLIEST_DATE, LATEST_DATE, DATE_RANGE_DAYS, DATE_RANGE_MONTHS
Numeric reductions require numeric columns; boolean reductions require bool columns; timestamp reductions require timestamp columns.

ColumnKind

The resolved kind on a returned Column. One of: string, bool, int, float, currency, percent, timestamp, single_select, multi_select, file, audio, image, knowledge_base, list_of_files, list_of_strings.

NumberKind

NumberKind.INT
NumberKind.FLOAT
NumberKind.CURRENCY
NumberKind.PERCENT

ExportFormat

ExportFormat.CSV
ExportFormat.EXCEL

ImportFormat

ImportFormat.CSV
ImportFormat.XLSX
ImportFormat.AUTO   # sniff by file extension

RunStatus

RunStatus.PENDING
RunStatus.RUNNING
RunStatus.COMPLETED
RunStatus.FAILED

ImportStatus

Same four values as RunStatus.

Row

TypedDict:
{"row_id": int, "values": dict[str, Any]}

RowsPage

TypedDict:
{"rows": list[Row], "total": int}

InsertRowsResult

TypedDict:
{"success": bool, "rows_inserted": int}

AggregationResult

TypedDict:
{"aggregations": dict[str, int | float | str | bool | None]}

NlQueryResult

TypedDict:
{
    "answer": str,
    "dataframes": list[dict[str, Any]],
    "used_dataframes": NotRequired[list[str]],
}

TableExportResult

TypedDict:
{
    "filename": str,
    "content": bytes,
    "format": ExportFormat,
    "s3_key":  NotRequired[str],
    "s3_url":  NotRequired[str],
}

TableRunTask

Frozen dataclass — a poll handle for Table.run.
FieldType
task_idstr
table_idstr
statusRunStatus
columnslist[str]
rows_processedOptional[int]
errorOptional[str]

TableImportTask

Frozen dataclass — a poll handle for Table.import_file.
FieldType
task_idstr
table_idstr
statusImportStatus
rows_importedOptional[int]
errorOptional[str]

Errors

All Table errors inherit from TableError (which inherits from VectorshiftError).
ExceptionRaised when
TableErrorBase class — catch this for any table-layer error
TableNotFoundfetch cannot locate the table
TableSchemaErrorA column/format combination is rejected by the server, or an unknown column kind comes back from the server (likely SDK-behind-server skew)
TableValueErrorA cell value cannot be coerced to its column format
TableRunFailedA run task ended in FAILED
TableRunTimeoutrun_and_wait exceeded its timeout
TableImportFailedAn import_file task ended in FAILED
TableImportTimeoutimport_file_and_wait exceeded its timeout
Catch VectorshiftApiError from vectorshift.request for transport-level failures (HTTP 4xx/5xx).