Conversation
## Describe your changes * `st.metric` Markdown support, color palette, and format * Sidebar width * `st.select_slider` Markdown in `options` * `st.logo` homepage link * Per-widget max upload size * Add **or** delete rows in `st.data_editor` (or both) * Float button icons right * Caching scope and caller's rights `SnowflakeConnection` * CCV2 all content optional * Expose OIDC tokens ## Screenshot or video (only for visual changes) n/a ## GitHub Issue Link (if applicable) n/a ## Testing Plan None. Docstrings only. --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.
## Describe your changes Fix a regression where creating container elements (`st.columns`, `st.tabs`) inside a container within a `st.spinner` context caused the app to crash with "Bad delta path index" errors. The root cause was that `SetNodeByDeltaPathVisitor.visitTransientNode` incorrectly consumed an index from the delta path when visiting TransientNodes, while `GetNodeByDeltaPathVisitor` correctly treats them as transparent. This caused delta paths to become misaligned with the actual tree structure. The fix treats TransientNode as transparent in the delta path hierarchy and preserves the transient wrapper when modifying nodes inside its anchor. ## GitHub Issue Link (if applicable) Closes #13658 ## Testing Plan - Unit Tests (JS): Updated and added tests for `SetNodeByDeltaPathVisitor.visitTransientNode` to verify the fix - E2E Tests: Added regression test `test_spinner_with_container_elements` that reproduces the exact scenario from the issue - All 5630 frontend tests pass - All 201 render-tree tests pass --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license. --------- Co-authored-by: Ken McGrady <[email protected]> Co-authored-by: Claude <[email protected]>
## Describe your changes
Fixes an issue with Snowflake connections not getting re-initialized
after having been closed.
<details>
<summary>Claude issue analysis</summary>
# Issue Report: Snowflake Connection "Connection is closed" Error
## Summary
After recent PRs adding `on_release` to `st.cache_resource` and
session-scoped connection support, users may encounter a
`snowflake.connector.errors.DatabaseError: 250002 (08003): Connection is
closed` error when using `st.connection("snowflake")` with cached data
queries.
## Related PRs
- **PR #13439**: Add `on_release` to `st.cache_resource`
- **PR #13482**: Add session scoping to caches
- **PR #13538**: Add `SnowflakeCallersRightsConnection`
- **PR #13506**: Add session-scoped connection support
## Error Details
```
Traceback (most recent call last):
File ".../streamlit/runtime/scriptrunner/exec_code.py", line 129, in exec_func_with_error_handling
result = func()
...
File ".../snowflake/snowpark/_internal/server_connection.py", line 205, in _cursor
self._thread_store.cursor = self._conn.cursor()
File ".../snowflake/connector/connection.py", line 1270, in cursor
Error.errorhandler_wrapper(...)
snowflake.connector.errors.DatabaseError: 250002 (08003): Connection is closed
```
## Root Cause Analysis
### Background
The PRs mentioned added important functionality:
1. **PR #13439** added the `on_release` callback to `st.cache_resource`,
which is called when cache entries are evicted
2. **PR #13506** modified `connection_factory.py` to use this
`on_release` callback to call `connection.close()` when a connection is
evicted from the cache
This is the relevant code in `connection_factory.py`:
```python
def on_release_wrapped(connection: ConnectionClass) -> None:
connection.close()
__create_connection = cache_resource(
max_entries=max_entries,
show_spinner="Running `st.connection(...)`.",
ttl=ttl,
scope=scope,
on_release=on_release_wrapped, # Calls close() when evicted
)(__create_connection)
```
### The Bug
In `BaseSnowflakeConnection.close()`, after calling
`self._raw_instance.close()`, the `_raw_instance` attribute was **NOT**
reset to `None`:
```python
def close(self) -> None:
"""Closes the underlying Snowflake connection."""
if self._raw_instance is not None:
self._raw_instance.close()
# BUG: _raw_instance was NOT set to None!
```
This caused the following issue:
1. When `close()` was called (e.g., via `on_release` when a cache entry
is evicted), the underlying connection was closed
2. However, `_raw_instance` still referenced the **closed** connection
object
3. The `_instance` property checks `if self._raw_instance is None` to
decide whether to create a new connection:
```python
@Property
def _instance(self) -> RawConnectionT:
if self._raw_instance is None:
self._raw_instance = self._connect(**self._kwargs)
return self._raw_instance
```
4. Since `_raw_instance` wasn't `None`, subsequent access to `_instance`
returned the **CLOSED** connection
5. Any operations on the closed connection failed with "Connection is
closed"
### When This Bug Manifests
The `on_release` callback (which calls `close()`) is triggered when:
- Cache entries expire due to TTL
- Cache is full and oldest entries are evicted (`max_entries`)
- `st.cache_resource.clear()` is called
- For session-scoped caches: when a session disconnects
For global-scoped connections like `st.connection("snowflake")`, this
typically only happens if:
- `st.cache_resource.clear()` is called explicitly
- TTL is set and expires
- `max_entries` is set and exceeded
### Additional Consideration: Snowpark Sessions
When users call `conn.session()`, they get a Snowpark Session that
internally references `self._instance`. If the underlying connection is
closed:
```python
def session(self) -> Session:
if running_in_sis():
return get_active_session()
return Session.builder.configs({"connection": self._instance}).create()
```
Any Snowpark Sessions created from the connection will also fail because
they hold a reference to the now-closed underlying connection object.
## Fix
The fix is simple: reset `_raw_instance` to `None` after closing the
connection:
```python
def close(self) -> None:
"""Closes the underlying Snowflake connection."""
if self._raw_instance is not None:
self._raw_instance.close()
self._raw_instance = None # Added this line
```
This ensures that after `close()` is called, the next access to
`_instance` will create a new connection instead of returning the closed
one.
## Files Changed
1. **`lib/streamlit/connections/snowflake_connection.py`**
- Fixed `close()` method to reset `_raw_instance = None` after closing
2. **`lib/tests/streamlit/connections/snowflake_connection_test.py`**
- Added `TestSnowflakeConnectionClose` test class with:
- `test_close_resets_raw_instance`: Verifies that `close()` closes the
connection AND resets `_raw_instance`
- `test_close_is_noop_when_not_connected`: Verifies that `close()`
doesn't fail when `_raw_instance` is already `None`
## Testing
```bash
PYTHONPATH=lib pytest lib/tests/streamlit/connections/snowflake_connection_test.py::TestSnowflakeConnectionClose -v
```
Output:
```
lib/tests/streamlit/connections/snowflake_connection_test.py::TestSnowflakeConnectionClose::test_close_resets_raw_instance PASSED
lib/tests/streamlit/connections/snowflake_connection_test.py::TestSnowflakeConnectionClose::test_close_is_noop_when_not_connected PASSED
```
## Recommendations for Users
Until this fix is released, users experiencing this issue can:
1. **Avoid storing Snowpark Sessions long-term**: Instead of caching
Snowpark Sessions, create them fresh when needed
2. **Check if using `st.cache_resource.clear()`**: If calling this
anywhere in the app, it will close all cached connections
3. **Consider connection TTL settings**: If TTL is set on the
connection, it may expire and close
## Impact
- **Affected**: Users of `st.connection("snowflake")` and
`st.connection("snowflake-callers-rights")` who experience cache
eviction scenarios
- **Severity**: Medium - The bug causes operations to fail with a
confusing error message, but the workaround (restarting the app or
avoiding cache clears) is available
- **Scope**: Only affects `SnowflakeConnection` and its subclasses;
other connection types (`SQLConnection`, `SnowparkConnection`) inherit
the no-op `close()` from `BaseConnection` and are not affected
</details>
## GitHub Issue Link (if applicable)
## Testing Plan
- Added unit test.
---
**Contribution License Agreement**
By submitting this pull request you agree that all contributions to this
project are made under the Apache 2.0 license.
…13674) ## Summary - Fixes an issue where a `TransientNode` without an anchor would not properly capture the existing `BlockNode` when replacing it at an empty delta path - This preserves the original block structure so it can be restored when transient elements (like spinners) are cleared - Mirrors the existing behavior in `visitElementNode` ## Test plan - [x] Added unit tests for the new behavior in `SetNodeByDeltaPathVisitor.test.ts` - [x] Added e2e test `test_spinner_with_delayed_container_write` that verifies container content written after a spinner renders appears correctly - [x] All existing unit tests pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <[email protected]>
…13648) ## Describe your changes Fixes issue #13646 where `st.multiselect()` and `st.selectbox` clears user selections after each script rerun when using custom class objects without `__eq__` implementation and a `format_func` parameter. This was a regression introduced in PR #13448. **Root Cause**: The validation logic compared multiselect values using `==`, which falls back to identity comparison for objects without `__eq__`. Since `register_widget()` deepcopies widget values, the new instances fail identity comparison with original options, causing valid selections to be filtered out. **Solution**: Changed validation to compare values using `format_func()` by their formatted string representation instead of using `==`. This is more robust and works correctly regardless of whether custom classes implement `__eq__`. ## Testing Plan - Unit Tests: Added 4 comprehensive test cases covering custom objects without `__eq__`, partial matches, objects with `__str__`, and edge cases where `format_func` fails on incompatible types - E2E Tests: Added `test_multiselect_custom_objects_without_eq` to verify selections persist across script reruns with custom class objects - Backward Compatibility: The `format_func` parameter has a default value of `str`, so existing code continues to work without changes --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license. --------- Co-authored-by: Claude <[email protected]>
…umn` (#13663) ## Describe your changes Allows selecting text of pills in the MultiselectColumn and ListColumn. To do this, I have moved a fixed version of the multi-select cell implementation from glide-data-grid to Streamlit since the release process is currently broken on glide-data-grid. This will be a bit more of a temporary solution, and it's planned to switch back soon. - Closes #13646 ## Testing Plan - Added unit tests. --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license. --------- Co-authored-by: Claude <[email protected]>
Contributor
✅ 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. |
Contributor
Author
✅ PR preview is ready!
|
db29615 to
0629d95
Compare
sfc-gh-bnisco
approved these changes
Jan 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated PR to merge release branch into develop.
Release version: 1.53.1