打包 streamlit 应用并在 Windows 上运行可执行文件
Posted
技术标签:
【中文标题】打包 streamlit 应用并在 Windows 上运行可执行文件【英文标题】:Package streamlit app and run executable on windows 【发布时间】:2021-11-19 22:22:01 【问题描述】:这是我在 *** 上的第一个问题。我希望我的问题很清楚,否则请告诉我,不要犹豫,问我更多细节。
我正在尝试为个人项目打包流线型应用程序。我正在 linux 下开发,但我必须在 Windows 上部署应用程序。我希望它是一个独立的可执行文件,一旦运行就会打开浏览器选项卡以显示应用程序,并在选项卡关闭时退出。我想使用pynsist
库来打包应用程序(已经用于另一个项目并且效果很好)。
我遵循了discussion 中的建议。它在 ubuntu 上运行良好,在使用 pynsist 打包应用程序后显然也在 Windows 上运行。 “显然”是因为可执行文件运行,但没有打开浏览器选项卡来显示应用程序。
这是我的代码的一些 sn-ps。
项目结构
|- installer.cfg
|- src
|- main.py
|- run_app.py
main.py
import streamlit as st
st.title("Test")
st.title("My first app deployed with Pynsist!")
run_app.py (编辑 2 在 Thomas K 发表评论后)
import os
import subprocess
import sys
from src.config import EnvironmentalVariableNames as EnvVar, get_env
def main():
executable = sys.executable
result = subprocess.run(
f"executable -m streamlit run os.path.join(get_env(EnvVar.EMPORIO_VESTIARIO_DASHBOARD_WORKING_DIR), 'src', 'main.py')",
shell=True,
capture_output=True,
text=True,
)
if __name__ == "__main__":
main()
EMPORIO_VESTIARIO_DASHBOARD_WORKING_DIR
是一个环境变量,让应用可以在linux和windows上运行(在windows上,设置为安装目录)。
pynsist installer.cfg
编辑:包括通过pip list
发现的streamlit的依赖项
编辑 2: 添加 MarkupSafe 作为 Jinja2 的依赖项
[Application]
name=Emporio Vestiario Dashboard
version=0.1.0
# How to lunch the app - this calls the 'main' function from the 'myapp' package:
entry_point=src.run_app:main
icon=resources/caritas-logo.ico
[Python]
version=3.8.10
bitness=64
[Include]
# Packages from PyPI that your application requires, one per line
# These must have wheels on PyPI:
pypi_wheels = altair==4.1.0
astor==0.8.1
attrs==21.2.0
backcall==0.2.0
backports.zoneinfo==0.2.1
base58==2.1.0
bleach==4.1.0
blinker==1.4
cachetools==4.2.2
certifi==2021.5.30
cffi==1.14.6
charset-normalizer==2.0.6
click==7.1.2
decorator==5.1.0
defusedxml==0.7.1
distlib==0.3.3
entrypoints==0.3
idna==3.2
jsonschema==3.2.0
mistune==0.8.4
mypy-extensions==0.4.3
numpy==1.21.1
packaging==21.0
pandas==1.3.3
pandocfilters==1.5.0
parso==0.8.2
pillow==8.3.2
platformdirs==2.4.0
prompt-toolkit==3.0.20
protobuf==3.18.0
pyarrow==5.0.0
pycparser==2.20
pydeck==0.7.0
pyparsing==2.4.7
pyrsistent==0.18.0
python-dateutil==2.8.2
pytz==2021.1
requests==2.26.0
requests-download==0.1.2
send2trash==1.8.0
setuptools==57.0.0
six==1.14.0
smmap==4.0.0
streamlit==0.89.0
terminado==0.12.1
testpath==0.5.0
toml==0.10.2
tomli==1.2.1
toolz==0.11.1
tornado==6.1
traitlets==5.1.0
typing-extensions==3.10.0.2
tzlocal==3.0
urllib3==1.26.7
validators==0.18.2
Jinja2==3.0.1
MarkupSafe==2.0.1
查看 Windows 上的可执行输出,当前工作目录已正确打印,但没有打印其他输出(流式应用程序初始化消息或错误消息)。我尝试打开浏览器并转到localhost:8501
,但出现连接错误。
关于如何使代码执行并自动打开浏览器选项卡的任何提示?非常感谢任何帮助!
编辑: 正如installer.cfg
中最后一个包的评论中指出的那样,该应用程序(具有 Jinja2 依赖项)已正确安装在 Windows 上,但启动时,该应用程序仍然找不到 Jinja2依赖。这是回溯:
Traceback (most recent call last):
File "Emporio_Vestiario_Dashboard.launch.pyw", line 34, in <module>
from src.run_app import main
File "C:\Users\tantardini\develop\caritas\pkgs\src\run_app.py", line 6, in <module>
import streamlit
File "C:\Users\tantardini\develop\caritas\pkgs\streamlit\__init__.py", line 75, in <module>
from streamlit.delta_generator import DeltaGenerator as _DeltaGenerator
File "C:\Users\tantardini\develop\caritas\pkgs\streamlit\delta_generator.py", line 70, in <module>
from streamlit.elements.arrow import ArrowMixin
File "C:\Users\tantardini\develop\caritas\pkgs\streamlit\elements\arrow.py", line 20, in <module>
from pandas.io.formats.style import Styler
File "C:\Users\tantardini\develop\caritas\pkgs\pandas\io\formats\style.py", line 49, in <module>
jinja2 = import_optional_dependency("jinja2", extra="DataFrame.style requires jinja2.")
File "C:\Users\tantardini\develop\caritas\pkgs\pandas\compat\_optional.py", line 118, in import_optional_dependency
raise ImportError(msg) from None
ImportError: Missing optional dependency 'Jinja2'. DataFrame.style requires jinja2. Use pip or conda to install Jinja2.
编辑 2: 感谢 Thomas K 的有用提示,我想出了一半的解决方案。应用程序运行并启动 streamlit。
但是。
这些是日志消息:
Welcome to Streamlit!
If you're one of our development partners or you're interested in getting
personal technical support or Streamlit updates, please enter your email
address below. Otherwise, you may leave the field blank.
Email:
2021-10-11 20:56:53.202 WARNING streamlit.config:
Warning: the config option 'server.enableCORS=false' is not compatible with 'server.enableXsrfProtection=true'.
As a result, 'server.enableCORS' is being overridden to 'true'.
More information:
In order to protect against CSRF attacks, we send a cookie with each request.
To do so, we must specify allowable origins, which places a restriction on
cross-origin resource sharing.
If cross origin resource sharing is required, please disable server.enableXsrfProtection.
2021-10-11 20:56:53.202 DEBUG streamlit.logger: Initialized tornado logs
2021-10-11 20:56:53.202 ERROR streamlit.credentials:
似乎应用程序的执行已停止,因为它正在等待一些凭据。我发现here 可以添加.streamlit/credentials.toml
,但我不确定windows 上的确切位置。我也尝试在subprocess.run
命令中显式添加--server.headless=false
,但同样没有效果。
为什么应用程序不像在 Linux 上那样自动启动?有没有一种无需用户额外配置即可启动应用的方法?
【问题讨论】:
如果您还没有,请尝试从命令提示符以described in the FAQ 运行已安装的应用程序 - 您可能会看到更多有关失败原因的信息。不过,我可能会猜测它没有找到streamlit
命令 - 使用 sys.executable -m streamlit ...
启动子进程可能会解决这个问题。
谢谢,我知道 C:/Users/.../AppData/Roaming 文件夹中的应用程序日志,但我错过了通过命令提示符启动应用程序的可能性。我发现问题是缺少一些依赖项,特别是作为 streamlit 依赖项的包。我想我必须将它们全部添加到installer.cfg 中。需要一些时间才能发现所有丢失的有一些线索和错误。
是的,您确实需要列出所有依赖项。如果你想简化试错,你可以尝试做一个空环境,用 pip 安装streamlit,然后使用pip freeze
来查看已经安装了什么。如果你让它工作,那么得到一个流线型示例in the examples folder for pynsist 会很棒。 :-)
嗯,你是对的。我想尽量不要让部署的应用程序的大小爆炸(在过去的项目中,我不必列出某些包的所有子依赖项),但这肯定会为我节省很多时间。我想我会走这条路。我会及时通知你我的发现,是的,分享一个例子会很棒;)
是的,我想你会的。这就是the new FAQ entry on subprocesses 的用武之地。我认为你需要类似sys.executable -m streamlit
【参考方案1】:
编辑:在pynsist
repo 的示例中添加了一个精简示例。 There 您可以找到一个工作应用程序(也包括 plotly)的最小且精炼的示例。
原始答案
我终于让它工作了。在我最后一次尝试中,我错误地设置了--server.headless=false
,而它必须是true
。我发现 streamlit 运行命令需要一个附加标志:--global.developmentMode=false
。这使得部署工作,即使我在streamlit configurations 中找不到对此配置的任何引用。
工作代码如下。
项目结构
|- wheels/
|- installer.cfg
|- src
|- main.py
|- run_app.py
main.py
import streamlit as st
st.title("Test")
st.title("My first app deployed with Pynsist!")
run_app.py
import os
import subprocess
import sys
import webbrowser
from src.config import EnvironmentalVariableNames as EnvVar, get_env
def main():
# Getting path to python executable (full path of deployed python on Windows)
executable = sys.executable
# Open browser tab. May temporarily display error until streamlit server is started.
webbrowser.open("http://localhost:8501")
# Run streamlit server
path_to_main = os.path.join(
get_env(EnvVar.EMPORIO_VESTIARIO_DASHBOARD_WORKING_DIR), "src", "app.py"
)
result = subprocess.run(
f"executable -m streamlit run path_to_main --server.headless=true --global.developmentMode=false",
shell=True,
capture_output=True,
text=True,
)
# These are printed only when server is stopped.
# NOTE: you have to manually stop streamlit server killing process.
print(result.stdout)
print(result.stderr)
if __name__ == "__main__":
main()
一些注意事项:
webbrowser.open
是在浏览器中自动打开一个新选项卡以显示流光应用程序所必需的。 subprocess.run
行仅启动一个新的流式服务器。
正如我在 cmets 中指出的,一旦退出浏览器中的 streamlit 选项卡,streamlit 服务器仍然存在并处于活动状态。您只需在地址栏中输入localhost:8501
即可再次访问仪表板。如果您多次单击 Windows 应用程序图标,则会启动多个 streamlit 服务器。我试过同时只激活两个,它们没有表现出冲突的行为。例如,要阻止它们,您必须通过任务管理器手动结束任务。
installer.cfg
[Application]
name=Emporio Vestiario Dashboard
version=0.1.0
# How to lunch the app - this calls the 'main' function from the 'myapp' package:
entry_point=src.run_app:main
icon=resources/caritas-logo.ico
[Python]
version=3.8.10
bitness=64
[Include]
# Packages from PyPI that your application requires, one per line
# These must have wheels on PyPI:
pypi_wheels = altair==4.1.0
astor==0.8.1
attrs==21.2.0
backcall==0.2.0
backports.zoneinfo==0.2.1
base58==2.1.0
bleach==4.1.0
blinker==1.4
cachetools==4.2.2
certifi==2021.5.30
cffi==1.14.6
charset-normalizer==2.0.6
click==7.1.2
decorator==5.1.0
defusedxml==0.7.1
distlib==0.3.3
entrypoints==0.3
idna==3.2
jsonschema==3.2.0
mistune==0.8.4
mypy-extensions==0.4.3
numpy==1.21.1
packaging==21.0
pandas==1.3.3
pandocfilters==1.5.0
parso==0.8.2
pillow==8.3.2
platformdirs==2.4.0
prompt-toolkit==3.0.20
protobuf==3.18.0
pyarrow==5.0.0
pycparser==2.20
pydeck==0.7.0
pyparsing==2.4.7
pyrsistent==0.18.0
python-dateutil==2.8.2
pytz==2021.1
requests==2.26.0
requests-download==0.1.2
send2trash==1.8.0
setuptools==57.0.0
six==1.14.0
smmap==4.0.0
streamlit==0.89.0
terminado==0.12.1
testpath==0.5.0
toml==0.10.2
tomli==1.2.1
toolz==0.11.1
tornado==6.1
traitlets==5.1.0
typing-extensions==3.10.0.2
tzlocal==3.0
urllib3==1.26.7
validators==0.18.2
Jinja2==3.0.1
MarkupSafe==2.0.1
extra_wheel_sources = ./wheels
注意:blinker
需要额外的***。
【讨论】:
感谢托马斯的帮助!我会尽快在 pynsist repo 中添加一个精简的示例以上是关于打包 streamlit 应用并在 Windows 上运行可执行文件的主要内容,如果未能解决你的问题,请参考以下文章
“ __conform__() 不是有效的 Streamlit 命令。”