Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: QdtProfile has now shortcuts to access to ini files and its installed alter-ego #383

Merged
merged 1 commit into from
Dec 29, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 132 additions & 30 deletions qgis_deployment_toolbelt/profiles/qdt_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pathlib import Path
from sys import platform as opersys
from sys import version_info
from typing import Literal

# Imports depending on Python version
if version_info[1] < 11:
Expand All @@ -28,8 +29,9 @@
from packaging.version import InvalidVersion, Version

# Package
from qgis_deployment_toolbelt.constants import OS_CONFIG
from qgis_deployment_toolbelt.constants import OS_CONFIG, 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 All @@ -55,27 +57,29 @@ class QdtProfile:

def __init__(
self,
alias: str = None,
author: str = None,
description: str = None,
email: str = None,
folder: Path = None,
icon: str = None,
json_ref_path: Path = None,
alias: str | None = None,
author: str | None = None,
description: str | None = None,
email: str | None = None,
folder: Path | None = None,
icon: str | None = None,
json_ref_path: Path | None = None,
loaded_from_json: bool = False,
name: str = None,
plugins: list = None,
qgis_maximum_version: str = None,
qgis_minimum_version: str = None,
splash: str = None,
version: str = None,
name: str | None = None,
plugins: list | None = None,
qgis_maximum_version: str | None = None,
qgis_minimum_version: str | None = None,
splash: str | None = None,
version: str | None = None,
**kwargs,
):
"""Initialize a QDT Profile object.

:param str name: name of the shortcut that will be created
:param str author: profile author name
"""
# 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(
Expand Down Expand Up @@ -132,23 +136,27 @@ def __init__(
self._version = version

@classmethod
def from_json(cls, profile_json_path: Path, profile_folder: Path = None) -> Self:
def from_json(
cls, profile_json_path: Path, profile_folder: Path | None = None
) -> "QdtProfile":
"""Load profile from a profile.json file.

:param Path profile_json_path: path to the profile json file
:param Path profile_folder: path to the profile folder, defaults to None
Args:
profile_json_path (Path): path to the profile json file
profile_folder (Path | None, optional): path to the profile folder,
defaults to None.

:return Self: QdtProfile object with attributes filled from JSON.
Returns:
QdtProfile: QdtProfile object with attributes filled from JSON.

:example:
Example:

.. code-block:: python

QdtProfile = QdtProfile.from_json(
Path(src_profile / "profile.json")
)
print(profile.splash.resolve())

"""
# checks
check_path(
Expand Down Expand Up @@ -193,7 +201,8 @@ def alias(self) -> str:
def folder(self) -> Path:
"""Returns the path to the folder where the profile is stored.

:return Path: profile folder path
Returns:
Path: profile folder path
"""
if isinstance(self._folder, Path):
return self._folder.resolve()
Expand Down Expand Up @@ -256,7 +265,7 @@ def path_in_qgis(self) -> Path:
Returns:
Path: path to the installed (i.e. in QGIS) profile folder
"""
return self.os_config.profiles_path / self.name
return self.os_config.profiles_path.joinpath(self.name)

@property
def plugins(self) -> list[QgisPlugin]:
Expand Down Expand Up @@ -349,18 +358,111 @@ def is_older_than(self, version_to_compare: str | Self) -> bool:

return profile_version < version_to_compare

def status(self) -> Literal["downloaded", "installed", "unknown"]:
"""Determine current profile status: downloaded (in QDT working folder),
installed (in QGIS3/profiles) or unknown.

Returns:
str: one of "downloaded", "installed", "unknown"
"""
if not isinstance(self.folder, Path):
return "unknown"

if self.folder.is_relative_to(self.os_config.profiles_path):
return "installed"
elif self.folder.is_relative_to(self.qdt_working_folder):
return "downloaded"
else:
return "unknown"

@property
def installed_profile(self) -> "QdtProfile | None":
"""Returns the installed profile object only if the corresponding profiles.json
exists.

Returns:
QdtProfile | None: QdtProfile object if profile.json exists, else None
"""

if self.status() == "installed":
return self
elif self.status() == "downloaded":
if self.path_in_qgis.joinpath("profile.json").is_file():
return self.from_json(
profile_json_path=self.path_in_qgis.joinpath("profile.json"),
profile_folder=self.path_in_qgis.resolve(),
)
else:
# TODO: develop a class method to load a profile from a folder
pass
return None

# -- QGIS*.ini files --
def has_qgis3_ini_file(self) -> bool:
"""Determine if a QGIS/QGIS3.ini file exists in the profile folder.

Returns:
bool: True if a QGIS/QGIS3.ini file exists in the profile folder.
"""
return check_path(
input_path=self.folder.joinpath("QGIS/QGIS3.ini"),
must_be_a_file=True,
must_be_a_folder=False,
must_be_readable=True,
must_exists=True,
raise_error=False,
)

def has_qgis3customization_ini_file(self) -> bool:
"""Determine if a QGIS/QGISCUSTOMIZATION3.ini file exists in the profile folder.

Returns:
bool: True if a QGIS/QGISCUSTOMIZATION3.ini file exists in the profile folder.
"""
return check_path(
input_path=self.folder.joinpath("QGIS/QGISCUSTOMIZATION3.ini"),
must_be_a_file=True,
must_be_a_folder=False,
must_be_readable=True,
must_exists=True,
raise_error=False,
)

def get_qgis3ini_helper(self) -> QgisIniHelper:
"""Return the QGIS3 ini helper for the profile configuration.

Returns:
QgisIniHelper: Ini helper loaded with profile's QGIS/QGIS3.ini
"""
logger.debug(
f"Returning QGISCUSTOMIZATION3.ini helper for profile '{self.name}' using "
f"this file: {self.folder.joinpath('QGIS/QGISCUSTOMIZATION3.ini')}"
)
return QgisIniHelper(
ini_filepath=self.folder.joinpath("QGIS/QGIS3.ini"),
ini_type="profile_qgis3",
)

def get_qgis3customizationini_helper(self) -> QgisIniHelper:
"""Return the QGIS3 ini helper for the profile customization.

Returns:
QgisIniHelper: Ini helper loaded with profile's QGIS/QGISCUSTOMIZATION3.ini
"""
logger.debug(
f"Returning QGISCUSTOMIZATION3.ini helper for profile '{self.name}' using "
f"this file: {self.folder.joinpath('QGIS/QGISCUSTOMIZATION3.ini')}"
)
return QgisIniHelper(
ini_filepath=self.folder.joinpath("QGIS/QGISCUSTOMIZATION3.ini"),
ini_type="profile_qgis3customization",
)


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

if __name__ == "__main__":
"""Standalone execution."""
profile_good_sample = Path("tests/fixtures/profiles/good_profile_complete.json")
assert profile_good_sample.is_file() is True

qdt_profile = QdtProfile.from_json(
profile_json_path=profile_good_sample, profile_folder=profile_good_sample.parent
)
assert isinstance(qdt_profile, QdtProfile)
assert isinstance(qdt_profile.plugins, list)
pass