Using PyInstaller (or similar) to create an executable

Hello @clementdavies56, thank you for your assistance. I’m currently working on a new project using Streamlit version 1.31.0 and encountering the following error.

Exception in callback AppSession._on_scriptrunner_event..() at C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py:470
handle: <Handle AppSession._on_scriptrunner_event..() at C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py:470>
Traceback (most recent call last):
File “C:\Users\703321944\AppData\Local\Programs\Python\Python310\lib\asyncio\events.py”, line 80, in _run
self._context.run(self._callback, *self._args)
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 470, in
lambda: self._handle_scriptrunner_event_on_event_loop(
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 540, in _handle_scriptrunner_event_on_event_loop
self._create_new_session_message(page_script_hash)
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 656, in _create_new_session_message
imsg.command_line = self._script_data.command_line
AttributeError: ‘ScriptData’ object has no attribute ‘command_line’

How can this be resolved? I successfully created an executable file with version 1.29.0, and it is working fine.

and also getting this error in version 1.30 and 1.31 but 1.29.0 works perfectly.

Exception in callback AppSession._on_scriptrunner_event..() at C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py:473
handle: <Handle AppSession._on_scriptrunner_event..() at C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py:473>
Traceback (most recent call last):
File “C:\Users\703321944\AppData\Local\Programs\Python\Python310\lib\asyncio\events.py”, line 80, in _run
self._context.run(self._callback, *self._args)
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 473, in
lambda: self._handle_scriptrunner_event_on_event_loop(
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 543, in _handle_scriptrunner_event_on_event_loop
self._create_new_session_message(page_script_hash)
File “C:\Users\703321944\Projects\Text Inquisition\application_test\app-beta\a15Feb2024.ticketEinstein\lib\site-packages\streamlit\runtime\app_session.py”, line 659, in _create_new_session_message
imsg.is_hello = self._script_data.is_hello
TypeError: ‘str’ object cannot be interpreted as an integer

Please help resolving this.

Hey, orudne! When I started the run_main.exe, it also used the port 3000 instead of 8501, could you please tell me more details about how you solved this issue? Thanks!

@Liz_Li
Well, in my case it was just a misunderstanding of the instructions given by hmasdev. As described in my EDIT2 I added a “.” in front when passing the streamlit path, which was wrong in my case. If you still have problems it might help if you post your run_main.spec.

@Dkdatascientist did you find the solution, I am getting same error with version you specified.

@arslan_siraj I did not find the solution yet but using the previous version of streamlit
1.29.0

Hi @Liz_Li, If you’re using --onedir instead of --onefile , move the .streamlit folder to the directory where the run_main.exe is located. Additionally, ensure that all dependent files are in the same directory by using --contents-directory "." when building the executable so it will be simpler.

I have exactly the same problem. The following message may help to solve the problem:

  1. When I run the app directly using streamlit run main.py, everything works fine.
  2. When I use the streamlit.web.bootstrap to run the app with python ./run_main.py, the mentioned errors occur.

The main.py file:

from app import streamlit_app

if __name__ == '__main__':
    streamlit_app()

The run_main.py file:

import os
import sys
import streamlit.web.bootstrap

sys.path.append('./')
sys.path.append('./src')

if __name__ == "__main__":
    os.chdir(os.path.dirname(__file__))

    flag_options = {
        "server. Port": 8501,
        "global.developmentMode": False,
    }

    streamlit.web.bootstrap.load_config_options(flag_options=flag_options)
    flag_options["_is_running_with_streamlit"] = True
    streamlit.web.bootstrap.run(
        "./src/main.py",
        "streamlit run",
        [],
        flag_options,
    )

Hi @mgissh,

is it working, or you still have the problem.?

Hi @mgissh,

is it working, or you still have the problem.?

I solved the problem by adding is_hello=False after flag_options.

  streamlit.web.bootstrap.run(
        "./src/main.py",
        args=[], 
        flag_options=[], 
        is_hello=False
    )
1 Like

Hi, does anyone have a solution to this?

I am using session_state to update my st.text_input value. If i change to using global variables even if the variables are updated, my text input is not re-rendered, so the value does not change. I tried doing st.rerun() too but it doesn’t work.

Are we supposed to replace the … in run_main.spec with something?

I’m getting:

Traceback (most recent call last):
File “c:\users\johns\appdata\local\programs\python\python37\lib\runpy.py”, line 193, in run_module_as_main
main”, mod_spec)
File “c:\users\johns\appdata\local\programs\python\python37\lib\runpy.py”, line 85, in run_code
exec(code, run_globals)
File "C:\Users\johns\AppData\Local\Programs\Python\Python37\Scripts\pyinstaller.exe_main
.py", line 7, in
File "c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller_main
.py", line 124, in run
run_build(pyi_config, spec_file, **vars(args))
File “c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller_main_.py”, line 58, in run_build
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
File “c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller\building\build_main.py”, line 803, in main
build(specfile, distpath, workpath, clean_build)
File “c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller\building\build_main.py”, line 725, in build
exec(code, spec_namespace)
File “run_main.spec”, line 22, in
File “c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller\building\api.py”, line 79, in init
self.toc.extend(t)
File “c:\users\johns\appdata\local\programs\python\python37\lib\site-packages\PyInstaller\building\datastruct.py”, line 99, in extend
for entry in other:
TypeError: ‘ellipsis’ object is not iterable

各位好~我是來自臺灣的 streamlit 使用者!
很感謝各位的協助,我在這裡得到了很多幫助!
但近期,我在分享給其他人這個 exe 檔案遇到了問題。

我使用上述的方法將程式打包之後,
我將這個 exe 分享給別人,
在其他人的電腦點擊執行之後,
他們有跳出 splash 的畫面,
但是並沒有接續著在 chrome 跳出 streamlit 的頁面,
因此完全無法使用,
可是在我的電腦這些過程是完全正常的,
因此一直困惑不知道是哪一個環節有問題。
謝謝!

以下是我的 run_main.py

import os
import streamlit.web.cli as stcli
import sys

try:
    import pyi_splash # type: ignore
    pyi_splash.close()
except:
    pass

if __name__ == "__main__":
    os.chdir(os.path.dirname(__file__))

    sys.argv = [
        "streamlit",
        "run",
        "./application/main.py",
        "--server.port=8501",
        "--global.developmentMode=false"
    ]

    # 執行 streamlit 並且在關閉後退出
    sys.exit(stcli.main())

以下是 spec 文件: run_main.spec:

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['run_main.py'],
    pathex=[],
    binaries=[],
    datas=[
            (
                "C:/Users/XXX/AppData/Local/Programs/Python/Python311/Lib/site-packages/altair/vegalite/v5/schema/vega-lite-schema.json",
                "./altair/vegalite/v5/schema"
            ),
            (
                "C:/Users/XXX/AppData/Local/Programs/Python/Python311/Lib/site-packages/streamlit/static",
                "./streamlit/static"
            ),
            (   
                "C:/XXXX/Streamlit_backend/application",
                "./application"
            )
    ],
    hiddenimports=[
        'streamlit', 
        'wget', 
        'pandas', 
        'numpy',
        'statsmodels.api',
        'scipy.optimize.curve_fit',
        'altair'
    ],
    hookspath=['./hooks'],
    hooksconfig={},
    runtime_hooks=[],
    excludes=['matplotlib', 'scipy.spatial', 'scipy.special', 'sklearn', 'scipy.io', 'PIL', 'tensorflow', 'torch', 'nltk', 'gensim', 'jieba'],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

splash = Splash(
    'Dashboard.png',
    binaries = a.binaries,
    datas = a.datas,
    text_pos = (30, 405),
    text_size = 12,
    text_color = 'black'
)

exe = EXE(
    pyz,
    splash,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='Media Report Dashboard',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=False,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon='publicis.ico'
)

coll = COLLECT(
    exe,
    splash.binaries,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='Media Report Dashboard'
)

我覺得你可以先檢查看看每一個套件的版本,
是否彼此之間完全相容,
因為我在打包時也有遇到這樣的問題,
雖然我在 spec 的 hidden import 都有確實包含,
但依舊沒有在 exe 有成功 import
我當時是 scipy, statemodels, numpy 這三個套件有這樣的問題。

Hi!

I was wondering did you ever figure out a solution to this? I’m still using 1.29.0 bc newer versions don’t work.

Translated with Google: You can use it to create a .bat file that runs a python script so that you can run streamlit,
code run.bat=" @echo off
call myapp_env\Scripts\activate
streamlit run main.py " , code run.py=" import streamlit.web.cli as stcli
import sys

if name == ‘main’:
sys.argv = [“streamlit”, “run”, “main.py”]
sys.exit(stcli.main()) ", where main.py is the entry file to the application

Hi Nikesh,
hope you are doing well? Change the magic function to the following in Lib\site-packages\streamlit\web\cli.py

def _main_run_clExplicit(file, is_hello=False, args=[], flag_options={}):
    bootstrap.run(file, is_hello, args, flag_options)

and change the run.py or the mainfile to

from streamlit.web import cli
# This import path depends on your Streamlit version
if __name__ == '__main__':
    cli._main_run_clExplicit('app.py', args=['run'])

This code has been tested and confirmed to be functional in the latest version 1.38.0 . However, please note that I haven’t built an executable file yet, so I hope it will work even when compiled into an executable format.

Hi, I got this post from jvcss/PyInstallerStreamlit (github.com). I am here for thanking you all for this magic solution and also I have improvements to share:

  1. it is not necessary to copy app.py into the Output folder. You may put app.py and all .py webpages into a folder under source folder. And add one line to include that webpage folder in run_app.spec:
...
a = Analysis(
    ...
    datas=[
...
        ("./webpages",
        "./PyInstallerStreamlit/webpage"),
    ]
    ...

(assume PyInstallerStreamlit is the root folder and the run_app root namespace)
And in the run_app.py change the path of the app.py

cli._main_run_clExplicit('webpage/app.py', args=['run'])
  1. It is not necessary to add the following Data in the run_app.spec with virtual env:
Analysis(
    ...
    datas=[
        (".env/Lib/site-packages/altair/vegalite/v5/schema/vega-lite-schema.json",
        "./altair/vegalite/v5/schema/"),

The better way is improving the .\hooks\hook-streamlit.py:

from PyInstaller.utils.hooks import collect_all
datas, binaries, hiddenimports = collect_all('streamlit', include_py_files=False, include_datas=['**/*.*'])

So you don’t need create virtual environment under project folder and may use Conda environment.
Write similar hook for other components such as hook-altair, hook-streamlit_antd_components etc. and don’t have to write datas copying for each subdirectory in those components.

btw, I really wanted to use _main_run to replace the magic _main_run_clExplicit but failed. I don’t understand how this simple magic function works while the original main_run doesn’t.