From 76d18c87d7b5e939bc67b4c3a5705434e8ac9bbe Mon Sep 17 00:00:00 2001 From: torzdf <36920800+torzdf@users.noreply.github.com> Date: Wed, 3 Jul 2019 11:07:21 +0000 Subject: [PATCH] Fixups Dependency Updater: Improve by pluging in to setup.py setup.py: Bugfix handling of Conda aliases GUI: Revert console background colour sysinfo: Handle errors in obtaining information --- lib/gui/menu.py | 4 +- lib/gui/utils.py | 10 +-- lib/logger.py | 2 +- lib/sysinfo.py | 11 ++- setup.py | 50 +++++++++----- update_deps.py | 172 ++--------------------------------------------- 6 files changed, 58 insertions(+), 191 deletions(-) diff --git a/lib/gui/menu.py b/lib/gui/menu.py index b79de334ec..32cb3e57a8 100644 --- a/lib/gui/menu.py +++ b/lib/gui/menu.py @@ -180,8 +180,8 @@ def output_sysinfo(self): self.root.config(cursor="watch") self.clear_console() print("Obtaining system information...") - from lib.sysinfo import SysInfo - info = SysInfo().full_info() + from lib.sysinfo import sysinfo + info = sysinfo self.clear_console() logger.debug("Obtained system information: %s", info) print(info) diff --git a/lib/gui/utils.py b/lib/gui/utils.py index a2d1f920c7..9968020e6b 100644 --- a/lib/gui/utils.py +++ b/lib/gui/utils.py @@ -481,7 +481,7 @@ def set_console_clear_var_trace(self): def build_console(self): """ Build and place the console """ logger.debug("Build console") - self.console.config(width=100, height=6, bg="#1E1E1E", fg="white") + self.console.config(width=100, height=6, bg="gray90", fg="black") self.console.pack(side=tk.LEFT, anchor=tk.N, fill=tk.BOTH, expand=True) scrollbar = ttk.Scrollbar(self, command=self.console.yview) @@ -494,11 +494,11 @@ def build_console(self): def add_tags(self): """ Add tags to text widget to color based on output """ logger.debug("Adding text color tags") - self.console.tag_config("default", foreground="#A6A7A8") + self.console.tag_config("default", foreground="#1E1E1E") self.console.tag_config("stderr", foreground="#E25056") - self.console.tag_config("info", foreground="#98CCFD") - self.console.tag_config("verbose", foreground="#6A9955") - self.console.tag_config("warning", foreground="#CE9178") + self.console.tag_config("info", foreground="#2B445E") + self.console.tag_config("verbose", foreground="#008140") + self.console.tag_config("warning", foreground="#F77B00") self.console.tag_config("critical", foreground="red") self.console.tag_config("error", foreground="red") diff --git a/lib/logger.py b/lib/logger.py index db9cd0628b..ed8f41262d 100644 --- a/lib/logger.py +++ b/lib/logger.py @@ -167,7 +167,7 @@ def crash_log(): with open(filename, "w") as outfile: outfile.writelines(freeze_log) traceback.print_exc(file=outfile) - outfile.write(sysinfo.full_info()) + outfile.write(sysinfo) return filename diff --git a/lib/sysinfo.py b/lib/sysinfo.py index 522a495949..30fe02ef98 100644 --- a/lib/sysinfo.py +++ b/lib/sysinfo.py @@ -358,4 +358,13 @@ def format_ram(self): return ", ".join(retval) -sysinfo = SysInfo() # pylint: disable=invalid-name +def get_sysinfo(): + """ Return sys info or error message if there is an error """ + try: + retval = SysInfo().full_info() + except Exception as err: # pylint: disable=broad-except + retval = "Exception occured trying to retrieve sysinfo: {}".format(err) + return retval + + +sysinfo = get_sysinfo() # pylint: disable=invalid-name diff --git a/setup.py b/setup.py index 01ebf5c78a..db82b7da63 100755 --- a/setup.py +++ b/setup.py @@ -24,10 +24,14 @@ class Environment(): """ The current install environment """ - def __init__(self): + def __init__(self, logger=None, updater=False): + """ logger will override built in Output() function if passed in + updater indicates that this is being run from update_deps.py + so certain steps can be skipped/output limited """ self.macos_required_packages = ["pynvx==0.0.4"] self.conda_required_packages = [("tk", )] - self.output = Output() + self.output = logger if logger else Output() + self.updater = updater # Flag that setup is being run by installer so steps can be skipped self.is_installer = False self.cuda_path = "" @@ -127,6 +131,8 @@ def get_required_packages(): def check_permission(self): """ Check for Admin permissions """ + if self.updater: + return if self.is_admin: self.output.info("Running as Root/Admin") else: @@ -134,10 +140,11 @@ def check_permission(self): def check_system(self): """ Check the system """ - self.output.info("The tool provides tips for installation\n" - "and installs required python packages") + if not self.updater: + self.output.info("The tool provides tips for installation\n" + "and installs required python packages") self.output.info("Setup in %s %s" % (self.os_version[0], self.os_version[1])) - if not self.os_version[0] in ["Windows", "Linux", "Darwin"]: + if not self.updater and not self.os_version[0] in ["Windows", "Linux", "Darwin"]: self.output.error("Your system %s is not supported!" % self.os_version[0]) exit(1) @@ -147,7 +154,7 @@ def check_python(self): self.py_version[1])) if not (self.py_version[0].split(".")[0] == "3" and self.py_version[0].split(".")[1] in ("3", "4", "5", "6", "7") - and self.py_version[1] == "64bit"): + and self.py_version[1] == "64bit") and not self.updater: self.output.error("Please run this script with Python version 3.3, 3.4, 3.5, 3.6 or " "3.7 64bit and try again.") exit(1) @@ -162,6 +169,8 @@ def output_runtime_info(self): def check_pip(self): """ Check installed pip version """ + if self.updater: + return try: import pip # noqa pylint:disable=unused-import except ImportError: @@ -532,14 +541,20 @@ def cudnn_checkfiles_windows(self): class Install(): """ Install the requirements """ def __init__(self, environment): - self.output = Output() + self.output = environment.output self.env = environment - if not self.env.is_installer: + if not self.env.is_installer and not self.env.updater: self.ask_continue() self.check_missing_dep() self.check_conda_missing_dep() + if (self.env.updater and + not self.env.missing_packages and not self.env.conda_missing_packages): + self.output.info("All Dependencies are up to date") + return self.install_missing_dep() + if self.env.updater: + return self.output.info("All python3 dependencies are met.\r\nYou are good to go.\r\n\r\n" "Enter: 'python faceswap.py -h' to see the options\r\n" " 'python faceswap.py gui' to launch the GUI") @@ -560,6 +575,9 @@ def check_missing_dep(self): if pkg is None: continue key = pkg.split("==")[0] + if self.env.is_conda: + # Get Conda alias for Key + key = CONDA_MAPPING.get(key, (key, None))[0] if key not in self.env.installed_packages: self.env.missing_packages.append(pkg) continue @@ -610,12 +628,10 @@ def install_python_packages(self): self.output.info("Installing Required Python Packages. This may take some time...") for pkg in self.env.missing_packages: if self.env.is_conda: - verbose = pkg.startswith("tensorflow") - pkg = CONDA_MAPPING.get(pkg, pkg) - channel = None - if isinstance(pkg, (tuple, list)): - channel = None if len(pkg) != 2 else pkg[1] - pkg = pkg[0] + verbose = pkg.startswith("tensorflow") or self.env.updater + pkg = CONDA_MAPPING.get(pkg, (pkg, None)) + channel = None if len(pkg) != 2 else pkg[1] + pkg = pkg[0] if self.conda_installer(pkg, verbose=verbose, channel=channel, conda_only=False): continue self.pip_installer(pkg) @@ -631,7 +647,7 @@ def conda_installer(self, package, channel=None, verbose=False, conda_only=False """ Install a conda package """ success = True condaexe = ["conda", "install", "-y"] - if not verbose: + if not verbose or self.env.updater: condaexe.append("-q") if channel: condaexe.extend(["-c", channel]) @@ -657,7 +673,9 @@ def pip_installer(self, package): """ Install a pip package """ pipexe = [sys.executable, "-m", "pip"] # hide info/warning and fix cache hang - pipexe.extend(["install", "-qq", "--no-cache-dir"]) + pipexe.extend(["install", "--no-cache-dir"]) + if not self.env.updater: + pipexe.append("-qq") # install as user to solve perm restriction if not self.env.is_admin and not self.env.is_virtualenv: pipexe.append("--user") diff --git a/update_deps.py b/update_deps.py index 9843e6b855..b4a49452ab 100644 --- a/update_deps.py +++ b/update_deps.py @@ -4,174 +4,17 @@ Checks for installed Conda / Pip packages and updates accordingly """ -import locale -import os -import re -import sys -import ctypes - -from subprocess import CalledProcessError, run, PIPE, Popen +from setup import Environment, Install, Output _LOGGER = None -class Environment(): - """ Hold information about the running environment """ - def __init__(self): - self.is_conda = "conda" in sys.version.lower() - self.encoding = locale.getpreferredencoding() - self.is_admin = self.get_admin_status() - self.is_virtualenv = self.get_virtualenv - required_packages = self.get_required_packages() - self.installed_packages = self.get_installed_packages() - self.get_installed_conda_packages() - self.packages_to_install = self.get_packages_to_install(required_packages) - - @staticmethod - def get_admin_status(): - """ Check whether user is admin """ - try: - retval = os.getuid() == 0 - except AttributeError: - retval = ctypes.windll.shell32.IsUserAnAdmin() != 0 - return retval - - def get_virtualenv(self): - """ Check whether this is a virtual environment """ - if not self.is_conda: - retval = (hasattr(sys, "real_prefix") or - (hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix)) - else: - prefix = os.path.dirname(sys.prefix) - retval = (os.path.basename(prefix) == "envs") - return retval - - @staticmethod - def get_required_packages(): - """ Load requirements list """ - packages = list() - pypath = os.path.dirname(os.path.realpath(__file__)) - requirements_file = os.path.join(pypath, "requirements.txt") - with open(requirements_file) as req: - for package in req.readlines(): - package = package.strip() - if package and (not package.startswith("#")): - packages.append(package) - return packages - - def get_installed_packages(self): - """ Get currently installed packages """ - installed_packages = dict() - chk = Popen("\"{}\" -m pip freeze".format(sys.executable), - shell=True, stdout=PIPE) - installed = chk.communicate()[0].decode(self.encoding).splitlines() - - for pkg in installed: - if "==" not in pkg: - continue - item = pkg.split("==") - installed_packages[item[0]] = item[1] - return installed_packages - - def get_installed_conda_packages(self): - """ Get currently installed conda packages """ - if not self.is_conda: - return - chk = os.popen("conda list").read() - installed = [re.sub(" +", " ", line.strip()) - for line in chk.splitlines() if not line.startswith("#")] - for pkg in installed: - item = pkg.split(" ") - self.installed_packages[item[0]] = item[1] - - def get_packages_to_install(self, required_packages): - """ Get packages which need installing, upgrading or downgrading """ - to_install = list() - for pkg in required_packages: - pkg = self.check_os_requirement(pkg) - if pkg is None: - continue - key = pkg.split("==")[0] - if key not in self.installed_packages: - to_install.append(pkg) - else: - if (len(pkg.split("==")) > 1 and - pkg.split("==")[1] != self.installed_packages.get(key)): - to_install.append(pkg) - return to_install - - @staticmethod - def check_os_requirement(package): - """ Check whether this package is required for this OS """ - if ";" not in package and "sys_platform" not in package: - return package - package = "".join(package.split()) - pkg, tags = package.split(";") - tags = tags.split("==") - sys_platform = tags[tags.index("sys_platform") + 1].replace('"', "").replace("'", "") - if sys_platform == sys.platform: - return pkg - return None - - -class Installer(): - """ Install packages through Conda or Pip """ - def __init__(self, environment): - self.packages = environment.packages_to_install - self.env = environment - self.install() - - def install(self): - """ Install required pip packages """ - success = True - for pkg in self.packages: - output("Installing {}".format(pkg)) - if self.env.is_conda and self.conda_install(pkg): - continue - if not self.pip_install(pkg): - success = False - if not success: - output("There were problems updating one or more dependencies.") - else: - output("Dependencies succesfully updated.") - - @staticmethod - def conda_install(package): - """ Install a conda package """ - success = True - condaexe = ["conda", "install", "-y", package] - try: - with open(os.devnull, "w") as devnull: - run(condaexe, stdout=devnull, stderr=devnull, check=True) - except CalledProcessError: - output("{} not available in Conda. Installing with pip...".format(package)) - success = False - return success - - def pip_install(self, package): - """ Install a pip package """ - success = True - pipexe = [sys.executable, "-m", "pip"] - # hide info/warning and fix cache hang - pipexe.extend(["install", "-qq", "--no-cache-dir"]) - # install as user to solve perm restriction - if not self.env.is_admin and not self.env.is_virtualenv: - pipexe.append("--user") - pipexe.append(package) - try: - run(pipexe, check=True) - except CalledProcessError: - output("Couldn't install {}. Please install this package manually".format(package)) - success = False - return success - - def output(msg): """ Output to print or logger """ if _LOGGER is not None: _LOGGER.info(msg) else: - print(msg) + Output().info(msg) def main(logger=None): @@ -179,13 +22,10 @@ def main(logger=None): if logger is not None: global _LOGGER # pylint:disable=global-statement _LOGGER = logger - output("Updating Dependencies...") - update = Environment() - packages = update.packages_to_install - if not packages: - output("All Dependencies are up to date") - else: - Installer(update) + output("Updating dependencies...") + update = Environment(logger=logger, updater=True) + Install(update) + output("Dependencies updated") if __name__ == "__main__":