fix(downloads): use explorer /select on Windows + show open feedback
Reported: clicking "Open Downloads folder" did nothing visible. The
previous implementation called ``os.startfile(folder)`` on Windows,
which is known to silently no-op or open Explorer behind the active
window in some configurations (Streamlit running headless, no
foreground rights inherited by the click handler thread, etc.).
Switch to the more reliable ``explorer /select,<file>`` form:
- Opens Explorer with the just-saved file pre-highlighted instead of
just navigating to the folder — better UX than the old behavior.
- explorer.exe is a real GUI process that's spawned in the user's
session with foreground rights, so it shows up on top.
- Fallback chain on Windows: ``/select`` first, then plain
``explorer <folder>``, then ``os.startfile`` as a last resort.
macOS upgraded the same way: ``open -R <file>`` reveals in Finder
rather than opening the directory.
Linux: no reliable cross-distro reveal, so ``xdg-open <folder>``.
Plus user feedback at the call site:
- On successful dispatch: ``st.toast("Opening <folder>", icon="📂")``
— confirms we tried, in case the window comes up behind the
browser.
- On dispatch failure: ``st.warning`` with the full path the user
can copy/paste into their file manager manually.
2220 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -254,25 +254,60 @@ def _downloads_dir() -> "Path":
|
|||||||
return Path.home() / "Downloads"
|
return Path.home() / "Downloads"
|
||||||
|
|
||||||
|
|
||||||
def _open_in_file_manager(path: "Path") -> bool:
|
def _open_in_file_manager(folder: "Path", *, select: "Path | None" = None) -> bool:
|
||||||
"""Open *path* in the host OS's native file manager.
|
"""Open the OS file manager at *folder*, optionally highlighting *select*.
|
||||||
|
|
||||||
Returns ``True`` if the command was dispatched (no guarantee the
|
Windows
|
||||||
file manager actually opened — the user might have removed the
|
``explorer /select,<file>`` is preferred when *select* is given —
|
||||||
default handler). Returns ``False`` on platforms we don't know
|
Explorer pops to the foreground with the freshly-saved file
|
||||||
how to launch.
|
already highlighted. Falls back to ``explorer <folder>``, then
|
||||||
|
``os.startfile`` if both fail; ``os.startfile`` is known to
|
||||||
|
silently no-op or open behind the active window in some Windows
|
||||||
|
configurations, which is why we don't lead with it.
|
||||||
|
macOS
|
||||||
|
``open -R <file>`` reveals the file in Finder.
|
||||||
|
Linux / *BSD
|
||||||
|
``xdg-open`` on the folder. No reliable cross-distro way to
|
||||||
|
highlight a specific file.
|
||||||
|
|
||||||
|
Returns ``True`` if any of the dispatch attempts succeeded
|
||||||
|
(no guarantee the window actually surfaced — the caller should
|
||||||
|
surface a fallback path so the user can paste it manually).
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
# explorer.exe with /select wants a literal "/select," followed
|
||||||
|
# by the path — no space between the comma and the filename, or
|
||||||
|
# Explorer misinterprets and opens "My Computer" instead.
|
||||||
|
attempts = []
|
||||||
|
if select is not None:
|
||||||
|
attempts.append(["explorer", f"/select,{select}"])
|
||||||
|
attempts.append(["explorer", str(folder)])
|
||||||
|
for cmd in attempts:
|
||||||
|
try:
|
||||||
|
subprocess.Popen(cmd)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
os.startfile(str(folder)) # type: ignore[attr-defined]
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
try:
|
||||||
|
if select is not None:
|
||||||
|
subprocess.Popen(["open", "-R", str(select)])
|
||||||
|
else:
|
||||||
|
subprocess.Popen(["open", str(folder)])
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
# Linux / *BSD / etc.
|
||||||
try:
|
try:
|
||||||
if sys.platform == "win32":
|
subprocess.Popen(["xdg-open", str(folder)])
|
||||||
os.startfile(str(path)) # type: ignore[attr-defined]
|
|
||||||
return True
|
|
||||||
if sys.platform == "darwin":
|
|
||||||
subprocess.Popen(["open", str(path)])
|
|
||||||
return True
|
|
||||||
# Linux / *BSD / etc.
|
|
||||||
subprocess.Popen(["xdg-open", str(path)])
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
@@ -353,13 +388,24 @@ def local_download_button(
|
|||||||
|
|
||||||
saved_path_str = st.session_state.get(saved_key)
|
saved_path_str = st.session_state.get(saved_key)
|
||||||
if saved_path_str:
|
if saved_path_str:
|
||||||
|
saved_path = Path(saved_path_str)
|
||||||
st.success(f"✓ Saved to `{saved_path_str}`")
|
st.success(f"✓ Saved to `{saved_path_str}`")
|
||||||
if st.button(
|
if st.button(
|
||||||
"📂 Open Downloads folder",
|
"📂 Open Downloads folder",
|
||||||
key=open_key,
|
key=open_key,
|
||||||
type="secondary",
|
type="secondary",
|
||||||
):
|
):
|
||||||
_open_in_file_manager(Path(saved_path_str).parent)
|
opened = _open_in_file_manager(saved_path.parent, select=saved_path)
|
||||||
|
if opened:
|
||||||
|
# The dispatch returned non-zero; the OS may still have
|
||||||
|
# opened the window behind the active one. Surface a
|
||||||
|
# confirmation so the user knows we tried.
|
||||||
|
st.toast(f"Opening {saved_path.parent}", icon="📂")
|
||||||
|
else:
|
||||||
|
st.warning(
|
||||||
|
f"Could not open the file manager from here. "
|
||||||
|
f"The file is at:\n\n`{saved_path_str}`"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Back-compat alias: existing call sites use the old name. New code
|
# Back-compat alias: existing call sites use the old name. New code
|
||||||
|
|||||||
Reference in New Issue
Block a user