[spec] Support thousand separator in sprintf format#13293
[spec] Support thousand separator in sprintf format#13293lukasmasuch merged 10 commits intodevelopfrom
format#13293Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
There was a problem hiding this comment.
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
| - `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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
agree, I will clarify this and create a dedicate feature request for supporting the full set of formats in st.number_input
There was a problem hiding this comment.
we actually already have a feature request on that: #4897
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
📉 Frontend coverage change detectedThe frontend unit test (vitest) coverage has decreased by 0.0000%
✅ Coverage change is within normal range. |
|
|
||
| ### Implementation Notes | ||
|
|
||
| The implementation vendors [sprintf-js](https://github.com/alexei/sprintf.js) as TypeScript |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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`) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
|
Problem: ✅ |
jrieke
left a comment
There was a problem hiding this comment.
SGTM. Two comments beyond the scope of this change:
- Agree that fixing
st.number_inputto 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.
I added a follow-up analysis / spec here for supporting python format: We can theoretically do this. But would keep this as a follow-up and needs another check on the overall implementation complexity. |
Rendered spec: https://issues.streamlit.app/spec_renderer?pr=13293
GitHub Issue Link (if applicable)
st.data_editorandst.dataframe#7702Open 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.