mirror of
https://github.com/deepfakes/faceswap
synced 2025-06-07 10:43:27 -04:00
* Remove tensorflow_probability requirement * setup.py - fix progress bars * requirements.txt: Remove pre python 3.9 packages * update apple requirements.txt * update INSTALL.md * Remove python<3.9 code * setup.py - fix Windows Installer * typing: python3.9 compliant * Update pytest and readthedocs python versions * typing fixes * Python Version updates - Reduce max version to 3.10 - Default to 3.10 in installers - Remove incompatible 3.11 tests * Update dependencies * Downgrade imageio dep for Windows * typing: merge optional unions and fixes * Updates - min python version 3.10 - typing to python 3.10 spec - remove pre-tf2.10 code - Add conda tests * train: re-enable optimizer saving * Update dockerfiles * Update setup.py - Apple Conda deps to setup.py - Better Cuda + dependency handling * bugfix: Patch logging to prevent Autograph errors * Update dockerfiles * Setup.py - Setup.py - stdout to utf-8 * Add more OSes to github Actions * suppress mac-os end to end test
109 lines
4 KiB
Python
109 lines
4 KiB
Python
#!/usr/bin/env python3
|
|
""" Miscellaneous Utility functions for the GUI. Includes LongRunningTask object """
|
|
from __future__ import annotations
|
|
import logging
|
|
import sys
|
|
import typing as T
|
|
|
|
from threading import Event, Thread
|
|
from queue import Queue
|
|
|
|
from .config import get_config
|
|
|
|
if T.TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
from types import TracebackType
|
|
from lib.multithreading import _ErrorType
|
|
|
|
|
|
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
|
|
|
|
|
|
class LongRunningTask(Thread):
|
|
""" Runs long running tasks in a background thread to prevent the GUI from becoming
|
|
unresponsive.
|
|
|
|
This is sub-classed from :class:`Threading.Thread` so check documentation there for base
|
|
parameters. Additional parameters listed below.
|
|
|
|
Parameters
|
|
----------
|
|
widget: tkinter object, optional
|
|
The widget that this :class:`LongRunningTask` is associated with. Used for setting the busy
|
|
cursor in the correct location. Default: ``None``.
|
|
"""
|
|
_target: Callable
|
|
_args: tuple
|
|
_kwargs: dict[str, T.Any]
|
|
_name: str
|
|
|
|
def __init__(self,
|
|
target: Callable | None = None,
|
|
name: str | None = None,
|
|
args: tuple = (),
|
|
kwargs: dict[str, T.Any] | None = None,
|
|
*,
|
|
daemon: bool = True,
|
|
widget=None):
|
|
logger.debug("Initializing %s: (target: %s, name: %s, args: %s, kwargs: %s, "
|
|
"daemon: %s)", self.__class__.__name__, target, name, args, kwargs,
|
|
daemon)
|
|
super().__init__(target=target, name=name, args=args, kwargs=kwargs,
|
|
daemon=daemon)
|
|
self.err: _ErrorType = None
|
|
self._widget = widget
|
|
self._config = get_config()
|
|
self._config.set_cursor_busy(widget=self._widget)
|
|
self._complete = Event()
|
|
self._queue: Queue = Queue()
|
|
logger.debug("Initialized %s", self.__class__.__name__,)
|
|
|
|
@property
|
|
def complete(self) -> Event:
|
|
""" :class:`threading.Event`: Event is set if the thread has completed its task,
|
|
otherwise it is unset.
|
|
"""
|
|
return self._complete
|
|
|
|
def run(self) -> None:
|
|
""" Commence the given task in a background thread. """
|
|
try:
|
|
if self._target is not None:
|
|
retval = self._target(*self._args, **self._kwargs)
|
|
self._queue.put(retval)
|
|
except Exception: # pylint: disable=broad-except
|
|
self.err = T.cast(tuple[type[BaseException], BaseException, "TracebackType"],
|
|
sys.exc_info())
|
|
assert self.err is not None
|
|
logger.debug("Error in thread (%s): %s", self._name,
|
|
self.err[1].with_traceback(self.err[2]))
|
|
finally:
|
|
self._complete.set()
|
|
# Avoid a ref-cycle if the thread is running a function with
|
|
# an argument that has a member that points to the thread.
|
|
del self._target, self._args, self._kwargs
|
|
|
|
def get_result(self) -> T.Any:
|
|
""" Return the result from the given task.
|
|
|
|
Returns
|
|
-------
|
|
varies:
|
|
The result of the thread will depend on the given task. If a call is made to
|
|
:func:`get_result` prior to the thread completing its task then ``None`` will be
|
|
returned
|
|
"""
|
|
if not self._complete.is_set():
|
|
logger.warning("Aborting attempt to retrieve result from a LongRunningTask that is "
|
|
"still running")
|
|
return None
|
|
if self.err:
|
|
logger.debug("Error caught in thread")
|
|
self._config.set_cursor_default(widget=self._widget)
|
|
raise self.err[1].with_traceback(self.err[2])
|
|
|
|
logger.debug("Getting result from thread")
|
|
retval = self._queue.get()
|
|
logger.debug("Got result from thread")
|
|
self._config.set_cursor_default(widget=self._widget)
|
|
return retval
|