Skip to content

Commit 7be73e8

Browse files
fix: prevent FileBrowser from using relative paths for directory sync
When `selected` was set to a relative path after previously being set to an absolute path, the `sync_directory_from_selected` function would incorrectly resolve the relative path against the process CWD instead of the FileBrowser's current directory, leading to FileNotFoundError. Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 597109e commit 7be73e8

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

solara/components/file_browser.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ def sync_directory_from_selected():
148148
# if we select a file, we need to make sure the directory is correct
149149
# NOTE: although we expect a Path, abuse might make it a string
150150
if isinstance(selected_private, Path):
151-
# Note that we do not call .resolve() before using .parent, otherwise /some/path/.. will
152-
# set the current directory to /, moving up two levels.
153-
current_dir.value = selected_private.parent.resolve()
151+
# Only sync directory from selected if the path is absolute.
152+
# Relative paths would resolve against the process CWD, not the
153+
# current directory shown in the FileBrowser, leading to incorrect paths.
154+
if selected_private.is_absolute():
155+
# Note that we do not call .resolve() before using .parent, otherwise /some/path/.. will
156+
# set the current directory to /, moving up two levels.
157+
current_dir.value = selected_private.parent.resolve()
154158

155159
solara.use_effect(sync_directory_from_selected, [selected_private])
156160

tests/unit/file_browser_test.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,3 +445,43 @@ def on_files_change(change):
445445
assert "file2.txt" not in new_files
446446

447447
rc.close()
448+
449+
450+
def test_file_browser_selected_relative_path_after_full_path(tmpdir: Path):
451+
"""Test that FileBrowser handles setting selected to a relative path after a full path.
452+
453+
Regression test for issue where:
454+
1. User sets selected to a full path like /some/path/subdir/file.txt
455+
2. User then sets selected to a relative path like subdir/file.txt
456+
3. The current_dir would incorrectly become /some/path/subdir/subdir
457+
because the relative path's parent was appended to the existing directory.
458+
"""
459+
tmpdir = Path(tmpdir)
460+
subdir = tmpdir / "subdir"
461+
subdir.mkdir()
462+
(subdir / "file.txt").write_text("content")
463+
464+
selected = solara.reactive(cast(Optional[Path], None))
465+
466+
@solara.component
467+
def Test():
468+
return solara.FileBrowser(tmpdir, selected=selected, can_select=True)
469+
470+
div, rc = solara.render_fixed(Test(), handle_error=False)
471+
472+
# First, set selected to a full path
473+
full_path = subdir / "file.txt"
474+
selected.value = full_path
475+
476+
# Verify we're now in the subdir
477+
current_dir_text = div.children[0].children[0]
478+
assert str(subdir) in current_dir_text
479+
480+
# Now set selected to a relative path (simulating user setting selected to "subdir/file.txt")
481+
# This should work and stay in the same subdir, not create /subdir/subdir
482+
relative_path = Path("subdir") / "file.txt"
483+
selected.value = relative_path
484+
485+
# This should not raise FileNotFoundError
486+
# The current_dir should resolve relative to cwd, not to the previous current_dir
487+
rc.close()

0 commit comments

Comments
 (0)