🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

[chore] Replace tomli-w with in-house writer - #17342

Merged
lukasmasuch merged 3 commits into
developfrom
lukasmasuch/tomli-w-streamlit-replacement
Oct 12, 2026
Merged

lukasmasuch merged 3 commits into
developfrom
lukasmasuch/tomli-w-streamlit-replacement

Conversation

@lukasmasuch

@lukasmasuch lukasmasuch commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Describe your changes

Replaces the tomli-w runtime dependency with a small writer for the two documents Streamlit produces: credentials.toml and streamlit config show assignments.

  • Credentials files stay [general] with email = "...".
  • Font-face values stay one inline-table assignment under the [theme] header that config show prints. A separate [[fontFaces]] table would close that section.
  • A value outside that subset, such as a date or a list inside a font face, raises TypeError so config show fails visibly.

GitHub Issue Link (if applicable)

Testing Plan

  • Unit Tests (JS and/or Python)

  • E2E Tests

  • Any manual testing needed?

  • lib/tests/streamlit/toml_writer_test.py — writer spelling, escapes, the credentials document, and font faces staying under [theme]

  • lib/tests/streamlit/config_util_test.py — config-show values round-trip, and a set font face stays under the printed [theme] header

  • lib/tests/streamlit/runtime/credentials_test.py — existing test_Credentials_save still asserts the unchanged credentials file contents

  • e2e_playwright/lazy_loaded_modules_test.py — tomli_w is no longer imported at startup

Credentials and config show only need a small TOML subset.
@lukasmasuch
lukasmasuch requested a review from a team as a code owner October 8, 2026 20:12
Copilot AI balanced review requested due to automatic review settings October 8, 2026 20:12
@lukasmasuch lukasmasuch added change:chore PR contains maintenance or housekeeping change impact:users PR changes affect end users labels Oct 8, 2026

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@snyk-io

snyk-io Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

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

Status Scan Engine 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.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-17342/streamlit-1.65.0-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts

@lukasmasuch lukasmasuch added the ai-review If applied to PR or issue will run AI review workflow label Oct 8, 2026
@greptile-apps

greptile-apps Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium impact] The changes since the last review appear safe to merge.

Summary

Replaces tomli-w with a small TOML writer for credentials and streamlit config show.

  • Keeps credentials in the existing [general] format.
  • Writes font faces inline so they stay under [theme].
  • Changes since the last review add clearer errors and update tests without changing successful output.
  • No new actionable issues were found. No previous review threads were supplied.

Reviews (3) · Last reviewed commit: "Name the config option when a value cann..." · Reviewed by Greptile

@github-actions github-actions Bot removed the ai-review If applied to PR or issue will run AI review workflow label Oct 8, 2026

@github-actions github-actions Bot left a comment

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.

Summary

All three expected reviews finished: gpt-5.6-terra-xhigh, claude-opus-5-5-medium, and grok-4.7-xhigh. None failed to complete review. All three approved.

This PR removes the tomli-w runtime dependency and replaces it with lib/streamlit/toml_writer.py, a private serializer for the two TOML documents Streamlit writes: ~/.streamlit/credentials.toml and the assignments printed by streamlit config show. config_util._dump_toml_value and Credentials.save call toml_writer.dumps. The dependency is also removed from lib/pyproject.toml, uv.lock, scripts/assets/min-constraints-gen.txt, and the lazy-loaded-modules e2e list.

The reviewers agreed that the writer is limited to the types those paths use, that the credentials file text stays the same, and that two config show changes are fixes: font faces stay inline under [theme], and Unicode line separators are escaped. They differed on whether rejecting dates and nested arrays preserves old error behavior. It does not. That difference is intentional and is not merge-blocking (see Backwards Compatibility).

Product Alignment

This has limited user-facing impact. streamlit config show is an existing CLI surface, and Streamlit stops installing tomli-w. The PR adds no public API, configuration option, default, or command. All three reviewers agreed a merged product spec is not required. Nothing in specs/ covers credentials files or config show, and the PR body does not claim a separate product approval. That fits a dependency-maintenance change plus a correction to CLI text.

The reviewers agreed on the user-visible results:

  • Streamlit no longer installs tomli-w.
  • A theme.fontFaces value stays one inline-table assignment under the [theme] header that config show already prints. tomli-w switched a long face to [[fontFaces]] once the inline form passed 100 characters, which closes [theme] when that text is pasted under the header.
  • U+0085, U+2028, and U+2029 are escaped, so a commented-out value stays on one physical line. Parsed strings are unchanged.

The implementation matches the font-face decision in the PR body, and it matches the decision to raise TypeError for values outside the supported subset. The common credentials and config-show cases stay the same, with no new parameters or defaults.

Code Quality

All three reviewers found the writer proportionate: one module, no extra types, and no attempt to be a general TOML library. That matches the dependency guidance in lib/AGENTS.md. Private helpers are underscored, annotations are present, and dumps is the only public function. Both call sites pass a plain dict.

Details all three reviews treated as correct, and that match tomli-w 1.2.0 for the shapes Streamlit writes:

  • bool is handled before int.
  • Basic strings escape quotes, backslashes, C0 controls, and DEL. Tab stays raw.
  • Scalar assignments come before child tables. Non-bare keys, including the empty key, are quoted. A dot inside a key is quoted, so it does not become another table path.
  • Dicts inside arrays are inline tables. A multiline value inside an inline table raises TypeError.

Claude noted a pre-existing quirk the other reviews did not mention. A dict-valued option such as server.trustedUserHeaders is still emitted as a [trustedUserHeaders] header, which closes the [server] section config show already printed. tomli-w did the same for mappings. This PR leaves that behavior as it was. Fixing it is a separate follow-up.

Performance

All three reviewers agreed there is no meaningful hot-path impact. Credential save and streamlit config show run outside script reruns, element creation, message transport, and frontend rendering. There is no frontend change.

Grok noted that toml_writer is imported with config_util and credentials, while tomli_w was imported only when those commands ran. Claude and GPT treated that cost as negligible. That assessment holds: the new module imports re and typing and compiles one key regex. Normal script runs no longer load tomli-w. Performance-specific coverage is not needed.

Test Coverage

All three reviewers agreed the changed behavior is covered well enough to merge.

  • lib/tests/streamlit/toml_writer_test.py covers scalar spelling, escapes, Unicode line separators, the credentials document, empty containers, array layout, short and long font faces (including a tomllib parse under a [theme] header), quoted keys, tuples, and rejected types.
  • test_dump_toml_value_round_trips_config_options parses every current config option's default and value back through tomllib and checks type and equality, including that booleans stay booleans.
  • Existing Credentials.save still asserts the exact credentials file text. This PR does not modify that test file.
  • e2e_playwright/lazy_loaded_modules_test.py expects 14 markdown rows after tomli_w leaves the lazy-import list.

New tests follow lib/tests/AGENTS.md. The e2e edit updates the existing count.

Claude wanted one more integration assertion through show_config for a set theme.fontFaces value. GPT and Grok treated the writer test as enough. The writer test already parses a long font face under a [theme] header, which is the regression this PR fixes. That difference is optional coverage, recorded as an inline comment.

Backwards Compatibility

Supported documents stay compatible. All three reviewers agreed on these points:

  • A normal credentials file is still [general] with email = "...". Emails with quotes or backslashes still parse back to the same string. test_Credentials_save locks the exact text.
  • Config-show lists, booleans, numbers, and ordinary strings keep the spelling the current tests lock in.
  • A long font face changes from [[fontFaces]] to one inline table. Both forms describe the same data. The array-of-tables form closed the [theme] section in this output.
  • Escaping U+0085, U+2028, and U+2029 changes the bytes of a string that contains those characters. tomllib reads the same string back.
  • A project that imported tomli_w without declaring it, and relied on Streamlit to install it, needs its own dependency. tomli-w was not a Streamlit API.

The reviews disagreed on dates and nested arrays. Claude described unsupported values as still raising TypeError. GPT and Grok described a behavior change. tomli-w 1.2.0 confirms GPT and Grok: format_literal writes date and datetime with str(), and an array of tables whose inline form contains a newline or exceeds 100 characters becomes [[fontFaces]]. The new writer raises TypeError for a date and for a multiline value inside an inline table. No current config option uses date, datetime, time, or Decimal, and theme font faces are flat tables. config show only dumps config values, so this is not a practical break. The inaccurate part is the PR body's "still raises" wording (see Readability).

Security & Risk

All three reviewers agreed the risk is low. The writer serializes local config and credential values. It does no I/O and no evaluation. Basic strings escape ", \, and the controls a TOML basic string cannot contain raw, plus the Unicode line separators that would split a config-show comment. A quote, newline, or ] in an email or header name stays inside a quoted string or quoted key. File path handling and who may call Credentials.save are unchanged. No WebSocket, auth, cookie, upload, HTML, or eval changes. Removing a runtime dependency shrinks the supply-chain surface.

External test recommendation

  • Recommend external_test: No
  • Triggered categories: None
  • Evidence:
    • lib/streamlit/toml_writer.py: in-process TOML text only.
    • lib/streamlit/config_util.py and lib/streamlit/runtime/credentials.py: serializer swap for CLI text and the local credentials file. No routes, cookies, WebSockets, embedding, storage, cross-origin behavior, or browser policies.
    • lib/pyproject.toml, uv.lock, scripts/assets/min-constraints-gen.txt: dependency removal.
    • e2e_playwright/lazy_loaded_modules.py: startup import list. No embed, CORS, or asset-serving change.
  • Suggested external_test focus areas:
    • None. Local unit tests cover document spelling and round-trips.
  • Confidence: High
  • Assumptions and gaps: Credentials stay a file under the user's home directory, and config show stays terminal text. No externally hosted or embedded behavior depends on tomli-w. Tests were not executed in this review.

All three reviewers reached this recommendation.

Accessibility

Not applicable. There are no frontend or UI changes. All three reviewers agreed.

Readability

Code comments explain the non-obvious constraints: bool before int, a raw tab, deferred dicts, inline font faces, and Unicode line separators. Test names say what they lock in. All three reviewers found the title clear: [chore] Replace tomli-w with in-house writer.

PR description

  • "still raises TypeError" describes dates and nested font-face arrays as if tomli-w already rejected them. tomli-w 1.2.0 writes dates with str() and emits [[fontFaces]] when an inline table would be multiline. GPT and Grok flagged this; Claude's review repeated the "still" wording. Proposed bullet: "A value outside that subset, such as a date or a list inside a font face, raises TypeError so config show fails visibly."
  • The Testing Plan lists lib/tests/streamlit/runtime/credentials_test.py — credentials file contents, and that file is not in the diff. Claude flagged this. Proposed line: "lib/tests/streamlit/runtime/credentials_test.py — existing test_Credentials_save still asserts the unchanged credentials file contents."
  • "Made with Cursor" is meta-commentary. GPT and Grok flagged it. Remove the line.

lib/streamlit/toml_writer.py

  • Line 54: "numbers" is broader than the supported numeric types. GPT flagged this. Proposed sentence: "Supports strings, booleans, integers, floats, lists, tuples, and dicts."
  • Line 127: the docstring limits inline tables to dictionaries nested in arrays. The formatter also writes a dictionary nested inside an inline table. GPT flagged this. Proposed docstring: "Serialize a dict as a TOML inline table."
  • Lines 15–21: the module docstring is already accurate. Grok proposed naming the writer as the actor in the last sentence. Optional closing sentence: "The writer raises TypeError for dates and any other unsupported type."

These are wording cleanups.

Recommendations

  1. In the PR body, replace the "still raises TypeError" bullet with the wording in Readability, point the credentials testing-plan line at the existing assertion, and remove "Made with Cursor".
  2. Optionally, apply the toml_writer.py docstring wording in Readability.
  3. Optionally, track the existing config show behavior where a dict-valued option such as [trustedUserHeaders] closes the surrounding section. That behavior predates this PR.

Verdict

APPROVED: All three reviews approve, and the verified differences from tomli-w are a font-face paste fix, tighter string escaping, and an intentional TypeError for types no current config option uses.


This is an automated consolidated AI review by grok-4.7-xhigh. Please verify the feedback and use your judgment.

This review also includes 1 inline comment(s) on specific code lines.

Comment thread lib/tests/streamlit/config_util_test.py
Leaked "_test" options made the full-suite round-trip fail, and config show
now asserts a set font face stays under [theme].
@lukasmasuch lukasmasuch added ai-final-review If applied to PR or issue will run AI review workflow with the latest generation of AI models. ai-qa-test If applied to PR, an AI qa testing will run on the feature implemented in the PR. labels Oct 8, 2026
@github-actions github-actions Bot removed the ai-final-review If applied to PR or issue will run AI review workflow with the latest generation of AI models. label Oct 8, 2026

@github-actions github-actions Bot left a comment

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.

Summary

All four expected reviews completed (gpt-5.6-sol-high, claude-opus-5-5-high, gemini-3.8-flash-high, grok-4.7-xhigh). None failed.

This PR removes the tomli-w runtime dependency and replaces it with lib/streamlit/toml_writer.py, used for the two TOML documents Streamlit writes: ~/.streamlit/credentials.toml and each assignment printed by streamlit config show. lib/pyproject.toml, uv.lock, the minimum-constraints file, and the lazy-loaded-modules e2e expectation are updated with it.

All four reviews approve. They agree the writer is limited to the types Streamlit actually writes, credentials output stays the same, and a long theme.fontFaces value stays an inline table under the [theme] header that config show prints. Differences are about how to describe that CLI change and about optional wording. No reviewer found a merge-blocking defect.

Product Alignment

This has limited user-facing impact. streamlit config show changes for long font-face arrays, and tomli-w is no longer installed with Streamlit. There is no new public API, config option, default, or UI.

gemini-3.8-flash-high marked product alignment not applicable and described CLI formats as preserved. The other three reviews, and the implementation, show a real output change: font faces are always inline tables, so a long face stays under the [theme] section config show already printed. tomli-w turned that array into [[fontFaces]], which closed the section. Gemini's own summary already describes that font-face behavior. The resolved assessment is the one shared by Claude, GPT, and Grok.

credentials.toml stays [general] with email = "...". U+0085, U+2028, and U+2029 are escaped so a commented config-show line stays one physical line; the parsed string is unchanged. A value outside this subset, such as a date or a list nested inside a font face, raises TypeError. Current options are strings, bools, ints, floats, lists, and dicts of those.

No product spec on develop covers this change, and none is required. specs/AGENTS.md excludes bug fixes and small non-controversial maintenance. The PR body does not claim a separate product approval, which is expected here. The common path — copying a config-show block into config.toml — stays valid TOML, and the change adds no permanent st.* surface.

Code Quality

All four reviews find the module proportionate to the dependency it removes, in line with lib/AGENTS.md (add a dependency only when the behavior cannot easily be replicated in-house). The file is one dumps entry point plus private helpers, with future annotations, _-prefixed internals, and a Numpydoc dumps docstring.

Spelling follows tomli-w for the documents Streamlit writes: 4-space multiline arrays with a trailing comma, the same compact escapes, bare keys limited to ASCII letters, digits, _, and -, and str() for ints and floats so a whole-number float stays a float after parsing. The intentional divergence is that a dict inside an array is always an inline table, including faces longer than tomli-w's 100-character heuristic. That is the config-show fix, and the tests lock it in. Unsupported types raise TypeError instead of guessing.

Optional notes on error text, a pre-existing dict-option layout, and a missing _format_string docstring are inline comments. No reviewer asked for a structural change.

Performance

All four reviews agree there is no meaningful hot-path impact. dumps runs only when saving credentials or printing config, on small documents. Element enqueue, ForwardMsg, reruns, caches, Arrow, and the frontend are untouched.

gemini-3.8-flash-high also said dropping the package reduces cold-start import overhead. The other three are more precise, and the diff matches them: tomli-w was imported lazily, only on write, and the e2e list already required it to stay unloaded at startup. config_util and credentials now import toml_writer at import time. That module only uses re, which config_util already imports, so script startup still avoids a third-party TOML import. The practical win is one fewer installed dependency. Performance coverage is not warranted.

Test Coverage

Coverage is sufficient, and all four reviews agree:

  • lib/tests/streamlit/toml_writer_test.py checks scalar spelling, escapes (including Unicode line separators), the credentials document, quoted keys, empty containers, multiline arrays, font faces staying inline under [theme], and TypeError for unsupported values, non-dict documents, non-string keys, and a list inside an inline table.
  • lib/tests/streamlit/config_util_test.py round-trips every real config option's default and current value through tomllib, and parses a set font face out of the printed [theme] section.
  • test_Credentials_save still asserts the exact credentials file body.
  • e2e_playwright/lazy_loaded_modules_test.py drops tomli_w and expects 14 markdown rows, matching the updated app script.

A CLI serializer does not need a new browser scenario. One overlapping unit test is called out inline; the credentials document and the dict-as-table behavior remain covered by other tests.

Backwards Compatibility

Reading config.toml and credentials.toml is unchanged (tomllib). Credentials written for a normal email, including quotes and backslashes, match the previous file body. Current config values keep their parsed types. The visible config-show difference is the long font-face case, which previously produced a section break and now stays valid TOML.

tomli-w is no longer installed as a Streamlit dependency. An environment that imported tomli_w without declaring it will need its own dependency. Streamlit does not treat that transitive import as a public API. Claude, GPT, and Grok all note this. Gemini's "fully backwards-compatible" leaves it out. It is ordinary dependency churn, and Streamlit's public API is unchanged. A release-note line is optional.

Security & Risk

All four reviews rate this low risk, and the writer matches that assessment. Credential emails are TOML basic strings. Quotes, backslashes, newlines, other C0 controls, DEL, and the Unicode line separators are escaped, so an email cannot break out of the string and add keys. The credentials path, permissions, and write path are unchanged. Dropping a runtime dependency shrinks the install-time supply chain. There is no new subprocess, eval, network call, authentication change, or path handling.

streamlit config show raises TypeError for a nested list inside a font face instead of emitting a [[fontFaces]] block. That aborts the command before it prints, which is the behavior the PR describes, and current theme options do not use that shape.

External test recommendation

  • Recommend external_test: No
  • Triggered categories: None
  • Evidence: All four reviews agree, and the external-test checklist matches the diff.
    • lib/streamlit/toml_writer.py serializes in-process values for credentials and streamlit config show.
    • lib/streamlit/config_util.py and lib/streamlit/runtime/credentials.py only replace that local writer.
    • lib/pyproject.toml and uv.lock drop the tomli-w install dependency.
    • e2e_playwright/lazy_loaded_modules.py updates the startup import list.
    • No routing, auth, WebSocket, embedding, asset serving, cross-origin, client storage, SiS/Snowflake, or security-header behavior changes. Test mentions of server.trustedUserHeaders are config-show formatting of an existing option, not identity binding.
  • Suggested external_test focus areas: None. Embedded hosting, auth handshakes, asset URLs, and SiS/Snowflake runtimes are unaffected.
  • Confidence: High
  • Assumptions and gaps: Call sites are credentials save and streamlit config show. No remaining tomli_w import is part of this change.

Accessibility

Not applicable. There are no frontend, rendered UI, or interaction changes. All four reviews agree.

Readability

Module and helper docs are in good shape: the module docstring states the supported subset and the font-face rule, _iter_table explains why dict values are deferred, and the bool-before-int check and the Unicode line-separator comment say why they exist. The credentials comment ("TOML has no null, so a missing email is stored as an empty string.") is clear. Line-level wording on _format_string, one error message, and one test name is in inline comments.

PR title. [chore] Replace tomli-w with in-house writer matches [type] Description and stands alone. Claude, GPT, and Gemini leave it as is. Grok would name the format explicitly. tomli-w already identifies TOML, so the current title is enough.

Optional title if the PR is edited again:

[chore] Replace tomli-w with a built-in TOML writer

PR description. GPT finds the current text sufficient: it names both documents, the font-face constraint, the TypeError behavior, and the tests, and the template sections are present. Claude, Gemini, and Grok want the motivation in the first sentences: one fewer runtime dependency, and tomli-w's long-value heuristic emitting [[fontFaces]]. That context is present, but it sits in the second bullet after the mechanism. The empty issue-link heading is the template default when there is no issue.

Optional opening if the description is edited again:

Streamlit writes `credentials.toml` and `streamlit config show` with a built-in TOML writer and no longer depends on `tomli-w`.

`tomli-w` turns a long font-face array into `[[fontFaces]]`, which closes the `[theme]` section that config show prints itself. The built-in writer keeps that array as one inline-table assignment under `[theme]`.

Recommendations

  1. No change is required before merge. All four reviews approve, and the remaining disagreements are optional wording and follow-ups.
  2. If release notes are updated for this change, one line that tomli-w is no longer installed with Streamlit would help users who imported it without declaring their own dependency.

Verdict

APPROVED: Four reviews agree this is a well-tested replacement of tomli-w that preserves credentials output, corrects long font-face config-show text, and introduces no merge-blocking product, performance, security, or compatibility issue.


This is an automated consolidated AI review by grok-4.7-xhigh. Please verify the feedback and use your judgment.

This review also includes 5 inline comment(s) on specific code lines.

Comment thread lib/streamlit/config_util.py Outdated
Comment thread lib/streamlit/toml_writer.py Outdated
Comment thread lib/streamlit/toml_writer.py
Comment thread lib/streamlit/toml_writer.py
Comment thread lib/tests/streamlit/toml_writer_test.py Outdated

@github-actions github-actions Bot left a comment

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.

Auto-approved by AI final review (workflow run).

@github-actions github-actions Bot removed the ai-qa-test If applied to PR, an AI qa testing will run on the feature implemented in the PR. label Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

QA Report: Replace tomli-w with in-house TOML writer

Summary

Overall status

PASS

Test results

Passed tests

ID Scenario Notes
F1 tomli_w not loaded find_spec is missing and the module is not in sys.modules after the debug server starts. streamlit.toml_writer is loaded.
F2 Credentials save and load File is exactly [general]\nemail = "user@example.com"\n and Credentials.load returns that email.
F3 In-app config show config.show_config() completed. The section body parses with tomllib.
F4 Font faces stay under [theme] No uncommented [[ table. baseFontSize stays 18 on theme. Live font-face families match the printed inline tables.
F5 Theme config load Running app loaded primary #E11D48, sidebar #0F766E, baseFontSize 18, heading weights [800, 700], chart colors, and both font-face families from [[theme.fontFaces]].
F6 Visible option round-trip Every visible option's default and current value dumped and parsed back as the same type and value.
F7 Credentials spelling some_email is written as [general]\nemail = "some_email"\n, matching the existing unit-test fixture.
F8 CLI streamlit config show Exit 0. Parsed theme has both families, weight "400" on each face, baseFontSize 18, sidebar primary #0F766E, and no array-of-tables header.
F9 Dependency removal lib/pyproject.toml, uv.lock, and scripts/assets/min-constraints-gen.txt do not reference tomli-w or tomli_w.
E1 Email with quotes and backslashes weird"email\name@example.com round-trips through the credentials file and Credentials.load.
E2 Empty email Stored and loaded as email = "".
E3 Unsupported values date, bytes, set, object, and None raise TypeError from dumps. _dump_toml_value(None) returns "".
E4 List inside a font face TypeError whose message says inline tables cannot contain multiline values.
E5 Unicode line separators U+0085, U+2028, and U+2029 stay escaped on one line and parse back.
E6 Empty containers Empty document, empty array, and empty table use the expected spellings.
E7 Quoted key "X-User Name" is quoted and round-trips.
E8 String escapes Newline, tab, quotes, backslash, DEL, and café round-trip.
E9 Multiline arrays Heading weights and chart colors use one item per line and parse back. A nested numeric array round-trips.
E10 Non-finite floats This interpreter's tomllib accepts nan, inf, and -inf from the writer.
V1 Primary button color Main primary button background is rgb(225, 29, 72) (#E11D48).
V2 App renders cleanly No stException and no error alert.
V3 Sidebar theme color Sidebar primary button background is rgb(15, 118, 110) (#0F766E).
V4 Narrow viewport At 390px the main primary button is still rgb(225, 29, 72).
I1 Save credentials from the form Entering qa"user\name@example.com and clicking Save credentials rewrote the file and reported the same email.
I2 Save empty email from a button The button wrote email = "" and reported a successful load.
U1 toml_writer_test.py Passed in the combined pytest run (141 passed, 0 failed).
U2 config_util_test.py Passed in the same run, including font-face config show and option round-trip coverage.
U3 credentials_test.py Passed in the same run, including test_Credentials_save.

Failed tests

None.

Blocked tests

None.

Issues found

Issue 1: Live server rewrites font-face weight to weight_range before config show

  • Severity: Low
  • Test ID: F4 (in-app output) compared with F8 (CLI)
  • Description: This is pre-existing and outside the writer diff. app_session renames weight to weight_range on the dict stored in the config option while building the theme protobuf. config.show_config() inside the debug server therefore prints weight_range = "400". The user-facing streamlit config show process never builds that protobuf, and its output keeps weight = "400". The writer serializes the dict it is given.
  • Steps to reproduce:
    1. Put weight = "400" under [[theme.fontFaces]] in config.toml.
    2. Open the app so a session is created.
    3. Call config.show_config() in that same process and compare it with a fresh streamlit config show.
  • Expected: Both outputs use the weight key from the file.
  • Actual: The CLI keeps weight. The in-process dump after a browser session uses weight_range.
  • Screenshot: final_state.png (app still applied the theme; this key rename is not visible in the UI)

Recommendations

  • No writer change is required for this pull request. CLI config show, credentials files, theme loading, and the existing unit tests match the documented behavior.
  • A separate change can copy font-face dicts before renaming weight to weight_range, so an in-process config show does not rewrite the stored option.

Notes

  • No product spec and no agent-wiki/pull-requests/17342/ checkout were available. Expectations came from the PR body, toml_writer.py, config_util.py, credentials.py, and the new unit tests.
  • Debug session: work-tmp/debug/20261008-212057-test_app.py-9330/. App URL http://localhost:3001. Backend and frontend logs had no Python traceback. The frontend log recorded Cannot send rerun backMessage when disconnected from server while the narrow-viewport page connected, and repeated aria-label warnings. The page still rendered and the color checks passed.
  • streamlit config show still starts with an uncommented ~/.streamlit/config.toml. intro line, so the raw stdout is not one TOML document until that intro is removed. That string is unchanged by this PR. The section body, including the new font-face assignments, parses.
  • Credentials.load rejects some_email because _verify_email requires zero or one @. The historical file spelling is still produced. Load coverage used user@example.com, the quoted email, and the empty email.
  • Non-finite floats are not used by current config options. Python 3.14's tomllib accepted the writer's nan / inf spellings.
  • Screenshots: final_state.png (desktop, after both credential buttons) and narrow_state.png.
  • Unit tests: uv run pytest lib/tests/streamlit/toml_writer_test.py lib/tests/streamlit/config_util_test.py lib/tests/streamlit/runtime/credentials_test.py — 141 passed in 9.34s.

This is an automated QA report by grok-4.7-xhigh.

Unsupported config-show values now include the option key, and an inline table that does not fit on one line names the field.
@lukasmasuch

Copy link
Copy Markdown
Collaborator Author

The weight to weight_range rewrite happens in the live session before serialization and is outside this writer change. CLI config show, credentials files, and theme loading stay as tested, so I am leaving that rename for a follow-up.

@lukasmasuch
lukasmasuch merged commit fdedc8c into develop Oct 12, 2026
38 checks passed
@lukasmasuch
lukasmasuch deleted the lukasmasuch/tomli-w-streamlit-replacement branch October 12, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:chore PR contains maintenance or housekeeping change impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants