Packaging sanic runtime error

runtime environment:
pyinstaller:5.9.0
python 3.10
sanic:23.3
os:windows11
use pyinstaller to packup windows application,but when running this exe file, the error is as follows~ How do you solve it?thanks

Traceback (most recent call last):
  File "app.py", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\__init__.py", line 2, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\app.py", line 51, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\application\state.py", line 13, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\server\__init__.py", line 5, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\server\runners.py", line 8, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\config.py", line 13, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\errorpages.py", line 26, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "sanic\pages\error.py", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "tracerite\__init__.py", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 352, in exec_module
  File "tracerite\html.py", line 6, in <module>
  File "pkg_resources\__init__.py", line 1166, in resource_string
  File "pkg_resources\__init__.py", line 1412, in get_resource_string
  File "pkg_resources\__init__.py", line 1579, in _get
  File "PyInstaller\loader\pyimod02_importers.py", line 197, in get_data
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\mypc\\AppData\\Local\\Temp\\_MEI27362\\tracerite\\style.css'
[8120] Failed to execute script 'app' due to unhandled exception!

I don’t claim to even attempt to support pyinstalle. I’ve never gotten anything but a hello world app working. Anything more complex, let alone a Sanic app, is beyond me. There was someone that recently reported doing it by using single_process=True.

But, anything more, and I am sorry to say, I cannot help. This isn’t so much a Sanic problem as it is a pyinstaller problem.

If you must bundle the Sanic server by pyinstaller, you can do like this:

By the way, My environment is:

  • Ubuntu 22.04
  • Python 3.10.6
  • Sanic[ext] 23.6.0
  • PyInstaller 5.13.0

First, the error may be caused by PyInstaller not bundle module tracerite, so you can add a python file named hook-tracerite.py:

# hook-tracerite.py
from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all("tracerite")

module tracerite require module html5tagger, so add a python file named hook-html5tagger.py as above:

# hook-tracerite.py
from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all("html5tagger")

Then, you need to change the sever single process, and unset TOUCHUP, like this:

from sanic import Sanic, response

app = Sanic("HelloApp")
app.config.TOUCHUP = False

@app.get("/hello")
async def hello(request):
    return response.text("world")

if __name__ == '__main__':
    app.run(host="0.0.0.0",single_process=True)

The archstructure of this project like:

.
├── hello_server.py
├── pyinstaller-hook
│   ├── hook-html5tagger.py
│   └── hook-tracerite.py
└── venv

Use command to bundle the Server:

pyinstaller --additional-hooks-dir=./pyinstaller-hook -F hello_server.py

What is more, if you have used sanic_ext, you need to add hook-sanic_ext.py

2 Likes

What is app.config.TOUCHUP = False for? I didn’t find document about what this config is.

I was able to create working pyinstaller bundle with sanic 23.12, with multi-worker.

Important was to update source code to use multiprocessing.freeze_support() before actually running Sanic application (Common Issues and Pitfalls — PyInstaller 6.5.0+g4f194dc documentation). Despite Python documentation saying this makes sense in Windows environments only!

$ cat hello_sanic.py


from sanic import Sanic
from sanic.response import text

app = Sanic("helloworld")

@app.route("/")
async def hello_world(request):
    return text("Hello, World!")

if __name__ == "__main__":
    # below lines are a must for making pyinstaller bundle
    import multiprocessing
    multiprocessing.freeze_support()

    app.run(host="0.0.0.0", port=8000, workers=2)

Then, actual build of the pyinstaller bundle:

python3 -m venv venv
source venv/bin/activate
pip3 install sanic==23.12.* pyinstaller

pyinstaller --collect-all tracerite --collect-all sanic hello_sanic.py

Then testing:

$ dist/hello_sanic/hello_sanic
[2024-04-12 13:30:17 +0200] [3002] [INFO]
  ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                          Sanic v23.12.1                                          │
  │                                 Goin' Fast @ http://0.0.0.0:8000                                 │
  ├───────────────────────┬──────────────────────────────────────────────────────────────────────────┤
  │                       │      app: helloworld                                                         │
  │     ▄███ █████ ██     │     mode: production, w/ 2 workers                                       │
  │    ██                 │   server: sanic, HTTP/1.1                                                │
  │     ▀███████ ███▄     │   python: 3.10.12                                                        │
  │                 ██    │ platform: Linux-5.15.146.1-microsoft-standard-WSL2-x86_64-with-glibc2.35 │
  │    ████ ████████▀     │ packages: sanic-routing==23.12.0                                         │
  │                       │                                                                          │
  │ Build Fast. Run Fast. │                                                                          │
  └───────────────────────┴──────────────────────────────────────────────────────────────────────────┘

[2024-04-12 13:30:17 +0200] [3002] [WARNING] Sanic is running in PRODUCTION mode. Consider using '--debug' or '--dev' while actively developing your application.
[2024-04-12 13:30:18 +0200] [3013] [INFO] Starting worker [3013]
[2024-04-12 13:30:18 +0200] [3012] [INFO] Starting worker [3012]
### meantime in another shell:
$ curl 127.0.0.1:8000
Hello, World!
###
^C
[2024-04-12 13:30:23 +0200] [3012] [INFO] Stopping worker [3012]
[2024-04-12 13:30:23 +0200] [3013] [INFO] Stopping worker [3013]
[2024-04-12 13:30:23 +0200] [3002] [INFO] Received signal SIGINT. Shutting down.
[2024-04-12 13:30:23 +0200] [3013] [INFO] Worker complete [3013]
[2024-04-12 13:30:23 +0200] [3012] [INFO] Worker complete [3012]
[2024-04-12 13:30:23 +0200] [3002] [INFO] Server Stopped