diff options
Diffstat (limited to 'sources/pyside-tools/deploy_lib/python_helper.py')
-rw-r--r-- | sources/pyside-tools/deploy_lib/python_helper.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/sources/pyside-tools/deploy_lib/python_helper.py b/sources/pyside-tools/deploy_lib/python_helper.py new file mode 100644 index 000000000..7cbf323ed --- /dev/null +++ b/sources/pyside-tools/deploy_lib/python_helper.py @@ -0,0 +1,122 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import logging +import os +import sys + +from importlib import util +from importlib.metadata import version +from pathlib import Path + +from . import Config, run_command + + +class PythonExecutable: + """ + Wrapper class around Python executable + """ + + def __init__(self, python_path: Path = None, dry_run: bool = False, init: bool = False, + force: bool = False): + + self.dry_run = dry_run + self.init = init + if not python_path: + response = "yes" + # checking if inside virtual environment + if not self.is_venv() and not force and not self.dry_run and not self.init: + response = input(("You are not using a virtual environment. pyside6-deploy needs " + "to install a few Python packages for deployment to work " + "seamlessly. \n Proceed? [Y/n]")) + + if response.lower() in ["no", "n"]: + print("[DEPLOY] Exiting ...") + sys.exit(0) + + self.exe = Path(sys.executable) + else: + self.exe = python_path + + logging.info(f"[DEPLOY] Using Python at {str(self.exe)}") + + @property + def exe(self): + return Path(self._exe) + + @exe.setter + def exe(self, exe): + self._exe = exe + + @staticmethod + def is_venv(): + venv = os.environ.get("VIRTUAL_ENV") + return True if venv else False + + def is_pyenv_python(self): + pyenv_root = os.environ.get("PYENV_ROOT") + + if pyenv_root: + resolved_exe = self.exe.resolve() + if str(resolved_exe).startswith(pyenv_root): + return True + + return False + + def install(self, packages: list = None): + _, installed_packages = run_command(command=[str(self.exe), "-m", "pip", "freeze"], + dry_run=False, fetch_output=True) + installed_packages = [p.decode().split('==')[0] for p in installed_packages.split()] + for package in packages: + package_info = package.split('==') + package_components_len = len(package_info) + package_name, package_version = None, None + if package_components_len == 1: + package_name = package_info[0] + elif package_components_len == 2: + package_name = package_info[0] + package_version = package_info[1] + else: + raise ValueError(f"{package} should be of the format 'package_name'=='version'") + if (package_name not in installed_packages) and (not self.is_installed(package_name)): + logging.info(f"[DEPLOY] Installing package: {package}") + run_command( + command=[self.exe, "-m", "pip", "install", package], + dry_run=self.dry_run, + ) + elif package_version: + installed_version = version(package_name) + if package_version != installed_version: + logging.info(f"[DEPLOY] Installing package: {package_name}" + f"version: {package_version}") + run_command( + command=[self.exe, "-m", "pip", "install", "--force", package], + dry_run=self.dry_run, + ) + else: + logging.info(f"[DEPLOY] package: {package_name}=={package_version}" + " already installed") + else: + logging.info(f"[DEPLOY] package: {package_name} already installed") + + def is_installed(self, package): + return bool(util.find_spec(package)) + + def install_dependencies(self, config: Config, packages: str, is_android: bool = False): + """ + Installs the python package dependencies for the target deployment platform + """ + packages = config.get_value("python", packages).split(",") + if not self.init: + # install packages needed for deployment + logging.info("[DEPLOY] Installing dependencies") + self.install(packages=packages) + # nuitka requires patchelf to make patchelf rpath changes for some Qt files + if sys.platform.startswith("linux") and not is_android: + self.install(packages=["patchelf"]) + elif is_android: + # install only buildozer + logging.info("[DEPLOY] Installing buildozer") + buildozer_package_with_version = ([package for package in packages + if package.startswith("buildozer")]) + self.install(packages=list(buildozer_package_with_version)) |