Skip to content

Instantly share code, notes, and snippets.

@Hu-Wentao
Forked from benlansdell/filepicker.py
Last active December 12, 2024 09:16
Show Gist options
  • Select an option

  • Save Hu-Wentao/4a490de02c520ff009ebff53e1929ec7 to your computer and use it in GitHub Desktop.

Select an option

Save Hu-Wentao/4a490de02c520ff009ebff53e1929ec7 to your computer and use it in GitHub Desktop.
streamlit: FilePicker
"""
UPDATE: Please see https://github.com/Hu-Wentao/st_tools?tab=readme-ov-file#pathfilefolderselector-st_path_selector
"""
import os
from typing import Callable, Any
import streamlit as st
def st_path_selector(
label='选择文件/文件夹', key='st_path_selector', path: str = '.', help: str = None,
) -> str:
# ==
def s_path(update: str = None, navi_to: str = None) -> str: # 核心状态, 选中的path, 可能是文件/文件夹
if update: # 当path以`/`结尾, 修复路径,移除`/`
update = os.path.normpath(update)
if navi_to is not None:
update = os.path.abspath(os.path.join(s_path_dir(), navi_to))
return tool_s_state(update, key, init=os.path.abspath(path))
def s_path_dir(): # 选中路径所在的文件夹(如果选中文件夹则返回文件夹)
_p = s_path()
return _p if os.path.isdir(_p) else os.path.dirname(_p)
def s_path_navi(update: str = None) -> str: # 路径导航, 当前路径到 .. 或到 /foo 等...
return tool_s_state(update, f"{key}.s_path_navi", init=os.path.abspath(path))
# ==
s_path()
c1, c2 = st.columns([3, 1])
c1.text_input('当前路径', key=key, placeholder='在此处粘贴或在右侧选择 文件/文件夹',
help=help, on_change=st.rerun)
from natsort import natsorted
c2.selectbox(
key=f"{key}.s_path_navi",
label=label,
options=['.', '..', *natsorted(os.listdir(s_path_dir()))],
format_func=lambda
x: f"{'🗂️' if os.path.isdir(os.path.join(s_path_dir(), x)) else '🗒️'} {
".\t(当前路径)" if x == '.' else
"..\t(上级路径)" if x == '..' else
x}",
on_change=lambda: s_path(navi_to=s_path_navi())
)
return s_path()
def tool_s_state(update, k: str, init: Callable[[], Any] | Any = None,
force_update=False, force_init=False):
"""
# see: https://gist.github.com/Hu-Wentao/1711debf08581d6ce25fa78619926b02
:param force_init: force init value, ignore key in st.session_state
:param force_update: force update value, ignore `update` is or not None
:param update: update state value
:param k: st.state_session state key
:param init: init state value or init function
:return: state
"""
if update is not None or force_update: # 有新值(或强制刷新)
st.session_state[k] = update
elif k not in st.session_state or force_init: # 无值,且未注册key (或强制更新为init)
if isinstance(init, Callable):
_value = init()
else:
_value = init
st.session_state[k] = _value
return st.session_state[k]
if __name__ == '__main__':
selected_path = st_path_selector(
path=".",
label="Choose a file",
key="my_file_selector"
)
st.info(f"{selected_path=}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment