How to convert a .py to .exe if i want to include many subfolders and imported modules in the final executable?

122 Views Asked by At

I have developed a project which has the following structure :

web_app
└── website
|   ├── __init__.py
|   ├── auth.py
|   ├── models.py
|   ├── views.py
|   ├── static
|   │   ├── images
|   │   │   └── logo_kg.png
|   │   ├── app.js
|   │   ├── index.js
|   │   └── styles.css
|   └── templates
|       ├── base.html
|       ├── home.html
|       ├── login.html
|       ├── sign_up.html
|       └── viewProjects.html
└── main.py

I want to convert my main.py to an executable in order to distribute it easily without the need of the client to have python installed on his system. I want to embed all the imported modules of my project and its subfolders (based on the project structure) into one executable file.

All the imported modules i have are :

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
from flask import Blueprint, render_template, request, flash, redirect, url_for
from .models import User
from werkzeug.security import generate_password_hash, check_password_hash
from . import db
from flask_login import login_user, login_required, logout_user, current_user
from website import create_app
from . import db
from flask_login import UserMixin
from sqlalchemy.sql import func
from flask import Blueprint, render_template, request, flash, jsonify
from flask_login import login_required, current_user
from .models import Project
from . import db
import json
import base64
from sqlalchemy import func

Some of the commands i tried

I tried running commands like :

pyinstaller --add-data "website/static;static" --add-data "website/templates;templates" --hidden-import flask,flask_sqlalchemy,flask_login,werkzeug.security,sqlalchemy.sql,sqlalchemy,flask_login.mixins,flask_login.utils,flask_login.config,flask_login.signals,flask_login.view,flask_login.login_manager --hidden-import website.models,website.db,json,base64 --onefile website/main.py

but upon running the generated .exe i was met with the localhost page displaying :

Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

and the console showing the following errors :

Created Database!
ERROR:website:Exception on /login [GET]
Traceback (most recent call last):
  File "flask\app.py", line 2190, in wsgi_app
  File "flask\app.py", line 1486, in full_dispatch_request
  File "flask\app.py", line 1484, in full_dispatch_request
  File "flask\app.py", line 1469, in dispatch_request
  File "auth.py", line 26, in login
  File "flask\templating.py", line 150, in render_template
  File "jinja2\environment.py", line 1081, in get_or_select_template
  File "jinja2\environment.py", line 1010, in get_template
  File "jinja2\environment.py", line 969, in _load_template
  File "jinja2\loaders.py", line 126, in load
  File "flask\templating.py", line 64, in get_source
  File "flask\templating.py", line 98, in _get_source_fast
jinja2.exceptions.TemplateNotFound: login.html

I don't really know how to proceed with generating one executable that will have embedded all the project structure and include the referenced imports.

1

There are 1 best solutions below

5
Magnus Enebakk On

Try using a spec file to manage pyinstaller properly.

# main.spec

block_cipher = None

a = Analysis(['main.py'],
             pathex=['<path_to_your_project>'],
             binaries=[],
             datas=[('<path_to_your_project>/website/static', 'static'),
                    ('<path_to_your_project>/website/templates', 'templates')],
             hiddenimports=['flask', 'flask_sqlalchemy', 'flask_login', 'werkzeug.security', 'sqlalchemy.sql', 'sqlalchemy', 'flask_login.mixins', 'flask_login.utils', 'flask_login.config', 'flask_login.signals', 'flask_login.view', 'flask_login.login_manager', 'website.models', 'website.db', 'json', 'base64'],
             hookspath=[],
             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='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True)

Save that as main.spec and run pyinstaller main.spec