Files
torzdf 837bc2d51d Faceswap 3 (#1516)
* FaceSwap 3 (#1515)
* Update extract pipeline
* Update requirements + setup for nvidia
* Remove allow-growth option
* tf.keras to keras updates
* lib.model.losses - Port + fix all loss functions for Keras3
* lib.model - port initializers, layers. normalization to Keras3
* lib.model.autoclip to Keras 3
* Update mixed precision layer storage
* model file to .keras format
* Restructure nn_blocks to initialize layers in __init__
* Tensorboard
  - Trainer: Add Torch compatible Tensorboard callbacks
  - GUI event reader remove TF dependency
* Loss logging
  - Flush TB logs on save
  - Replace TB live iterator for GUI
* Backup models on total loss drop rather than per side
* Update all models to Keras3 Compat
* Remove lib.model.session
* Update clip ViT to Keras 3
* plugins.extract.mask.unet-dfl - Fix for Keras3/Torch backend
* Port AdaBelief to Keras 3
* setup.py:
  - Add --dev flag for dev tool install
* Fix Keras 3 syntax
* Fix LR Finder for Keras 3
* Fix mixed precision switching for Keras  3
* Add more optimizers + open up config setting
* train: Remove updating FS1 weights to FS2 models
* Alignments: Remove support for legacy .json files
* tools.model:
  - Remove TF Saved Format saving
  - Fix Backup/Restore + Nan-Scan
* Fix inference model creation for Keras 3
* Preview tool: Fix for Keras3
* setup.py: Configure keras backend
* train: Migration of FS2 models to FS3
* Training: Default coverage to 100%
* Remove DirectML backend
* Update setup for MacOS
* GUI: Force line reading to UTF-8
* Remove redundant Tensorflow references
* Remove redundant code
* Legacy model loading: Fix TFLamdaOp scalar ops and DepthwiseConv2D
* Add vertical offset option for training
* Github actions: Add more python versions
* Add python version to workflow names
* Github workflow: Exclude Python 3.12 for macOS
* Implement custom training loop
* Fs3 - Add RTX5xxx and ROCm 6.1-6.4 support (#1511)
* setup.py: Add Cuda/ROCm version select options
* bump minimum python version to 3.11
* Switch from setup.cgf to pyproject.toml
* Documentation: Update all docs to use automodapi
* Allow sysinfo to run with missing packages + correctly install tk under Linux
* Bugfix: dot naming convention in clip models
* lib.config: Centralise globally rather than passing as object
- Add torch DataParallel for multi-gpu training
  - GUI: Group switches together when generating cli args
  - CLI: Remove deprecated multi-character argparse args
  - Refactor:
    - Centralise tensorboard reading/writing + unit tests
    - Create trainer plugin interfaces + add original + distributed
* Update installers
2025-12-21 02:45:11 +00:00

257 lines
11 KiB
Python

#!/usr/bin python3
""" Pytest unit tests for :mod:`lib.system.system` """
import ctypes
import locale
import os
import platform
import sys
import pytest
import pytest_mock
# pylint:disable=import-error
import lib.system.system as system_mod
from lib.system.system import _lines_from_command, VALID_PYTHON, Packages, System
# pylint:disable=protected-access
def test_valid_python() -> None:
""" Confirm python version has a min and max and that it is Python 3 """
assert len(VALID_PYTHON) == 2
assert all(len(v) == 2 for v in VALID_PYTHON)
assert all(isinstance(x, int) for v in VALID_PYTHON for x in v)
assert all(v[0] == 3 for v in VALID_PYTHON)
assert VALID_PYTHON[0] <= VALID_PYTHON[1]
def test_lines_from_command(mocker: pytest_mock.MockerFixture) -> None:
""" Confirm lines from command executes as expected """
input_ = ["test", "input"]
subproc_out = " this \nis\n test\noutput \n"
mock_run = mocker.patch("lib.system.system.run")
mock_run.return_value.stdout = subproc_out
result = _lines_from_command(input_)
assert mock_run.called
assert result == subproc_out.splitlines()
# System
@pytest.fixture(name="system_instance")
def system_fixture() -> System:
""" Single :class:`lib.system.System` object for tests """
return System()
def test_system_init(system_instance: System) -> None:
""" Test :class:`lib.system.System` __init__ and attributes """
assert isinstance(system_instance, System)
attrs = ["platform", "system", "machine", "release", "processor", "cpu_count",
"python_implementation", "python_version", "python_architecture", "encoding",
"is_conda", "is_admin", "is_virtual_env"]
assert all(a in system_instance.__dict__ for a in attrs)
assert all(a in attrs for a in system_instance.__dict__)
assert system_instance.platform == platform.platform()
assert system_instance.system == platform.system().lower()
assert system_instance.machine == platform.machine()
assert system_instance.release == platform.release()
assert system_instance.processor == platform.processor()
assert system_instance.cpu_count == os.cpu_count()
assert system_instance.python_implementation == platform.python_implementation()
assert system_instance.python_version == platform.python_version()
assert system_instance.python_architecture == platform.architecture()[0]
assert system_instance.encoding == locale.getpreferredencoding()
assert system_instance.is_conda == ("conda" in sys.version.lower() or
os.path.exists(os.path.join(sys.prefix, "conda-meta")))
assert isinstance(system_instance.is_admin, bool)
assert isinstance(system_instance.is_virtual_env, bool)
def test_system_properties(system_instance: System) -> None:
""" Test :class:`lib.system.System` properties """
assert hasattr(system_instance, "is_linux")
assert isinstance(system_instance.is_linux, bool)
if platform.system().lower() == "linux":
assert system_instance.is_linux
assert not system_instance.is_macos
assert not system_instance.is_windows
assert hasattr(system_instance, "is_macos")
assert isinstance(system_instance.is_macos, bool)
if platform.system().lower() == "darwin":
assert system_instance.is_macos
assert not system_instance.is_linux
assert not system_instance.is_windows
assert hasattr(system_instance, "is_windows")
assert isinstance(system_instance.is_windows, bool)
if platform.system().lower() == "windows":
assert system_instance.is_windows
assert not system_instance.is_linux
assert not system_instance.is_macos
def test_system_get_permissions(system_instance: System) -> None:
""" Test :class:`lib.system.System` _get_permissions method """
assert hasattr(system_instance, "_get_permissions")
is_admin = system_instance._get_permissions()
if platform.system() == "Windows":
assert is_admin == (ctypes.windll.shell32.IsUserAnAdmin() != 0) # type:ignore
else:
assert is_admin == (os.getuid() == 0) # type:ignore # pylint:disable=no-member
def test_system_check_virtual_env(system_instance: System,
monkeypatch: pytest.MonkeyPatch) -> None:
""" Test :class:`lib.system.System` _check_virtual_env method """
system_instance.is_conda = True
monkeypatch.setattr(system_mod.sys, "prefix", "/home/user/miniconda3/envs/testenv")
assert system_instance._check_virtual_env()
monkeypatch.setattr(system_mod.sys, "prefix", "/home/user/miniconda3/bin/")
assert not system_instance._check_virtual_env()
system_instance.is_conda = False
monkeypatch.setattr(system_mod.sys, "base_prefix", "/home/user/venv/")
monkeypatch.setattr(system_mod.sys, "prefix", "/usr/bin/")
assert system_instance._check_virtual_env()
monkeypatch.setattr(system_mod.sys, "base_prefix", "/usr/bin/")
assert not system_instance._check_virtual_env()
def test_system_validate_python(system_instance: System,
monkeypatch: pytest.MonkeyPatch,
mocker: pytest_mock.MockerFixture) -> None:
""" Test :class:`lib.system.System` _validate_python method """
monkeypatch.setattr(system_mod, "VALID_PYTHON", (((3, 11), (3, 13))))
monkeypatch.setattr(system_mod.sys, "version_info", (3, 12, 0))
monkeypatch.setattr("builtins.input", lambda _: "")
system_instance.python_architecture = "64bit"
assert system_instance.validate_python()
assert system_instance.validate_python(max_version=(3, 12))
sys_exit = mocker.patch("lib.system.system.sys.exit")
system_instance.python_architecture = "32bit"
system_instance.validate_python()
assert sys_exit.called
system_instance.python_architecture = "64bit"
system_instance.validate_python(max_version=(3, 11))
assert sys_exit.called
for vers in ((3, 10, 0), (3, 14, 0)):
monkeypatch.setattr(system_mod.sys, "version_info", vers)
system_instance.validate_python()
assert sys_exit.called
@pytest.mark.parametrize("system_name, machine, is_conda, should_exit", [
("other", "x86_64", False, True), # Unsupported OS
("darwin", "arm64", True, False), # Apple Silicon inside conda
("darwin", "arm64", False, True), # Apple Silicon outside conda
("linux", "x86_64", True, False), # Supported
("windows", "x86_64", True, False), # Supported
])
def test_system_validate(system_instance: System,
mocker: pytest_mock.MockerFixture,
system_name,
machine,
is_conda,
should_exit) -> None:
""" Test :class:`lib.system.System` _validate method """
validate_python = mocker.patch("lib.system.System.validate_python")
system_instance.system = system_name
system_instance.machine = machine
system_instance.is_conda = is_conda
sys_exit = mocker.patch("lib.system.system.sys.exit")
system_instance.validate()
if should_exit:
assert sys_exit.called
else:
assert not sys_exit.called
assert validate_python.called
# Packages
@pytest.fixture(name="packages_instance")
def packages_fixture() -> Packages:
""" Single :class:`lib.system.Packages` object for tests """
return Packages()
def test_packages_init(packages_instance: Packages, mocker: pytest_mock.MockerFixture) -> None:
""" Test :class:`lib.system.Packages` __init__ and attributes """
assert isinstance(packages_instance, Packages)
attrs = ["_conda_exe", "_installed_python", "_installed_conda"]
assert all(a in packages_instance.__dict__ for a in attrs)
assert all(a in attrs for a in packages_instance.__dict__)
assert isinstance(packages_instance._conda_exe,
str) or packages_instance._conda_exe is None
assert isinstance(packages_instance._installed_python, dict)
assert isinstance(packages_instance._installed_conda,
list) or packages_instance._installed_conda is None
which = mocker.patch("lib.system.system.which")
Packages()
which.assert_called_once_with("conda")
def test_packages_properties(packages_instance: Packages) -> None:
""" Test :class:`lib.system.Packages` properties """
for prop in ("installed_python", "installed_conda"):
assert hasattr(packages_instance, prop)
assert isinstance(getattr(packages_instance, prop), dict)
pretty = f"{prop}_pretty"
assert hasattr(packages_instance, pretty)
assert isinstance(getattr(packages_instance, pretty), str)
def test_packages_get_installed_python(packages_instance: Packages,
mocker: pytest_mock.MockerFixture,
monkeypatch: pytest.MonkeyPatch) -> None:
""" Test :class:`lib.system.Packages` get_installed_python method """
lines_from_command = mocker.patch("lib.system.system._lines_from_command")
monkeypatch.setattr(system_mod.sys, "executable", "python")
out = packages_instance._get_installed_python()
lines_from_command.assert_called_once_with(["python", "-m", "pip", "freeze", "--local"])
assert isinstance(out, dict)
monkeypatch.setattr(system_mod, "_lines_from_command", lambda _: ["pacKage1==1.0.0",
"PACKAGE2==1.1.0",
"# Ignored",
"malformed=1.2.3",
"package3==0.2.1"])
out = packages_instance._get_installed_python()
assert out == {"package1": "1.0.0", "package2": "1.1.0", "package3": "0.2.1"}
def test_packages_get_installed_conda(packages_instance: Packages,
mocker: pytest_mock.MockerFixture,
monkeypatch: pytest.MonkeyPatch) -> None:
""" Test :class:`lib.system.Packages` get_installed_conda method """
packages_instance._conda_exe = None
packages_instance._installed_conda = None
packages_instance._get_installed_conda()
assert packages_instance._installed_conda is None
packages_instance._conda_exe = "conda"
lines_from_command = mocker.patch("lib.system.system._lines_from_command")
packages_instance._get_installed_conda()
lines_from_command.assert_called_once_with(["conda", "list", "--show-channel-urls"])
monkeypatch.setattr(system_mod, "_lines_from_command", lambda _: [])
packages_instance._get_installed_conda()
assert packages_instance._installed_conda == ["Could not get Conda package list"]
_pkgs = [
"package1 4.15.0 pypi_0 pypi",
"pkg2 2025b h78e105d_0 conda-forge",
"Packag3 3.1.3 pypi_0 defaults"]
monkeypatch.setattr(system_mod, "_lines_from_command", lambda _: _pkgs)
packages_instance._get_installed_conda()
assert packages_instance._installed_conda == _pkgs