q2sfx
https://github.com/AndreiPuchko/q2sfx
q2sfx is a Python package and CLI tool to create self-extracting executables (SFX) from Python applications built with PyInstaller.
It embeds your Python application (as a ZIP archive) into a Go-based SFX installer, supports console or GUI modes, and can optionally create a desktop shortcut.
✨ Key Features
- Build Python apps using PyInstaller (optional, can start from existing build).
- Pack PyInstaller output into a ZIP payload (optional, can start from existing ZIP).
- Embed payload into a Go-based self-extracting executable (SFX).
The generated SFX executable provides:
-
Installer: on the first run extracts all payload data (PyApp) into the given folder(optional), creates the shortcut (optional) and runs PyApp.
-
Updater: When updating, the tool only overwrites core components (
.exe,.ver,_internal/, andassets/) and runs PyApp. Custom user folders, logs, or local databases remain untouched. Before overwriting, existing core files and directories are automatically backed up as.bak. A platform-specific rollback script (_rollback.baton Windows or_rollback.shon Linux/macOS) is generated, allowing the previous version to be fully restored if needed. -
CLI Flexibility: SFX Supports flags to force console mode, change the installation path or shortcut name.
-
Progress bar with animated spinner.
-
Cross-platform: Windows, Linux, macOS.
-
Progress indication during extraction, including an animated spinner.
-
Safe overwrite behavior — only predefined folders and files are modified (
_internal,assets, and the executable itself), preventing accidental data loss.
Requirements
- Python 3.8–3.11
- Go (for building the SFX)
- PyInstaller (if you want the builder to run it automatically)
Installation
For End Users
Install q2sfx as a Python package via Poetry:
poetry add q2sfx
or
pip install q2sfx
For Developers
git clone https://github.com/AndreiPuchko/q2sfx
cd q2sfx
poetry install
poetry add --group dev pytest pytest-cov
Usage
CLI usage
q2sfx --help
usage: q2sfx [-h] [--version] [-o OUTPUT] [--console] [--no-pyinstaller] [--dist DIST] [--payload PAYLOAD] [--build-time BUILD_TIME] [--no-ver-file] app
Build a self-extracting executable (SFX) from a Python application using PyInstaller + Go.
positional arguments:
app Path to the Python entry script (e.g. app.py)
options:
-h, --help show this help message and exit
--version show program's version number and exit
-o OUTPUT, --output OUTPUT
Output SFX file path (default: <app_name>_sfx.exe in dist.sfx)
--console Build payload application with console (default: GUI)
--no-pyinstaller Assume PyInstaller build already exists (skip PyInstaller step)
--dist DIST Use existing PyInstaller dist directory instead of running PyInstaller
--payload PAYLOAD Use existing payload zip instead of creating one
--build-time BUILD_TIME
Build timestamp for .ver file (default: current datetime)
--no-ver-file Do not include a .ver file in dist.zip
Basic usage
Build a console application from Python code
This runs PyInstaller with default options and wraps the result into an SFX.
from q2sfx import Q2SFXBuilder
final_exe = Q2SFXBuilder.build_sfx_from("tests/test_app.py", console=True)
print("Built SFX:", final_exe)
Build an SFX from an existing PyInstaller dist/ directory Useful when PyInstaller requires custom options or hooks.
final_exe = Q2SFXBuilder.build_sfx_from(dist_path="dist/test_app", output_name="t2.exe")
print("Built SFX:", final_exe)
Build an SFX from a ZIP payload Useful when your distribution contains extra assets or was prepared externally.
final_exe = Q2SFXBuilder.build_sfx_from(payload_zip="dist.zip/test_app.zip", output_name="t3.exe")
print("Built SFX:", final_exe)
Advanced usage
You can start the builder from any stage:
builder = Q2SFXBuilder("your_app.py", console=True)
Use an existing PyInstaller dist folder
builder.set_dist("dist/your_app")
Or use an existing ZIP payload
builder.set_payload("dist/your_app.zip")
Build SFX
builder.build_sfx("dist.sfx/my_app_setup.exe")
ZIP file notes
- The Python application name must match the ZIP archive name.
- By default, SFX will be generated in the
dist.sfx/folder.
Simple Auto-update example
Each SFX build produced by q2sfx can include a .ver file containing
the build timestamp (for example: 2025-12-31 18:42:10).
The application can compare its local .ver file with a remote one
and automatically download and run a newer SFX build.
Expected files on the update server
test_app_sfx.exe
test_app_sfx.ver
How it works
- On startup, the application checks whether it is running as a frozen executable.
- It reads its local
<app>.verfile. - It downloads and compares the remote
.verfile. - If a newer build is available:
- the new SFX is downloaded
- launched in detached mode
- the current application exits
- The new SFX handles safe replacement and rollback internally
(
.bakfiles +_rollback.bat/_rollback.sh) and starts updated app
Example update logic
if new_build_time > current_build_time:
# download new SFX
# run installer
# exit current app
Simple GUI demo workflow (for Windows)
# create virtual enviroment (python 3.9 used)
py -3.9 -m venv .venv
# activate virtual enviroment
.\.venv\Scripts\activate
# install deps for demo project
pip install q2db q2gui
pip install git+https://github.com/AndreiPuchko/q2sfx.git
# clone demo project
git clone https://github.com/AndreiPuchko/q2-short.git
# build SFX
q2sfx .\q2-short\app.py
# run the result
cd dist.sfx
./app_sfx.exe
License
MIT License
Metadata
Release files for q2sfx 0.1.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| q2sfx-0.1.8.tar.gz | 11.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| q2sfx-0.1.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.5 kB
Release files / q2sfx-0.1.8.tar.gz
| Download URL | q2sfx-0.1.8.tar.gz |
|---|---|
| Size | 11.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
64ee6d6f9ab2df6eb759db9086bab92879ec6b4fe0a3315e3cf552f6df30fdf2
|
|
BLAKE2b-256 checksum How to use checksums |
ef2f03e0e63b6e9a59d0b42fa5a6182b4617a38c6024ea784ce05cfc142bd793
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.5.0 CPython/3.11.7 Windows/10
|
Release files / q2sfx-0.1.8-py3-none-any.whl
| Download URL | q2sfx-0.1.8-py3-none-any.whl |
|---|---|
| Size | 12.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a29dde34e89b66cd1d1484d194fbfb5006e1f92be9ab5c482d4ac1e643eb6d6e
|
|
BLAKE2b-256 checksum How to use checksums |
7be96688ba252e2fea13471c80b90c4a273f020c11745ed2804a30ef827f3b0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.5.0 CPython/3.11.7 Windows/10
|