Skip to content

fix(table): export menu works for plain-Python data without pandas/polars/pyarrow#9246

Merged
kirangadhave merged 4 commits intomainfrom
kg/default-df-export-btn-bug
Apr 17, 2026
Merged

fix(table): export menu works for plain-Python data without pandas/polars/pyarrow#9246
kirangadhave merged 4 commits intomainfrom
kg/default-df-export-btn-bug

Conversation

@kirangadhave
Copy link
Copy Markdown
Member

When using python dict or list(dict) with mo.ui.table without any dataframe library installed, the Export button was hidden.

DefaultTableManager.supports_download() checked for dataframe libraries and returned False. We now always show the download button. We can support csv, json, md with stdlib in python. If user selects parquet, we show a toast for missing packages and an install button.

The MissingPackagePrompt is mode-aware. In run mode where users cannot install packages it shows a Parquet export isn't available in this notebook without an install button.

Notes
The DefaultTableManager always uses csv lib even if pandas/polars is installed. Exporting actual dataframe objects is not affected.
We suggest polars instead of pyarrow because we already have a polars code path which is well tested

Screen.Recording.2026-04-17.at.10.27.37.AM.mov

@kirangadhave kirangadhave requested review from Light2Dark and mscolnick and removed request for Light2Dark April 17, 2026 17:56
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Apr 17, 2026 6:48pm

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes mo.ui.table export behavior when the table is backed by plain-Python data (dict / list[dict]) and no dataframe libraries are installed, by ensuring the Export UI is available and providing a structured “missing dependency” flow for Parquet.

Changes:

  • Remove dependency-gated download support for DefaultTableManager and implement CSV export via Python stdlib (csv).
  • Extend the download RPC contract to return structured error / missing_packages for unsupported formats (notably Parquet without deps), and surface this in the Export UI via a new mode-aware prompt.
  • Add/adjust backend and frontend tests covering the new behaviors.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
marimo/_plugins/ui/_impl/tables/default_table.py Removes dep-based download gating; implements stdlib CSV export and CSV cell serialization helper.
marimo/_plugins/ui/_impl/table.py Extends download response shape; adds Parquet missing-deps short-circuit for tables.
frontend/src/components/data-table/schemas.ts Updates RPC schema typings/output to include error and missing_packages.
frontend/src/components/data-table/export-actions.tsx Handles missing-package download responses by showing a toast with an install prompt + retry.
frontend/src/components/datasources/missing-package-prompt.tsx New reusable mode-aware missing-package UI (hides install option in read mode).
frontend/src/core/mode.ts Adds useInstallAllowed() helper based on current app mode.
tests/_plugins/ui/_impl/test_table.py Adds backend test asserting Parquet-without-deps returns structured missing-packages response.
tests/_plugins/ui/_impl/tables/test_default_table.py Adds/updates tests for supports_download() and CSV output for plain-Python default tables.
frontend/src/components/datasources/__tests__/missing-package-prompt.test.tsx New tests validating prompt copy/button behavior in edit vs read mode.

Comment thread marimo/_plugins/ui/_impl/tables/default_table.py
Comment thread marimo/_plugins/ui/_impl/table.py Outdated
if args.format == "parquet":
has_polars = DependencyManager.polars.has()
has_pandas = DependencyManager.pandas.has()
has_pyarrow = DependencyManager.pyarrow.has()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may do more work than required (has() would import things). but its not a common path so don't need to optimize

@kirangadhave kirangadhave merged commit 0f934c1 into main Apr 17, 2026
29 of 43 checks passed
@kirangadhave kirangadhave deleted the kg/default-df-export-btn-bug branch April 17, 2026 19:05
@github-actions
Copy link
Copy Markdown

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.2-dev50

akshayka added a commit that referenced this pull request Apr 21, 2026
#9246 moved DefaultTableManager.to_csv_str to the stdlib csv module,
which emits column name "value" for single-column data. Previously the
fallback went through pandas (via _as_table_manager), so a list of ints
became a DataFrame with integer column 0. The test's expected_df still
used {0: [1, 2, 3]}; update it to {"value": [1, 2, 3]} to match.

The post-search assertion was already {"value": [2]}, so no change
there.
akshayka added a commit that referenced this pull request Apr 21, 2026
Unblocks the test_be CI after #9305. Each of these five failures has an
independent root cause — grouping them since the fixes are small and
share the same goal.

- **`test_download_as[df0]`** — the Parquet short-circuit in
`_download_as` required `polars OR (pandas AND pyarrow)`, rejecting
pyarrow-alone environments even though pyarrow can write Parquet
natively. Relax to `polars OR pyarrow`. The
`_parquet_without_libs_reports_missing_packages` and
`_parquet_with_pandas_only_prompts_pyarrow` regression tests still pass.

- **`test_get_data_url_no_deps`** — #9246 rewrote
`DefaultTableManager.to_csv_str` to use the stdlib `csv` module, so
`_to_chart_data_url` now returns CSV instead of falling through to JSON.
Update the test expectation.

- **`test_get_data_url_values`** — same #9246 change: stdlib CSV emits
column name `"value"` for single-column data, where the old pandas
fallback produced integer column `0`. Update the first `expected_df` to
`{"value": [1, 2, 3]}`. (Landed as a separate commit after I found it on
a broader sweep with the `test-optional` group.)

- **`test_serve_static_allowed_files`** — `serve_static` returned
`FileResponse` without checking existence, so Starlette raised
`RuntimeError` at request time when the file was missing. CI copies
`index.html` and `favicon.ico` into `_static/` but not `manifest.json`,
which is how this surfaced. Add an `is_file()` guard that 404s. The test
passed locally only because `_static/` doesn't exist on dev machines and
`PathValidator` rejected upstream.

- **`test_get_completion_options_bails_out_when_timeout_elapsed`** —
#9247 switched the production code to `time.monotonic` but the test
still mocked `time.time`, so the budget never expired and all
completions got types set. Mock `time.monotonic`.

## Test plan

- [x] Ran all four originally-failing tests; they pass.
- [x] Ran the affected modules (`test_table.py`, `test_assets.py`,
`test_complete.py`) with the `test` group — no new failures;
pre-existing `test_index*` failures need a built `_static/` which CI
provides.
- [x] Ran the same modules with `test-optional` (pandas + polars +
pyarrow + altair) — uncovered and fixed `test_get_data_url_values`.
- [x] Confirmed the Parquet "missing packages" prompts still fire
correctly under pandas-only and no-lib environments.
- [ ] Let CI verify Linux/Windows.
jacobcbeaudin pushed a commit to jacobcbeaudin/marimo that referenced this pull request Apr 21, 2026
…o-team#9306)

Unblocks the test_be CI after marimo-team#9305. Each of these five failures has an
independent root cause — grouping them since the fixes are small and
share the same goal.

- **`test_download_as[df0]`** — the Parquet short-circuit in
`_download_as` required `polars OR (pandas AND pyarrow)`, rejecting
pyarrow-alone environments even though pyarrow can write Parquet
natively. Relax to `polars OR pyarrow`. The
`_parquet_without_libs_reports_missing_packages` and
`_parquet_with_pandas_only_prompts_pyarrow` regression tests still pass.

- **`test_get_data_url_no_deps`** — marimo-team#9246 rewrote
`DefaultTableManager.to_csv_str` to use the stdlib `csv` module, so
`_to_chart_data_url` now returns CSV instead of falling through to JSON.
Update the test expectation.

- **`test_get_data_url_values`** — same marimo-team#9246 change: stdlib CSV emits
column name `"value"` for single-column data, where the old pandas
fallback produced integer column `0`. Update the first `expected_df` to
`{"value": [1, 2, 3]}`. (Landed as a separate commit after I found it on
a broader sweep with the `test-optional` group.)

- **`test_serve_static_allowed_files`** — `serve_static` returned
`FileResponse` without checking existence, so Starlette raised
`RuntimeError` at request time when the file was missing. CI copies
`index.html` and `favicon.ico` into `_static/` but not `manifest.json`,
which is how this surfaced. Add an `is_file()` guard that 404s. The test
passed locally only because `_static/` doesn't exist on dev machines and
`PathValidator` rejected upstream.

- **`test_get_completion_options_bails_out_when_timeout_elapsed`** —
marimo-team#9247 switched the production code to `time.monotonic` but the test
still mocked `time.time`, so the budget never expired and all
completions got types set. Mock `time.monotonic`.

## Test plan

- [x] Ran all four originally-failing tests; they pass.
- [x] Ran the affected modules (`test_table.py`, `test_assets.py`,
`test_complete.py`) with the `test` group — no new failures;
pre-existing `test_index*` failures need a built `_static/` which CI
provides.
- [x] Ran the same modules with `test-optional` (pandas + polars +
pyarrow + altair) — uncovered and fixed `test_get_data_url_values`.
- [x] Confirmed the Parquet "missing packages" prompts still fire
correctly under pandas-only and no-lib environments.
- [ ] Let CI verify Linux/Windows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants