I downloaded and installed Python 3.10.6 on windows 10 pro, installed Shiny for Python, created the sample app and run it. This worked fine.
I installed pyinstaller and converted the app to an exe. I tried to run the app it threw (please see below).
Does anyone know if this can work and if so how?
This is the file2.spec that worked:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
import os
# /c/Users/raz/AppData/Local/Programs/Python/Python310/Lib/site-packages/
shiny = os.path.abspath("../AppData/Local/Programs/Python/Python310/Lib/site-packages/shiny")
a = Analysis(
['file2.py'],
pathex=[],
binaries=[],
datas=[('app.py', '/'), (shiny,'/shiny')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='file2',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
This below did not work:
raz@rays8350 MINGW64 ~/shiny
$ cat app.py
from shiny import App, render, ui
app_ui = ui.page_fluid(
ui.h2("Hello Shiny!"),
ui.input_slider("n", "N", 0, 100, 20),
ui.output_text_verbatim("txt"),
)
def server(input, output, session):
@output
@render.text
def txt():
return f"n*2 is {input.n() * 2}"
app = App(app_ui, server)
raz@rays8350 MINGW64 ~/shiny
$
raz@rays8350 MINGW64 ~/shiny
$ ../AppData/Local/Programs/Python/Python310/Scripts/shiny.exe run --reload dist/app/app.exe
INFO: Will watch for changes in these directories: ['C:\\Users\\raz\\shiny\\dist\\app']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [23368] using StatReload
Process SpawnProcess-1:
Traceback (most recent call last):
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\multiprocessing\process.py", line 314, in _bootstrap
self.run()
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\multiprocessing\process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\_subprocess.py", line 76, in subp
rocess_started
target(sockets=sockets)
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\server.py", line 60, in run
return asyncio.run(self.serve(sockets=sockets))
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 646, in run_until_complet
e
return future.result()
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\server.py", line 67, in serve
config.load()
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\config.py", line 479, in load
self.loaded_app = import_from_string(self.app)
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\importer.py", line 24, in import_
from_string
raise exc from None
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\site-packages\uvicorn\importer.py", line 21, in import_
from_string
module = importlib.import_module(module_str)
File "C:\Users\raz\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'app'
Since writing my original answer I have discovered an even simpler means of using pyinstaller to create a shiny application executable.
This is a simplified step by step:
Steps 1-4 are the same as the original answer (see below) and simply involve opening a new directory and creating a virtual environment for the project.
run_app
to execute the app without needing to use the command line:from shiny import App, render, ui
from shiny._main import run_app
app_ui = ui.page_fluid(
ui.h2("Hello Shiny!"),
ui.input_slider("n", "N", 0, 100, 20),
ui.output_text_verbatim("txt"),
)
def server(input, output, session):
@output
@render.text
def txt():
return f"n*2 is {input.n() * 2}"
app = App(app_ui, server)
run_app(app)
pyinstaller -F --collect-all shiny --name MyAppName file1.py
And thats it. The executable will be in the dist
folder.
Okay... So here are the steps I took to make it work.
python -m venv venv
venv\scripts\activate.bat
pip install pyinstaller shiny
file1.py
)from shiny import App, render, ui
app_ui = ui.page_fluid(
ui.h2("Hello Shiny!"),
ui.input_slider("n", "N", 0, 100, 20),
ui.output_text_verbatim("txt"),
)
def server(input, output, session):
@output
@render.text
def txt():
return f"n*2 is {input.n() * 2}"
app = App(app_ui, server)
file2.py
) and copy pasteimport os
import sys
from shiny._main import main
path = os.path.dirname(os.path.abspath(__file__))
apath = os.path.join(path, "file1.py")
# these next two lines are only if you are using Windows OS
drive, apath = os.path.splitdrive(apath)
apath = apath.replace("\\","/")
#
sys.argv = ['shiny', 'run', apath]
main()
pyinstaller -F file2.py
file2.spec
file open it and make the changes in the code below:file2.spec
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
import os
# use OS equivalent for path below
shiny = os.path.abspath("./venv/Lib/site-packages/shiny")
a = Analysis(
...
...
datas = [('file1.py', '/'), (shiny,'/shiny')] # fill in the datas value
...
...
Last step:
pyinstaller file2.spec
At the end of this your top level directory should look like this:
build
dist
venv
file1.py
file2.py
file2.spec
That is what worked for me. And the exe is in the dist
folder.
If you want to change the name of the executable or the icon or any of that stuff that can all be done in the spec
file and instructions can be found in the pyinstaller docs