Skip to content

[spec] Support thousand separator in sprintf format#13293

Merged
lukasmasuch merged 10 commits intodevelopfrom
spec/sprintf-thousand-separator
Jan 27, 2026
Merged

[spec] Support thousand separator in sprintf format#13293
lukasmasuch merged 10 commits intodevelopfrom
spec/sprintf-thousand-separator

Conversation

@lukasmasuch
Copy link
Copy Markdown
Collaborator

@lukasmasuch lukasmasuch commented Dec 10, 2025

Rendered spec: https://issues.streamlit.app/spec_renderer?pr=13293

GitHub Issue Link (if applicable)

Open Questions


Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

Copilot AI review requested due to automatic review settings December 10, 2025 16:16
@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Dec 10, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@lukasmasuch lukasmasuch added the change:spec Issue contains a product or tech spec label Dec 10, 2025
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

This PR introduces a product specification for adding thousand separator support to Streamlit's sprintf-style format strings. The feature enables developers to format large numbers with comma or underscore separators (e.g., 1,234,567 or 1_234_567) using the , and _ flags in format strings, addressing a long-standing user request with 130+ upvotes.

Key Changes:

  • Adds specification for new , and _ flags in sprintf format strings for thousand separators
  • Documents behavior across multiple numeric format types (d, i, f, e, g) and flag combinations
  • Outlines affected components including sliders, metrics, and column configurations

@streamlit streamlit deleted a comment from github-actions bot Dec 10, 2025
- `st.metric` — `format` parameter
- `st.slider` — `format` parameter

The `format` for `st.number_input` is already very limited, so we might not be able to support this in the initial implementation.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion (if-minor): We should make it clear if this will or will not be in scope for the first pass. Right now it sounds like a possibility, but it would be better to prevent scope creep and be definitive if it will be in a follow-up or not.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

agree, I will clarify this and create a dedicate feature request for supporting the full set of formats in st.number_input

Copy link
Copy Markdown
Collaborator Author

@lukasmasuch lukasmasuch Dec 10, 2025

Choose a reason for hiding this comment

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

we actually already have a feature request on that: #4897

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.

Number input formatting is really annoying, and fixing this likely requires moving away from the base React component being used on the frontend.

The underlying input component doesn't separate out display formatting from other formatting.

Copy link
Copy Markdown
Collaborator Author

@lukasmasuch lukasmasuch Dec 10, 2025

Choose a reason for hiding this comment

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

Agreed, we have the plan to migrate away from Baseweb UI, and I think we should add that to the requirements list for whatever we choose as the basis of number input.


### Implementation Notes

The implementation vendors [sprintf-js](https://github.com/alexei/sprintf.js) as TypeScript
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: Given the comments about the library in this block, it seems like the library itself hasn't been updated in 2 years, and requires our own additions. Have you weighed implementing this fully in-house instead?

Copy link
Copy Markdown
Collaborator Author

@lukasmasuch lukasmasuch Dec 10, 2025

Choose a reason for hiding this comment

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

library itself hasn't been updated in 2 years, and requires our own additions.

yep, the additions are quite minimal and the actual sprintf-js implementation is just 230 LOC. My suggestion would be to vendor in the dependency similar to fzy.js and change it "in-house". Probably not worth it to keep an unmaintained single-file dependency in our dependency tree. Afaik, its BSD-3 (more permissive) which should be fine to vendor in to Apache 2 with the appropriate notice and included license.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you for the additional thoughts here. Ultimately, I wonder if all of that is worth it vs a reimplementation done in-house given the limited scope of what this library does, but I will not block on this either way.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think we might end up with a reimplementation (typscript, conforming to our eslint rules), but might still want to treat it as "vendored" in the sense that we have the licenses next to the code file and add it to notices. But I'm fine with either way.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 13, 2025

📉 Frontend coverage change detected

The frontend unit test (vitest) coverage has decreased by 0.0000%

  • Current PR: 86.2800% (13504 lines, 1852 missed)
  • Latest develop: 86.2800% (13504 lines, 1852 missed)

✅ Coverage change is within normal range.

📊 View detailed coverage comparison


### Implementation Notes

The implementation vendors [sprintf-js](https://github.com/alexei/sprintf.js) as TypeScript
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you for the additional thoughts here. Ultimately, I wonder if all of that is worth it vs a reimplementation done in-house given the limited scope of what this library does, but I will not block on this either way.


### Implementation Notes

The implementation vendors [sprintf-js](https://github.com/alexei/sprintf.js) as TypeScript
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion: I took another look at this in the code and I realized that we already utilize sprintf-js in 3 locations. This doc should outline which callsites will continue to use the external sprintf-js, and which ones will use the customized sprintf-js.

Specifically, I think at least frontend/lib/src/components/widgets/NumberInput/utils.ts will want to continue to use the external sprintf-js as we don't want to modify that component's behavior as previously stated.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think we can just use the in-house / vendored version in all of these places. We already perform backend validation for unsupported format uses in number input -StreamlitInvalidNumberFormatError - and we can do the same for the thousand separator as well.


**Unsupported specifiers:**

The `,` and `_` flags are silently ignored for non-decimal formats (`%o`, `%x`, `%X`, `%b`)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: I was looking at our current implementation of formatNumber and I see that it currently throws when given an invalid sprintf format. Some callsites will wrap it and display a fallback (eg: safeFormatNumber in frontend/lib/src/components/elements/Metric/Metric.tsx), whereas others (the different cells in the Dataframe) will render an error cell.

Given that this doc states that it will be silently ignored here, should we expect a behavior change in the Dataframe with this change?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

What the dataframe handles are syntax errors thrown when we are not able to parse/apply the sprintf. But in this specific case - thousand separator with one of these formats - i think it is fine to not cause a syntax error since the output format just doesn't have large enough numbers to qualify for a thousand seperator. But this is a bit of the same as with applying it to a 100 as value -> which also isn't applied because the number isn't big enough.

@sfc-gh-tteixeira
Copy link
Copy Markdown
Contributor

Problem: ✅
Solution: ✅ so long as we get this cheaply with the JS library we use
Implementation: 🙈

Copy link
Copy Markdown
Collaborator

@jrieke jrieke left a comment

Choose a reason for hiding this comment

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

SGTM. Two comments beyond the scope of this change:

  • Agree that fixing st.number_input to support all of this stuff (especially showing a currency sign) is important. But as you mentioned this should be out of scope since we need to move away from BaseWeb.
  • If we do end up reimplementing the underlying library, I wonder if it's worth (additionally?) supporting modern Python-style formatting options, similar to what the original issue asked for. But not sure how complex that would be and if we could do it in a backwards-compatible way. Again, probably a project for the future, but might be worth thinking through implications.

@lukasmasuch
Copy link
Copy Markdown
Collaborator Author

If we do end up reimplementing the underlying library, I wonder if it's worth (additionally?) supporting modern Python-style formatting options, similar to what the original issue asked for. But not sure how complex that would be and if we could do it in a backwards-compatible way. Again, probably a project for the future, but might be worth thinking through implications.

I added a follow-up analysis / spec here for supporting python format:
https://github.com/streamlit/streamlit/blob/ce5cd8f999b113b8ed13311f58aba4c364eb19af/specs/0000-sprintf-thousand-separator/follow-up-python-format-spec.md

We can theoretically do this. But would keep this as a follow-up and needs another check on the overall implementation complexity.

@lukasmasuch lukasmasuch enabled auto-merge (squash) January 27, 2026 00:27
@lukasmasuch lukasmasuch disabled auto-merge January 27, 2026 00:54
@lukasmasuch lukasmasuch enabled auto-merge (squash) January 27, 2026 00:54
@lukasmasuch lukasmasuch merged commit 0452e1f into develop Jan 27, 2026
36 of 37 checks passed
@lukasmasuch lukasmasuch deleted the spec/sprintf-thousand-separator branch January 27, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:spec Issue contains a product or tech spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants