zaz-pip/source/pythonpath/install_pip_from_wheel.py

142 lines
4.9 KiB
Python

from __future__ import annotations
import os
from typing import Any
import tempfile
from pathlib import Path
import easymacro as app
from contextlib import contextmanager
import uno
@contextmanager
def change_dir(directory):
"""
A context manager that changes the current working directory to the specified directory
temporarily and then changes it back when the context is exited.
"""
current_dir = os.getcwd()
os.chdir(directory)
try:
yield
finally:
os.chdir(current_dir)
class InstallPipFromWheel:
"""Download and install PIP from wheel url"""
def __init__(self, pip_wheel_url: str, lo_identifier: str) -> None:
self._pip_url = pip_wheel_url
self._lo_identifier = lo_identifier
def install(self, dst: str | Path = "") -> None:
"""
Install pip from wheel file.
Downloads the pip wheel file from the url provided in the config file and unzips it to the destination directory.
Args:
dst (str | Path, Optional): The destination directory where the pip wheel file will be installed. If not provided, the ``pythonpath`` location will be used.
Returns:
None:
Raises:
None:
"""
if not self._pip_url:
app.error("PIP installation has failed - No wheel url")
return
if not dst:
root_pth = Path(app.Paths.from_id(self._lo_identifier))
dst = root_pth / "pythonpath"
with tempfile.TemporaryDirectory() as temp_dir:
# temp_dir = tempfile.gettempdir()
path_pip = Path(temp_dir)
filename = path_pip / "pip-wheel.whl"
data, _, err = app.url_open(self._pip_url, verify=False)
if err:
app.error("Unable to download PIP installation wheel file")
return
filename.write_bytes(data)
if filename.exists():
app.info("PIP wheel file has been saved")
else:
app.error("PIP wheel file has not been saved")
return
try:
self._unzip_wheel(filename=filename, dst=dst)
except Exception:
return
# now that pip has been installed from wheel force a reinstall to ensure it is the latest version
self._force_install_pip()
def _unzip_wheel(self, filename: Path, dst: str | Path) -> None:
"""Unzip the downloaded wheel file"""
if isinstance(dst, str):
dst = Path(dst)
try:
# app.zip.unzip(source=str(filename), target=str(dst))
self.unzip_file(zip_file=filename, dest_dir=dst)
if dst.exists():
app.debug(f"PIP wheel file has been unzipped to {dst}")
else:
app.error("PIP wheel file has not been unzipped")
raise Exception("PIP wheel file has not been unzipped")
except Exception as err:
app.error(f"Unable to unzip wheel file: {err}", exc_info=True)
raise
def _force_install_pip(self) -> None:
"""Now that pip has been installed, force reinstall it to ensure it is the latest version"""
cmd = [app.paths.python, "-m", "pip", "install", "--upgrade", "pip"]
app.popen(command=" ".join(cmd))
def unzip_file(self, zip_file: str | Path, dest_dir: str | Path = "") -> None:
"""
Unzip the given zip file to the specified destination directory.
Args:
zip_file (str | Path): The zip file to unzip.
dest_dir (str | Path, optional): The destination directory to unzip to.
Returns:
None:
"""
from zipfile import ZipFile
zip_file_path = Path(zip_file) if isinstance(zip_file, str) else zip_file
if not zip_file_path.is_file():
raise ValueError(f"Expected file, got '{zip_file_path}'")
if not zip_file_path.is_absolute():
zip_file_path = zip_file_path.absolute()
if not zip_file_path.exists():
raise FileNotFoundError(f"File '{zip_file_path}' not found")
if isinstance(dest_dir, str):
dest_dir = zip_file_path.parent if dest_dir == "" else Path(dest_dir)
else:
dest_dir = dest_dir.absolute()
if not dest_dir.is_dir():
raise ValueError(f"Expected folder, got '{dest_dir}'")
if not dest_dir.exists():
try:
dest_dir.mkdir(parents=True)
except Exception as e:
raise FileNotFoundError(f"Folder '{dest_dir}' not found, unable to create folder.") from e
if not dest_dir.exists():
raise FileNotFoundError(f"Folder '{dest_dir}' not found")
with change_dir(dest_dir):
with ZipFile(zip_file_path) as f:
f.extractall(dest_dir)
# with change_dir(dest_dir):
# shutil.unpack_archive(zip_file_path, dest_dir)