Skip to content

Commit

Permalink
Merge pull request #49 from jgraichen/fix/yaml-datetime
Browse files Browse the repository at this point in the history
fix: Type error with YAML dates in frontmatter
  • Loading branch information
liang2kl committed Apr 12, 2023
2 parents 8bdcc8e + e67cd8a commit 5a0b4ad
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 20 deletions.
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"

0 comments on commit 5a0b4ad

Please sign in to comment.