dt2 — DataTables v2 for Shiny for Python 
A Python port of the R DT2 package: an anywidget binding for DataTables v2, designed for Shiny for Python (and usable in Jupyter).
It configures DataTables via plain Python (1:1 with the JS API), reusing the same DataTables runtime (2.3.4) and extensions as the R package.
📖 Documentation: https://strategicprojects.github.io/dt2py/ · 📦 PyPI: https://pypi.org/project/dt2/
Status: feature-complete toward R parity, pre-release. Config, all 15 extensions, server-side processing, proxy, events and inline inputs are implemented and unit-tested. The live in-browser Comm transport has not yet been visually verified. See ROADMAP.md and CHANGELOG.md.
Install (dev)
npm install && npm run build # build the JS bundle into src/dt2/static/
uv venv && uv pip install -e ".[shiny,pandas]"
(The built bundle is committed, so an installed wheel needs no Node toolchain.)
Quick start
import pandas as pd
from shiny import App, ui
from shinywidgets import output_widget, render_widget
from dt2 import dt2
df = pd.read_csv("data.csv")
app_ui = ui.page_fluid(output_widget("tbl"))
def server(input, output, session):
@render_widget
def tbl():
return dt2(df, select=True, pageLength=10)
app = App(app_ui, server)
Configure with Options
Chainable builder mirroring the R pipe helpers:
from dt2 import Options, JS, dt2
opts = (Options(df)
.cols_align(["revenue"], "right")
.format_number(["revenue"], thousands=".", decimal=",", digits=2, prefix="R$ ")
.format_datetime(["updated"], from_="YYYY-MM-DD", to="DD/MM/YYYY")
.cols_render(["score"], JS("function(d,t){ return t==='display' ? d+'%' : d; }"))
.order(("revenue", "desc"))
.length_menu([10, 25, -1]))
dt2(df, options=opts)
JS(...) is the parity for htmlwidgets::JS(): the source is revived into a
real function in the browser, with DataTable, $ and moment in scope.
Extensions
All 15 DataTables extensions are bundled; activate via Options:
opts = (Options(df)
.buttons(["copyHtml5", "csvHtml5", "excelHtml5"]) # jszip bundled; PDF needs pdfmake
.select({"style": "os"})
.responsive()
.fixed_header()
.row_group("field"))
dt2.extensions() lists what is bundled.
Server-side processing
Keep large data Python-side; DataTables fetches pages over the Comm:
dt2(big_df, server_side=True, pageLength=25)
Filtering/ordering/paging run in dt2.server.process_ssp.
Proxy, events and inline inputs
# proxy (Python -> table): call on the rendered widget
tbl.widget.search("ada")
tbl.widget.order(("field", "desc"))
tbl.widget.select_rows([1, 3])
# events (table -> Python): read reactively
from shinywidgets import reactive_read
reactive_read(tbl.widget, "selected_rows") # also: state, row_check, row_button
# inline row inputs
opts = Options(df).col_checkbox("select", value_col="active").col_button("act", label="Ping")
See examples/ for runnable apps:
app.py, app_config.py, app_extensions.py, app_serverside.py,
app_proxy_inputs.py.
How it relates to the R package
The DataTables runtime is shared conceptually with R DT2. What differs is the
transport: R talks to Shiny via window.Shiny; here the widget talks to the
Python kernel over the anywidget Comm, bridged to Shiny reactivity by
shinywidgets. The htmlwidgets::JS() mechanism becomes the JS() marker +
client-side reviver. See the header of js/index.js for the full mapping.
Authors
- André Leite (maintainer) — Universidade Federal de Pernambuco
- Hugo Vasconcelos — Universidade Federal de Pernambuco
- Diogo Bezerra — Universidade Federal de Pernambuco
- Marcos Wasiliew
- Carlos Amorim — Universidade Federal de Pernambuco
License
MIT © André Leite
Release files for dt2 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dt2-0.1.2.tar.gz | 277.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dt2-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 525.1 kB
Release files / dt2-0.1.2.tar.gz
| Download URL | dt2-0.1.2.tar.gz |
|---|---|
| Size | 277.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b981b9bde48b873b16c77bd6e6ea58bfeb83de77d9a8c87ffe2ca640bb2f925b
|
|
BLAKE2b-256 checksum How to use checksums |
0f6c8367cbc76906815e6dfee0b925f6c27de0b56a2f04b592edf3eb50c1eecb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency logRelease files / dt2-0.1.2-py3-none-any.whl
| Download URL | dt2-0.1.2-py3-none-any.whl |
|---|---|
| Size | 247.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17751a53465477128410e19a0db111dcae0b961d0e8beb94daa27e4f3ee41d68
|
|
BLAKE2b-256 checksum How to use checksums |
6447422d96bf1cda8c96df8466c1674d7c35d9b360c82d7ec8a04204461442d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log