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: add option to set default timezone #142

Merged
merged 8 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
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
26 changes: 22 additions & 4 deletions docs/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"oneOf": [
{
"markdownDescription": "https://guts.github.io/mkdocs-rss-plugin/",
"enum": ["rss"]
"enum": [
"rss"
]
},
{
"type": "object",
Expand Down Expand Up @@ -45,13 +47,29 @@
"default": null,
"properties": {
"as_creation": {
"type": ["boolean", "string"]
"type": [
"boolean",
"string"
]
},
"as_update": {
"type": ["boolean", "string"]
"type": [
"boolean",
"string"
]
},
"datetime_format": {
"type": ["null", "string"]
"type": [
"null",
"string"
]
},
"default_timezone": {
"type": [
"null",
"string"
],
"default": "UTC"
}
}
},
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plugins:
as_creation: "date"
as_update: false
datetime_format: "%Y-%m-%d %H:%M"
default_timezone: "Europe/Paris"
image: https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png
match_path: ".*"
pretty_print: false
Expand Down
5 changes: 5 additions & 0 deletions mkdocs_rss_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(self):
# dates source
self.src_date_created = self.src_date_updated = "git"
self.meta_datetime_format = None
self.meta_default_timezone = "UTC"
# pages storage
self.pages_to_filter = []
# prepare output feeds
Expand Down Expand Up @@ -129,6 +130,9 @@ def on_config(self, config: config_options.Config) -> dict:
self.meta_datetime_format = self.config.get("date_from_meta").get(
"datetime_format", "%Y-%m-%d %H:%M"
)
self.meta_default_timezone = self.config.get("date_from_meta").get(
"default_timezone", "UTC"
)
logger.debug(
"[rss-plugin] Dates will be retrieved from page meta (yaml "
"frontmatter). The git log will be used as fallback."
Expand Down Expand Up @@ -196,6 +200,7 @@ def on_page_content(
source_date_creation=self.src_date_created,
source_date_update=self.src_date_updated,
meta_datetime_format=self.meta_datetime_format,
meta_default_timezone=self.meta_default_timezone,
)

# handle custom URL parameters
Expand Down
53 changes: 53 additions & 0 deletions mkdocs_rss_plugin/timezoner_pre39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#! python3 # noqa: E265


"""
Manage timezones for pages date(time)s using pytz module.
Meant to be dropped when Python 3.8 reaches EOL.
"""

# ############################################################################
# ########## Libraries #############
# ##################################

# standard library
import logging
from datetime import datetime

# 3rd party
import pytz

# ############################################################################
# ########## Globals #############
# ################################


logger = logging.getLogger("mkdocs.mkdocs_rss_plugin")


# ############################################################################
# ########## Functions ###########
# ################################


def set_datetime_zoneinfo(
input_datetime: datetime, config_timezone: str = "UTC"
) -> datetime:
"""Apply timezone to a naive datetime.

:param input_datetime: offset-naive datetime
:type input_datetime: datetime
:param config_timezone: name of timezone as registered in IANA database,
defaults to "UTC". Example : Europe/Paris.
:type config_timezone: str, optional

:return: offset-aware datetime
:rtype: datetime
"""
if input_datetime.tzinfo:
return input_datetime
elif not config_timezone:
return input_datetime.replace(tzinfo=pytz.utc)
else:
config_tz = pytz.timezone(config_timezone)
return config_tz.localize(input_datetime)
51 changes: 51 additions & 0 deletions mkdocs_rss_plugin/timezoner_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#! python3 # noqa: E265


"""
Manage timezones for pages date(time)s using zoneinfo module, added in Python 3.9.

"""

# ############################################################################
# ########## Libraries #############
# ##################################

# standard library
import logging
from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# ############################################################################
# ########## Globals #############
# ################################


logger = logging.getLogger("mkdocs.mkdocs_rss_plugin")


# ############################################################################
# ########## Functions ###########
# ################################


def set_datetime_zoneinfo(
input_datetime: datetime, config_timezone: str = "UTC"
) -> datetime:
"""Apply timezone to a naive datetime.

:param input_datetime: offset-naive datetime
:type input_datetime: datetime
:param config_timezone: name of timezone as registered in IANA database,
defaults to "UTC". Example : Europe/Paris.
:type config_timezone: str, optional

:return: offset-aware datetime
:rtype: datetime
"""
if input_datetime.tzinfo:
return input_datetime
elif not config_timezone:
return input_datetime.replace(tzinfo=timezone.utc)
else:
config_tz = ZoneInfo(config_timezone)
return input_datetime.replace(tzinfo=config_tz)
58 changes: 40 additions & 18 deletions mkdocs_rss_plugin/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
# standard library
import logging
import ssl
from datetime import date, datetime
from email.utils import formatdate
import sys
from datetime import date, datetime, timedelta, timezone
from email.utils import format_datetime, formatdate
from mimetypes import guess_type
from pathlib import Path
from typing import Iterable, Tuple
Expand All @@ -21,12 +22,18 @@
from git import GitCommandError, GitCommandNotFound, InvalidGitRepositoryError, Repo
from mkdocs.config.config_options import Config
from mkdocs.structure.pages import Page
from mkdocs.utils import get_build_timestamp
from mkdocs.utils import get_build_datetime

# package
from mkdocs_rss_plugin import __about__
from mkdocs_rss_plugin.git_manager.ci import CiHandler

# conditional imports
if sys.version_info < (3, 9):
from mkdocs_rss_plugin.timezoner_pre39 import set_datetime_zoneinfo
else:
from mkdocs_rss_plugin.timezoner_py39 import set_datetime_zoneinfo

# ############################################################################
# ########## Globals #############
# ################################
Expand All @@ -36,11 +43,6 @@
"User-Agent": "{}/{}".format(__about__.__title__, __about__.__version__),
}


# ############################################################################
# ########## Globals ###############
# ##################################

logger = logging.getLogger("mkdocs.mkdocs_rss_plugin")


Expand Down Expand Up @@ -98,6 +100,7 @@ def get_file_dates(
source_date_creation: str = "git",
source_date_update: str = "git",
meta_datetime_format: str = "%Y-%m-%d %H:%M",
meta_default_timezone: str = "UTC",
) -> Tuple[int, int]:
"""Extract creation and update dates from page metadata (yaml frontmatter) or \
git log for given file.
Expand All @@ -124,6 +127,7 @@ def get_file_dates(
dt_created = self.get_date_from_meta(
date_metatag_value=in_page.meta.get(source_date_creation),
meta_datetime_format=meta_datetime_format,
meta_datetime_timezone=meta_default_timezone,
)
if isinstance(dt_created, str):
logger.error(dt_created)
Expand All @@ -133,6 +137,7 @@ def get_file_dates(
dt_updated = self.get_date_from_meta(
date_metatag_value=in_page.meta.get(source_date_update),
meta_datetime_format=meta_datetime_format,
meta_datetime_timezone=meta_default_timezone,
)
if isinstance(dt_updated, str):
logger.error(dt_updated)
Expand Down Expand Up @@ -170,23 +175,32 @@ def get_file_dates(
" Trace: %s" % err
)
self.git_is_valid = 0
# convert timestamps into datetimes
if isinstance(dt_created, (str, float, int)) and dt_created:
dt_created = set_datetime_zoneinfo(
datetime.fromtimestamp(float(dt_created)), meta_default_timezone
)
if isinstance(dt_updated, (str, float, int)) and dt_updated:
dt_updated = set_datetime_zoneinfo(
datetime.fromtimestamp(float(dt_updated)), meta_default_timezone
)
else:
pass

# return results
if all([dt_created, dt_updated]):
return (
int(dt_created),
int(dt_updated),
dt_created,
dt_updated,
)
else:
logging.warning(
"[rss-plugin] Dates could not be retrieved for page: %s."
% in_page.file.abs_src_path
)
return (
get_build_timestamp(),
get_build_timestamp(),
get_build_datetime(),
get_build_datetime(),
)

def get_authors_from_meta(self, in_page: Page) -> Tuple[str] or None:
Expand Down Expand Up @@ -257,18 +271,23 @@ def get_categories_from_meta(
return sorted(output_categories)

def get_date_from_meta(
self, date_metatag_value: str, meta_datetime_format: str
) -> float:
self,
date_metatag_value: str,
meta_datetime_format: str,
meta_datetime_timezone: str,
) -> datetime:
"""Get date from page.meta handling str with associated datetime format and \
date already transformed by MkDocs.

:param date_metatag_value: value of page.meta.{tag_for_date}
:type date_metatag_value: str
:param meta_datetime_format: expected format of datetime
:type meta_datetime_format: str
:param meta_datetime_timezone: timezone to use
:type meta_datetime_timezone: str

:return: datetime as timestamp
:rtype: float
:return: datetime
:rtype: datetime
"""
out_date = None
try:
Expand All @@ -285,7 +304,10 @@ def get_date_from_meta(
err
)

return out_date.timestamp()
if not out_date.tzinfo:
out_date = set_datetime_zoneinfo(out_date, meta_datetime_timezone)

return out_date

def get_description_or_abstract(self, in_page: Page, chars_count: int = 160) -> str:
"""Returns description from page meta. If it doesn't exist, use the \
Expand Down Expand Up @@ -516,7 +538,7 @@ def filter_pages(pages: list, attribute: str, length: int) -> list:
"guid": page.guid,
"image": page.image,
"link": page.url_full,
"pubDate": formatdate(getattr(page, attribute)),
"pubDate": format_datetime(dt=getattr(page, attribute)),
"title": page.title,
}
)
Expand Down
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@

GitPython>=3.1,<3.2
mkdocs>=1.1,<1.5
pytz==2022.* ; python_version < "3.9"
tzdata==2022.* ; python_version >= "3.9"
9 changes: 5 additions & 4 deletions tests/fixtures/mkdocs_complete.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@ site_name: MkDocs RSS Plugin - TEST
site_description: Basic setup to test against MkDocs RSS plugin
site_author: Julien Moura (Guts)
site_url: https://guts.github.io/mkdocs-rss-plugin
copyright: 'Guts - In Geo Veritas'
copyright: "Guts - In Geo Veritas"

# Repository
repo_name: 'guts/mkdocs-rss-plugin'
repo_url: 'https://github.com/guts/mkdocs-rss-plugin'
repo_name: "guts/mkdocs-rss-plugin"
repo_url: "https://github.com/guts/mkdocs-rss-plugin"

use_directory_urls: true

plugins:
- rss:
abstract_chars_count: 160 # -1 for full content
abstract_chars_count: 160 # -1 for full content
categories:
- tags
comments_path: "#__comments"
date_from_meta:
as_creation: "date"
as_update: false
datetime_format: "%Y-%m-%d %H:%M"
default_timezone: Europe/Paris
enabled: true
feed_ttl: 1440
image: https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png
Expand Down
Loading