Skip to content

Commit

Permalink
Improve: cleanup OSConfig and refacto CLI's tests to run outside real…
Browse files Browse the repository at this point in the history
… QGIS profiles folder (#427)

Some fixes and clean up following
#421
  • Loading branch information
Guts authored Feb 22, 2024
2 parents ca780a1 + 015b7d2 commit 9cd5379
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 86 deletions.
9 changes: 6 additions & 3 deletions qgis_deployment_toolbelt/commands/deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
from urllib.parse import urlsplit

# submodules
from qgis_deployment_toolbelt.constants import OS_CONFIG, get_qdt_working_directory
from qgis_deployment_toolbelt.constants import (
SUPPORTED_OPERATING_SYSTEMS_CODENAMES,
get_qdt_working_directory,
)
from qgis_deployment_toolbelt.jobs import JobsOrchestrator
from qgis_deployment_toolbelt.scenarios import ScenarioReader
from qgis_deployment_toolbelt.utils.bouncer import exit_cli_error, exit_cli_success
Expand Down Expand Up @@ -151,10 +154,10 @@ def run(args: argparse.Namespace):
exit_cli_error(result_scenario_validity)

# check operating system
if opersys not in OS_CONFIG:
if opersys not in SUPPORTED_OPERATING_SYSTEMS_CODENAMES:
raise OSError(
f"Your operating system {opersys} is not supported. "
f"Supported platforms: {','.join(OS_CONFIG.keys())}."
f"Supported platforms: {','.join(SUPPORTED_OPERATING_SYSTEMS_CODENAMES)}."
)

# -- Run --
Expand Down
28 changes: 5 additions & 23 deletions qgis_deployment_toolbelt/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from pathlib import Path
from shutil import which
from sys import platform as opersys
from typing import Literal

# package
from qgis_deployment_toolbelt.utils.check_path import check_path
Expand All @@ -38,6 +37,10 @@
# defaults
DEFAULT_QDT_WORKING_FOLDER = Path.home().joinpath(".cache/qgis-deployment-toolbelt")

# Operating systems
SUPPORTED_OPERATING_SYSTEMS_CODENAMES: tuple[str, ...] = ("darwin", "linux", "win32")


# #############################################################################
# ########## Functions #############
# ##################################
Expand Down Expand Up @@ -225,7 +228,7 @@ def valid_shortcut_name(self, shortcut_name: str) -> bool:
@classmethod
def from_opersys(
cls,
operating_system_codename: Literal["darwin", "linux", "win32"] | None = None,
operating_system_codename: str | None = None,
) -> OSConfiguration:
"""Create configuration object with defaults values from a operating system
code name.
Expand Down Expand Up @@ -300,24 +303,3 @@ def from_opersys(
f"Unsupported operating system specified: {operating_system_codename}. "
"Must be one of: {', '.join('darwin', 'linux', 'win32')}"
)


# #############################################################################
# ########## Main ##################
# ##################################

# "static" dictionary. Useful when need to access settings at the program (module)
# beginning (instanciation)
OS_CONFIG: dict[str, OSConfiguration] = {
"darwin": OSConfiguration.from_opersys(operating_system_codename="darwin"),
"linux": OSConfiguration.from_opersys(operating_system_codename="linux"),
"win32": OSConfiguration.from_opersys(operating_system_codename="win32"),
}

# #############################################################################
# ##### Stand alone program ########
# ##################################

if __name__ == "__main__":
"""Standalone execution."""
pass
1 change: 0 additions & 1 deletion qgis_deployment_toolbelt/jobs/generic_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ def __init__(self) -> None:

# destination profiles folder
self.qgis_profiles_path: Path = self.os_config.qgis_profiles_path
print(f"PROFILES DESTINATION FOLDER: {self.qgis_profiles_path}")
if not self.qgis_profiles_path.exists():
logger.info(
f"Installed QGIS profiles folder not found: {self.qgis_profiles_path}. "
Expand Down
16 changes: 0 additions & 16 deletions qgis_deployment_toolbelt/jobs/job_profiles_synchronizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,22 +350,6 @@ def sync_installed_profiles_from_downloaded_profiles(
f"{self.qgis_profiles_path.resolve()}"
)

def sync_copy_only_missing(self, profiles_folder_to_copy: tuple[Path]) -> None:
"""Copy only missing profiles from downloaded ones to QGIS profiles folder to
local destination.
Args:
profiles_folder_to_copy (tuple[Path]): folders to copy.
"""
# copy downloaded profiles into this
for d in profiles_folder_to_copy:
copytree(
d,
self.qgis_profiles_path,
copy_function=copy2,
dirs_exist_ok=True,
)

def sync_overwrite_local_profiles(
self, profiles_to_copy: tuple[QdtProfile]
) -> None:
Expand Down
5 changes: 0 additions & 5 deletions qgis_deployment_toolbelt/jobs/job_shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
# Standard library
import logging
from pathlib import Path
from sys import platform as opersys

# package
from qgis_deployment_toolbelt.__about__ import __title__, __version__
from qgis_deployment_toolbelt.constants import OS_CONFIG
from qgis_deployment_toolbelt.jobs.generic_job import GenericJob
from qgis_deployment_toolbelt.profiles.qdt_profile import QdtProfile
from qgis_deployment_toolbelt.shortcuts import ApplicationShortcut
Expand Down Expand Up @@ -114,9 +112,6 @@ def __init__(self, options: dict) -> None:
super().__init__()
self.options: dict = self.validate_options(options)

# profile folder
self.os_config = OS_CONFIG.get(opersys)

def run(self) -> None:
"""Execute job logic."""
# check of there are some profiles folders within the downloaded folder
Expand Down
13 changes: 5 additions & 8 deletions qgis_deployment_toolbelt/profiles/qdt_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import json
import logging
from pathlib import Path
from sys import platform as opersys
from sys import version_info
from typing import Literal

Expand All @@ -29,7 +28,10 @@
from packaging.version import InvalidVersion, Version

# Package
from qgis_deployment_toolbelt.constants import OS_CONFIG, get_qdt_working_directory
from qgis_deployment_toolbelt.constants import (
OSConfiguration,
get_qdt_working_directory,
)
from qgis_deployment_toolbelt.plugins.plugin import QgisPlugin
from qgis_deployment_toolbelt.profiles.qgis_ini_handler import QgisIniHelper
from qgis_deployment_toolbelt.utils.check_path import check_path
Expand Down Expand Up @@ -81,12 +83,7 @@ def __init__(
# store QDT working folder
self.qdt_working_folder = get_qdt_working_directory()
# retrieve operating system specific configuration
if opersys not in OS_CONFIG:
raise OSError(
f"Your operating system {opersys} is not supported. "
f"Supported platforms: {','.join(OS_CONFIG.keys())}."
)
self.os_config = OS_CONFIG.get(opersys)
self.os_config = OSConfiguration.from_opersys()

# default values for immutable attributes
self.loaded_from_json = loaded_from_json
Expand Down
12 changes: 3 additions & 9 deletions qgis_deployment_toolbelt/shortcuts/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
from string import Template
from sys import platform as opersys

# 3rd party

# Imports depending on operating system
if opersys == "win32":
"""windows"""
Expand All @@ -34,8 +32,9 @@
else:
pass

# package
from qgis_deployment_toolbelt.__about__ import __title__, __version__
from qgis_deployment_toolbelt.constants import OS_CONFIG
from qgis_deployment_toolbelt.constants import OSConfiguration
from qgis_deployment_toolbelt.utils.check_path import check_path
from qgis_deployment_toolbelt.utils.slugger import sluggy

Expand Down Expand Up @@ -72,12 +71,7 @@ def __init__(
:param Union[str, Path] work_dir: current folder where to start the executable, defaults to None. In QDT, it's the profile folder.
"""
# retrieve operating system specific configuration
if opersys not in OS_CONFIG:
raise OSError(
f"Your operating system {opersys} is not supported. "
f"Supported platforms: {','.join(OS_CONFIG.keys())}."
)
self.os_config = OS_CONFIG.get(opersys)
self.os_config = OSConfiguration.from_opersys()

# -- CHECK TYPE AND STORE ATTRIBUTES
# mandatory
Expand Down
61 changes: 49 additions & 12 deletions tests/test_cli_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@
# ########## Libraries #############
# ##################################


# Standard library
import tempfile
from os import environ, getenv
from pathlib import Path

# 3rd party
import pytest

# module to test
# project
from qgis_deployment_toolbelt import __about__, cli
from qgis_deployment_toolbelt.profiles.qdt_profile import QdtProfile

# #############################################################################
# ######## Globals #################
Expand Down Expand Up @@ -81,11 +85,37 @@ def test_cli_version(capsys, option):
@pytest.mark.parametrize("option", good_scenarios)
def test_main_run(capsys, option):
"""Test main cli command"""
with pytest.raises(SystemExit):
cli.main(option)

out, err = capsys.readouterr()
assert err == ""
with tempfile.TemporaryDirectory(
prefix="QDT_test_cli_run_",
ignore_cleanup_errors=True,
) as tmpdirname:
# customize QDT working folder and profiles destination folder
tmp_dir = Path(tmpdirname).joinpath(f"scenario_{good_scenarios.index(option)}")
environ[
"QDT_LOCAL_WORK_DIR"
] = f"{Path(tmpdirname).joinpath('qdt_working_folder').resolve()}"
environ["QGIS_CUSTOM_CONFIG_PATH"] = f"{tmp_dir.resolve()}"

assert getenv("QGIS_CUSTOM_CONFIG_PATH") is not None

with pytest.raises(SystemExit):
cli.main(option)

out, err = capsys.readouterr()
assert err == ""

# checks
created_profiles = [
QdtProfile.from_json(profile_json_path=f, profile_folder=f.parent)
for f in tmp_dir.glob("**/profile.json")
]

assert Path(getenv("QGIS_CUSTOM_CONFIG_PATH")).is_dir()
assert len(created_profiles) > 0

# clean up environment vars
environ.pop("QGIS_CUSTOM_CONFIG_PATH")


def test_main_run_unexising_jobs(capsys):
Expand Down Expand Up @@ -113,13 +143,20 @@ def test_main_run_failed(capsys):

def test_main_run_removing_splash(capsys):
"""Test main cli command"""
with pytest.raises(SystemExit):
cli.main(
["deploy", f"--scenario={sample_scenario_good_splash_removal.resolve()}"]
)

out, err = capsys.readouterr()
assert err == ""
with tempfile.TemporaryDirectory(
prefix="qdt_test_cli_main_", ignore_cleanup_errors=True
) as tmpdirname:
environ["QGIS_CUSTOM_CONFIG_PATH"] = tmpdirname
with pytest.raises(SystemExit):
cli.main(
[
"deploy",
f"--scenario={sample_scenario_good_splash_removal.resolve()}",
]
)

out, err = capsys.readouterr()
assert err == ""


# #############################################################################
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cli_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
get_latest_release,
replace_domain,
)
from qgis_deployment_toolbelt.constants import OS_CONFIG
from qgis_deployment_toolbelt.constants import SUPPORTED_OPERATING_SYSTEMS_CODENAMES

# #############################################################################
# ######## Functions ###############
Expand Down Expand Up @@ -77,7 +77,7 @@ def test_release_assets_download_links(self):
get_download_url_for_os(latest_release.get("assets"), override_opersys=os)[
0
]
for os in OS_CONFIG.keys()
for os in SUPPORTED_OPERATING_SYSTEMS_CODENAMES
]
self.assertTrue(len(dl_hyperlinks), 3)
self.assertTrue(all([dl_url.startswith("https") for dl_url in dl_hyperlinks]))
Expand Down
18 changes: 11 additions & 7 deletions tests/test_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

# project
from qgis_deployment_toolbelt.constants import (
OS_CONFIG,
OSConfiguration,
get_qdt_logs_folder,
get_qdt_working_directory,
Expand All @@ -43,8 +42,8 @@ def setUp(self) -> None:

def test_constants(self):
"""Test types."""
self.assertIsInstance(OS_CONFIG, dict)
os_config = OS_CONFIG.get(opersys)

os_config = OSConfiguration.from_opersys()
self.assertIsInstance(os_config, OSConfiguration)

self.assertIsInstance(os_config.qgis_profiles_path, Path)
Expand All @@ -65,6 +64,11 @@ def test_constants(self):
os_config_forbidden_chars.valid_shortcut_name(shortcut_name="qgis_ltr_3_28")
)

def test_unsupported_operating_system(self):
"""Test that a bad operating system name raise an error."""
with self.assertRaises(ValueError):
OSConfiguration.from_opersys("fake_operating_system_name")

def test_get_qdt_logs_folder(self):
"""Test how QDT logs folder is retrieved"""
# default value
Expand Down Expand Up @@ -110,7 +114,7 @@ def test_get_qdt_working_folder(self):

def test_get_qgis_bin_path(self):
"""Test get GIS exe path helper property"""
os_config: OSConfiguration = OS_CONFIG.get(opersys)
os_config = OSConfiguration.from_opersys()
# default value
self.assertEqual(os_config.get_qgis_bin_path, os_config.qgis_bin_exe_path)

Expand All @@ -119,12 +123,12 @@ def test_get_qgis_bin_path_with_env_var_str(self):
if "QDT_QGIS_EXE_PATH" in environ:
environ.pop("QDT_QGIS_EXE_PATH")
environ["QDT_QGIS_EXE_PATH"] = "/usr/bin/toto"
os_config: OSConfiguration = OS_CONFIG.get(opersys)
os_config = OSConfiguration.from_opersys()
self.assertEqual(os_config.get_qgis_bin_path, Path("/usr/bin/toto"))

environ.pop("QDT_QGIS_EXE_PATH")
environ["QDT_QGIS_EXE_PATH"] = "~/qgis-ltr-bin.exe"
os_config: OSConfiguration = OS_CONFIG.get(opersys)
os_config = OSConfiguration.from_opersys()
self.assertEqual(
os_config.get_qgis_bin_path,
Path(expanduser("~/qgis-ltr-bin.exe")).resolve(),
Expand All @@ -144,7 +148,7 @@ def test_get_qgis_bin_path_with_env_var_dict(self):
}
environ["QDT_QGIS_EXE_PATH"] = str(d_test)

os_config: OSConfiguration = OS_CONFIG.get(opersys)
os_config = OSConfiguration.from_opersys()

self.assertEqual(
os_config.get_qgis_bin_path,
Expand Down

0 comments on commit 9cd5379

Please sign in to comment.