bootstack.DataTable#
- class bootstack.DataTable(*, columns=None, rows=None, data_source=None, selection_mode='single', sorting_mode='single', searchable=True, allow_filter=True, paging_mode='standard', page_size=25, allow_add=False, allow_edit=False, allow_delete=False, allow_export=False, export_formats=None, striped=True, density='default', allow_group=False, show_status_bar=True, show_column_chooser=False, show_selection_controls=False, id_field='id', form=None, parent=None, **kwargs)#
Bases:
PublicWidgetBaseA feature-rich data table with sorting, filtering, search, and grouping.
Backed by an in-memory
SqliteDataSourceby default. Supplyrows=to pre-load data, or pass an existingdata_source=to share any data source that implements the data-source protocol (SqliteDataSource,MemoryDataSource,FileDataSource, or your own).- Parameters:
columns (list[str | ColumnSpec] | None) – Column definitions — a list of field-key strings, or
ColumnSpecdicts ('key','text','width','minwidth','anchor', and the editor keys'editor','editor_options','dtype','readonly','required'that shape the add/edit dialog).rows (list | None) – Initial data rows (list of dicts or sequences).
data_source (DataSourceProtocol | None) – Existing data source to use instead of creating one. Any object implementing the data-source protocol is accepted (
SqliteDataSource,MemoryDataSource,FileDataSource, or a custom source).selection_mode (SelectionMode) – Row selection behavior. Default
'single'.sorting_mode (Literal['single', 'none']) – Whether columns can be sorted. Default
'single'.searchable (bool) – Show the search bar. Default
True.allow_filter (bool) – Enable column filtering. Default
True.paging_mode (Literal['standard', 'virtual']) –
'standard'paginates the rows;'virtual'scrolls them in a single virtual view. Default'standard'.page_size (int) – Rows per page in standard paging mode. Default
25.allow_add (bool) – Allow adding rows via a form dialog. Default
False.allow_edit (bool) – Allow editing rows via a form dialog. Default
False.allow_delete (bool) – Allow deleting rows. Default
False.allow_export (bool) – Show an export menu (Copy to clipboard / Save to file). The actions export the selected rows if any are selected, otherwise all rows in the current filter/sort. Saves CSV; Excel (
.xlsx) is also offered when the optionalbootstack[excel]dependency is installed. For explicit control useexport_file()/to_csv()withscope=. DefaultFalse.export_formats (list[Literal['csv', 'tsv', 'xlsx', 'json', 'jsonl', 'xml', 'parquet', 'feather', 'hdf5']] | None) – Which formats the export menu offers. Default
('csv',). Formats needing an optional dependency (xlsx`→`bootstack[excel],parquet/feather`→`bootstack[parquet],hdf5`→`bootstack[hdf5]) appear only when it is installed. Registry formats export the displayed columns; for the full record set usedata_source.save(path).striped (bool) – Alternate row background colors. Default
True.density (WidgetDensity) – Row compactness —
'default'or'compact'(tighter row height, smaller body font and padding). Default'default'.allow_group (bool) – Allow grouping rows by a column. Default
False.show_status_bar (bool) – Show the footer — the filter/sort/group status and the pager. The pager auto-hides on a single page, and the whole footer collapses when there’s nothing to show. Default
True.show_column_chooser (bool) – Show a button to toggle column visibility. Default
False.show_selection_controls (bool) – Show a per-row checkbox in the leading icon slot while in
'multi'selection mode — filled with the accent when selected, a muted outline otherwise. With the checkboxes visible, a plain click toggles the row (no Ctrl/Shift needed). Has no effect in'single'mode (the row highlight is enough) or while grouped, where the slot holds the group’s expand/collapse control. DefaultFalse.id_field (str) – Record field used as the stable row identity. When your rows carry this field (default
'id'), its value becomes the row id used byselect_rows, events, andupdate_rows/delete_rows, so your own ids round-trip; otherwise an id is auto-assigned. Ignored when you pass your owndata_source(set it on the source instead). Default'id'.form (FormOptions | None) – Layout options for the built-in add/edit dialog — a
FormOptionsdict (col_count,min_col_width,scrollable,resizable).parent (Any) – Override the context-stack parent.
**kwargs (Any) – Layout placement options applied by the parent container —
fill,expand,anchor,margin,row,column,sticky. See Layout & Spacing.
- property data_source: DataSourceProtocol#
The underlying data source instance.
- property is_attached: bool#
Whether the widget is currently placed in its layout.
Truewhile the widget occupies space in its parent;Falseafterdetach(or before it has ever been placed). A detached widget keeps its state and can be returned to the layout withattach.
- property schedule: Schedule#
Scheduler tied to this widget’s lifetime.
All jobs are automatically cancelled when the widget is destroyed. First access creates the
Scheduleinstance; subsequent accesses return the same instance.Usage:
self.schedule.delay(500, callback) self.schedule.every(1000, tick) job = self.schedule.idle(refresh) job.cancel()
- property selection: dict | list[dict] | None#
The selected row(s) — the data bag.
In
'single'mode, the selected recorddict(orNonewhen nothing is selected). In'multi'mode, alistof record dicts (empty when nothing is selected). Each record carries its non-displayed fields too, indexed by key like any record. Read-only.
- attach(**kwargs)#
Return a detached widget to its layout, optionally moving it.
With no arguments, restores the widget to exactly where
detachtook it from. Any layout kwargs accepted by the original placement (e.g.fill,expand,anchor,sticky,margin) override the stored options. For stacked widgets,index=sets the position among the currently attached siblings (or pass an explicitbefore=/after=sibling); without one, the snapshotted position is used.Calling
attachon a widget that is already attached moves it (the kwargs are re-applied). Fireson_attach.- Parameters:
**kwargs (Any) – Layout placement options to override for this placement.
- Raises:
ParentResolutionError – If the widget was never placed in a layout.
- clear_filters()#
Remove all active column filters (leaves the search term intact).
- clear_grouping()#
Remove the active grouping.
- clear_search()#
Clear the free-text search term (leaves column filters intact).
- clear_selection()#
Clear the selection.
Users can also press
Escapeover the table to clear it — useful in single-select mode, where clicking cannot return to an empty selection.
- clear_sorting()#
Remove all active sort orders.
- collapse_all()#
Collapse all groups.
- delete_rows(rows_or_ids)#
Delete rows by record
idor by record dict.- Parameters:
rows_or_ids (list) – List of record ids or record dicts with an
idkey.
- deselect_rows(record_ids)#
Remove the given rows from the selection by record
id.- Parameters:
record_ids (list) – Record ids to deselect.
- destroy()#
Destroy the widget and release the resources it holds.
Removes the widget from its parent, destroys its children, and cancels any pending or repeating jobs on its
schedule. After this the widget must not be used again. Destroying a container destroys everything inside it.
- detach()#
Remove the widget from its layout without destroying it.
The widget stops occupying space but keeps its state, children, and event bindings, ready to be returned with
attach. The current position is snapshotted so a plainattach()restores it exactly — for stacked siblings this is the index among the currently attached siblings, so detaching other siblings first shifts that index.Calling
detachon a widget that is already detached, or one that was never placed in a layout, does nothing. Fireson_detach.
- edit_row(record_id)#
Open the built-in Edit Record dialog for a row and save on submit.
On save the row is updated and a
rows_updateevent fires (orrows_deleteif the user deletes it); the saved record is also returned.
- emit(event, *, data=None)#
Fire a named event on this widget, as if it produced the event itself.
This is how a composite widget surfaces high-level activity to its listeners, and the generic counterpart to the
on_*()shorthands for firing events that have no dedicated method.- Parameters:
event (str) – The event name, unprefixed — the same name you pass to
on()or anon_<event>()shorthand (e.g.'change','select').data (Any) – The payload delivered to handlers. For a data-carrying event, pass the matching payload dataclass from
bootstack.events— the same object anon_<event>()handler receives. Leave as None for native events (click, hover, focus, …), which carry no payload.
Example
widget.emit("change", data=bs.events.ChangeEvent(value=new_value))
- expand_all()#
Expand all groups.
- export_file(path, scope='all', *, format=None, chunk_size=1000, on_progress=None)#
Stream the data to
path, paging so memory stays flat.The format is inferred from the path extension (
.csv,.tsv,.xlsx) unlessformatis given..xlsxrequiresbootstack[excel].- Parameters:
path (str) – Destination file path.
scope (ExportScope) –
'all','page', or'selection'.format (ExportFormat | None) – Override the format —
'csv','tsv', or'xlsx'.chunk_size (int) – Rows read/written per batch.
on_progress (Callable[[int, int], Any] | None) – Called as
on_progress(written, total)after each batch.
- Returns:
The number of rows written.
- Return type:
- export_file_async(path, scope='all', *, format=None, chunk_size=1000, on_progress=None, on_done=None)#
Stream the data to
pathwithout blocking the UI; return a job.Writes one chunk per event-loop idle tick, so the UI stays responsive and the export can be cancelled mid-run via the returned job’s
cancel(). A cancelled or failed export removes the partial file.- Parameters:
path (str) – Destination file path.
scope (ExportScope) –
'all','page', or'selection'.format (ExportFormat | None) – Override the format —
'csv','tsv', or'xlsx'.chunk_size (int) – Rows read/written per idle tick.
on_progress (Callable[[int, int], Any] | None) – Called as
on_progress(written, total)after each chunk.on_done (Callable[[str, int, Any], Any] | None) – Called as
on_done(status, written, error)at the end, withstatusone of'completed','cancelled', or'error'.
- Returns:
A job handle with a
cancel()method.- Return type:
ExportJob
- get_clipboard()#
Return the current text contents of the system clipboard.
- Returns:
The clipboard text, or an empty string when the clipboard is empty or holds non-text data.
- Return type:
- get_filters()#
Return the active column filters as
{column_key: allowed_values}.
- get_grouping()#
Return the currently grouped column key, or
None.
- get_search()#
Return the active free-text search term.
- get_sorting()#
Return the current sort state as
{column_key: ascending}dict.
- go_to_page(index)#
Show the page at the given zero-based index.
- Parameters:
index (int) – Zero-based page index.
- group_by(column)#
Group rows by a column (collapsible group headers).
- Parameters:
column (str) – Column key to group by.
- iter_rows(scope='all', chunk_size=1000)#
Lazily yield record dicts one at a time, paging the data source.
Memory stays flat regardless of size — suitable for very large exports.
- Parameters:
scope (ExportScope) –
'all','page', or'selection'.chunk_size (int) – Rows read from the source per batch.
- new_row(defaults=None)#
Open the built-in New Record dialog and insert on save.
Honors each column’s editor configuration (
editor,dtype,readonly,required). On save the row is inserted and anrows_insertevent fires; the saved record is also returned here.
- next_page()#
Advance to the next page (no-op on the last page).
- on(event, handler=None)#
Bind
handlertoevent, or return a composableStream.With a handler — binds immediately and returns a
Subscription:sub = widget.on("change", handler) sub.cancel()
Without a handler — returns a
Streamfor operator chaining. The Tk binding is created lazily when.listen()is called:sub = widget.on("change").debounce(300).listen(handler) sub.cancel()
- Parameters:
event (str) – Event name (e.g.
"change","click").handler (Callable[[Any], Any] | None) – Optional callback. If omitted, a
Streamis returned.
- Returns:
Subscriptionwhen a handler is provided;Streamotherwise.- Return type:
- on_attach(handler=None)#
Register a callback fired when the widget enters the layout.
Fires each time the widget becomes visible in its parent — on initial placement and on every
attach. Pair it withon_detachto keep per-visibility resources (timers, observers) tied to the widget’s presence on screen. The handler receives a curatedEvent.- Parameters:
handler (Callable[[Event], Any] | None) – Called when the widget is attached. Omit to get a composable
Stream.- Returns:
A cancellable
Subscriptionwhen a handler is given, otherwise aStream.- Return type:
- on_destroy(handler=None)#
Register a callback fired when the widget is destroyed.
Fires once, as the widget is torn down — the place to release resources the widget owns that aren’t cleaned up automatically (file handles, observers, external subscriptions). The handler receives a curated
Event.- Parameters:
handler (Callable[[Event], Any] | None) – Called as the widget is destroyed. Omit to get a composable
Stream.- Returns:
A cancellable
Subscriptionwhen a handler is given, otherwise aStream.- Return type:
- on_detach(handler=None)#
Register a callback fired when the widget leaves the layout.
Fires each time the widget stops occupying space in its parent — on
detachand when an ancestor hides it. Pair it withon_attachto release per-visibility resources. The handler receives a curatedEvent.- Parameters:
handler (Callable[[Event], Any] | None) – Called when the widget is detached. Omit to get a composable
Stream.- Returns:
A cancellable
Subscriptionwhen a handler is given, otherwise aStream.- Return type:
- on_export() Stream#
- on_export(handler: Callable[[ExportEvent], Any]) Subscription
Fired after the data is exported (copied or saved).
- Parameters:
handler (Callable[[ExportEvent], Any] | None) – Called with an
ExportEvent(count,target—'clipboard'or'file'—format, andpath). Omit to get a composableStreaminstead.- Returns:
A cancellable
Subscriptionwhen a handler is given, otherwise aStream.- Return type:
- on_row_click() Stream#
- on_row_click(handler: Callable[[RowEvent], Any]) Subscription
Fired when a row is clicked.
- on_row_double_click() Stream#
- on_row_double_click(handler: Callable[[RowEvent], Any]) Subscription
Fired when a row is double-clicked.
- on_row_right_click() Stream#
- on_row_right_click(handler: Callable[[RowEvent], Any]) Subscription
Fired when a row is right-clicked.
- on_rows_delete() Stream#
- on_rows_delete(handler: Callable[[RowsEvent], Any]) Subscription
Fired after rows are deleted.
- on_rows_insert() Stream#
- on_rows_insert(handler: Callable[[RowsEvent], Any]) Subscription
Fired after rows are inserted.
- on_rows_move() Stream#
- on_rows_move(handler: Callable[[RowsEvent], Any]) Subscription
Fired after rows are reordered.
- on_rows_update() Stream#
- on_rows_update(handler: Callable[[RowsEvent], Any]) Subscription
Fired after rows are updated.
- on_select() Stream#
- on_select(handler: Callable[[SelectionEvent], Any]) Subscription
Fired when the set of selected rows changes.
- Parameters:
handler (Callable[[SelectionEvent], Any] | None) – Called with a
SelectionEvent(records,ids). Omit to get a composableStreaminstead.- Returns:
A cancellable
Subscriptionwhen a handler is given, otherwise aStream.- Return type:
- prev_page()#
Go to the previous page (no-op on the first page).
- scroll_to_row(record_id)#
Scroll the table so the row with the given
idis visible.- Parameters:
record_id (Any) – Record id of the row.
- select_all()#
Select all rows in the current view.
- select_rows(record_ids)#
Select rows by record
id.Only rows on the current page can be selected.
- Parameters:
record_ids (list) – Record ids of the rows to select.
- set_clipboard(text)#
Replace the system clipboard contents with
text.- Parameters:
text (str) – The text to place on the clipboard.
- set_filter(column, values=None)#
Filter a column to the given values, or clear it when
valuesis None.Composes with the search term and other column filters.
- set_rows(rows)#
Replace the entire dataset with
rows.- Parameters:
rows (list) – List of dicts (or sequences) to load.
- set_search(text)#
Set the free-text search term.
Searches across all columns. Leaves any active column filters intact.
- Parameters:
text (str) – The search term. Pass an empty string to clear the search.
- sort_by(column, ascending=True)#
Sort the table by a column.
- to_csv(scope='all', *, max_rows=100000)#
Return the data as a CSV string (materialized — small data).
For large datasets use
export_file(), which streams to disk.- Parameters:
scope (ExportScope) –
'all','page', or'selection'.max_rows (int | None) – Raise if the row count exceeds this.
Nonelifts the cap.
- to_rows(scope='all', *, max_rows=100000)#
Return the data as a list of record dicts (materialized — small data).
Loads every matching row into memory. For large datasets use
iter_rows()(streaming) orexport_file()instead.- Parameters:
scope (ExportScope) – Which rows —
'all'(the filtered set),'page'(current page), or'selection'(selected rows).max_rows (int | None) – Raise if the row count exceeds this. Pass
Noneto lift the cap (at your own memory risk).