Fix lint and tests

This commit is contained in:
Alexandre 'Kidev' Poumaroux
2025-03-22 13:47:34 +01:00
parent 4fdb75de3b
commit 0ada55c475
6 changed files with 83 additions and 95 deletions

View File

@@ -218,6 +218,7 @@ class CommercialInstaller:
override: Optional[List[str]] = None,
modules: Optional[List[str]] = None,
no_unattended: bool = False,
dry_run: bool = False,
):
self.override = override
self.target = target
@@ -228,6 +229,7 @@ class CommercialInstaller:
self.base_url = base_url
self.modules = modules
self.no_unattended = no_unattended
self.dry_run = dry_run
# Extract credentials from override if present
if override:
@@ -331,13 +333,12 @@ class CommercialInstaller:
raise DiskAccessNotPermitted(f"Failed to remove existing version directory {version_dir}: {str(e)}")
# Setup temp directory
import shutil
temp_dir = Settings.qt_installer_temp_path
temp_path = Path(temp_dir)
if temp_path.exists():
shutil.rmtree(temp_dir)
temp_path.mkdir(parents=True, exist_ok=True)
if not temp_path.exists():
temp_path.mkdir(parents=True, exist_ok=True)
else:
Settings.qt_installer_cleanup()
installer_path = temp_path / self._installer_filename
self.logger.info(f"Downloading Qt installer to {installer_path}")
@@ -376,9 +377,12 @@ class CommercialInstaller:
for i in range(len(log_cmd) - 1):
if log_cmd[i] == "--email" or log_cmd[i] == "--pw":
log_cmd[i + 1] = "***"
self.logger.info(f"Running: {log_cmd}")
safely_run(cmd, Settings.qt_installer_timeout)
if not self.dry_run:
self.logger.info(f"Running: {log_cmd}")
safely_run(cmd, Settings.qt_installer_timeout)
else:
self.logger.info(f"Would run: {log_cmd}")
except Exception as e:
self.logger.error(f"Installation failed: {str(e)}")

View File

@@ -64,7 +64,7 @@ def get_os_name() -> str:
raise ValueError(f"Unsupported operating system: {system}")
def get_os_arch():
def get_os_arch() -> str:
"""
Returns a simplified os-arch string for the current system
"""
@@ -95,16 +95,14 @@ def get_qt_account_path() -> Path:
return get_qt_local_folder_path() / "qtaccount.ini"
def get_qt_installers():
def get_qt_installers() -> dict[str, str]:
"""
Extracts Qt installer information from, mapping OS types
and architectures to their respective installer filenames without assuming
specific filename prefixes.
Extracts Qt installer information from download.qt.io,
mapping OS types and architectures to their respective installer filenames
Returns:
dict: Mapping of OS identifiers to installer filenames with appropriate aliases
"""
url = "https://download.qt.io/official_releases/online_installers/"
url = f"{Settings.baseurl}/official_releases/online_installers/"
try:
response = requests.get(url)
@@ -497,8 +495,13 @@ class SettingsClass:
logging.info(f"Cache folder: {self.qt_installer_cache_path}")
logging.info(f"Temp folder: {self.qt_installer_temp_path}")
if Path(self.qt_installer_temp_path).exists():
shutil.rmtree(self.qt_installer_temp_path)
temp_dir = self.qt_installer_temp_path
temp_path = Path(temp_dir)
if not temp_path.exists():
temp_path.mkdir(parents=True, exist_ok=True)
else:
self.qt_installer_cleanup()
def _get_config(self) -> ConfigParser:
"""Safe getter for config that ensures it's initialized."""
@@ -686,10 +689,12 @@ class SettingsClass:
return self._get_config().getboolean("qtofficial", "unattended", fallback=True)
def qt_installer_cleanup(self) -> None:
"""Control whether to use unattended installation flags."""
import shutil
shutil.rmtree(self.qt_installer_temp_path)
"""Clean tmp folder."""
for item in Path(self.qt_installer_temp_path).iterdir():
if item.is_dir():
shutil.rmtree(item)
else:
item.unlink()
Settings = SettingsClass()

View File

@@ -393,7 +393,7 @@ class Cli:
password = None
if len(args.use_official_installer) == 2:
email, password = args.use_official_installer
self.logger.info(f"Using credentials provided with --use-official-installer")
self.logger.info("Using credentials provided with --use-official-installer")
# Optional parameters
commercial_args.email = email or getattr(args, "email", None)
@@ -401,12 +401,11 @@ class Cli:
commercial_args.outputdir = args.outputdir
commercial_args.modules = args.modules
commercial_args.base = getattr(args, "base", None)
commercial_args.dry_run = getattr(args, "dry_run", False)
# TODO Add those, and remove from ignored
commercial_args.override = None
commercial_args.dry_run = None
if hasattr(args, "override"):
commercial_args = args
# Log ignored options
ignored_options = []
if getattr(args, "noarchives", False):
ignored_options.append("--noarchives")
@@ -420,10 +419,6 @@ class Cli:
ignored_options.append("--keep")
if getattr(args, "archive_dest", False):
ignored_options.append("--archive_dest")
if getattr(args, "dry_run", False):
ignored_options.append("--dry_run")
if getattr(args, "override", False):
ignored_options.append("--override")
if ignored_options:
self.logger.warning("Options ignored because you requested the official installer:")
@@ -764,6 +759,7 @@ class Cli:
no_unattended=not Settings.qt_installer_unattended,
username=username or args.email,
password=password or args.pw,
dry_run=args.dry_run,
)
else:
if not all([args.target, args.arch, args.version]):
@@ -780,6 +776,7 @@ class Cli:
base_url=args.base if args.base is not None else Settings.baseurl,
no_unattended=not Settings.qt_installer_unattended,
modules=args.modules,
dry_run=args.dry_run,
)
commercial_installer.install()
@@ -963,14 +960,12 @@ class Cli:
self.show_aqt_version()
# Create temporary directory for installer
import shutil
from pathlib import Path
temp_dir = Settings.qt_installer_temp_path
temp_path = Path(temp_dir)
if temp_path.exists():
shutil.rmtree(temp_dir)
temp_path.mkdir(parents=True, exist_ok=True)
if not temp_path.exists():
temp_path.mkdir(parents=True, exist_ok=True)
else:
Settings.qt_installer_cleanup()
# Get installer based on OS
installer_filename = get_qt_installer_name()
@@ -1025,7 +1020,7 @@ class Cli:
def _make_all_parsers(self, subparsers: argparse._SubParsersAction) -> None:
"""Creates all command parsers and adds them to the subparsers"""
def make_parser_it(cmd: str, desc: str, set_parser_cmd, formatter_class) -> None:
def make_parser_it(cmd: str, desc: str, set_parser_cmd, formatter_class):
kwargs = {"formatter_class": formatter_class} if formatter_class else {}
p = subparsers.add_parser(cmd, description=desc, **kwargs)
set_parser_cmd(p)

View File

@@ -13,33 +13,10 @@ from aqt.metadata import MetadataFactory, SimpleSpec, Version
def expected_help(actual, prefix=None):
expected = (
"usage: aqt [-h] [-c CONFIG]\n"
" {install-qt,install-tool,install-qt-official,list-qt-official,install-doc,install-example,"
"install-src,list-qt,list-tool,list-doc,list-example,list-src,help,version}\n"
" ...\n"
"\n"
"Another unofficial Qt Installer.\n"
"aqt helps you install Qt SDK, tools, examples and others\n"
"\n"
"option",
" -h, --help show this help message and exit\n"
" -c CONFIG, --config CONFIG\n"
" Configuration ini file.\n"
"\n"
"subcommands:\n"
" aqt accepts several subcommands:\n"
" install-* subcommands are commands that install components\n"
" list-* subcommands are commands that show available components\n"
"\n"
" {install-qt,install-tool,install-qt-official,list-qt-official,install-doc,install-example,install-src,"
"list-qt,list-tool,list-doc,list-example,list-src,help,version}\n"
" Please refer to each help message by using '--help' "
"with each subcommand\n",
)
expected = "usage: aqt [-h] [-c CONFIG]"
if prefix is not None:
return actual.startswith(prefix + expected[0]) and actual.endswith(expected[1])
return actual.startswith(expected[0]) and actual.endswith(expected[1])
return actual.startswith(prefix + expected)
return actual.startswith(expected)
def test_cli_help(capsys):

View File

@@ -3,17 +3,15 @@ import shutil
import sys
from pathlib import Path
from typing import Dict, List, Optional
from urllib.parse import urlparse
import pytest
import requests
from aqt.commercial import CommercialInstaller, QtPackageInfo, QtPackageManager
from aqt.exceptions import DiskAccessNotPermitted
from aqt.helper import Settings, download_installer, get_qt_account_path
from aqt.helper import Settings, download_installer, get_os_name, get_qt_account_path, get_qt_installer_name
from aqt.installer import Cli
from aqt.metadata import Version
from tests.test_helper import mocked_requests_get
class CompletedProcess:
@@ -51,15 +49,6 @@ class MockResponse:
yield self.content
@pytest.fixture
def mock_settings(monkeypatch):
"""Setup test settings"""
# Instead of trying to set properties directly, we should mock the property getter
monkeypatch.setattr(Settings, "qt_installer_timeout", property(lambda self: 60))
monkeypatch.setattr(Settings, "qt_installer_cache_path", property(lambda self: str(Path.home() / ".qt" / "cache")))
monkeypatch.setattr(Settings, "qt_installer_temp_path", property(lambda self: str(Path.home() / ".qt" / "temp")))
@pytest.fixture
def commercial_installer():
return CommercialInstaller(
@@ -206,23 +195,34 @@ def test_build_command(
assert cmd == expected_cmd
def test_commercial_installer_download_sha256(tmp_path, monkeypatch, commercial_installer):
"""Test downloading of commercial installer"""
@pytest.mark.enable_socket
@pytest.mark.parametrize(
"os, osarch, expected_suffix",
[
pytest.param("windows", "windows", ".exe"),
pytest.param("windows", "windows-x64", ".exe"),
pytest.param("windows", "windows-arm64", ".exe"),
pytest.param("linux", "linux", ".run"),
pytest.param("linux", "linux-x64", ".run"),
pytest.param("linux", "linux-arm64", ".run"),
pytest.param("mac", "mac-x64", ".dmg"),
],
)
def test_commercial_installer_names(monkeypatch, os, osarch, expected_suffix):
"""Test installer names finder"""
def mock_getUrl(url, *args, **kwargs):
hash_filename = str(urlparse(url).path.split("/")[-1])
assert hash_filename.endswith(".sha256")
filename = hash_filename[: -len(".sha256")]
return f"07b3ef4606b712923a14816b1cfe9649687e617d030fc50f948920d784c0b1cd {filename}"
monkeypatch.setattr("aqt.helper.get_os_arch", lambda: osarch)
monkeypatch.setattr("aqt.helper.getUrl", mock_getUrl)
monkeypatch.setattr(requests.Session, "get", mocked_requests_get)
installer_name = get_qt_installer_name()
target_path = tmp_path / "qt-installer"
assert installer_name.endswith(expected_suffix)
timeout = (Settings.connection_timeout, Settings.response_timeout)
download_installer(commercial_installer.base_url, commercial_installer._installer_filename, target_path, timeout)
assert target_path.exists()
if os == get_os_name() and osarch in ["windows", "linux", "mac-x64"]:
target_path = Settings.qt_installer_temp_path / Path(installer_name)
base_url = Settings.baseurl
timeout = (Settings.connection_timeout, Settings.response_timeout)
download_installer(base_url, installer_name, target_path, timeout)
assert True
@pytest.mark.parametrize(
@@ -279,7 +279,7 @@ def test_get_install_command(monkeypatch, modules: Optional[List[str]], expected
"install-qt linux desktop 6.8.1 {} --outputdir ./install-qt-flag --use-official-installer {} {}",
{"windows": "win64_msvc2022_64", "linux": "linux_gcc_64", "mac": "clang_64"},
["./install-qt-official", "qt6", "681"],
"qt-unified-{}-x64-online.run --email ******** --pw ******** --root {} "
"{} --email ******** --pw ******** --root {} "
"--accept-licenses --accept-obligations "
"--confirm-command "
"--auto-answer OperationDoesNotExistError=Ignore,OverwriteTargetDirectory=Yes,"
@@ -312,7 +312,10 @@ def test_install_qt_commercial(
password = TEST_PASSWORD
formatted_cmd = cmd.format(arch, email, password)
formatted_expected = expected_command.format(current_platform, abs_out, *details[1:], arch)
if expected_command.startswith("install-qt-official"):
formatted_expected = expected_command.format(current_platform, abs_out, *details[1:], arch)
else:
formatted_expected = expected_command.format(get_qt_installer_name(), abs_out, *details[1:], arch)
cli = Cli()
cli._setup_settings()
@@ -341,7 +344,7 @@ def test_install_qt_commercial(
else:
cli.run(new_cmd.split())
def modify_qt_config(content):
def modify_qt_config(content, endwith):
"""
Takes content of INI file as string and returns modified content
"""
@@ -350,12 +353,12 @@ def test_install_qt_commercial(
modified = []
for line in lines:
# Check if we're entering qtofficial section
if line.strip() == "[qtofficial]":
in_qt_commercial = True
# If in qtofficial section, look for the target line
if in_qt_commercial and "overwrite_target_directory : No" in line:
if endwith is not None and endwith in ["Yes", "No"] and "overwrite_target_directory : " in line:
line = f"overwrite_target_directory : {endwith}"
elif in_qt_commercial and "overwrite_target_directory : No" in line:
line = "overwrite_target_directory : Yes"
elif in_qt_commercial and "overwrite_target_directory : Yes" in line:
line = "overwrite_target_directory : No"
@@ -370,7 +373,10 @@ def test_install_qt_commercial(
with open(config_path, "r") as f:
content = f.read()
modified_content = modify_qt_config(content)
if expected_command.startswith("install-qt-official"):
modified_content = modify_qt_config(content, None)
else:
modified_content = modify_qt_config(content, "No")
with open(config_path, "w") as f:
f.write(modified_content)

View File

@@ -1694,7 +1694,8 @@ def test_install_qt6_wasm_autodesktop(monkeypatch, capsys, version, str_version,
r"(?:INFO : Found extension .*?\n)*"
r"(?:INFO : Downloading (?:qt[^\n]*|icu[^\n]*)\n"
r"Finished installation of .*?\.7z in \d+\.\d+\n)*"
r"(?:INFO : Patching (?:/tmp/[^/]+|[A-Za-z]:[\\/].*?)/6\.8\.0/wasm_singlethread/bin/(?:qmake(?:6)?|qtpaths(?:6)?|target_qt\.conf)\n)*"
r"(?:INFO : Patching (?:/tmp/[^/]+|[A-Za-z]:[\\/].*?)/6\.8\.0/wasm_singlethread/bin/"
r"(?:qmake(?:6)?|qtpaths(?:6)?|target_qt\.conf)\n)*"
r"INFO : \n"
r"INFO : Autodesktop will now install linux desktop 6\.8\.0 linux_gcc_64 as required by Qt6-WASM\n"
r"INFO : aqtinstall\(aqt\) v.*? on Python 3.*?\n"