From 8fd6f7419ae0146e685e7be5752f9f13d4a97b3b Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Mon, 2 Dec 2024 13:22:10 +0100 Subject: [PATCH] update(chore): use typed dataclasses instead of dict --- mkdocs_rss_plugin/models.py | 29 ++++++++++++++- mkdocs_rss_plugin/plugin.py | 73 +++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/mkdocs_rss_plugin/models.py b/mkdocs_rss_plugin/models.py index 7e863bd..93ea01d 100644 --- a/mkdocs_rss_plugin/models.py +++ b/mkdocs_rss_plugin/models.py @@ -5,15 +5,21 @@ # ################################## # standard +from dataclasses import dataclass, field from datetime import datetime from pathlib import Path -from typing import NamedTuple, Optional +from typing import Optional +# package modules +from mkdocs_rss_plugin.__about__ import __title__, __version__ # ############################################################################ # ########## Classes ############### # ################################## -class PageInformation(NamedTuple): + + +@dataclass +class PageInformation: """Data type to set and get page information in order to produce the RSS feed.""" abs_path: Optional[Path] = None @@ -27,3 +33,22 @@ class PageInformation(NamedTuple): updated: Optional[datetime] = None url_comments: Optional[str] = None url_full: Optional[str] = None + + +@dataclass +class RssFeedBase: + author: Optional[str] = None + buildDate: Optional[str] = None + copyright: Optional[str] = None + description: Optional[str] = None + entries: list[PageInformation] = field(default_factory=list) + generator: str = f"{__title__} - v{__version__}" + html_url: Optional[str] = None + json_url: Optional[str] = None + language: Optional[str] = None + logo_url: Optional[str] = None + pubDate: Optional[str] = None + repo_url: Optional[str] = None + rss_url: Optional[str] = None + title: Optional[str] = None + ttl: Optional[int] = None diff --git a/mkdocs_rss_plugin/plugin.py b/mkdocs_rss_plugin/plugin.py index a9e7beb..3f2a38b 100644 --- a/mkdocs_rss_plugin/plugin.py +++ b/mkdocs_rss_plugin/plugin.py @@ -7,6 +7,7 @@ # standard library import json from copy import deepcopy +from dataclasses import asdict from datetime import datetime from email.utils import formatdate from pathlib import Path @@ -33,7 +34,7 @@ from mkdocs_rss_plugin.integrations.theme_material_social_plugin import ( IntegrationMaterialSocialCards, ) -from mkdocs_rss_plugin.models import PageInformation +from mkdocs_rss_plugin.models import PageInformation, RssFeedBase from mkdocs_rss_plugin.util import Util # ############################################################################ @@ -81,8 +82,8 @@ def on_startup( self.pages_to_filter: list[PageInformation] = [] # prepare output feeds - self.feed_created: dict = {} - self.feed_updated: dict = {} + self.feed_created: RssFeedBase = RssFeedBase() + self.feed_updated: RssFeedBase = RssFeedBase() def on_config(self, config: MkDocsConfig) -> MkDocsConfig: """The config event is the first event called on build and @@ -139,30 +140,30 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig: self.tpl_folder = DEFAULT_TEMPLATE_FOLDER # start a feed dictionary using global config vars - base_feed = { - "author": config.site_author or None, - "buildDate": formatdate(get_build_timestamp()), - "copyright": config.copyright, - "description": ( + base_feed = RssFeedBase( + author=config.site_author or None, + buildDate=formatdate(get_build_timestamp()), + copyright=config.copyright, + description=( self.config.feed_description if self.config.feed_description else config.site_description ), - "entries": [], - "generator": f"{__title__} - v{__version__}", - "html_url": self.util.get_site_url(mkdocs_config=config), - "language": self.util.guess_locale(mkdocs_config=config), - "pubDate": formatdate(get_build_timestamp()), - "repo_url": config.repo_url, - "title": ( + entries=[], + generator=f"{__title__} - v{__version__}", + html_url=self.util.get_site_url(mkdocs_config=config), + language=self.util.guess_locale(mkdocs_config=config), + pubDate=formatdate(get_build_timestamp()), + repo_url=config.repo_url, + title=( self.config.feed_title if self.config.feed_title else config.site_name ), - "ttl": self.config.feed_ttl, - } + ttl=self.config.feed_ttl, + ) # feed image if self.config.image: - base_feed["logo_url"] = self.config.image + base_feed.logo_url = self.config.image # pattern to match pages included in output self.match_path_pattern = re_compile(self.config.match_path) @@ -224,19 +225,19 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig: self.feed_updated = deepcopy(base_feed) # final feed url - if base_feed.get("html_url"): + if base_feed.html_url: # concatenate both URLs - self.feed_created["rss_url"] = ( - base_feed.get("html_url") + self.config.feeds_filenames.rss_created + self.feed_created.rss_url = ( + base_feed.html_url + self.config.feeds_filenames.rss_created ) - self.feed_updated["rss_url"] = ( - base_feed.get("html_url") + self.config.feeds_filenames.rss_updated + self.feed_updated.rss_url = ( + base_feed.html_url + self.config.feeds_filenames.rss_updated ) - self.feed_created["json_url"] = ( - base_feed.get("html_url") + self.config.feeds_filenames.json_created + self.feed_created.json_url = ( + base_feed.html_url + self.config.feeds_filenames.json_created ) - self.feed_updated["json_url"] = ( - base_feed.get("html_url") + self.config.feeds_filenames.json_updated + self.feed_updated.json_url = ( + base_feed.html_url + self.config.feeds_filenames.json_updated ) else: logger.error( @@ -244,9 +245,9 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig: "configuration file whereas a URL is mandatory to publish. " "See: https://validator.w3.org/feed/docs/rss2.html#requiredChannelElements" ) - self.feed_created["rss_url"] = self.feed_updated["json_url"] = ( - self.feed_updated["rss_url"] - ) = self.feed_updated["json_url"] = None + self.feed_created.rss_url = self.feed_updated.json_url = ( + self.feed_updated.rss_url + ) = self.feed_updated.json_url = None # ending event return config @@ -371,7 +372,7 @@ def on_post_build(self, config: config_options.Config) -> None: ) # created items - self.feed_created.get("entries").extend( + self.feed_created.entries.extend( self.util.filter_pages( pages=self.pages_to_filter, attribute="created", @@ -380,7 +381,7 @@ def on_post_build(self, config: config_options.Config) -> None: ) # updated items - self.feed_updated.get("entries").extend( + self.feed_updated.entries.extend( self.util.filter_pages( pages=self.pages_to_filter, attribute="updated", @@ -419,7 +420,7 @@ def on_post_build(self, config: config_options.Config) -> None: # write feeds to files stripping out spaces and new lines with out_feed_created.open(mode="w", encoding="UTF8") as fifeed_created: prev_char = "" - for char in template.render(feed=self.feed_created): + for char in template.render(feed=asdict(self.feed_created)): if char == "\n": continue if char == " " and prev_char == " ": @@ -429,7 +430,7 @@ def on_post_build(self, config: config_options.Config) -> None: fifeed_created.write(char) with out_feed_updated.open(mode="w", encoding="UTF8") as fifeed_updated: - for char in template.render(feed=self.feed_updated): + for char in template.render(feed=asdict(self.feed_updated)): if char == "\n": prev_char = char continue @@ -443,14 +444,14 @@ def on_post_build(self, config: config_options.Config) -> None: if self.config.json_feed_enabled: with out_json_created.open(mode="w", encoding="UTF8") as fp: json.dump( - self.util.feed_to_json(self.feed_created), + self.util.feed_to_json(asdict(self.feed_created)), fp, indent=4 if self.config.pretty_print else None, ) with out_json_updated.open(mode="w", encoding="UTF8") as fp: json.dump( - self.util.feed_to_json(self.feed_updated, updated=True), + self.util.feed_to_json(asdict(self.feed_updated), updated=True), fp, indent=4 if self.config.pretty_print else None, )