Skip to content

Commit

Permalink
Fixups
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torzdf committed Jul 3, 2019
1 parent 22069f5 commit 76d18c8
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 191 deletions.
4 changes: 2 additions & 2 deletions lib/gui/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions lib/gui/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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")

Expand Down
2 changes: 1 addition & 1 deletion lib/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
11 changes: 10 additions & 1 deletion lib/sysinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 34 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand Down Expand Up @@ -127,17 +131,20 @@ 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:
self.output.warning("Running without root/admin privileges")

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)

Expand All @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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")
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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])
Expand All @@ -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")
Expand Down
172 changes: 6 additions & 166 deletions update_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,188 +4,28 @@
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):
""" Check for and update dependencies """
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__":
Expand Down

0 comments on commit 76d18c8

Please sign in to comment.