From 9baf2ac21782783d7ec3504509a9d10f17754d4c Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Thu, 1 Aug 2024 22:47:30 +0200 Subject: [PATCH 01/16] refactor(rss): move RSS reader to its own folder --- qtribu/logic/__init__.py | 1 - qtribu/logic/news_feed/__init__.py | 0 qtribu/logic/{ => news_feed}/rss_reader.py | 0 qtribu/plugin_main.py | 3 ++- 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 qtribu/logic/news_feed/__init__.py rename qtribu/logic/{ => news_feed}/rss_reader.py (100%) diff --git a/qtribu/logic/__init__.py b/qtribu/logic/__init__.py index f76fcbbb..bae5415d 100644 --- a/qtribu/logic/__init__.py +++ b/qtribu/logic/__init__.py @@ -1,4 +1,3 @@ #! python3 # noqa: E265 from .custom_datatypes import RssItem # noqa: F401 -from .rss_reader import RssMiniReader # noqa: F401 from .splash_changer import SplashChanger # noqa: F401 diff --git a/qtribu/logic/news_feed/__init__.py b/qtribu/logic/news_feed/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/qtribu/logic/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py similarity index 100% rename from qtribu/logic/rss_reader.py rename to qtribu/logic/news_feed/rss_reader.py diff --git a/qtribu/plugin_main.py b/qtribu/plugin_main.py index 5ce9b174..b35dd7d6 100644 --- a/qtribu/plugin_main.py +++ b/qtribu/plugin_main.py @@ -22,7 +22,8 @@ from qtribu.gui.dlg_settings import PlgOptionsFactory from qtribu.gui.form_article import ArticleForm from qtribu.gui.form_rdp_news import RdpNewsForm -from qtribu.logic import RssMiniReader, SplashChanger +from qtribu.logic.news_feed.rss_reader import RssMiniReader +from qtribu.logic.splash_changer import SplashChanger from qtribu.toolbelt import NetworkRequestsManager, PlgLogger, PlgOptionsManager from qtribu.toolbelt.commons import open_url_in_browser, open_url_in_webviewer From a8aac5b5554442cf1f7bcccc0fe85670352bc91e Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 08:07:36 +0200 Subject: [PATCH 02/16] fix(tests): use new path to import --- tests/qgis/test_plg_rss_rdr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qgis/test_plg_rss_rdr.py b/tests/qgis/test_plg_rss_rdr.py index bac65597..31fb7116 100644 --- a/tests/qgis/test_plg_rss_rdr.py +++ b/tests/qgis/test_plg_rss_rdr.py @@ -14,7 +14,7 @@ import unittest # project -from qtribu.logic import RssMiniReader +from qtribu.logic.news_feed.rss_reader import RssMiniReader # ############################################################################ # ########## Classes ############# From 2212b274ffdf7ab0c51a060f3c311b558e8db9bc Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 14:35:37 +0200 Subject: [PATCH 03/16] feature(rss): add files'age checker --- qtribu/toolbelt/file_stats.py | 80 +++++++++++++++++++++++++++++ qtribu/toolbelt/preferences.py | 5 +- tests/qgis/test_utils_file_stats.py | 59 +++++++++++++++++++++ 3 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 qtribu/toolbelt/file_stats.py create mode 100644 tests/qgis/test_utils_file_stats.py diff --git a/qtribu/toolbelt/file_stats.py b/qtribu/toolbelt/file_stats.py new file mode 100644 index 00000000..1578de3f --- /dev/null +++ b/qtribu/toolbelt/file_stats.py @@ -0,0 +1,80 @@ +#! python3 # noqa: E265 + +"""Check file statistcs.""" + +# ############################################################################ +# ########## IMPORTS ############# +# ################################ + +# standard library +import logging +from datetime import datetime, timedelta +from pathlib import Path +from sys import platform as opersys +from typing import Literal + +# ############################################################################ +# ########## GLOBALS ############# +# ################################ + +# logs +logger = logging.getLogger(__name__) + +# ############################################################################ +# ########## FUNCTIONS ########### +# ################################ + + +def is_file_older_than( + local_file_path: Path, + expiration_rotating_hours: int = 24, + dt_reference_mode: Literal["auto", "creation", "modification"] = "auto", +) -> bool: + """Check if the creation/modification date of the specified file is older than the \ + mount of hours. + + Args: + local_file_path (Path): local path to the file + expiration_rotating_hours (int, optional): number in hours to consider the \ + local file outdated. Defaults to 24. + dt_reference_mode (Literal['auto', 'creation', 'modification'], optional): + reference date type: auto to handle differences between operating systems, + creation for creation date, modification for last modification date. + Defaults to "auto". + + Returns: + bool: True if the creation/modification date of the file is older than the \ + specified number of hours. + """ + if not local_file_path.is_file() and not local_file_path.exists(): + logger.debug(f"{local_file_path} does not exist.") + return True + + # modification date varies depending on operating system: on some systems (like + # Unix) creation date is the time of the last metadata change, and, on others + # (like Windows), is the creation time for path. + if dt_reference_mode == "auto" and opersys == "win32": + dt_reference_mode = "modification" + else: + dt_reference_mode = "creation" + + # get file reference datetime - modification or creation + if dt_reference_mode == "modification": + f_ref_dt = datetime.fromtimestamp(local_file_path.stat().st_mtime) + dt_type = "modified" + else: + f_ref_dt = datetime.fromtimestamp(local_file_path.stat().st_ctime) + dt_type = "created" + + if (datetime.now() - f_ref_dt) < timedelta(hours=expiration_rotating_hours): + logger.debug( + f"{local_file_path} has been {dt_type} less than " + f"{expiration_rotating_hours} hours ago." + ) + return False + else: + logger.debug( + f"{local_file_path} has been {dt_type} more than " + f"{expiration_rotating_hours} hours ago." + ) + return True diff --git a/qtribu/toolbelt/preferences.py b/qtribu/toolbelt/preferences.py index 251166cf..e5bba271 100644 --- a/qtribu/toolbelt/preferences.py +++ b/qtribu/toolbelt/preferences.py @@ -31,14 +31,15 @@ class PlgSettingsStructure: local_app_folder: Path = get_app_dir(dir_name="cache") # RSS feed - rss_source: str = "https://geotribu.fr/feed_rss_created.xml" json_feed_source: str = "https://geotribu.fr/feed_json_created.json" + latest_content_guid: str = "" + rss_source: str = "https://geotribu.fr/feed_rss_created.xml" + rss_poll_frequency_hours: int = 24 # usage browser: int = 1 notify_push_info: bool = True notify_push_duration: int = 10 - latest_content_guid: str = "" splash_screen_enabled: bool = False license_global_accept: bool = False integration_qgis_news_feed: bool = True diff --git a/tests/qgis/test_utils_file_stats.py b/tests/qgis/test_utils_file_stats.py new file mode 100644 index 00000000..ecb1e190 --- /dev/null +++ b/tests/qgis/test_utils_file_stats.py @@ -0,0 +1,59 @@ +#! python3 # noqa E265 + +""" + Usage from the repo root folder: + + .. code-block:: bash + # for whole tests + python -m unittest tests.unit.test_utils_file_stats + # for specific test + python -m unittest tests.unit.test_utils_file_stats.TestUtilsFileStats.test_created_file_is_not_expired +""" + + +# standard library +import unittest +from pathlib import Path +from tempfile import TemporaryDirectory +from time import sleep + +# project +from qtribu.__about__ import __title_clean__, __version__ +from qtribu.toolbelt.file_stats import is_file_older_than + +# ############################################################################ +# ########## Classes ############# +# ################################ + + +class TestUtilsFileStats(unittest.TestCase): + """Test utils related to files stats.""" + + def test_created_file_is_not_expired(self): + """Test file creation 'age' is OK.""" + with TemporaryDirectory( + f"{__title_clean__}_{__version__}_not_expired_" + ) as tempo_dir: + tempo_file = Path(tempo_dir, "really_recent_file.txt") + tempo_file.touch() + sleep(3) + self.assertFalse(is_file_older_than(Path(tempo_file))) + + def test_created_file_has_expired(self): + """Test file creation 'age' is too old.""" + with TemporaryDirectory( + prefix=f"{__title_clean__}_{__version__}_expired_" + ) as tempo_dir: + tempo_file = Path(tempo_dir, "not_so_really_recent_file.txt") + tempo_file.touch() + sleep(3) + self.assertTrue( + is_file_older_than(Path(tempo_file), expiration_rotating_hours=0) + ) + + +# ############################################################################ +# ####### Stand-alone run ######## +# ################################ +if __name__ == "__main__": + unittest.main() From dbde0fbc560df8f04add847760b4a300f8f7732d Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 14:38:32 +0200 Subject: [PATCH 04/16] improve(downloader): make sure a parent dirs exist before downloading a file --- qtribu/toolbelt/network_manager.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/qtribu/toolbelt/network_manager.py b/qtribu/toolbelt/network_manager.py index 239a5408..62eb0ac1 100644 --- a/qtribu/toolbelt/network_manager.py +++ b/qtribu/toolbelt/network_manager.py @@ -11,7 +11,8 @@ # Standard library import logging from functools import lru_cache -from typing import Optional +from pathlib import Path +from typing import Optional, Union from urllib.parse import urlparse, urlunparse # PyQGIS @@ -180,7 +181,7 @@ def get_from_source( logger.error(err_msg) self.log(message=err_msg, log_level=2, push=True) - def download_file(self, remote_url: str, local_path: str) -> str: + def download_file_to(self, remote_url: str, local_path: Union[Path, str]) -> str: """Download a file from a remote web server accessible through HTTP. :param remote_url: remote URL @@ -190,6 +191,13 @@ def download_file(self, remote_url: str, local_path: str) -> str: :return: output path :rtype: str """ + # check if destination path is a str and if parent folder exists + if isinstance(local_path, Path): + local_path.parent.mkdir(parents=True, exist_ok=True) + local_path = f"{local_path.resolve()}" + elif isinstance(local_path, str): + Path(local_path).parent.mkdir(parents=True, exist_ok=True) + self.log( message=f"Downloading file from {remote_url} to {local_path}", log_level=4 ) From 10faaebbb9c11bef4ff7dde13556f2266a5b80b1 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 16:06:09 +0200 Subject: [PATCH 05/16] refactor(feeds): move and rename feeds readers related code --- qtribu/gui/dlg_contents.py | 4 ++-- qtribu/logic/__init__.py | 1 - qtribu/logic/custom_datatypes.py | 22 ---------------------- qtribu/logic/{ => news_feed}/json_feed.py | 6 +++--- qtribu/logic/news_feed/mdl_rss_item.py | 21 +++++++++++++++++++++ 5 files changed, 26 insertions(+), 28 deletions(-) delete mode 100644 qtribu/logic/custom_datatypes.py rename qtribu/logic/{ => news_feed}/json_feed.py (97%) create mode 100644 qtribu/logic/news_feed/mdl_rss_item.py diff --git a/qtribu/gui/dlg_contents.py b/qtribu/gui/dlg_contents.py index 28103ead..82533ec7 100644 --- a/qtribu/gui/dlg_contents.py +++ b/qtribu/gui/dlg_contents.py @@ -16,8 +16,8 @@ from qtribu.constants import ICON_ARTICLE, ICON_GEORDP from qtribu.gui.form_article import ArticleForm from qtribu.gui.form_rdp_news import RdpNewsForm -from qtribu.logic import RssItem -from qtribu.logic.json_feed import JsonFeedClient +from qtribu.logic.news_feed.json_feed import JsonFeedClient +from qtribu.logic.news_feed.mdl_rss_item import RssItem from qtribu.toolbelt import PlgLogger, PlgOptionsManager from qtribu.toolbelt.commons import open_url_in_browser, open_url_in_webviewer diff --git a/qtribu/logic/__init__.py b/qtribu/logic/__init__.py index bae5415d..16192f77 100644 --- a/qtribu/logic/__init__.py +++ b/qtribu/logic/__init__.py @@ -1,3 +1,2 @@ #! python3 # noqa: E265 -from .custom_datatypes import RssItem # noqa: F401 from .splash_changer import SplashChanger # noqa: F401 diff --git a/qtribu/logic/custom_datatypes.py b/qtribu/logic/custom_datatypes.py deleted file mode 100644 index e0020e59..00000000 --- a/qtribu/logic/custom_datatypes.py +++ /dev/null @@ -1,22 +0,0 @@ -#! python3 # noqa: E265 - -# Standard library -from collections import namedtuple - -# Data structures -RssItem = namedtuple( - typename="RssItem", - field_names=[ - "abstract", - "author", - "categories", - "date_pub", - "guid", - "image_length", - "image_type", - "image_url", - "title", - "url", - ], - defaults=(None, None, None, None, None, None, None, None, None), -) diff --git a/qtribu/logic/json_feed.py b/qtribu/logic/news_feed/json_feed.py similarity index 97% rename from qtribu/logic/json_feed.py rename to qtribu/logic/news_feed/json_feed.py index db358739..d3bf3f58 100644 --- a/qtribu/logic/json_feed.py +++ b/qtribu/logic/news_feed/json_feed.py @@ -18,7 +18,7 @@ # plugin from qtribu.__about__ import __title__, __version__ -from qtribu.logic import RssItem +from qtribu.logic.news_feed.mdl_rss_item import RssItem from qtribu.toolbelt import NetworkRequestsManager, PlgLogger, PlgOptionsManager # -- GLOBALS -- @@ -30,7 +30,7 @@ FETCH_UPDATE_INTERVAL_SECONDS = 7200 -## -- CLASSES -- +# -- CLASSES -- class JsonFeedClient: @@ -115,7 +115,7 @@ def _map_item(item: dict[str, Any]) -> RssItem: """ return RssItem( abstract=item.get("content_html"), - author=[i["name"] for i in item.get("authors")], + authors=[i["name"] for i in item.get("authors")], categories=item.get("tags", []), date_pub=datetime.fromisoformat(item.get("date_published")), guid=item.get("id"), diff --git a/qtribu/logic/news_feed/mdl_rss_item.py b/qtribu/logic/news_feed/mdl_rss_item.py new file mode 100644 index 00000000..31a3fb79 --- /dev/null +++ b/qtribu/logic/news_feed/mdl_rss_item.py @@ -0,0 +1,21 @@ +#! python3 # noqa: E265 + +# Standard library +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class RssItem: + """Dataclass describing a RSS channel item.""" + + abstract: Optional[str] = None + authors: Optional[list[Optional[str]]] = None + categories: Optional[list[Optional[str]]] = None + date_pub: Optional[tuple[int, ...]] = None + guid: Optional[str] = None + image_length: Optional[str] = None + image_type: Optional[str] = None + image_url: Optional[str] = None + title: Optional[str] = None + url: Optional[str] = None From 29a07d043fbf7d0df5c1c40e8e5fea5f168576b2 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 16:06:30 +0200 Subject: [PATCH 06/16] refactor(rss): improve RSS reader consistency --- qtribu/logic/news_feed/rss_reader.py | 187 +++++++++++++++++++++------ 1 file changed, 144 insertions(+), 43 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index b84a80e4..04ca17e8 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -13,16 +13,23 @@ import logging import xml.etree.ElementTree as ET from email.utils import parsedate -from typing import List, Optional +from functools import partial +from pathlib import Path +from typing import Optional # QGIS from qgis.core import Qgis, QgsSettings from qgis.PyQt.QtCore import QCoreApplication +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QAction # project -from qtribu.__about__ import __title__, __version__ -from qtribu.logic.custom_datatypes import RssItem +from qtribu.__about__ import DIR_PLUGIN_ROOT, __title__, __version__ +from qtribu.logic.news_feed.mdl_rss_item import RssItem from qtribu.toolbelt import PlgLogger, PlgOptionsManager +from qtribu.toolbelt.commons import open_url_in_browser, open_url_in_webviewer +from qtribu.toolbelt.file_stats import is_file_older_than +from qtribu.toolbelt.network_manager import NetworkRequestsManager # ############################################################################ # ########## Globals ############### @@ -38,63 +45,154 @@ class RssMiniReader: """Minimalist RSS feed parser.""" - FEED_ITEMS: Optional[tuple] = None + FEED_ITEMS: Optional[list[RssItem]] = None HEADERS: dict = { b"Accept": b"application/xml", b"User-Agent": bytes(f"{__title__}/{__version__}", "utf8"), } PATTERN_INCLUDE: list = ["articles/", "rdp/"] - def __init__(self): + def __init__(self, action_read: Optional[QAction] = None): """Class initialization.""" self.log = PlgLogger().log + self.ntwk_manager = NetworkRequestsManager() + self.plg_settings = PlgOptionsManager.get_plg_settings() + self.local_feed_filepath: Path = self.plg_settings.local_app_folder.joinpath( + "rss.xml" + ) + self.action_read = action_read - def read_feed(self, in_xml: str) -> tuple[RssItem]: - """Parse the feed XML as string and store items into an ordered tuple of tuples. + def process(self): + """Download, parse and read RSS feed than store items as attribute.""" + # download remote RSS feed to cache folder + self.download_feed() + if not self.local_feed_filepath.exists(): + self.log( + message=self.tr( + "The RSS feed is not available locally. " + "Disabling RSS reader related features." + ), + log_level=1, + ) + return + + # parse the local RSS feed + self.read_feed() + + # check if a new item has been published since last check + if not self.has_new_content: + self.log(message="No new item found in RSS feed.", log_level=4) + return + # notify + if isinstance(self.latest_item, RssItem): + latest_item = self.latest_item + self.log( + message="{} {}".format( + self.tr("New content published:"), + latest_item.title, + ), + log_level=3, + push=PlgOptionsManager().get_plg_settings().notify_push_info, + duration=PlgOptionsManager().get_plg_settings().notify_push_duration, + button=True, + button_label=self.tr("Read it!"), + button_connect=partial(self.on_read_item, latest_item), + ) - :param in_xml: XML as string. Must be RSS compliant. - :type in_xml: str + def download_feed(self) -> bool: + """Download RSS feed locally if it's older than latest 24 hours. - :return: RSS items loaded as namedtuples - :rtype: Tuple[RssItem] + :return: True is a new file has been downloaded. + :rtype: bool """ - feed_items = [] - tree = ET.ElementTree(ET.fromstring(in_xml)) - root = tree.getroot() - items = root.findall("channel/item") + if is_file_older_than( + local_file_path=self.local_feed_filepath, + expiration_rotating_hours=self.plg_settings.rss_poll_frequency_hours, + ): + self.ntwk_manager.download_file_to( + remote_url=self.plg_settings.rss_source, + local_path=self.local_feed_filepath, + ) + self.log( + message=f"The remote RSS feed ({self.plg_settings.rss_source}) has been " + f"downloaded to {self.local_feed_filepath}", + log_level=0, + ) + return True + self.log( + message=f"A fresh local RSS feed already exists: {self.local_feed_filepath}", + log_level=0, + ) + return False + + def on_read_item(self, rss_item: RssItem): + """Slot ran when end-user want to a read an item. + + :param rss_item: RSS item. + :type rss_item: RssItem + """ + open_url_in_webviewer(rss_item.url, rss_item.title) + + if isinstance(self.action_read, QAction): + self.action_read.setIcon( + QIcon(str(DIR_PLUGIN_ROOT / "resources/images/logo_green_no_text.svg")) + ) + self.action_read.setToolTip(self.tr("Newest article")) + + # save latest RSS item displayed + PlgOptionsManager().set_value_from_key( + key="latest_content_guid", value=self.rss_reader.latest_item.guid + ) + + def read_feed(self) -> list[RssItem]: + """Parse the feed XML as string and store items into an ordered list of RSS items. + + :return: list of RSS items dataclasses + :rtype: list[RssItem] + """ + feed_items: list[RssItem] = [] + tree = ET.parse(self.local_feed_filepath) + items = tree.findall("channel/item") for item in items: try: # filter on included pattern if not any([i in item.find("link").text for i in self.PATTERN_INCLUDE]): - logging.debug( - "Item ignored because unmatches the include pattern: {}".format( - item.find("title") - ) + self.log( + message="Item ignored because unmatches the include pattern: {}".format( + item.find("title").text + ), + log_level=4, ) continue - # add items to the feed - feed_items.append( - RssItem( - abstract=item.find("description").text, - author=[author.text for author in item.findall("author")] - or None, - categories=[ - category.text for category in item.findall("category") - ] - or None, - date_pub=parsedate(item.find("pubDate").text), - guid=item.find("guid").text, - image_length=item.find("enclosure").attrib.get("length"), - image_type=item.find("enclosure").attrib.get("type"), - image_url=item.find("enclosure").attrib.get("url"), - title=item.find("title").text, - url=item.find("link").text, - ) + # feed item object + feed_item_obj = RssItem( + abstract=item.find("description").text, + authors=[author.text for author in item.findall("author")] or None, + categories=[category.text for category in item.findall("category")] + or None, + date_pub=parsedate(item.find("pubDate").text), + guid=item.find("guid").text, + image_length=item.find("enclosure").attrib.get("length"), + image_type=item.find("enclosure").attrib.get("type"), + image_url=item.find("enclosure").attrib.get("url"), + title=item.find("title").text, + url=item.find("link").text, ) + if item.find("enclosure") is not None: + item_enclosure = item.find("enclosure") + feed_item_obj.image_length = item_enclosure.attrib.get("length") + feed_item_obj.image_type = item_enclosure.attrib.get("type") + feed_item_obj.image_url = item_enclosure.attrib.get("url") + + # add items to the feed + feed_items.append(feed_item_obj) except Exception as err: - err_msg = f"Feed item triggers an error. Trace: {err}" - logger.error(err_msg) + item_idx: Optional[int] = None + if hasattr(items, "index"): + item_idx = items.index(item) + + err_msg = f"Feed item {item_idx} triggers an error. Trace: {err}" self.log(message=err_msg, log_level=2) # store feed items as attribute and return it @@ -102,7 +200,7 @@ def read_feed(self, in_xml: str) -> tuple[RssItem]: return feed_items @property - def latest_item(self) -> RssItem: + def latest_item(self) -> Optional[RssItem]: """Returns the latest feed item, based on index 0. :return: latest feed item. @@ -117,7 +215,7 @@ def latest_item(self) -> RssItem: return self.FEED_ITEMS[0] - def latest_items(self, count: int = 36) -> List[RssItem]: + def latest_items(self, count: int = 36) -> list[RssItem]: """Returns the latest feed items. :param count: number of items to fetch :type count: int @@ -143,7 +241,10 @@ def has_new_content(self) -> bool: :rtype: bool """ settings = PlgOptionsManager.get_plg_settings() - if self.latest_item.guid != settings.latest_content_guid: + if ( + isinstance(self.latest_item, RssItem) + and self.latest_item.guid != settings.latest_content_guid + ): return True else: return False @@ -187,7 +288,7 @@ def add_latest_item_to_news_feed(self) -> bool: key=f"news-feed/items/httpsfeedqgisorg/entries/items/{item_id}/content", value=f"

{latest_geotribu_article.abstract}

" + self.tr("Author(s): ") - + f"{', '.join(latest_geotribu_article.author)}

" + + f"{', '.join(latest_geotribu_article.authors)}

" + self.tr("Keywords: ") + f"{', '.join(latest_geotribu_article.categories)}

", section=QgsSettings.App, From c089f665e5f1f40e095376a199659e67475dc63d Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 16:06:50 +0200 Subject: [PATCH 07/16] improve(commons): handle bad import of WebViewer --- qtribu/toolbelt/commons.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/qtribu/toolbelt/commons.py b/qtribu/toolbelt/commons.py index 0eea3d09..8c82c8f5 100644 --- a/qtribu/toolbelt/commons.py +++ b/qtribu/toolbelt/commons.py @@ -1,9 +1,12 @@ from qgis.PyQt.QtCore import QUrl from qgis.PyQt.QtGui import QDesktopServices -from qtribu.logic.web_viewer import WebViewer +try: + from qtribu.logic.web_viewer import WebViewer -web_viewer = WebViewer() + web_viewer = WebViewer() +except ImportError: + web_viewer = None def open_url_in_browser(url: str) -> bool: @@ -27,6 +30,9 @@ def open_url_in_webviewer(url: str, window_title: str) -> None: :param window_title: title to give to the webviewer window :type window_title: str """ + if web_viewer is None: + open_url_in_browser(url=url) + web_viewer.display_web_page(url) if web_viewer.wdg_web: web_viewer.set_window_title(window_title) From 428766f43c9d5fb7294629e3294876bd0b12351f Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 16:08:04 +0200 Subject: [PATCH 08/16] refactor(rss): rename action and method related to latest content display --- qtribu/plugin_main.py | 62 +++++++++++++------------------------------ 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/qtribu/plugin_main.py b/qtribu/plugin_main.py index b35dd7d6..a016324b 100644 --- a/qtribu/plugin_main.py +++ b/qtribu/plugin_main.py @@ -70,7 +70,7 @@ def __init__(self, iface: QgisInterface): ) # sub-modules - self.rss_rdr = RssMiniReader() + self.rss_reader = RssMiniReader() self.splash_chgr = SplashChanger(self) def initGui(self): @@ -89,14 +89,14 @@ def initGui(self): self.form_rdp_news = None # -- Actions - self.action_run = QAction( + self.action_show_latest_content = QAction( QIcon(str(DIR_PLUGIN_ROOT / "resources/images/logo_green_no_text.svg")), self.tr("Newest article"), self.iface.mainWindow(), ) - self.action_run.setToolTip(self.tr("Newest article")) - self.action_run.triggered.connect(self.run) + self.action_show_latest_content.setToolTip(self.tr("Newest article")) + self.action_show_latest_content.triggered.connect(self.show_latest_content) self.action_contents = QAction( QgsApplication.getThemeIcon("mActionOpenTableVisible.svg"), @@ -142,7 +142,7 @@ def initGui(self): self.action_splash.triggered.connect(self.splash_chgr.switch) # -- Menu - self.iface.addPluginToWebMenu(__title__, self.action_run) + self.iface.addPluginToWebMenu(__title__, self.action_show_latest_content) self.iface.addPluginToWebMenu(__title__, self.action_contents) self.iface.addPluginToWebMenu(__title__, self.action_form_rdp_news) self.iface.addPluginToWebMenu(__title__, self.action_form_article) @@ -188,7 +188,7 @@ def initGui(self): self.iface.helpMenu().addAction(self.action_osgeofr) # -- Toolbar - self.toolbar.addAction(self.action_run) + self.toolbar.addAction(self.action_show_latest_content) self.toolbar.addAction(self.action_contents) self.toolbar.addAction(self.action_form_rdp_news) self.toolbar.addAction(self.action_form_article) @@ -202,7 +202,7 @@ def unload(self): self.iface.removePluginWebMenu(__title__, self.action_help) self.iface.removePluginWebMenu(__title__, self.action_form_article) self.iface.removePluginWebMenu(__title__, self.action_form_rdp_news) - self.iface.removePluginWebMenu(__title__, self.action_run) + self.iface.removePluginWebMenu(__title__, self.action_show_latest_content) self.iface.removePluginWebMenu(__title__, self.action_contents) self.iface.removePluginWebMenu(__title__, self.action_settings) self.iface.removePluginWebMenu(__title__, self.action_splash) @@ -218,7 +218,6 @@ def unload(self): self.iface.unregisterOptionsWidgetFactory(self.options_factory) # remove actions - del self.action_run del self.action_help del self.action_georezo @@ -228,48 +227,25 @@ def post_ui_init(self): :raises Exception: if there is no item in the feed """ try: - qntwk = NetworkRequestsManager() - rss_feed_content = qntwk.get_from_source( - headers=self.rss_rdr.HEADERS, - response_expected_content_type="application/xml", - ) - - self.rss_rdr.read_feed(rss_feed_content) - if not self.rss_rdr.latest_item: - raise Exception("No item found") + self.rss_reader.process() # change tooltip - self.action_run.setToolTip( + self.action_show_latest_content.setToolTip( "{} - {}".format( - self.tr("Newest article"), self.rss_rdr.latest_item.title + self.tr("Newest article"), self.rss_reader.latest_item.title ) ) # check if a new content has been published - if self.rss_rdr.has_new_content: + if self.rss_reader.has_new_content: # change action icon - self.action_run.setIcon( + self.action_show_latest_content.setIcon( QIcon( str( DIR_PLUGIN_ROOT / "resources/images/logo_orange_no_text.svg" ) ), ) - # notify - self.log( - message="{} {}".format( - self.tr("New content published:"), - self.rss_rdr.latest_item.title, - ), - log_level=3, - push=PlgOptionsManager().get_plg_settings().notify_push_info, - duration=PlgOptionsManager() - .get_plg_settings() - .notify_push_duration, - button=True, - button_label=self.tr("Newest article"), - button_connect=self.run, - ) except Exception as err: self.log( @@ -281,7 +257,7 @@ def post_ui_init(self): # insert latest item within news feed try: - self.rss_rdr.add_latest_item_to_news_feed() + self.rss_reader.add_latest_item_to_news_feed() except Exception as err: self.log( message=self.tr( @@ -303,22 +279,22 @@ def tr(self, message: str) -> str: """ return QCoreApplication.translate(self.__class__.__name__, message) - def run(self): + def show_latest_content(self): """Main action on plugin icon pressed event.""" try: - if not self.rss_rdr.latest_item: + if not self.rss_reader.latest_item: self.post_ui_init() open_url_in_webviewer( - self.rss_rdr.latest_item.url, self.rss_rdr.latest_item.title + self.rss_reader.latest_item.url, self.rss_reader.latest_item.title ) - self.action_run.setIcon( + self.action_show_latest_content.setIcon( QIcon(str(DIR_PLUGIN_ROOT / "resources/images/logo_green_no_text.svg")) ) - self.action_run.setToolTip(self.tr("Newest article")) + self.action_show_latest_content.setToolTip(self.tr("Newest article")) # save latest RSS item displayed PlgOptionsManager().set_value_from_key( - key="latest_content_guid", value=self.rss_rdr.latest_item.guid + key="latest_content_guid", value=self.rss_reader.latest_item.guid ) except Exception as err: self.log( From e62bbe962ceb5c399f0d1f0624a4e8ee61cf22a8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:08:17 +0000 Subject: [PATCH 09/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- qtribu/logic/news_feed/rss_reader.py | 2 +- qtribu/plugin_main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index 04ca17e8..ae58e4ba 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -27,7 +27,7 @@ from qtribu.__about__ import DIR_PLUGIN_ROOT, __title__, __version__ from qtribu.logic.news_feed.mdl_rss_item import RssItem from qtribu.toolbelt import PlgLogger, PlgOptionsManager -from qtribu.toolbelt.commons import open_url_in_browser, open_url_in_webviewer +from qtribu.toolbelt.commons import open_url_in_webviewer from qtribu.toolbelt.file_stats import is_file_older_than from qtribu.toolbelt.network_manager import NetworkRequestsManager diff --git a/qtribu/plugin_main.py b/qtribu/plugin_main.py index a016324b..4b9045b3 100644 --- a/qtribu/plugin_main.py +++ b/qtribu/plugin_main.py @@ -24,7 +24,7 @@ from qtribu.gui.form_rdp_news import RdpNewsForm from qtribu.logic.news_feed.rss_reader import RssMiniReader from qtribu.logic.splash_changer import SplashChanger -from qtribu.toolbelt import NetworkRequestsManager, PlgLogger, PlgOptionsManager +from qtribu.toolbelt import PlgLogger, PlgOptionsManager from qtribu.toolbelt.commons import open_url_in_browser, open_url_in_webviewer # ############################################################################ From ebe2be6aa88750975da2166cdb53d57655f22a7e Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 17:35:00 +0200 Subject: [PATCH 10/16] fix(test): rm flaky test --- tests/qgis/test_plg_rss_rdr.py | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 tests/qgis/test_plg_rss_rdr.py diff --git a/tests/qgis/test_plg_rss_rdr.py b/tests/qgis/test_plg_rss_rdr.py deleted file mode 100644 index 31fb7116..00000000 --- a/tests/qgis/test_plg_rss_rdr.py +++ /dev/null @@ -1,34 +0,0 @@ -#! python3 # noqa E265 - -""" - Usage from the repo root folder: - - .. code-block:: bash - # for whole tests - python -m unittest tests.test_plg_rss_rdr - # for specific test - python -m unittest tests.test_plg_rss_rdr.TestRssReader.test_version_semver -""" - -# standard library -import unittest - -# project -from qtribu.logic.news_feed.rss_reader import RssMiniReader - -# ############################################################################ -# ########## Classes ############# -# ################################ - - -class TestRssReader(unittest.TestCase): - def test_rss_reader(self): - """Test RSS reader basic behavior.""" - self.rss_rdr = RssMiniReader() - - -# ############################################################################ -# ####### Stand-alone run ######## -# ################################ -if __name__ == "__main__": - unittest.main() From 306659338e352bcba368f50ade5fe42400492c69 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 18:03:52 +0200 Subject: [PATCH 11/16] fix(parameter): rename author into authors --- qtribu/gui/dlg_contents.py | 2 +- qtribu/logic/news_feed/json_feed.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qtribu/gui/dlg_contents.py b/qtribu/gui/dlg_contents.py index 82533ec7..8e7f10b5 100644 --- a/qtribu/gui/dlg_contents.py +++ b/qtribu/gui/dlg_contents.py @@ -257,7 +257,7 @@ def _build_tree_widget_item_from_content(content: RssItem) -> QTreeWidgetItem: [ content.date_pub.strftime("%d %B"), content.title, - ", ".join(content.author), + ", ".join(content.authors), tags, content.url, ] diff --git a/qtribu/logic/news_feed/json_feed.py b/qtribu/logic/news_feed/json_feed.py index d3bf3f58..62f4d92a 100644 --- a/qtribu/logic/news_feed/json_feed.py +++ b/qtribu/logic/news_feed/json_feed.py @@ -89,7 +89,7 @@ def authors(self) -> list[str]: """ authors = [] for content in self.fetch(): - for ca in content.author: + for ca in content.authors: authors.append(" ".join([a.title() for a in ca.split(" ")])) return sorted(set(authors)) @@ -142,7 +142,7 @@ def _matches(query: str, item: RssItem) -> bool: return all([JsonFeedClient._matches(w, item) for w in words]) return ( query.upper() in item.abstract.upper() - or query.upper() in ",".join(item.author).upper() + or query.upper() in ",".join(item.authors).upper() or query.upper() in ",".join(item.categories).upper() or query.upper() in item.date_pub.isoformat().upper() or query.upper() in item.image_url.upper() From 6e50fe1121794ace9fc65d0e1cad0a986f6115dd Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 18:04:29 +0200 Subject: [PATCH 12/16] refactor(rss): add log and condition reletd to settings --- qtribu/toolbelt/commons.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/qtribu/toolbelt/commons.py b/qtribu/toolbelt/commons.py index 8c82c8f5..a9d1b2cf 100644 --- a/qtribu/toolbelt/commons.py +++ b/qtribu/toolbelt/commons.py @@ -1,6 +1,7 @@ from qgis.PyQt.QtCore import QUrl from qgis.PyQt.QtGui import QDesktopServices +# project try: from qtribu.logic.web_viewer import WebViewer @@ -8,6 +9,9 @@ except ImportError: web_viewer = None +from qtribu.toolbelt.log_handler import PlgLogger +from qtribu.toolbelt.preferences import PlgOptionsManager + def open_url_in_browser(url: str) -> bool: """Opens an url in a browser using user's desktop environment @@ -30,7 +34,13 @@ def open_url_in_webviewer(url: str, window_title: str) -> None: :param window_title: title to give to the webviewer window :type window_title: str """ - if web_viewer is None: + if web_viewer is None and PlgOptionsManager().get_plg_settings().browser == 1: + PlgLogger.log( + message="The embedded webviewer is not avaible, probably because " + "of unfilled system dependencies (QtWebEngine). Using default system " + "browser as fallback.", + log_level=2, + ) open_url_in_browser(url=url) web_viewer.display_web_page(url) From 57cf4228cc7f06f93c84b38eb28494b980dff257 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Fri, 2 Aug 2024 18:06:17 +0200 Subject: [PATCH 13/16] refactor(rss): use action and slot from plugin main --- qtribu/logic/news_feed/rss_reader.py | 40 +++++++++++++--------------- qtribu/plugin_main.py | 34 ++++++++--------------- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index ae58e4ba..a864ec94 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -15,7 +15,7 @@ from email.utils import parsedate from functools import partial from pathlib import Path -from typing import Optional +from typing import Callable, Optional # QGIS from qgis.core import Qgis, QgsSettings @@ -52,7 +52,11 @@ class RssMiniReader: } PATTERN_INCLUDE: list = ["articles/", "rdp/"] - def __init__(self, action_read: Optional[QAction] = None): + def __init__( + self, + action_read: Optional[QAction] = None, + on_read_button: Optional[Callable] = None, + ): """Class initialization.""" self.log = PlgLogger().log self.ntwk_manager = NetworkRequestsManager() @@ -61,6 +65,7 @@ def __init__(self, action_read: Optional[QAction] = None): "rss.xml" ) self.action_read = action_read + self.on_read_button = on_read_button def process(self): """Download, parse and read RSS feed than store items as attribute.""" @@ -96,9 +101,19 @@ def process(self): duration=PlgOptionsManager().get_plg_settings().notify_push_duration, button=True, button_label=self.tr("Read it!"), - button_connect=partial(self.on_read_item, latest_item), + button_connect=self.on_read_button, ) + # change action icon + if isinstance(self.action_read, QAction): + self.action_read.setIcon( + QIcon( + str( + DIR_PLUGIN_ROOT / "resources/images/logo_orange_no_text.svg" + ) + ), + ) + def download_feed(self) -> bool: """Download RSS feed locally if it's older than latest 24 hours. @@ -125,25 +140,6 @@ def download_feed(self) -> bool: ) return False - def on_read_item(self, rss_item: RssItem): - """Slot ran when end-user want to a read an item. - - :param rss_item: RSS item. - :type rss_item: RssItem - """ - open_url_in_webviewer(rss_item.url, rss_item.title) - - if isinstance(self.action_read, QAction): - self.action_read.setIcon( - QIcon(str(DIR_PLUGIN_ROOT / "resources/images/logo_green_no_text.svg")) - ) - self.action_read.setToolTip(self.tr("Newest article")) - - # save latest RSS item displayed - PlgOptionsManager().set_value_from_key( - key="latest_content_guid", value=self.rss_reader.latest_item.guid - ) - def read_feed(self) -> list[RssItem]: """Parse the feed XML as string and store items into an ordered list of RSS items. diff --git a/qtribu/plugin_main.py b/qtribu/plugin_main.py index 4b9045b3..7551ed3a 100644 --- a/qtribu/plugin_main.py +++ b/qtribu/plugin_main.py @@ -70,7 +70,7 @@ def __init__(self, iface: QgisInterface): ) # sub-modules - self.rss_reader = RssMiniReader() + self.rss_reader = None self.splash_chgr = SplashChanger(self) def initGui(self): @@ -96,7 +96,7 @@ def initGui(self): ) self.action_show_latest_content.setToolTip(self.tr("Newest article")) - self.action_show_latest_content.triggered.connect(self.show_latest_content) + self.action_show_latest_content.triggered.connect(self.on_show_latest_content) self.action_contents = QAction( QgsApplication.getThemeIcon("mActionOpenTableVisible.svg"), @@ -194,6 +194,10 @@ def initGui(self): self.toolbar.addAction(self.action_form_article) # -- Post UI initialization + self.rss_reader = RssMiniReader( + action_read=self.action_show_latest_content, + on_read_button=self.on_show_latest_content, + ) self.iface.initializationCompleted.connect(self.post_ui_init) def unload(self): @@ -228,28 +232,9 @@ def post_ui_init(self): """ try: self.rss_reader.process() - - # change tooltip - self.action_show_latest_content.setToolTip( - "{} - {}".format( - self.tr("Newest article"), self.rss_reader.latest_item.title - ) - ) - - # check if a new content has been published - if self.rss_reader.has_new_content: - # change action icon - self.action_show_latest_content.setIcon( - QIcon( - str( - DIR_PLUGIN_ROOT / "resources/images/logo_orange_no_text.svg" - ) - ), - ) - except Exception as err: self.log( - message=self.tr(f"Michel, we've got a problem: {err}"), + message=self.tr(f"Reading the RSS feed failed. Trace: {err}"), log_level=2, push=True, ) @@ -279,12 +264,15 @@ def tr(self, message: str) -> str: """ return QCoreApplication.translate(self.__class__.__name__, message) - def show_latest_content(self): + def on_show_latest_content(self): """Main action on plugin icon pressed event.""" try: if not self.rss_reader.latest_item: self.post_ui_init() + rss_item = self.rss_reader.latest_item + open_url_in_webviewer(url=rss_item.url, window_title=rss_item.title) + # save latest RSS item displayed open_url_in_webviewer( self.rss_reader.latest_item.url, self.rss_reader.latest_item.title ) From ae1e87c0592a76d79b7edc3f8025b8d9518f704e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:08:15 +0000 Subject: [PATCH 14/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- qtribu/logic/news_feed/rss_reader.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index a864ec94..6e7b3c47 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -13,7 +13,6 @@ import logging import xml.etree.ElementTree as ET from email.utils import parsedate -from functools import partial from pathlib import Path from typing import Callable, Optional @@ -27,7 +26,6 @@ from qtribu.__about__ import DIR_PLUGIN_ROOT, __title__, __version__ from qtribu.logic.news_feed.mdl_rss_item import RssItem from qtribu.toolbelt import PlgLogger, PlgOptionsManager -from qtribu.toolbelt.commons import open_url_in_webviewer from qtribu.toolbelt.file_stats import is_file_older_than from qtribu.toolbelt.network_manager import NetworkRequestsManager From d7721adf68c2c0606ad305c5916e57598a6607a9 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Mon, 5 Aug 2024 06:54:42 +0200 Subject: [PATCH 15/16] refactor(rss): improve log message clarity https://github.com/geotribu/qtribu/pull/188#discussion_r1703274955 --- qtribu/logic/news_feed/rss_reader.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index 6e7b3c47..04e66ccd 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -65,15 +65,15 @@ def __init__( self.action_read = action_read self.on_read_button = on_read_button - def process(self): + def process(self) -> None: """Download, parse and read RSS feed than store items as attribute.""" # download remote RSS feed to cache folder self.download_feed() if not self.local_feed_filepath.exists(): self.log( message=self.tr( - "The RSS feed is not available locally. " - "Disabling RSS reader related features." + f"The RSS feed is not available locally: {self.local_feed_filepath}. " + "Features related to the RSS reader are disabled." ), log_level=1, ) From d5eb120dcf2ca5b9a5810855b2456c4bc25ab531 Mon Sep 17 00:00:00 2001 From: "Julien M." Date: Mon, 5 Aug 2024 07:13:17 +0200 Subject: [PATCH 16/16] refactor(rss): use Qgis enums for log levels https://github.com/geotribu/qtribu/pull/188#discussion_r1703275923 --- qtribu/logic/news_feed/rss_reader.py | 16 ++++++++-------- qtribu/toolbelt/log_handler.py | 9 +++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/qtribu/logic/news_feed/rss_reader.py b/qtribu/logic/news_feed/rss_reader.py index 04e66ccd..f8261a9c 100644 --- a/qtribu/logic/news_feed/rss_reader.py +++ b/qtribu/logic/news_feed/rss_reader.py @@ -75,7 +75,7 @@ def process(self) -> None: f"The RSS feed is not available locally: {self.local_feed_filepath}. " "Features related to the RSS reader are disabled." ), - log_level=1, + log_level=Qgis.Critical, ) return @@ -84,7 +84,7 @@ def process(self) -> None: # check if a new item has been published since last check if not self.has_new_content: - self.log(message="No new item found in RSS feed.", log_level=4) + self.log(message="No new item found in RSS feed.", log_level=Qgis.NoLevel) return # notify if isinstance(self.latest_item, RssItem): @@ -94,7 +94,7 @@ def process(self) -> None: self.tr("New content published:"), latest_item.title, ), - log_level=3, + log_level=Qgis.Success, push=PlgOptionsManager().get_plg_settings().notify_push_info, duration=PlgOptionsManager().get_plg_settings().notify_push_duration, button=True, @@ -129,12 +129,12 @@ def download_feed(self) -> bool: self.log( message=f"The remote RSS feed ({self.plg_settings.rss_source}) has been " f"downloaded to {self.local_feed_filepath}", - log_level=0, + log_level=Qgis.Info, ) return True self.log( message=f"A fresh local RSS feed already exists: {self.local_feed_filepath}", - log_level=0, + log_level=Qgis.Info, ) return False @@ -155,7 +155,7 @@ def read_feed(self) -> list[RssItem]: message="Item ignored because unmatches the include pattern: {}".format( item.find("title").text ), - log_level=4, + log_level=Qgis.NoLevel, ) continue @@ -187,7 +187,7 @@ def read_feed(self) -> list[RssItem]: item_idx = items.index(item) err_msg = f"Feed item {item_idx} triggers an error. Trace: {err}" - self.log(message=err_msg, log_level=2) + self.log(message=err_msg, log_level=Qgis.Critical) # store feed items as attribute and return it self.FEED_ITEMS = feed_items @@ -263,7 +263,7 @@ def add_latest_item_to_news_feed(self) -> bool: if not plg_settings.integration_qgis_news_feed: self.log( message="The QGIS news feed integration is disabled. Abort!", - log_level=4, + log_level=Qgis.NoLevel, ) return False diff --git a/qtribu/toolbelt/log_handler.py b/qtribu/toolbelt/log_handler.py index cb765fe8..68331ef2 100644 --- a/qtribu/toolbelt/log_handler.py +++ b/qtribu/toolbelt/log_handler.py @@ -99,6 +99,15 @@ def log( button_more_text=detailed_error_message ) log(message="Plugin loaded - TEST", log_level=4, push=0) + + # also works using enums from Qgis: + # Qgis.Info, Qgis.Warning, Qgis.Critical, Qgis.Success, Qgis.NoLevel + from qgis.core import Qgis + log( + message="Something went wrong but it's not blocking", + log_level=Qgis.Warning + ) + """ # if not debug mode and not push, let's ignore INFO, SUCCESS and TEST debug_mode = plg_prefs_hdlr.PlgOptionsManager.get_plg_settings().debug_mode