Skip to content

Commit b9b6e14

Browse files
authored
Fix and refactoring get_qgis_path which was failing because of bad type passed to ast.literal_eval (#241)
2 parents 45a8799 + 43da71f commit b9b6e14

File tree

2 files changed

+115
-29
lines changed

2 files changed

+115
-29
lines changed

qgis_deployment_toolbelt/constants.py

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
from pathlib import Path
2121
from shutil import which
2222

23+
# package
24+
from qgis_deployment_toolbelt.utils.check_path import check_path
25+
2326
# #############################################################################
2427
# ########## Globals ###############
2528
# ##################################
@@ -75,7 +78,7 @@ class OSConfiguration:
7578
name_python: str
7679
names_alter: list = None
7780
profiles_path: Path = getenv("QGIS_CUSTOM_CONFIG_PATH")
78-
qgis_bin_exe_path: str = None
81+
qgis_bin_exe_path: Path = None
7982
shortcut_extension: str = None
8083
shortcut_forbidden_chars: tuple[str] = None
8184
shortcut_icon_extensions: tuple[str] = None
@@ -88,32 +91,61 @@ def get_qgis_bin_path(self) -> Path:
8891
Returns:
8992
Path: path to the QGIS bin/exe
9093
"""
91-
if getenv("QDT_QGIS_EXE_PATH"):
92-
qdt_qgis_exe_path = ast.literal_eval(getenv("QDT_QGIS_EXE_PATH"))
93-
if isinstance(qdt_qgis_exe_path, str):
94-
logger.debug(
95-
f"'QDT_QGIS_EXE_PATH' is a simple string: {getenv('QDT_QGIS_EXE_PATH')}"
96-
)
97-
return Path(expandvars(expanduser(getenv("QDT_QGIS_EXE_PATH"))))
98-
elif isinstance(qdt_qgis_exe_path, dict):
94+
if envvar := getenv("QDT_QGIS_EXE_PATH"):
95+
if envvar.startswith("{") and envvar.endswith("}"):
96+
try:
97+
qdt_qgis_exe_path = ast.literal_eval(envvar)
98+
if isinstance(qdt_qgis_exe_path, dict):
99+
logger.debug(
100+
f"'QDT_QGIS_EXE_PATH' is a valid dictionary: {envvar}"
101+
)
102+
for k, v in qdt_qgis_exe_path.items():
103+
if k in self.names_alter + [self.name_python]:
104+
logger.debug(
105+
f"QGIS path found in 'QDT_QGIS_EXE_PATH' dictionary: {v}"
106+
)
107+
return Path(expandvars(expanduser(v)))
108+
except Exception as err:
109+
logger.error(
110+
f"Failed to interpret 'QDT_QGIS_EXE_PATH' value: {envvar}."
111+
f"Trace: {err}"
112+
)
113+
elif check_path(
114+
input_path=envvar,
115+
must_exists=False,
116+
must_be_readable=False,
117+
raise_error=False,
118+
):
99119
logger.debug(
100-
f"'QDT_QGIS_EXE_PATH' is a dictionary: {getenv('QDT_QGIS_EXE_PATH')}"
120+
f"'QDT_QGIS_EXE_PATH' is a simple string and a valid path: {envvar}"
101121
)
102-
for k, v in qdt_qgis_exe_path.items():
103-
if k in self.names_alter + [self.name_python]:
104-
return Path(expandvars(expanduser(v)))
105-
else:
106-
return qdt_qgis_exe_path
107-
elif which("qgis"):
108-
return Path(which("qgis"))
122+
return Path(expandvars(expanduser(envvar)))
123+
124+
# fallback
125+
logger.warning(
126+
f"Unrecognised value format for 'QDT_QGIS_EXE_PATH': {envvar}. "
127+
"Fallback to default path: "
128+
f"{Path(expandvars(expanduser(self.qgis_bin_exe_path)))}"
129+
)
130+
return Path(expandvars(expanduser(self.qgis_bin_exe_path)))
131+
elif which_qgis_path := which("qgis"):
132+
logger.debug(f"QGIS path found using which: {which_qgis_path}")
133+
return Path(which_qgis_path)
109134
else:
135+
logger.debug(
136+
f"QGIS path not found, using default value: {self.qgis_bin_exe_path}"
137+
)
110138
return Path(expandvars(expanduser(self.qgis_bin_exe_path)))
111139

112140
def valid_shortcut_name(self, shortcut_name: str) -> bool:
113-
"""Check if a shortcut name is valid.
141+
"""Check if a given string is a valid shortcut name for the current operating
142+
system.
143+
144+
Args:
145+
shortcut_name (str): given shortcut name to check
114146
115-
:param str shortcut_name: _description_
116-
:return bool: _description_
147+
Returns:
148+
bool: True if the givn string can be used as shortcut name
117149
"""
118150
if self.shortcut_forbidden_chars is None:
119151
return True
@@ -140,7 +172,7 @@ def valid_shortcut_name(self, shortcut_name: str) -> bool:
140172
Path.home() / "Library/Application Support/QGIS/QGIS3/profiles/",
141173
)
142174
),
143-
qgis_bin_exe_path="/usr/bin/qgis",
175+
qgis_bin_exe_path=Path("/usr/bin/qgis"),
144176
shortcut_extension="app",
145177
shortcut_icon_extensions=("icns",),
146178
),
@@ -153,7 +185,7 @@ def valid_shortcut_name(self, shortcut_name: str) -> bool:
153185
Path.home() / ".local/share/QGIS/QGIS3/profiles/",
154186
)
155187
),
156-
qgis_bin_exe_path="/usr/bin/qgis",
188+
qgis_bin_exe_path=Path("/usr/bin/qgis"),
157189
shortcut_extension=".desktop",
158190
shortcut_icon_extensions=("ico", "svg", "png"),
159191
),
@@ -165,7 +197,9 @@ def valid_shortcut_name(self, shortcut_name: str) -> bool:
165197
"QGIS_CUSTOM_CONFIG_PATH", expandvars("%APPDATA%/QGIS/QGIS3/profiles")
166198
)
167199
),
168-
qgis_bin_exe_path="%PROGRAMFILES%/QGIS/3_22/bin/qgis-ltr-bin.exe",
200+
qgis_bin_exe_path=Path(
201+
expandvars(expanduser("%PROGRAMFILES%/QGIS/3_22/bin/qgis-ltr-bin.exe"))
202+
),
169203
shortcut_extension=".lnk",
170204
shortcut_forbidden_chars=("<", ">", ":", '"', "/", "\\", "|", "?", "*"),
171205
shortcut_icon_extensions=("ico",),

tests/test_constants.py

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"""
1212

1313
import unittest
14+
from os import environ, getenv, unsetenv
15+
from os.path import expanduser, expandvars
1416
from pathlib import Path
1517
from sys import platform as opersys
1618

@@ -25,6 +27,11 @@
2527
class TestConstants(unittest.TestCase):
2628
"""Test package static variables."""
2729

30+
def setUp(self) -> None:
31+
if "QDT_QGIS_EXE_PATH" in environ or getenv("QDT_QGIS_EXE_PATH"):
32+
unsetenv("QDT_QGIS_EXE_PATH")
33+
environ.pop("QDT_QGIS_EXE_PATH")
34+
2835
def test_constants(self):
2936
"""Test types."""
3037
self.assertIsInstance(constants.OS_CONFIG, dict)
@@ -58,12 +65,57 @@ def test_get_qdt_working_folder(self):
5865
)
5966

6067
# using environment variable
61-
# environ["QDT_LOCAL_WORK_DIR"] = "~/.cache/qdt/unit-tests-env-var/"
62-
# self.assertEqual(
63-
# constants.get_qdt_working_directory(),
64-
# Path(Path.home(), ".cache/qdt/unit-tests-env-var/"),
65-
# )
66-
# unsetenv("QDT_LOCAL_WORK_DIR")
68+
environ["QDT_LOCAL_WORK_DIR"] = "~/.cache/qdt/unit-tests-env-var/"
69+
self.assertEqual(
70+
constants.get_qdt_working_directory(),
71+
Path(Path.home(), ".cache/qdt/unit-tests-env-var/"),
72+
)
73+
unsetenv("QDT_LOCAL_WORK_DIR")
74+
75+
def test_get_qgis_bin_path(self):
76+
"""Test get GIS exe path helper property"""
77+
os_config: constants.OS_CONFIG = constants.OS_CONFIG.get(opersys)
78+
# default value
79+
self.assertEqual(os_config.get_qgis_bin_path, os_config.qgis_bin_exe_path)
80+
81+
def test_get_qgis_bin_path_with_env_var_str(self):
82+
"""Test with environment var set as str"""
83+
if "QDT_QGIS_EXE_PATH" in environ:
84+
environ.pop("QDT_QGIS_EXE_PATH")
85+
environ["QDT_QGIS_EXE_PATH"] = "/usr/bin/toto"
86+
os_config: constants.OS_CONFIG = constants.OS_CONFIG.get(opersys)
87+
self.assertEqual(os_config.get_qgis_bin_path, Path("/usr/bin/toto"))
88+
89+
environ.pop("QDT_QGIS_EXE_PATH")
90+
environ["QDT_QGIS_EXE_PATH"] = "~/qgis-ltr-bin.exe"
91+
os_config: constants.OS_CONFIG = constants.OS_CONFIG.get(opersys)
92+
self.assertEqual(
93+
os_config.get_qgis_bin_path,
94+
Path(expanduser("~/qgis-ltr-bin.exe")).resolve(),
95+
)
96+
97+
environ.pop("QDT_QGIS_EXE_PATH")
98+
99+
def test_get_qgis_bin_path_with_env_var_dict(self):
100+
"""Test get GIS exe path helper property"""
101+
if "QDT_QGIS_EXE_PATH" in environ:
102+
environ.pop("QDT_QGIS_EXE_PATH")
103+
# with environment var set as dict
104+
d_test = {
105+
"linux": "/usr/bin/qgis",
106+
"darwin": "/usr/bin/qgis",
107+
"win32": "%PROGRAMFILES%/QGIS/3_22/bin/qgis-ltr-bin.exe",
108+
}
109+
environ["QDT_QGIS_EXE_PATH"] = str(d_test)
110+
111+
os_config: constants.OS_CONFIG = constants.OS_CONFIG.get(opersys)
112+
113+
self.assertEqual(
114+
os_config.get_qgis_bin_path,
115+
Path(expandvars(expanduser(d_test.get(opersys)))),
116+
)
117+
118+
environ.pop("QDT_QGIS_EXE_PATH")
67119

68120

69121
# ############################################################################

0 commit comments

Comments
 (0)