Skip to content

Commit fccfcab

Browse files
authored
fix: don't resolve symlinks when backing up in FileBrowser
1 parent 1a19f8a commit fccfcab

2 files changed

Lines changed: 64 additions & 1 deletion

File tree

solara/components/file_browser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,12 @@ def on_item(item, double_click):
206206
on_path_select(None)
207207
return
208208
if item["name"] == "..":
209-
new_dir = current_dir.value.resolve().parent
209+
if current_dir.value.is_symlink():
210+
new_dir = current_dir.value.parent
211+
elif any([d.is_symlink() for d in current_dir.value.parents]):
212+
new_dir = current_dir.value.parent
213+
else:
214+
new_dir = current_dir.value.resolve().parent
210215
action_change_directory = (can_select and double_click) or (not can_select and not double_click)
211216
if action_change_directory and change_dir(new_dir):
212217
if scroll_pos_stack:

tests/unit/file_browser_test.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,61 @@ def Test():
485485
# This should not raise FileNotFoundError
486486
# The current_dir should resolve relative to cwd, not to the previous current_dir
487487
rc.close()
488+
489+
490+
def test_file_browser_symlink_parent_navigation(tmpdir: Path):
491+
"""Test that navigating back (..) from a symlinked directory returns to the logical parent.
492+
493+
Regression test for issue #1133 where:
494+
1. User is in workingdir containing a symlink to ../symlinkdir
495+
2. User enters the symlinked directory
496+
3. User clicks ".." to go back
497+
4. Expected: return to workingdir
498+
5. Actual (bug): goes to parent of the resolved symlink target
499+
"""
500+
tmpdir = Path(tmpdir)
501+
workingdir = tmpdir / "workingdir"
502+
symlinkdir = tmpdir / "symlinkdir"
503+
workingdir.mkdir()
504+
symlinkdir.mkdir()
505+
506+
# Create a symlink inside workingdir pointing to symlinkdir
507+
symlink = workingdir / "symlinkdir"
508+
symlink.symlink_to(symlinkdir)
509+
510+
# Create a file in symlinkdir so we can verify we entered it
511+
(symlinkdir / "file.txt").write_text("content")
512+
513+
@solara.component
514+
def Test():
515+
return solara.FileBrowser(workingdir)
516+
517+
div, rc = solara.render_fixed(Test(), handle_error=False)
518+
file_list: solara.components.file_browser.FileListWidget = div.children[1]
519+
520+
# Verify we're in workingdir and can see the symlink
521+
current_dir_text = div.children[0].children[0]
522+
assert str(workingdir) in current_dir_text
523+
file_names = {f["name"] for f in file_list.files}
524+
assert "symlinkdir" in file_names
525+
526+
# Enter the symlinked directory (single click navigates when can_select=False)
527+
file_list.test_click("symlinkdir", double_click=False)
528+
529+
# Verify we're now in the symlinked directory
530+
current_dir_text = div.children[0].children[0]
531+
file_names = {f["name"] for f in file_list.files}
532+
assert "file.txt" in file_names
533+
534+
# Navigate back with ".."
535+
file_list.test_click("..", double_click=False)
536+
537+
# We should be back in workingdir, not in tmpdir (parent of resolved symlink target)
538+
current_dir_text = div.children[0].children[0]
539+
assert str(workingdir) in current_dir_text, f"Expected to be in {workingdir}, but current directory text is: {current_dir_text}"
540+
541+
# Verify we can see the symlink again
542+
file_names = {f["name"] for f in file_list.files}
543+
assert "symlinkdir" in file_names
544+
545+
rc.close()

0 commit comments

Comments
 (0)