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

fix: Type error with YAML dates in frontmatter #49

Merged
merged 5 commits into from
Apr 12, 2023
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
15 changes: 11 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,17 @@ Of all the options mentioned above, these deserve special attention:
- `time_format` in *global settings* is used to change the display style of the time, with higher priority than `locale`.

- `meta_time_format` in *global settings* is used to tell the plugin how to parse the given time string from the meta.
When `meta_time_format` is set, for all posts with a `time` or `date` metadata, the plugin will
use this format to parse the that time, and replace the time from git logs. This is
useful to alter specific posts' time when git commit time is not accurate or desired.
See [the list of datetime placeholders](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes).
- When `meta_time_format` is set, for all posts with a `time` or `date` metadata, the plugin will
use this format to parse the time, and replace the timestamp from git logs. This is
useful to alter specific posts' time if git commit time is not accurate or desired.
See [the list of datetime placeholders](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) for reference.

Please make sure that the time is wrapped by quotes \(issue [#48](https://github.com/liang2kl/mkdocs-blogging-plugin/issues/48)\). Otherwise, native YAML date and time literals will always be used if present in the file metadata, regardless of this setting. For example:

```yaml
time: 2023-4-13 00:48 # without quotes
time: !!timestamp "2023-4-13 00:48" # provide the `timestamp` tag
```

- When `paging` in *category settings* is set to `false`, if `size` is not set, all posts will be displayed on the first page; otherwise the first
`size` posts will be displayed and *the rest will not*.
Expand Down
33 changes: 21 additions & 12 deletions mkdocs_blogging_plugin/plugin.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import os
import logging
import os
import re
from datetime import date, datetime
from pathlib import Path
from typing import Dict

from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
from mkdocs.config import config_options
from mkdocs.plugins import BasePlugin
from mkdocs.exceptions import PluginError
from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
from mkdocs.plugins import BasePlugin

from mkdocs_blogging_plugin.config import BloggingConfig

from .util import Util
from pathlib import Path
from datetime import datetime

DIR_PATH = Path(os.path.dirname(os.path.realpath(__file__)))
BLOG_PAGE_PATTERN = re.compile(
Expand Down Expand Up @@ -332,13 +335,10 @@ def generate_html(self, category) -> str:

def with_timestamp(self, page, by_revision):
timestamp = None
if self.meta_time_format:
if "time" in page.meta:
timestamp = datetime.strptime(
page.meta["time"], self.meta_time_format).timestamp()
elif "date" in page.meta:
timestamp = datetime.strptime(
page.meta["date"], self.meta_time_format).timestamp()
if "time" in page.meta:
timestamp = self._parse_time(page.meta["time"])
if "date" in page.meta and timestamp is None:
timestamp = self._parse_time(page.meta["date"])
if not timestamp:
timestamp = self.util.get_git_commit_timestamp(
page.file.abs_src_path, is_first_commit=(not by_revision))
Expand All @@ -347,3 +347,12 @@ def with_timestamp(self, page, by_revision):
timestamp, False, format=self.time_format, _locale=self.locale)

return page

def _parse_time(self, value):
if isinstance(value, datetime):
return value.timestamp()
if isinstance(value, date):
return datetime.combine(value, datetime.min.time()).timestamp()
if self.meta_time_format and isinstance(value, str):
return datetime.strptime(value, self.meta_time_format).timestamp()
return None
35 changes: 31 additions & 4 deletions tests/test_format.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from datetime import datetime
import datetime
import os
import unittest
from pathlib import Path
from types import SimpleNamespace
import unittest

from mkdocs_blogging_plugin.plugin import BloggingPlugin

Expand All @@ -29,12 +29,39 @@ def test_date(self):
meta_date_str = "2022-05-03 11:09:00"
page = SimpleNamespace(meta={"time": meta_date_str})

date = datetime.strptime(
date = datetime.datetime.strptime(
meta_date_str, self.config["meta_time_format"])

page = self.plugin.with_timestamp(page, False)

expected_output = datetime.strftime(
expected_output = datetime.datetime.strftime(
date, self.config["time_format"])

assert page.meta["localized-time"] == expected_output

def test_date_object(self):
page = SimpleNamespace(meta={"date": datetime.date(2023, 4, 12)})
page = self.plugin.with_timestamp(page, False)

assert page.meta["localized-time"] == "2023/04/12 00:00:00"

def test_datetime_object(self):
page = SimpleNamespace(meta={"date": datetime.datetime(2023, 4, 12, 9, 15, 30)})
page = self.plugin.with_timestamp(page, False)

assert page.meta["localized-time"] == "2023/04/12 09:15:30"

def test_datetime_object_fallback(self):
"""
If meta.time is present but is an invalid type, we want to fall
back to using meta.date if available and valid.
"""
page = SimpleNamespace(
meta={
"time": 500,
"date": datetime.datetime(2023, 4, 12, 9, 15, 30),
}
)
page = self.plugin.with_timestamp(page, False)

assert page.meta["localized-time"] == "2023/04/12 09:15:30"