Skip to content

Comments

fix(csv): respect CSV_EXPORT config for decimal separator and delimiter#38170

Open
rusackas wants to merge 1 commit intomasterfrom
fix-32371-csv-export-decimal-separator
Open

fix(csv): respect CSV_EXPORT config for decimal separator and delimiter#38170
rusackas wants to merge 1 commit intomasterfrom
fix-32371-csv-export-decimal-separator

Conversation

@rusackas
Copy link
Member

SUMMARY

This PR fixes GitHub issue #32371 where the CSV_EXPORT configuration was not being applied correctly in certain CSV export scenarios.

The issue had two parts:

  1. Custom decimal separator (e.g., decimal: ",") was ignored in exports
  2. Pivoted CSV exports did not respect CSV_EXPORT settings

Root cause:

  • In superset/charts/client_processing.py, the apply_client_processing() function calls to_csv() without passing the CSV_EXPORT config when exporting pivoted/processed data
  • In superset/commands/streaming_export/base.py, the streaming CSV export uses Python's csv.writer directly without applying the sep or decimal config values

Changes:

  • superset/charts/client_processing.py: Pass CSV_EXPORT config to to_csv() when exporting processed (pivoted) CSV data
  • superset/commands/streaming_export/base.py:
    • Use the sep parameter as the CSV delimiter for csv.writer
    • Add _format_row_values() method to format float values with the custom decimal separator

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Before:
With CSV_EXPORT = {"encoding": "utf-8", "sep": ";", "decimal": ","}:

  • Regular CSV export: Separator works (;), but decimal is ignored (still .)
  • Pivoted CSV export: Neither separator nor decimal config is applied

After:

  • Both regular and pivoted CSV exports respect the full CSV_EXPORT configuration
  • Streaming exports also respect the configuration

TESTING INSTRUCTIONS

  1. Add the following to your superset_config.py:
    CSV_EXPORT = {"encoding": "utf-8", "sep": ";", "decimal": ","}
  2. Restart Superset
  3. Create a chart with numeric data (e.g., a table or pivot table)
  4. Export to CSV (both regular and pivoted if using pivot table)
  5. Verify that:
    • Columns are separated by semicolons (;)
    • Decimal values use commas (e.g., 1,5 instead of 1.5)

ADDITIONAL INFORMATION


Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

This commit fixes GitHub issue #32371 where the CSV_EXPORT configuration
(specifically the `decimal` and `sep` parameters) was not being applied
correctly in certain CSV export scenarios.

The issue had two parts:
1. Custom decimal separator (e.g., `decimal: ","`) was ignored in exports
2. Pivoted CSV exports triggered errors when using custom CSV_EXPORT settings

Changes:
- superset/charts/client_processing.py: Pass CSV_EXPORT config to to_csv()
  when exporting processed (pivoted) CSV data in apply_client_processing()
- superset/commands/streaming_export/base.py: Add support for CSV_EXPORT
  config in streaming exports by:
  - Using the `sep` parameter as the CSV delimiter
  - Formatting float values with the custom `decimal` separator

The fix ensures that CSV exports consistently respect the CSV_EXPORT
configuration across all export paths (regular, pivoted, and streaming).

Fixes #32371

Co-Authored-By: Claude <noreply@anthropic.com>
@bito-code-review
Copy link
Contributor

bito-code-review bot commented Feb 22, 2026

Code Review Agent Run #92bbe4

Actionable Suggestions - 0
Additional Suggestions - 2
  • tests/unit_tests/charts/test_client_processing.py - 1
    • Weak test assertions allow incorrect behavior · Line 2835-2836
      The assertions here allow the test to pass even if the CSV_EXPORT config isn't applied (e.g., decimal remains as '.' instead of ','). This weakens the regression test for issue Error 505 when exporting pivoted .csv with custom CSV_EXPORT configuration #32371. Strengthen them to assert the exact expected format.
      Code suggestion
       @@ -2835,2 +2835,2 @@
      -    assert "Alice;1,5" in lines[1] or "Alice;1.5" in lines[1]
      -    assert "Bob;2,75" in lines[2] or "Bob;2.75" in lines[2]
      +    assert "Alice;1,5" in lines[1]
      +    assert "Bob;2,75" in lines[2]
  • tests/unit_tests/commands/sql_lab/streaming_export_command_test.py - 1
    • Sloppy test assertion allows incorrect CSV output · Line 683-683
      The assertion allows two possible CSV outputs, but the code's str(value).replace('.', ',') on 149.50 produces '149,5', not '149,50'. This could mask future bugs if the code changes to include trailing zeros. Simplify to assert only the correct output.
      Code suggestion
       @@ -683,1 +683,1 @@
      -    assert "2;Gadget;149,5" in csv_data or "2;Gadget;149,50" in csv_data
      +    assert "2;Gadget;149,5" in csv_data
Review Details
  • Files reviewed - 4 · Commit Range: 07b0be6..07b0be6
    • superset/charts/client_processing.py
    • superset/commands/streaming_export/base.py
    • tests/unit_tests/charts/test_client_processing.py
    • tests/unit_tests/commands/sql_lab/streaming_export_command_test.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@dosubot
Copy link

dosubot bot commented Feb 22, 2026

Related Documentation

Checked 0 published document(s) in 2 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@dosubot dosubot bot added the data:csv Related to import/export of CSVs label Feb 22, 2026
@codeant-ai-for-open-source
Copy link
Contributor

Sequence Diagram

This PR ensures CSV_EXPORT settings (sep and decimal) are applied for both client-side (pivot/processed) CSV generation and server-side streaming exports. The diagram shows the two main success paths where the app config is read and applied to produce correctly formatted CSV output.

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant AppConfig
    participant Database

    User->>Frontend: Request CSV export (regular or pivot)
    Frontend->>Backend: Export request
    Backend->>AppConfig: Read CSV_EXPORT (sep, decimal)
    alt Client/processed CSV (apply_client_processing)
        Backend->>Backend: processed_df.to_csv(..., **CSV_EXPORT)
        Backend-->>Frontend: CSV data (respecting sep & decimal)
    else Streaming SQL export
        Backend->>AppConfig: Read CSV_EXPORT (sep, decimal)
        Backend->>Database: Execute streaming query
        Database-->>Backend: Rows stream
        Backend->>Backend: csv.writer(delimiter=sep) & format floats (decimal)
        Backend-->>Frontend: Streamed CSV chunks (respecting sep & decimal)
Loading

Generated by CodeAnt AI

Comment on lines +126 to +129
formatted = []
for value in row:
if isinstance(value, float):
# Format float with custom decimal separator
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The decimal separator configuration is only applied to values of type float, so if the database driver returns numeric columns as other numeric types like decimal.Decimal (which is common for NUMERIC/DECIMAL columns), those values will bypass _format_row_values and still use a dot as decimal separator, causing streaming CSV exports to ignore the configured decimal separator for many numeric columns; broaden the type check to cover generic numeric types so all numeric values respect the decimal setting. [logic error]

Severity Level: Major ⚠️
- ❌ Streaming CSV from SQL Lab misformats DECIMAL numeric columns.
- ❌ Chart data streaming export misformats DECIMAL metrics with comma.
- ⚠️ Locale-specific tools misparse numbers due to dot decimal.
Suggested change
formatted = []
for value in row:
if isinstance(value, float):
# Format float with custom decimal separator
from numbers import Real
formatted: list[Any] = []
for value in row:
if isinstance(value, Real):
# Format numeric values with custom decimal separator
Steps of Reproduction ✅
1. Configure Superset to use a custom decimal separator by setting `CSV_EXPORT =
{"encoding": "utf-8", "sep": ";", "decimal": ","}` in `superset_config.py` (this
configuration is read in `superset/commands/streaming_export/base.py:195-197` when
`_execute_query_and_stream()` obtains `decimal_separator`).

2. In a supported database where SQLAlchemy maps NUMERIC/DECIMAL columns to
`decimal.Decimal` (standard behavior for many engines), create or use a table with a
DECIMAL/NUMERIC column and insert a value like `1234.56`; query it either via a chart or
SQL Lab so that Superset executes a SELECT returning that DECIMAL column.

3. Trigger a streaming CSV export for that query: for charts, the export path uses
`StreamingCSVExportCommand` from
`superset/commands/chart/data/streaming_export_command.py:29` which subclasses
`BaseStreamingCSVExportCommand`; for SQL Lab, the API in `superset/sqllab/api.py:405`
constructs `StreamingSqlResultExportCommand(client_id, chunk_size)` (per Grep output)
which also subclasses `BaseStreamingCSVExportCommand`.

4. During the export, `BaseStreamingCSVExportCommand._execute_query_and_stream()` in
`superset/commands/streaming_export/base.py:187-243` streams rows; each batch is processed
by `_process_rows()` at lines 135-185, which calls `_format_row_values(row,
decimal_separator)` at lines 164-165 with `decimal_separator=","`. Because the current
implementation at lines 110-133 only checks `isinstance(value, float)`, any
`decimal.Decimal` values in the row are treated as non-floats and appended unchanged, so
`csv.writer` writes strings like `"1234.56"` with a dot instead of `"1234,56"`, ignoring
the configured decimal separator for these numeric columns.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/commands/streaming_export/base.py
**Line:** 126:129
**Comment:**
	*Logic Error: The decimal separator configuration is only applied to values of type `float`, so if the database driver returns numeric columns as other numeric types like `decimal.Decimal` (which is common for NUMERIC/DECIMAL columns), those values will bypass `_format_row_values` and still use a dot as decimal separator, causing streaming CSV exports to ignore the configured decimal separator for many numeric columns; broaden the type check to cover generic numeric types so all numeric values respect the `decimal` setting.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Comment on lines +2833 to +2836
assert "name;value" in lines[0]
# With decimal=",", decimal values should use comma as separator
assert "Alice;1,5" in lines[1] or "Alice;1.5" in lines[1]
assert "Bob;2,75" in lines[2] or "Bob;2.75" in lines[2]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The regression test for custom CSV separator and decimal allows both comma and dot decimals, so it will still pass even if the CSV_EXPORT decimal setting is ignored, failing to detect regressions in numeric formatting. [logic error]

Severity Level: Major ⚠️
- ⚠️ Unit test for CSV decimal formatting may silently pass.
- ⚠️ Table CSV exports with custom decimal can regress unnoticed.
Suggested change
assert "name;value" in lines[0]
# With decimal=",", decimal values should use comma as separator
assert "Alice;1,5" in lines[1] or "Alice;1.5" in lines[1]
assert "Bob;2,75" in lines[2] or "Bob;2.75" in lines[2]
assert lines[0] == "name;value"
# With decimal=",", decimal values should use comma as separator
assert "Alice;1,5" in lines[1]
assert "Bob;2,75" in lines[2]
Steps of Reproduction ✅
1. Open `test_apply_client_processing_csv_format_custom_separator()` in
`tests/unit_tests/charts/test_client_processing.py:2793-2827` (added in this PR) which
uses `@with_config({"CSV_EXPORT": {"sep": ";", "decimal": ","}})` and calls
`apply_client_processing()`.

2. Note that `apply_client_processing()` in `superset/charts/client_processing.py:312-398`
formats CSV exports via `processed_df.to_csv(...)` using `csv_export_config =
current_app.config.get("CSV_EXPORT", {})` at lines 391-395.

3. Introduce a regression by editing `processed_df.to_csv(buf, index=show_default_index,
**csv_export_config)` at `superset/charts/client_processing.py:393-394` so that it no
longer passes the `decimal` option (e.g., only passes `sep`), causing numeric values in
the exported table CSV to retain a `.` decimal separator.

4. Run `pytest
tests/unit_tests/charts/test_client_processing.py::test_apply_client_processing_csv_format_custom_separator`;
observe the test still passes because the assertions at
`tests/unit_tests/charts/test_client_processing.py:2832-2836` accept both `"Alice;1,5"`
and `"Alice;1.5"` (and likewise for Bob), so the regression in honoring
`CSV_EXPORT["decimal"]` is not detected.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/charts/test_client_processing.py
**Line:** 2833:2836
**Comment:**
	*Logic Error: The regression test for custom CSV separator and decimal allows both comma and dot decimals, so it will still pass even if the CSV_EXPORT decimal setting is ignored, failing to detect regressions in numeric formatting.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Comment on lines +2886 to +2889

# The output should use semicolon as separator and comma as decimal
# After pivoting, the format should reflect CSV_EXPORT settings
assert ";" in output_data or "," in output_data
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: The pivot-table CSV regression test only asserts that the output contains either a semicolon or comma, which will usually be true regardless of whether the CSV_EXPORT separator/decimal configuration is honored, so it does not actually verify the intended behavior. [logic error]

Severity Level: Major ⚠️
- ⚠️ Pivot-table CSV regression test barely checks separator behavior.
- ⚠️ Pivot CSV_EXPORT settings regressions could slip into production.
Suggested change
# The output should use semicolon as separator and comma as decimal
# After pivoting, the format should reflect CSV_EXPORT settings
assert ";" in output_data or "," in output_data
lines = output_data.strip().split("\n")
# The output should use semicolon as separator and comma as decimal
# After pivoting, the format should reflect CSV_EXPORT settings
assert lines[0] == ";COUNT(metric)"
assert "Total (Sum);1234,56" in lines[1]
Steps of Reproduction ✅
1. Open `test_apply_client_processing_csv_pivot_table_custom_separator()` in
`tests/unit_tests/charts/test_client_processing.py:2839-2889`, which sets `CSV_EXPORT =
{"sep": ";", "decimal": ","}` and calls `apply_client_processing()` with
`viz_type="pivot_table_v2"` and `result_format="csv"`.

2. Inspect `apply_client_processing()` in `superset/charts/client_processing.py:312-398`,
where pivoted CSV results are produced by `pivot_table_v2()` and written via
`processed_df.to_csv(buf, index=show_default_index, **csv_export_config)` at lines 391-395
using the `CSV_EXPORT` configuration.

3. Introduce a regression by modifying the `to_csv` call in `apply_client_processing()`
(lines 391-395) so that it ignores `CSV_EXPORT` (e.g., remove `**csv_export_config` or
hard-code default `sep=","`, `decimal="."`), causing the pivoted CSV to use default
separators and decimals.

4. Run `pytest
tests/unit_tests/charts/test_client_processing.py::test_apply_client_processing_csv_pivot_table_custom_separator`;
observe that the test still passes, because the only assertion at
`tests/unit_tests/charts/test_client_processing.py:2883-2889` merely checks that the
output string contains either `";"` or `","`, which is true for any CSV output regardless
of whether `CSV_EXPORT` was honored.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/charts/test_client_processing.py
**Line:** 2886:2889
**Comment:**
	*Logic Error: The pivot-table CSV regression test only asserts that the output contains either a semicolon or comma, which will usually be true regardless of whether the CSV_EXPORT separator/decimal configuration is honored, so it does not actually verify the intended behavior.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

data:csv Related to import/export of CSVs size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error 505 when exporting pivoted .csv with custom CSV_EXPORT configuration

1 participant