Skip to content

Instantly share code, notes, and snippets.

@wmachert
Last active May 8, 2024 06:23
Show Gist options
  • Save wmachert/133b26abdf39f219042c6024b0dde5d6 to your computer and use it in GitHub Desktop.
Save wmachert/133b26abdf39f219042c6024b0dde5d6 to your computer and use it in GitHub Desktop.
Portable Windows Python Setup
@echo off
:: Portable Windows Python Setup
:: Downloads and installs a portable Python runtime as well as all requirements.
::
:: Usage: setup.bat [INSTALL-LOCATION] [PYTHON-VERSION]
:: INSTALL-LOCATION - python installation folder, default: .\rt
:: PYTHON-VERSION - major Python version, supported: 35 - 312, default: 312
::
:: To install python 3.12, pip, and all dependencies from the current directory into the directory .\python:
:: > setup.bat python 312
setlocal enabledelayedexpansion
:: arg 1: install location
if [%1] == [] (
:: default install location is .\rt
set PYTHON_HOME=%~dp0rt
) else (
set PYTHON_HOME=%~f1
)
:: arg 2: python version and download urls
if [%2] == [35] (
set PYTHON_VERSION=35
set PYTHON_URL=https://www.python.org/ftp/python/3.5.4/python-3.5.4-embed-amd64.zip
) else (
if [%2] == [36] (
set PYTHON_VERSION=36
set PYTHON_URL=https://www.python.org/ftp/python/3.6.8/python-3.6.8-embed-amd64.zip
) else (
if [%2] == [37] (
set PYTHON_VERSION=37
set PYTHON_URL=https://www.python.org/ftp/python/3.7.9/python-3.7.9-embed-amd64.zip
) else (
if [%2] == [38] (
set PYTHON_VERSION=38
set PYTHON_URL=https://www.python.org/ftp/python/3.8.10/python-3.8.10-embed-amd64.zip
) else (
if [%2] == [39] (
set PYTHON_VERSION=39
set PYTHON_URL=https://www.python.org/ftp/python/3.9.13/python-3.9.13-embed-amd64.zip
) else (
if [%2] == [310] (
set PYTHON_VERSION=310
set PYTHON_URL=https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-amd64.zip
) else (
if [%2] == [311] (
set PYTHON_VERSION=311
set PYTHON_URL=https://www.python.org/ftp/python/3.11.9/python-3.11.9-embed-amd64.zip
) else (
:: default python version
set PYTHON_VERSION=312
set PYTHON_URL=https://www.python.org/ftp/python/3.12.3/python-3.12.3-embed-amd64.zip
)))))))
:: install python runtime
call :install_python %PYTHON_VERSION% %PYTHON_URL%
call :unpack_lib2to3 %PYTHON_VERSION%
:: install pip and requirements
call :install_pip %PYTHON_VERSION%
call :install_requirements
goto :eof
:: ensure installed python - arguments: <python-major-version> <embedded-python-url>
:install_python
if not exist "%PYTHON_HOME%\python.exe" (
echo Downloading Python %1...
if not exist "%PYTHON_HOME%" mkdir "%PYTHON_HOME%"
if not exist "%PYTHON_HOME%\python-download.zip" curl -sL %2 -o "%PYTHON_HOME%\python-download.zip"
:: unzip python archive
powershell -Command "Expand-Archive '%PYTHON_HOME%\python-download.zip' -DestinationPath '%PYTHON_HOME%'"
del "%PYTHON_HOME%\python-download.zip"
:: add parent directory to default path
echo .\..>> "%PYTHON_HOME%\python%1._pth"
)
exit /b
:: ensure accessible lib2to3 grammar files - arguments: <python-major-version>
:unpack_lib2to3
if not exist "%PYTHON_HOME%\lib\lib2to3" (
echo Extracting lib2to3 and repacking base library...
"%PYTHON_HOME%\python.exe" -c "import os; import zipfile; pythonhome=os.environ['PYTHON_HOME'].replace('\\', '/'); i=zipfile.ZipFile(pythonhome + '/python%1.zip'); o=zipfile.ZipFile(pythonhome + '/python%1.zip.tmp', 'w'); [i.extract(f.filename, pythonhome + '/lib') if f.filename.startswith('lib2to3/') else o.writestr(f, i.read(f.filename)) for f in i.infolist()]; o.close();"
del "%PYTHON_HOME%\python%1.zip"
rename "%PYTHON_HOME%\python%1.zip.tmp" "python%1.zip"
)
exit /b
:: ensure pip installation - arguments: <python-major-version>
:install_pip
"%PYTHON_HOME%\python.exe" -c "from importlib.util import find_spec; import sys; sys.exit(1 if find_spec('pip') is None else 0)" >nul 2>nul
if [%ERRORLEVEL%] == [1] (
:: enable library path loading
echo lib>> "%PYTHON_HOME%\python%1._pth"
echo lib\site-packages>> "%PYTHON_HOME%\python%1._pth"
echo Installing pip...
:: handle legacy python versions
if [%1] == [35] (set PIP_URL=https://bootstrap.pypa.io/pip/3.5/get-pip.py) else (
if [%1] == [36] (set PIP_URL=https://bootstrap.pypa.io/pip/3.6/get-pip.py) else (
:: pip installer for current python versions
set PIP_URL=https://bootstrap.pypa.io/get-pip.py
)
)
:: install pip
"%PYTHON_HOME%\python.exe" -c "from urllib.request import urlretrieve; import os; urlretrieve('!PIP_URL!', os.environ['PYTHON_HOME'].replace('\\', '/') + '/get-pip.py')" && "%PYTHON_HOME%\python.exe" "%PYTHON_HOME%\get-pip.py" --no-warn-script-location && del "%PYTHON_HOME%\get-pip.py"
)
exit /b
:: install requirements
:install_requirements
:: requirements from pyproject
if exist "%~dp0pyproject.toml" (
"%PYTHON_HOME%\python.exe" -m pip install --no-warn-script-location "%~dp0."
)
:: requirements from requirements.txt
if exist "%~dp0requirements.txt" (
"%PYTHON_HOME%\python.exe" -m pip install --no-warn-script-location -r "%~dp0requirements.txt"
)
exit /b
endlocal
@wmachert
Copy link
Author

wmachert commented Sep 27, 2022

curl -sL https://gist.githubusercontent.com/wmachert/133b26abdf39f219042c6024b0dde5d6/raw/python-setup.bat -o setup.bat && setup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment