打包 Streamlit 应用程序并在 Windows 上运行可执行文件

2023-11-27

这是我在 Stackoverflow 上的第一个问题。我希望我的问题很清楚,否则请告诉我,并随时向我询问更多详细信息。

我正在尝试为个人项目打包一个 Streamlit 应用程序。我正在 Linux 下开发,但我必须在 Windows 上部署该应用程序。我希望它是一个独立的可执行文件,一旦运行,它就会打开浏览器选项卡以显示应用程序,并在选项卡关闭时退出。我想用pynsist库来打包应用程序(已用于另一个项目并且工作正常)。

我遵循了在此发现的建议讨论。它在 ubuntu 上运行良好,在使用 pynsist 打包应用程序后,显然在 Windows 上也运行良好。 “显然”是因为可执行文件运行,但没有打开浏览器选项卡来显示该应用程序。

这是我的代码的一些片段。

项目结构

|- 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!")

运行应用程序.py (EDIT 2Thomas 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 安装程序.cfg

EDIT:包括通过发现的streamlit的依赖关系pip list

EDIT 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 上的可执行输出,可以正确打印当前工作目录,但没有打印其他输出(streamlit 应用程序初始化消息或错误消息)。我尝试打开浏览器并转到localhost:8501,但我遇到连接错误。

有关如何使代码执行并自动打开浏览器选项卡的任何提示?任何帮助是极大的赞赏!

EDIT:正如对最后一个包的评论中指出的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.

EDIT 2:感谢 Thomas K 的有用提示,我想出了一半的解决方案。应用程序运行并启动 Streamlit。

But.

这些是日志消息:

  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 that a .streamlit/credentials.toml可以添加,但我不确定 Windows 上的确切位置。我也尝试过明确添加--server.headless=false in the subprocess.run命令,但再次没有效果。

为什么应用程序不像 Linux 上那样自动启动?有没有一种方法无需用户进行额外配置即可启动应用程序?


EDIT:在示例中添加了一个 Streamlit 示例pynsist repo. Here您可以找到工作应用程序的最小且精致的示例(其中还包括绘图)。

原答案

终于我让它发挥作用了。在我上次的尝试中,我通过设置犯了一个错误--server.headless=false,虽然它必须是true反而。我发现 Streamlit run 命令需要一个附加标志:--global.developmentMode=false。这使得部署工作,即使我在中找不到任何对此配置的引用流线型配置.

工作代码如下。

项目结构

|- 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!")

运行应用程序.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()

一些注意事项:

  1. webbrowser.open需要在浏览器中自动打开一个新选项卡才能显示 Streamlit 应用程序。这subprocess.runlines 仅启动一个新的 Streamlit 服务器。
  2. 正如我在评论中指出的,一旦退出浏览器中的 Streamlit 选项卡,Streamlit 服务器仍然存在并处于活动状态。您只需键入即可再次访问仪表板localhost:8501在地址栏中。如果多次单击 Windows 应用程序图标,则会启动多个 Streamlit 服务器。我尝试过同时只使用两个活动,并且它们没有表现出冲突的行为。例如,要阻止它们,您必须通过任务管理器手动结束任务。

安装程序.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

Note: blinker需要额外的轮子。

EDIT 2

正如 @ananvodo 指出的那样,可能无法立即清楚什么EnvVar and get_env是。为了完整起见,我在此处复制了 config.py 的相关部分。

import os


class EnvironmentalVariableNames:
    """Defines the names of the environmental variables used in the code and useful shortcuts"""

    # Environmental variables for Zaccheo app
    EMPORIO_VESTIARIO_DASHBOARD_WORKING_DIR= "EMPORIO_VESTIARIO_DASHBOARD_WORKING_DIR"

    # Other environmental variable names defined hereafter


def get_env(env_var):
    """Returns the value of the environment variable env_var"""
    return os.environ[env_var]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

打包 Streamlit 应用程序并在 Windows 上运行可执行文件 的相关文章

随机推荐

  • 调试:为多列创建多个滞后的函数 (dplyr)

    我想创建多个变量的多个滞后 所以我认为编写一个函数会很有帮助 我的代码抛出警告 将向量截断为长度 1 和错误结果 library dplyr time lt c 2000 2009 2000 2009 x lt c 1 10 10 19 i
  • 将 HTML 转换为 XML

    我有数百个 HTML 文件需要转换为 XML 我们使用这些 HTML 为应用程序提供内容 但现在我们必须以 XML 形式提供这些内容 HTML 文件包含 表格 div 图像 p b 或强标记等 我用谷歌搜索并找到了一些应用程序 但我还无法实
  • 是否有比使用 C++ 的 FindFirstFile/FindNextFile 更快的枚举文件夹替代方法?

    我需要获取文件夹内子文件夹的所有路径 使用 WinAPI 和 C 到目前为止 我发现的唯一解决方案是递归调用查找第一个文件 查找下一个文件但在层次结构较深的文件夹上执行此操作需要花费大量时间 所以我想知道 只是为了获取文件夹名称 是否有更快
  • 有没有比忙等待更智能的方法来检查 System.Net.WebClient.DownloadFileAsync() 的下载完成情况?

    我正在使用 System Net WebClient DownloadFileAsync 下载文件 使用异步版本的唯一原因是显示下载进度 在达到 100 之前 我的代码执行可能不会继续 目前我正在使用忙等待 参见代码 但我想知道是否有更聪明
  • fgetpos() 行为取决于换行符

    考虑这两个文件 file1 txt Windows 换行符 abc r n def r n file2 txt Unix 换行符 abc n def n 我注意到对于 file2 txt 通过以下方式获得的位置fgetpos没有正确增加 我
  • 可移动/可拖动

    这是我更新和修改的脚本 它完全可以工作 除了我想通用它 观察 我怎样才能做到这一点 这样我就不必这样做function e BOX Draggable elemen e target e srcElement elementDraggabl
  • Jenkins:在 MultiJob 中共享变量

    我使用 Jenkins 进行测试 构建 因此我使用以下配置创建了一个 MultiJob 项目 Test Job 建立工作 安装工作 MultiJob 从 Master Jenkins 启动 但其他作业从其他 Node 启动 构建作业执行创建
  • DVCLAL 的所有可能值的列表是什么?

    当我遇到这个函数时 我正在阅读 SysUtils function ALR Pointer var LibModule PLibModule begin if MainInstance lt gt 0 then Result Pointer
  • sql触发器打印消息

    我是在数据库中使用触发器的新手 我创建了一些对我来说非常有效的触发器 除了当我尝试创建一个在删除行后显示一条消息的触发器时 我尝试使用这段代码 ALTER TRIGGER mycustomerTrigger AFTER delete ON
  • 如何在 git 中查看传入的提交? [复制]

    这个问题在这里已经有答案了 可能的重复 使用 Git 如何在本地和远程之间查找修改过的文件 如何在 git 中查看传入的提交 或者甚至更好 看看我刚刚说的git fetch git pulled Edit 为了澄清这个问题 有人告诉我 为了
  • 为什么 JVM 不缓存 JIT 编译的代码?

    Sun 的规范 JVM 实现对字节码应用了一些相当复杂的优化 以便在代码运行几次后获得接近本机的执行速度 问题是 为什么不将此编译后的代码缓存到磁盘以供后续使用同一函数 类时使用 按照目前的情况 每次执行程序时 JIT 编译器都会重新启动
  • 用于图像去模糊的维纳滤波器

    我正在尝试实现维纳滤波器来对模糊图像执行反卷积 我的实现是这样的 import numpy as np from numpy fft import fft2 ifft2 def wiener filter img kernel K 10 d
  • 使用 JfreeChart 动态向 XYSeries 添加点

    我在向 XYSeries 添加点时遇到问题 我有两节课 一是Sample 它有一个main方法 另一个类是JfreeChart 它有JfreeChart代码 在我的Sample类我有一个二维数组sample row 2 最初有 10 行 然
  • 如何检查 double 是否最多有 n 位小数?

    目前我有这个方法 static boolean checkDecimalPlaces double d int decimalPlaces if d 0 return true double multiplier Math pow 10 d
  • android 出现所有包无法下载的错误

    所有软件包均不提供下载 以下软件包不可用 包 ID 来源 android 24 我尝试使用 Web 服务从数据库获取数据 但运行应用程序时出现上述错误 如何在 android studio 中解决这个问题 弹出错误与您在应用程序中遇到的异常
  • 在C中获取LAN上的设备列表

    我想获取连接到我的本地网络的可用设备列表 它们的 IP 地址或主机名应该没问题 我有一些 C 示例 但找不到任何使用 C C 的示例 我熟悉 BSD 套接字 API 只是为了澄清一下 我有一个 存根 的想法 也许我应该确定 LAN 上的设备
  • 为什么不能将镜头类型更改为使用任何 Integral?

    take Int gt a gt a genericTake Integral i gt i gt a gt a 我读过不方便的类型take这是由于历史原因 更改它可能会导致某些代码损坏 但我不能更换吗take with genericTa
  • 梯度下降代码的向量化

    我正在 Matlab 上实现批量梯度下降 我的更新步骤有问题theta theta是两个分量 两行 的向量 X是一个矩阵 包含m行 训练样本数 和n 2列 特征数量 Y 是一个m行向量 在更新步骤中 我需要设置每个theta i to th
  • 在C++程序中使用mat文件

    请 谁能帮我 我有 Mat 文件包含特征向量数组结构 我需要在 C 程序中使用此文件 如何在我的 C 程序中加载该文件 你可以尝试matio图书馆 它至少支持版本 5 的 mat 文件 我认为是压缩和结构 也许还有更新的东西 看来正在积极开
  • 打包 Streamlit 应用程序并在 Windows 上运行可执行文件

    这是我在 Stackoverflow 上的第一个问题 我希望我的问题很清楚 否则请告诉我 并随时向我询问更多详细信息 我正在尝试为个人项目打包一个 Streamlit 应用程序 我正在 Linux 下开发 但我必须在 Windows 上部署