Source code for pymyinstall.win_installer.win_patch

"""
Patch the distribution to make it portable


:githublink:`%|py|5`
"""
from __future__ import print_function

import os
import re


[docs]class ShebangException(Exception): """ exception raised when the shebang is not correct :githublink:`%|py|14` """ pass
[docs]def win_patch_paths(folder, path_to_python="", fLOG=print): """ Paths are absolute when they are installed in all scripts *.exe*, we replaced them either by an empty string (``path_to_python == ""``) or the current folder. :param folder: folder where to find the executable :param path_to_python: new python path (replace by) :param fLOG: logging function :return: list of tuple ('exe or py', 'modified file') See `Create a portable Python with Pip on Windows <http://www.clemens-sielaff.com/create-a-portable-python-with-pip-on-windows/>`_ The first three parameters can be environment variables. They will be replaced by their values. :githublink:`%|py|32` """ if folder in os.environ: folder = os.environ[folder] if path_to_python not in (None, "") and path_to_python in os.environ: path_to_python = os.environ[path_to_python] if path_to_python is None: exe = os.path.join(folder, "python.exe") if os.path.exists(exe): path_to_python = os.path.absapth(folder) else: exe = os.path.join(folder, "..", "python.exe") path_to_python = os.path.normpath( os.path.abspath(os.path.join(folder, ".."))) files = os.listdir(folder) if len(path_to_python) > 0 and not path_to_python.endswith("\\"): path_to_python += "\\" pattern = "([#][!]((([A-Za-z][:])?[/\\\\]?[-a-zA-Z0-9_.]+[/\\\\])*?)(pythonw?[.]exe))" reg_exe = re.compile(pattern, re.IGNORECASE) breg_exe = re.compile(bytes(pattern, encoding="ascii"), re.IGNORECASE) g_path_to_python = path_to_python.replace("\\", "\\\\") bg_path_to_python = bytes(g_path_to_python, encoding="ascii") b1 = bytes("#!", encoding="ascii") b2 = bytes("\\5", encoding="ascii") operations = [] for file in files: full = os.path.join(folder, file) if os.path.isfile(full): ext = os.path.splitext(full)[-1] if ext in {".py", ""}: with open(full, "r") as f: content = f.read() new_content = reg_exe.sub( "#!" + g_path_to_python + "\\5", content) if new_content != content: fLOG("[pymy] update ", full) operations.append(("update", full)) with open(full, "w") as f: f.write(new_content) elif ext == ".exe": with open(full, "rb") as f: content = f.read() new_content = breg_exe.sub( b1 + bg_path_to_python + b2, content) if new_content != content: fLOG("[win_patch_paths] update ", full) operations.append(("update", full)) try: with open(full, "wb") as f: f.write(new_content) except PermissionError as e: with open(full + ".replace", "wb") as f: f.write(new_content) mes = ("unable to overwrite '{0}', it will have to be manually done, " + "another file was created with .replace as an extension").format( full) raise Exception(mes) from e else: pass return operations