mirror of
https://github.com/getpelican/pelican.git
synced 2026-10-15 23:36:55 +02:00
fix: Skip content whose empty slug is used in paths
A title made only of punctuation, such as "???", slugifies to an empty
string. When URL patterns use `{slug}`, the content was written to
".html", and two such articles crashed the build. Skip content with such
titles with an error that suggests setting a slug. Patterns that don't
use the slug, such as date-based `ARTICLE_SAVE_AS` patterns, are
unaffected.
This commit is contained in:
parent
6f10e8f2b6
commit
4e8ee91ae3
2 changed files with 72 additions and 0 deletions
|
|
@ -179,6 +179,29 @@ class Content:
|
|||
return False
|
||||
return True
|
||||
|
||||
def _has_valid_slug(self) -> bool:
|
||||
"""Return false if the slug is empty (e.g., for a title made only of
|
||||
punctuation) but used in the URL or save_as, which would produce file
|
||||
names such as ".html"."""
|
||||
# An empty title is already reported as a missing mandatory property.
|
||||
if getattr(self, "slug", None) != "" or not getattr(self, "title", None):
|
||||
return True
|
||||
|
||||
# Detect whether the slug is used by expanding with a placeholder.
|
||||
paths = (self.url, self.save_as)
|
||||
self.slug = "slug"
|
||||
try:
|
||||
uses_slug = (self.url, self.save_as) != paths
|
||||
finally:
|
||||
self.slug = ""
|
||||
if not uses_slug:
|
||||
return True
|
||||
|
||||
logger.error(
|
||||
"Skipping %s: its slug is empty; set a 'slug' in its metadata", self
|
||||
)
|
||||
return False
|
||||
|
||||
def _has_valid_save_as(self) -> bool:
|
||||
"""Return true if save_as doesn't write outside output path, false
|
||||
otherwise."""
|
||||
|
|
@ -220,6 +243,7 @@ class Content:
|
|||
return all(
|
||||
[
|
||||
self._has_valid_mandatory_properties(),
|
||||
self._has_valid_slug(),
|
||||
self._has_valid_save_as(),
|
||||
self._has_valid_status(),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -97,6 +97,54 @@ class TestPage(TestBase):
|
|||
page = Page("content", metadata={"title": "foobar"})
|
||||
self.assertTrue(page._has_valid_mandatory_properties())
|
||||
|
||||
def test_empty_slug_invalid(self):
|
||||
# A title made only of punctuation produces an empty slug, which would
|
||||
# otherwise result in a file named ".html".
|
||||
page = Page("content", metadata={"title": "???"})
|
||||
self.assertEqual(page.slug, "")
|
||||
self.assertFalse(page.is_valid())
|
||||
self.assertLogCountEqual(
|
||||
count=1,
|
||||
msg="Skipping .*: its slug is empty; set a 'slug' in its metadata",
|
||||
level=logging.ERROR,
|
||||
)
|
||||
|
||||
# An explicit slug, or a URL and save_as that don't use the slug, avoid
|
||||
# the empty file name.
|
||||
for metadata in (
|
||||
{"slug": "question-marks"},
|
||||
{"save_as": "q/index.html", "url": "q/"},
|
||||
):
|
||||
with self.subTest(metadata=metadata):
|
||||
page = Page("content", metadata={"title": "???", **metadata})
|
||||
self.assertTrue(page.is_valid())
|
||||
settings = get_settings(
|
||||
ARTICLE_URL="{date:%Y}/{date:%m}/{date:%d}/",
|
||||
ARTICLE_SAVE_AS="{date:%Y}/{date:%m}/{date:%d}/index.html",
|
||||
)
|
||||
article = Article(
|
||||
"content",
|
||||
metadata={"title": "???", "date": datetime.datetime(2026, 2, 9)},
|
||||
settings=settings,
|
||||
)
|
||||
self.assertTrue(article.is_valid())
|
||||
|
||||
# Overriding save_as alone still leaves the URL as ".html".
|
||||
page = Page("content", metadata={"title": "???", "save_as": "q.html"})
|
||||
self.assertFalse(page.is_valid())
|
||||
self.assertLogCountEqual(
|
||||
count=2,
|
||||
msg="Skipping .*: its slug is empty; set a 'slug' in its metadata",
|
||||
level=logging.ERROR,
|
||||
)
|
||||
|
||||
# An empty title is only reported as a missing title.
|
||||
page = Page("content", metadata={"title": ""})
|
||||
self.assertFalse(page.is_valid())
|
||||
self.assertLogCountEqual(
|
||||
count=2, msg="Skipping .*: its slug is empty.*", level=logging.ERROR
|
||||
)
|
||||
|
||||
def test_summary_from_metadata(self):
|
||||
# If a :summary: metadata is given, it should be used
|
||||
page = Page(**self.page_kwargs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue