1
0
Fork 0
mirror of https://github.com/deepfakes/faceswap synced 2025-06-07 10:43:27 -04:00

setup.py: implement logging

This commit is contained in:
torzdf 2022-07-28 23:53:31 +01:00
parent dcb436c9df
commit 03f6cb4e7e
12 changed files with 732 additions and 403 deletions

View file

@ -385,7 +385,7 @@ setup_faceswap() {
# Run faceswap setup script # Run faceswap setup script
info "Setting up Faceswap..." info "Setting up Faceswap..."
if [ $VERSION != "cpu" ] ; then args="--$VERSION" ; else args="" ; fi if [ $VERSION != "cpu" ] ; then args="--$VERSION" ; else args="" ; fi
python "$DIR_FACESWAP/setup.py" --installer $args python -u "$DIR_FACESWAP/setup.py" --installer $args
} }
create_gui_launcher () { create_gui_launcher () {

View file

@ -448,7 +448,7 @@ Function SetupFaceSwap
StrCpy $0 "$0 --$setupType" StrCpy $0 "$0 --$setupType"
${EndIf} ${EndIf}
SetDetailsPrint listonly SetDetailsPrint listonly
ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirConda\scripts\activate.bat$\" && conda activate $\"$envName$\" && python $\"$INSTDIR\setup.py$\" $0 && conda deactivate" ExecDos::exec /NOUNLOAD /ASYNC /DETAILED "$\"$dirConda\scripts\activate.bat$\" && conda activate $\"$envName$\" && python -u $\"$INSTDIR\setup.py$\" $0 && conda deactivate"
pop $0 pop $0
ExecDos::wait $0 ExecDos::wait $0
pop $0 pop $0

View file

@ -8,3 +8,5 @@ faceswap
plugins/plugins plugins/plugins
scripts scripts
tools/tools tools/tools
setup
update_deps

8
docs/full/setup.rst Normal file
View file

@ -0,0 +1,8 @@
************
setup module
************
.. automodule:: setup
:members:
:undoc-members:
:show-inheritance:

View file

@ -0,0 +1,8 @@
******************
update_deps module
******************
.. automodule:: update_deps
:members:
:undoc-members:
:show-inheritance:

View file

@ -238,6 +238,7 @@ class _SysOutRouter():
self._console = console self._console = console
self._out_type = out_type self._out_type = out_type
self._recolor = re.compile(r".+?(\s\d+:\d+:\d+\s)(?P<lvl>[A-Z]+)\s") self._recolor = re.compile(r".+?(\s\d+:\d+:\d+\s)(?P<lvl>[A-Z]+)\s")
self._ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
logger.debug("Initialized %s", self.__class__.__name__) logger.debug("Initialized %s", self.__class__.__name__)
def _get_tag(self, string): def _get_tag(self, string):
@ -254,6 +255,7 @@ class _SysOutRouter():
def write(self, string): def write(self, string):
""" Capture stdout/stderr """ """ Capture stdout/stderr """
string = self._ansi_escape.sub("", string)
self._console.insert(tk.END, string, self._get_tag(string)) self._console.insert(tk.END, string, self._get_tag(string))
self._console.see(tk.END) self._console.see(tk.END)
@ -315,9 +317,8 @@ class _WidgetRedirector:
tk_.createcommand(wgt, self.dispatch) tk_.createcommand(wgt, self.dispatch)
def __repr__(self): def __repr__(self):
return "%s(%s<%s>)" % (self.__class__.__name__, return (f"{self.__class__.__name__}({self.widget.__class__.__name__}"
self.widget.__class__.__name__, f"<{self.widget._w}>)") # pylint:disable=protected-access
self.widget._w) # pylint:disable=protected-access
def close(self): def close(self):
"de-register operations and revert redirection created by .__init__." "de-register operations and revert redirection created by .__init__."
@ -409,8 +410,7 @@ class _OriginalCommand:
self.orig_and_operation = (redirect.orig, operation) self.orig_and_operation = (redirect.orig, operation)
def __repr__(self): def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, return f"{self.__class__.__name__}({self.redirect}, {self.operation})"
self.redirect, self.operation)
def __call__(self, *args): def __call__(self, *args):
return self.tk_call(self.orig_and_operation + args) return self.tk_call(self.orig_and_operation + args)
@ -619,12 +619,8 @@ class Tooltip: # pylint:disable=too-few-public-methods
x_1, y_1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1] x_1, y_1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x_2, y_2 = x_1 + width, y_1 + height x_2, y_2 = x_1 + width, y_1 + height
x_delta = x_2 - s_width x_delta = max(x_2 - s_width, 0)
if x_delta < 0: y_delta = max(y_2 - s_height, 0)
x_delta = 0
y_delta = y_2 - s_height
if y_delta < 0:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0) offscreen = (x_delta, y_delta) != (0, 0)
@ -670,7 +666,7 @@ class Tooltip: # pylint:disable=too-few-public-methods
text = self._text text = self._text
if self._text_variable and self._text_variable.get(): if self._text_variable and self._text_variable.get():
text += "\n\nCurrent value: '{}'".format(self._text_variable.get()) text += f"\n\nCurrent value: '{self._text_variable.get()}'"
label = tk.Label(win, label = tk.Label(win,
text=text, text=text,
justify=tk.LEFT, justify=tk.LEFT,
@ -687,7 +683,7 @@ class Tooltip: # pylint:disable=too-few-public-methods
xpos, ypos = tip_pos_calculator(widget, label) xpos, ypos = tip_pos_calculator(widget, label)
self._topwidget.wm_geometry("+%d+%d" % (xpos, ypos)) self._topwidget.wm_geometry(f"+{xpos}+{ypos}")
def _hide(self): def _hide(self):
""" Hide the tooltip """ """ Hide the tooltip """
@ -819,7 +815,7 @@ class PopupProgress(tk.Toplevel):
center = np.array(( center = np.array((
(self.master.winfo_width() // 2) - (self.winfo_width() // 2), (self.master.winfo_width() // 2) - (self.winfo_width() // 2),
(self.master.winfo_height() // 2) - (self.winfo_height() // 2))) + offset (self.master.winfo_height() // 2) - (self.winfo_height() // 2))) + offset
self.wm_geometry("+{}+{}".format(*center)) self.wm_geometry(f"+{center[0]}+{center[1]}")
get_config().set_cursor_busy() get_config().set_cursor_busy()
self.grab_set() self.grab_set()

View file

@ -166,10 +166,10 @@ class FileMenu(tk.Menu): # pylint:disable=too-many-ancestors
kwargs = dict(filename=filename) kwargs = dict(filename=filename)
else: else:
load_func = self._config.tasks.load load_func = self._config.tasks.load
lbl = "{} Task".format(command) lbl = f"{command} Task"
kwargs = dict(filename=filename, current_tab=False) kwargs = dict(filename=filename, current_tab=False)
self.recent_menu.add_command( self.recent_menu.add_command(
label="{} ({})".format(filename, lbl.title()), label=f"{filename} ({lbl.title()})",
command=lambda kw=kwargs, fn=load_func: fn(**kw)) command=lambda kw=kwargs, fn=load_func: fn(**kw))
if removed_files: if removed_files:
for recent_item in removed_files: for recent_item in removed_files:
@ -188,7 +188,7 @@ class FileMenu(tk.Menu): # pylint:disable=too-many-ancestors
def clear_recent_files(serializer, menu_file): def clear_recent_files(serializer, menu_file):
""" Creates or clears recent file list """ """ Creates or clears recent file list """
logger.debug("clearing recent files list: '%s'", menu_file) logger.debug("clearing recent files list: '%s'", menu_file)
serializer.save(menu_file, list()) serializer.save(menu_file, [])
def refresh_recent_menu(self): def refresh_recent_menu(self):
""" Refresh recent menu on save/load of files """ """ Refresh recent menu on save/load of files """
@ -263,9 +263,9 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
error then `None` is returned error then `None` is returned
""" """
gitcmd = "git branch -a" gitcmd = "git branch -a"
cmd = Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) with Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) as cmd:
stdout, _ = cmd.communicate() stdout, _ = cmd.communicate()
retcode = cmd.poll() retcode = cmd.poll()
if retcode != 0: if retcode != 0:
logger.debug("Unable to list git branches. return code: %s, message: %s", logger.debug("Unable to list git branches. return code: %s, message: %s",
retcode, stdout.decode().strip().replace("\n", " - ")) retcode, stdout.decode().strip().replace("\n", " - "))
@ -315,10 +315,10 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
The branch to switch to The branch to switch to
""" """
logger.info("Switching branch to '%s'...", branch) logger.info("Switching branch to '%s'...", branch)
gitcmd = "git checkout {}".format(branch) gitcmd = f"git checkout {branch}"
cmd = Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) with Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) as cmd:
stdout, _ = cmd.communicate() stdout, _ = cmd.communicate()
retcode = cmd.poll() retcode = cmd.poll()
if retcode != 0: if retcode != 0:
logger.error("Unable to switch branch. return code: %s, message: %s", logger.error("Unable to switch branch. return code: %s, message: %s",
retcode, stdout.decode().strip().replace("\n", " - ")) retcode, stdout.decode().strip().replace("\n", " - "))
@ -358,7 +358,7 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
from lib.sysinfo import sysinfo # pylint:disable=import-outside-toplevel from lib.sysinfo import sysinfo # pylint:disable=import-outside-toplevel
info = sysinfo info = sysinfo
except Exception as err: # pylint:disable=broad-except except Exception as err: # pylint:disable=broad-except
info = "Error obtaining system info: {}".format(str(err)) info = f"Error obtaining system info: {str(err)}"
self.clear_console() self.clear_console()
logger.debug("Obtained system information: %s", info) logger.debug("Obtained system information: %s", info)
print(info) print(info)
@ -382,7 +382,7 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
success = False success = False
if self.check_for_updates(encoding): if self.check_for_updates(encoding):
success = self.do_update(encoding) success = self.do_update(encoding)
update_deps.main(logger=logger) update_deps.main(is_gui=True)
if success: if success:
logger.info("Please restart Faceswap to complete the update.") logger.info("Please restart Faceswap to complete the update.")
self.root.config(cursor="") self.root.config(cursor="")
@ -395,9 +395,9 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
update = False update = False
msg = "" msg = ""
gitcmd = "git remote update && git status -uno" gitcmd = "git remote update && git status -uno"
cmd = Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) with Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=_WORKING_DIR) as cmd:
stdout, _ = cmd.communicate() stdout, _ = cmd.communicate()
retcode = cmd.poll() retcode = cmd.poll()
if retcode != 0: if retcode != 0:
msg = ("Git is not installed or you are not running a cloned repo. " msg = ("Git is not installed or you are not running a cloned repo. "
"Unable to check for updates") "Unable to check for updates")
@ -427,15 +427,20 @@ class HelpMenu(tk.Menu): # pylint:disable=too-many-ancestors
""" Update Faceswap """ """ Update Faceswap """
logger.info("A new version is available. Updating...") logger.info("A new version is available. Updating...")
gitcmd = "git pull" gitcmd = "git pull"
cmd = Popen(gitcmd, shell=True, stdout=PIPE, stderr=STDOUT, bufsize=1, cwd=_WORKING_DIR) with Popen(gitcmd,
while True: shell=True,
output = cmd.stdout.readline().decode(encoding) stdout=PIPE,
if output == "" and cmd.poll() is not None: stderr=STDOUT,
break bufsize=1,
if output: cwd=_WORKING_DIR) as cmd:
logger.debug("'%s' output: '%s'", gitcmd, output.strip()) while True:
print(output.strip()) output = cmd.stdout.readline().decode(encoding)
retcode = cmd.poll() if output == "" and cmd.poll() is not None:
break
if output:
logger.debug("'%s' output: '%s'", gitcmd, output.strip())
print(output.strip())
retcode = cmd.poll()
logger.debug("'%s' returncode: %s", gitcmd, retcode) logger.debug("'%s' returncode: %s", gitcmd, retcode)
if retcode != 0: if retcode != 0:
logger.info("An error occurred during update. return code: %s", retcode) logger.info("An error occurred during update. return code: %s", retcode)
@ -482,7 +487,7 @@ class TaskBar(ttk.Frame): # pylint: disable=too-many-ancestors
frame.pack(side=tk.LEFT, anchor=tk.W, expand=False, padx=2) frame.pack(side=tk.LEFT, anchor=tk.W, expand=False, padx=2)
for loadtype in ("load", "save", "save_as", "clear", "reload"): for loadtype in ("load", "save", "save_as", "clear", "reload"):
btntype = "{}2".format(loadtype) btntype = f"{loadtype}2"
logger.debug("Adding button: '%s'", btntype) logger.debug("Adding button: '%s'", btntype)
loader, kwargs = self._loader_and_kwargs(loadtype) loader, kwargs = self._loader_and_kwargs(loadtype)
@ -507,7 +512,7 @@ class TaskBar(ttk.Frame): # pylint: disable=too-many-ancestors
kwargs = dict(save_as=True) kwargs = dict(save_as=True)
else: else:
loader = btntype loader = btntype
kwargs = dict() kwargs = {}
logger.debug("btntype: %s, loader: %s, kwargs: %s", btntype, loader, kwargs) logger.debug("btntype: %s, loader: %s, kwargs: %s", btntype, loader, kwargs)
return loader, kwargs return loader, kwargs
@ -516,7 +521,7 @@ class TaskBar(ttk.Frame): # pylint: disable=too-many-ancestors
frame = ttk.Frame(self._btn_frame) frame = ttk.Frame(self._btn_frame)
frame.pack(side=tk.LEFT, anchor=tk.W, expand=False, padx=2) frame.pack(side=tk.LEFT, anchor=tk.W, expand=False, padx=2)
for name in ("extract", "train", "convert"): for name in ("extract", "train", "convert"):
btntype = "settings_{}".format(name) btntype = f"settings_{name}"
btntype = btntype if btntype in get_images().icons else "settings" btntype = btntype if btntype in get_images().icons else "settings"
logger.debug("Adding button: '%s'", btntype) logger.debug("Adding button: '%s'", btntype)
btn = ttk.Button( btn = ttk.Button(

View file

@ -4,16 +4,19 @@ import collections
import logging import logging
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
import os import os
import platform
import re
import sys import sys
import time
import traceback import traceback
from datetime import datetime from datetime import datetime
from tqdm import tqdm from typing import Union
class FaceswapLogger(logging.Logger): class FaceswapLogger(logging.Logger):
""" A standard :class:`logging.logger` with additional "verbose" and "trace" levels added. """ """ A standard :class:`logging.logger` with additional "verbose" and "trace" levels added. """
def __init__(self, name): def __init__(self, name: str) -> None:
for new_level in (("VERBOSE", 15), ("TRACE", 5)): for new_level in (("VERBOSE", 15), ("TRACE", 5)):
level_name, level_num = new_level level_name, level_num = new_level
if hasattr(logging, level_name): if hasattr(logging, level_name):
@ -22,7 +25,7 @@ class FaceswapLogger(logging.Logger):
setattr(logging, level_name, level_num) setattr(logging, level_name, level_num)
super().__init__(name) super().__init__(name)
def verbose(self, msg, *args, **kwargs): def verbose(self, msg: str, *args, **kwargs) -> None:
# pylint:disable=wrong-spelling-in-docstring # pylint:disable=wrong-spelling-in-docstring
""" Create a log message at severity level 15. """ Create a log message at severity level 15.
@ -38,7 +41,7 @@ class FaceswapLogger(logging.Logger):
if self.isEnabledFor(15): if self.isEnabledFor(15):
self._log(15, msg, args, **kwargs) self._log(15, msg, args, **kwargs)
def trace(self, msg, *args, **kwargs): def trace(self, msg: str, *args, **kwargs) -> None:
# pylint:disable=wrong-spelling-in-docstring # pylint:disable=wrong-spelling-in-docstring
""" Create a log message at severity level 5. """ Create a log message at severity level 5.
@ -55,6 +58,102 @@ class FaceswapLogger(logging.Logger):
self._log(5, msg, args, **kwargs) self._log(5, msg, args, **kwargs)
class ColoredFormatter(logging.Formatter):
""" Overrides the stand :class:`logging.Formatter` to enable colored labels for message level
labels on supported platforms
Parameters
----------
fmt: str
The format string for the message as a whole
pad_newlines: bool, Optional
If ``True`` new lines will be padded to appear in line with the log message, if ``False``
they will be left aligned
kwargs: dict
Standard :class:`logging.Formatter` keyword arguments
"""
def __init__(self, fmt: str, pad_newlines: bool = False, **kwargs) -> None:
super().__init__(fmt, **kwargs)
self._use_color = platform.system().lower() in ("linux", "darwin")
self._level_colors = dict(CRITICAL="\033[31m", # red
ERROR="\033[31m", # red
WARNING="\033[33m", # yellow
INFO="\033[32m", # green
VERBOSE="\033[34m") # blue
self._default_color = "\033[0m"
self._newline_padding = self._get_newline_padding(pad_newlines, fmt)
def _get_newline_padding(self, pad_newlines: bool, fmt: str) -> int:
""" Parses the format string to obtain padding for newlines if requested
Parameters
----------
fmt: str
The format string for the message as a whole
pad_newlines: bool, Optional
If ``True`` new lines will be padded to appear in line with the log message, if
``False`` they will be left aligned
Returns
-------
int
The amount of padding to apply to the front of newlines
"""
if not pad_newlines:
return 0
msg_idx = fmt.find("%(message)") + 1
filtered = fmt[:msg_idx - 1]
spaces = filtered.count(" ")
pads = [int(pad.replace("s", "")) for pad in re.findall(r"\ds", filtered)]
if "asctime" in filtered:
pads.append(self._get_sample_time_string())
return sum(pads) + spaces
def _get_sample_time_string(self) -> int:
""" Obtain a sample time string and calculate correct padding.
This may be inaccurate wheb ticking over an integer from single to double digits, but that
shouldn't be a huge issue.
Returns
-------
int
The length of the formatted date-time string
"""
sample_time = time.time()
date_format = self.datefmt if self.datefmt else self.default_time_format
datestring = time.strftime(date_format, logging.Formatter.converter(sample_time))
if not self.datefmt and self.default_msec_format:
msecs = (sample_time - int(sample_time)) * 1000
datestring = self.default_msec_format % (datestring, msecs)
return len(datestring)
def format(self, record: logging.LogRecord) -> str:
""" Color the log message level if supported otherwise return the standard log message.
Parameters
----------
record: :class:`logging.LogRecord`
The incoming log record to be formatted for entry into the logger.
Returns
-------
str
The formatted log message
"""
formatted = super().format(record)
levelname = record.levelname
if self._use_color and levelname in self._level_colors:
formatted = re.sub(levelname,
f"{self._level_colors[levelname]}{levelname}{self._default_color}",
formatted,
1)
if self._newline_padding:
formatted = formatted.replace("\n", f"\n{' ' * self._newline_padding}")
return formatted
class FaceswapFormatter(logging.Formatter): class FaceswapFormatter(logging.Formatter):
""" Overrides the standard :class:`logging.Formatter`. """ Overrides the standard :class:`logging.Formatter`.
@ -63,7 +162,7 @@ class FaceswapFormatter(logging.Formatter):
Rewrites some upstream warning messages to debug level to avoid spamming the console. Rewrites some upstream warning messages to debug level to avoid spamming the console.
""" """
def format(self, record): def format(self, record: logging.LogRecord) -> str:
""" Strip new lines from log records and rewrite certain warning messages to debug level. """ Strip new lines from log records and rewrite certain warning messages to debug level.
Parameters Parameters
@ -102,7 +201,7 @@ class FaceswapFormatter(logging.Formatter):
return msg return msg
@classmethod @classmethod
def _rewrite_warnings(cls, record): def _rewrite_warnings(cls, record: logging.LogRecord) -> logging.LogRecord:
""" Change certain warning messages from WARNING to DEBUG to avoid passing non-important """ Change certain warning messages from WARNING to DEBUG to avoid passing non-important
information to output. information to output.
@ -133,7 +232,7 @@ class FaceswapFormatter(logging.Formatter):
return record return record
@classmethod @classmethod
def _lower_external(cls, record): def _lower_external(cls, record: logging.LogRecord) -> logging.LogRecord:
""" Some external libs log at a higher level than we would really like, so lower their """ Some external libs log at a higher level than we would really like, so lower their
log level. log level.
@ -162,7 +261,7 @@ class RollingBuffer(collections.deque):
"""File-like that keeps a certain number of lines of text in memory for writing out to the """File-like that keeps a certain number of lines of text in memory for writing out to the
crash log. """ crash log. """
def write(self, buffer): def write(self, buffer: str) -> None:
""" Splits lines from the incoming buffer and writes them out to the rolling buffer. """ Splits lines from the incoming buffer and writes them out to the rolling buffer.
Parameters Parameters
@ -178,7 +277,7 @@ class TqdmHandler(logging.StreamHandler):
""" Overrides :class:`logging.StreamHandler` to use :func:`tqdm.tqdm.write` rather than writing """ Overrides :class:`logging.StreamHandler` to use :func:`tqdm.tqdm.write` rather than writing
to :func:`sys.stderr` so that log messages do not mess up tqdm progress bars. """ to :func:`sys.stderr` so that log messages do not mess up tqdm progress bars. """
def emit(self, record): def emit(self, record: logging.LogRecord) -> None:
""" Format the incoming message and pass to :func:`tqdm.tqdm.write`. """ Format the incoming message and pass to :func:`tqdm.tqdm.write`.
Parameters Parameters
@ -186,11 +285,13 @@ class TqdmHandler(logging.StreamHandler):
record : :class:`logging.LogRecord` record : :class:`logging.LogRecord`
The incoming log record to be formatted for entry into the logger. The incoming log record to be formatted for entry into the logger.
""" """
# tqdm is imported here as it won't be installed when setup.py is running
from tqdm import tqdm # pylint:disable=import-outside-toplevel
msg = self.format(record) msg = self.format(record)
tqdm.write(msg) tqdm.write(msg)
def _set_root_logger(loglevel=logging.INFO): def _set_root_logger(loglevel: int = logging.INFO) -> logging.Logger:
""" Setup the root logger. """ Setup the root logger.
Parameters Parameters
@ -208,7 +309,7 @@ def _set_root_logger(loglevel=logging.INFO):
return rootlogger return rootlogger
def log_setup(loglevel, log_file, command, is_gui=False): def log_setup(loglevel, log_file: str, command: str, is_gui: bool = False) -> None:
""" Set up logging for Faceswap. """ Set up logging for Faceswap.
Sets up the root logger, the formatting for the crash logger and the file logger, and sets up Sets up the root logger, the formatting for the crash logger and the file logger, and sets up
@ -230,19 +331,32 @@ def log_setup(loglevel, log_file, command, is_gui=False):
numeric_loglevel = get_loglevel(loglevel) numeric_loglevel = get_loglevel(loglevel)
root_loglevel = min(logging.DEBUG, numeric_loglevel) root_loglevel = min(logging.DEBUG, numeric_loglevel)
rootlogger = _set_root_logger(loglevel=root_loglevel) rootlogger = _set_root_logger(loglevel=root_loglevel)
log_format = FaceswapFormatter("%(asctime)s %(processName)-15s %(threadName)-30s "
"%(module)-15s %(funcName)-30s %(levelname)-8s %(message)s", if command == "setup":
datefmt="%m/%d/%Y %H:%M:%S") log_format = FaceswapFormatter("%(asctime)s %(module)-16s %(funcName)-30s %(levelname)-8s "
f_handler = _file_handler(numeric_loglevel, log_file, log_format, command) "%(message)s", datefmt="%m/%d/%Y %H:%M:%S")
s_handler = _stream_handler(numeric_loglevel, is_gui) s_handler = _stream_setup_handler(numeric_loglevel)
c_handler = _crash_handler(log_format) f_handler = _file_handler(root_loglevel, log_file, log_format, command)
else:
log_format = FaceswapFormatter("%(asctime)s %(processName)-15s %(threadName)-30s "
"%(module)-15s %(funcName)-30s %(levelname)-8s %(message)s",
datefmt="%m/%d/%Y %H:%M:%S")
s_handler = _stream_handler(numeric_loglevel, is_gui)
f_handler = _file_handler(numeric_loglevel, log_file, log_format, command)
rootlogger.addHandler(f_handler) rootlogger.addHandler(f_handler)
rootlogger.addHandler(s_handler) rootlogger.addHandler(s_handler)
rootlogger.addHandler(c_handler)
logging.info("Log level set to: %s", loglevel.upper()) if command != "setup":
c_handler = _crash_handler(log_format)
rootlogger.addHandler(c_handler)
logging.info("Log level set to: %s", loglevel.upper())
def _file_handler(loglevel, log_file, log_format, command): def _file_handler(loglevel,
log_file: str,
log_format: FaceswapFormatter,
command: str) -> RotatingFileHandler:
""" Add a rotating file handler for the current Faceswap session. 1 backup is always kept. """ Add a rotating file handler for the current Faceswap session. 1 backup is always kept.
Parameters Parameters
@ -270,21 +384,21 @@ def _file_handler(loglevel, log_file, log_format, command):
filename += "_gui.log" if command == "gui" else ".log" filename += "_gui.log" if command == "gui" else ".log"
should_rotate = os.path.isfile(filename) should_rotate = os.path.isfile(filename)
log_file = RotatingFileHandler(filename, backupCount=1, encoding="utf-8") handler = RotatingFileHandler(filename, backupCount=1, encoding="utf-8")
if should_rotate: if should_rotate:
log_file.doRollover() handler.doRollover()
log_file.setFormatter(log_format) handler.setFormatter(log_format)
log_file.setLevel(loglevel) handler.setLevel(loglevel)
return log_file return handler
def _stream_handler(loglevel, is_gui): def _stream_handler(loglevel: int, is_gui: bool) -> Union[logging.StreamHandler, TqdmHandler]:
""" Add a stream handler for the current Faceswap session. The stream handler will only ever """ Add a stream handler for the current Faceswap session. The stream handler will only ever
output at a maximum of VERBOSE level to avoid spamming the console. output at a maximum of VERBOSE level to avoid spamming the console.
Parameters Parameters
---------- ----------
loglevel: str loglevel: int
The requested log level that messages should be logged at. The requested log level that messages should be logged at.
is_gui: bool, optional is_gui: bool, optional
Whether Faceswap is running in the GUI or not. Dictates where the stream handler should Whether Faceswap is running in the GUI or not. Dictates where the stream handler should
@ -311,7 +425,30 @@ def _stream_handler(loglevel, is_gui):
return log_console return log_console
def _crash_handler(log_format): def _stream_setup_handler(loglevel: int) -> logging.StreamHandler:
""" Add a stream handler for faceswap's setup.py script
This stream handler outputs a limited set of easy to use information using colored labels
if available. It will only ever output at a minimum of INFO level
Parameters
----------
loglevel: int
The requested log level that messages should be logged at.
Returns
-------
:class:`logging.StreamHandler`
The stream handler to use
"""
loglevel = max(loglevel, 15)
log_format = ColoredFormatter("%(levelname)-8s %(message)s", pad_newlines=True)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(log_format)
handler.setLevel(loglevel)
return handler
def _crash_handler(log_format: FaceswapFormatter) -> logging.StreamHandler:
""" Add a handler that stores the last 100 debug lines to :attr:'_DEBUG_BUFFER' for use in """ Add a handler that stores the last 100 debug lines to :attr:'_DEBUG_BUFFER' for use in
crash reports. crash reports.
@ -331,7 +468,7 @@ def _crash_handler(log_format):
return log_crash return log_crash
def get_loglevel(loglevel): def get_loglevel(loglevel: str) -> int:
""" Check whether a valid log level has been supplied, and return the numeric log level that """ Check whether a valid log level has been supplied, and return the numeric log level that
corresponds to the given string level. corresponds to the given string level.
@ -351,7 +488,7 @@ def get_loglevel(loglevel):
return numeric_level return numeric_level
def crash_log(): def crash_log() -> str:
""" On a crash, write out the contents of :func:`_DEBUG_BUFFER` containing the last 100 lines """ On a crash, write out the contents of :func:`_DEBUG_BUFFER` containing the last 100 lines
of debug messages to a crash report in the root Faceswap folder. of debug messages to a crash report in the root Faceswap folder.
@ -379,11 +516,11 @@ def crash_log():
_OLD_FACTORY = logging.getLogRecordFactory() _OLD_FACTORY = logging.getLogRecordFactory()
def _faceswap_logrecord(*args, **kwargs): def _faceswap_logrecord(*args, **kwargs) -> logging.LogRecord:
""" Add a flag to :class:`logging.LogRecord` to not strip formatting from particular """ Add a flag to :class:`logging.LogRecord` to not strip formatting from particular
records. """ records. """
record = _OLD_FACTORY(*args, **kwargs) record = _OLD_FACTORY(*args, **kwargs)
record.strip_spaces = True record.strip_spaces = True # type:ignore
return record return record

View file

@ -13,6 +13,6 @@ ffmpy==0.2.3
#nvidia-ml-py>=11.510,<300 #nvidia-ml-py>=11.510,<300
# Pin nvidida-ml-py to <11.515 until we know if bytes->str is an error or permanent change # Pin nvidida-ml-py to <11.515 until we know if bytes->str is an error or permanent change
nvidia-ml-py<11.515 nvidia-ml-py<11.515
tensorflow_probability<0.17 tensorflow-probability<0.17
typing-extensions>=4.0.0 typing-extensions>=4.0.0
pywin32>=228 ; sys_platform == "win32" pywin32>=228 ; sys_platform == "win32"

View file

@ -16,6 +16,8 @@ ignore_missing_imports = True
ignore_missing_imports = True ignore_missing_imports = True
[mypy-matplotlib.*] [mypy-matplotlib.*]
ignore_missing_imports = True ignore_missing_imports = True
[mypy-pexpect.*]
ignore_missing_imports = True
[mypy-PIL.*] [mypy-PIL.*]
ignore_missing_imports = True ignore_missing_imports = True
[mypy-plaidml.*] [mypy-plaidml.*]

787
setup.py

File diff suppressed because it is too large Load diff

View file

@ -3,30 +3,32 @@
Checks for installed Conda / Pip packages and updates accordingly Checks for installed Conda / Pip packages and updates accordingly
""" """
import logging
import os
import sys
from setup import Environment, Install, Output from lib.logger import log_setup
from setup import Environment, Install
_LOGGER = None logger = logging.getLogger(__name__)
def output(msg): def main(is_gui=False) -> None:
""" Output to print or logger """ """ Check for and update dependencies
if _LOGGER is not None:
_LOGGER.info(msg)
else:
Output().info(msg)
Parameters
def main(logger=None): ----------
""" Check for and update dependencies """ is_gui: bool, optional
if logger is not None: ``True`` if being called by the GUI. Prevents the updater from outputting progress bars
global _LOGGER # pylint:disable=global-statement which get scrambled in the GUI
_LOGGER = logger """
output("Updating dependencies...") logger.info("Updating dependencies...")
update = Environment(logger=logger, updater=True) update = Environment(updater=True)
Install(update) Install(update, is_gui=is_gui)
output("Dependencies updated") logger.info("Dependencies updated")
if __name__ == "__main__": if __name__ == "__main__":
logfile = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), "faceswap_update.log")
log_setup("INFO", logfile, "setup")
main() main()