Skip to content

Instantly share code, notes, and snippets.

@ysfchn
Last active May 25, 2023 20:55
Show Gist options
  • Save ysfchn/09e578991aa92a104e3d0c7bc4a5acc9 to your computer and use it in GitHub Desktop.
Save ysfchn/09e578991aa92a104e3d0c7bc4a5acc9 to your computer and use it in GitHub Desktop.
Super simple batch file to pack a Python project into a SFX. See below for instructions.
@echo off
setlocal
rem #
rem # peyexe
rem #
rem # Super simple batch file to pack a Python project into a single-executable exe using 7z SFX.
rem #
rem # ysfchn (https://ysfchn.com)
rem #
rem # Before getting started, make sure you have:
rem #
rem # - Obviously, an internet connection.
rem # An embedded verison of Python will be downloaded.
rem #
rem # - A "requirements.txt" in the current working directory to specify additional libraries.
rem #
rem # - A "peyexe.ini" file for configuration (in key=value format):
rem # * python
rem # Specifies which version of Python will be used. Example: "python=3.9.7"
rem # * sources
rem # Name of the folder that will includes project sources.
rem # * run
rem # Name of the file in the source directory that will be executed.
rem # * console
rem # 0 to disable Python console window. 1 (default) to show console.
rem # * progress
rem # 0 to hide extract progress. 1 (default) to show the progress.
rem # * pip_strategy
rem # 0 (default) to install packages beforehand (bigger exe size but starts faster),
rem # 1 to install pip packages when started (smaller exe size but slightly takes longer to start)
rem #
rem # If everything goes ok, an executable named "peyexe.exe" will be created in the current working directory.
rem #
rem # https://stackoverflow.com/a/4518146
@for /f "tokens=2 delims==" %%a in ('find "python=" "peyexe.ini"') do set PYTHONVERSION=%%a
@for /f "tokens=2 delims==" %%a in ('find "run=" "peyexe.ini"') do set PYTHONEXECUTE=%%a
@for /f "tokens=2 delims==" %%a in ('find "sources=" "peyexe.ini"') do set PYTHONSOURCES=%%a
@for /f "tokens=2 delims==" %%a in ('find "console=" "peyexe.ini"') do set PYTHONWINDOWMODE=%%a
@for /f "tokens=2 delims==" %%a in ('find "progress=" "peyexe.ini"') do set PYTHONPROGRESS=%%a
@for /f "tokens=2 delims==" %%a in ('find "pip_strategy=" "peyexe.ini"') do set PYTHONPIPSTRATEGY=%%a
bitsadmin /transfer . /download /priority foreground https://www.7-zip.org/a/7zr.exe %temp%\\7zr.exe
bitsadmin /transfer . /download /priority foreground https://sourceforge.net/projects/sevenzip/files/LZMA%%20SDK/lzma2201.7z/download %temp%\\lzmasdk.7z
bitsadmin /transfer . /download /priority foreground https://sourceforge.net/projects/sevenzip/files/7-Zip/22.01/7z2201-extra.7z/download %temp%\\7z.7z
bitsadmin /transfer . /download /priority foreground https://www.python.org/ftp/python/%PYTHONVERSION%/python-%PYTHONVERSION%-embed-win32.zip %temp%\\python-embed.zip
bitsadmin /transfer . /download /priority foreground https://bootstrap.pypa.io/get-pip.py %temp%\\get-pip.py
echo Extracting...
%temp%\7zr.exe x -bso0 -bsp0 -y -o%temp%\7z %temp%\7z.7z
%temp%\7z\7za.exe x -bso0 -bsp0 -y -o%temp%\lzma %temp%\lzmasdk.7z
%temp%\7z\7za.exe x -bso0 -bsp0 -y -o%temp%\python-embed %temp%\python-embed.zip
echo Setting up Python...
rem # Find python(VERSION)._pth file.
for /r "%temp%\python-embed" %%a in (*._pth) do set PYPATHFILE=%%~na
rem # Modify ._pth file to enable site-packages.
del %temp%\python-embed\%PYPATHFILE%._pth
echo %PYPATHFILE%.zip >> %temp%\python-embed\%PYPATHFILE%._pth
echo . >> %temp%\python-embed\%PYPATHFILE%._pth
echo | set /p a="import site" >> %temp%\python-embed\%PYPATHFILE%._pth
rem # Install pip.
move /Y %temp%\get-pip.py %temp%\python-embed >nul
%temp%\python-embed\python.exe %temp%\python-embed\get-pip.py --no-warn-script-location
rem # If pip_strategy is 1, only download wheels and install them on startup,
rem # otherwise, install packages right now and delete pip.
if "%PYTHONPIPSTRATEGY%"=="1" (
%temp%\python-embed\python.exe -m pip download -r %cd%\requirements.txt --dest %temp%\python-embed\external
copy /Y %cd%\requirements.txt %temp%\python-embed\requirements.txt >nul
) else (
%temp%\python-embed\python.exe -m pip install -r %cd%\requirements.txt --no-warn-script-location
%temp%\python-embed\python.exe -m pip uninstall pip -y
)
echo Packaging...
rem # Copy sources in python-embed.
mkdir %temp%\python-embed\app
xcopy %cd%\%PYTHONSOURCES% %temp%\python-embed\app /e
rem # Delete get-pip.py
del %temp%\python-embed\get-pip.py
set PYTHONEXECUTABLE=python.exe
set EXTRACTPROGRESS=yes
if "%PYTHONWINDOWMODE%"=="0" (set PYTHONEXECUTABLE=pythonw.exe)
if "%PYTHONPROGRESS%"=="0" (set EXTRACTPROGRESS=no)
rem # Create bootstrapper.
(
echo import subprocess
if "%PYTHONPIPSTRATEGY%"=="1" echo subprocess.call^("cd external && ..\python.exe -m pip install -r ../requirements.txt --no-index --find-links . && cd ..", shell=True^)
echo subprocess.call^(".\python.exe -E app/%PYTHONEXECUTE%", shell=True^)
) > %temp%\python-embed\bootstrap.py
rem # Pack the embedded Python.
%temp%\7zr.exe a -bso0 -bsp0 -y -mx0 %temp%\peyexe-source.7z %temp%\python-embed\*
rem # Create config file.
(
echo ;!@Install@!UTF-8!
echo Progress="%EXTRACTPROGRESS%"
echo RunProgram=".\%PYTHONEXECUTABLE% -E bootstrap.py"
echo ;!@InstallEnd@!
) > %temp%\peyexe-build.txt
rem # Build 7z SFX.
copy /Y /b %temp%\lzma\bin\7zSD.sfx + %temp%\peyexe-build.txt + %temp%\peyexe-source.7z peyexe.exe >nul
echo Cleaning up...
rmdir /s /q %temp%\python-embed
del %temp%\python-embed.zip
del %temp%\peyexe-build.txt
del %temp%\peyexe-source.7z
del %temp%\7zr.exe
rmdir /s /q %temp%\7z
rmdir /s /q %temp%\lzma
echo Done!

peyexe

Super simple batch file to pack a Python project into a standalone .exe using 7z SFX. (For legacy iexpress version see here.) It doesn't require anything, as the required software will be downloaded automatically.

Usage

  • Create a peyexe.ini configuration file and specify Python version, the name of the file and window mode.

    python=3.9.7
    ; Exact version of Python that the file will be run in.
    sources=sources
    ; Name of the folder that will includes project sources.
    run=myapplication.py
    ; Name of the file in the source directory that will be executed.
    console=1
    ; 0 to disable Python console window. 1 (default) to show console.
    progress=1
    ; 0 to hide extract progress. 1 (default) to show the progress.
    pip_strategy=0
    ; 0 (default) to install packages beforehand (bigger exe size but starts faster), 
    ; 1 to install pip packages when started (smaller exe size but slightly takes longer to start) 
  • Create a requirements.txt file to specify additional modules that your project requires.

  • Put these requirements.txt and peyexe.ini files in the same directory along with the source project directory.

    - requirements.txt
    - peyexe.ini
    - sources/
        - myapplication.py
        - otherfile.txt
        - myotherfile.py
    
  • Open up your favourite terminal in that directory.

  • Execute the command to build the .exe:

    cmd /c "bitsadmin /transfer . /download /priority foreground https://is.gd/laR0IM %temp%\\pyx.bat & %temp%\\pyx.bat"
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment