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