mirror of
https://github.com/getpelican/pelican.git
synced 2026-06-01 23:36:54 +02:00
Merge branch 'main' into patch-4
This commit is contained in:
commit
688a2a9a24
16 changed files with 101 additions and 65 deletions
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu, macos, windows]
|
||||
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
python: ["3.11", "3.12", "3.13", "3.14"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ version: 2
|
|||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
python: "3.11"
|
||||
|
||||
# Build HTML & PDF formats
|
||||
formats:
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@ import datetime
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
import tomli as tomllib
|
||||
|
||||
import tomllib
|
||||
|
||||
sys.path.append(os.path.abspath(os.pardir))
|
||||
|
||||
|
|
@ -32,7 +27,7 @@ source_suffix = ".rst"
|
|||
master_doc = "index"
|
||||
project = project_data.get("name").upper()
|
||||
year = datetime.datetime.fromtimestamp(
|
||||
int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.timezone.utc
|
||||
int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.UTC
|
||||
).year
|
||||
project_copyright = f"2010–{year}" # noqa: RUF001
|
||||
exclude_patterns = ["_build"]
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ class Article(Content):
|
|||
if self.date.tzinfo is None:
|
||||
now = datetime.datetime.now()
|
||||
else:
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
now = datetime.datetime.now(datetime.UTC)
|
||||
if self.date > now:
|
||||
self.status = "draft"
|
||||
|
||||
|
|
|
|||
|
|
@ -673,9 +673,10 @@ def configure_settings(settings: Settings) -> Settings:
|
|||
]
|
||||
|
||||
if any(settings.get(k) for k in feed_keys):
|
||||
if not settings.get("SITEURL"):
|
||||
if not (settings.get("SITEURL") or settings.get("FEED_DOMAIN")):
|
||||
logger.warning(
|
||||
"Feeds generated without SITEURL set properly may not be valid"
|
||||
"Feeds generated without SITEURL or FEED_DOMAIN set properly"
|
||||
" may not be valid"
|
||||
)
|
||||
|
||||
if "TIMEZONE" not in settings:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import copy
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
from os.path import abspath, dirname, join
|
||||
|
||||
from pelican import log
|
||||
from pelican.settings import (
|
||||
DEFAULT_CONFIG,
|
||||
DEFAULT_THEME,
|
||||
|
|
@ -11,7 +13,7 @@ from pelican.settings import (
|
|||
handle_deprecated_settings,
|
||||
read_settings,
|
||||
)
|
||||
from pelican.tests.support import unittest
|
||||
from pelican.tests.support import LogCountHandler, unittest
|
||||
|
||||
|
||||
class TestSettingsConfiguration(unittest.TestCase):
|
||||
|
|
@ -108,6 +110,39 @@ class TestSettingsConfiguration(unittest.TestCase):
|
|||
configure_settings(settings)
|
||||
self.assertEqual(settings["FEED_DOMAIN"], "http://feeds.example.com")
|
||||
|
||||
def _feeds_warning_settings(self, **overrides):
|
||||
base = {
|
||||
"LOCALE": "",
|
||||
"PATH": os.curdir,
|
||||
"THEME": DEFAULT_THEME,
|
||||
"FEED_RSS": "feeds/all.rss.xml",
|
||||
}
|
||||
base.update(overrides)
|
||||
handler = LogCountHandler()
|
||||
logger = logging.getLogger()
|
||||
logger.addHandler(handler)
|
||||
saved = log.LimitFilter._raised_messages.copy()
|
||||
log.LimitFilter._raised_messages = set()
|
||||
try:
|
||||
configure_settings(base)
|
||||
return handler.count_logs(
|
||||
"Feeds generated without SITEURL", logging.WARNING
|
||||
)
|
||||
finally:
|
||||
log.LimitFilter._raised_messages = saved
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_feeds_warning_with_siteurl(self):
|
||||
self.assertEqual(self._feeds_warning_settings(SITEURL="http://example.com"), 0)
|
||||
|
||||
def test_feeds_warning_with_feed_domain(self):
|
||||
self.assertEqual(
|
||||
self._feeds_warning_settings(FEED_DOMAIN="http://feeds.example.com"), 0
|
||||
)
|
||||
|
||||
def test_feeds_warning_without_siteurl_or_feed_domain(self):
|
||||
self.assertEqual(self._feeds_warning_settings(), 1)
|
||||
|
||||
def test_theme_settings_exceptions(self):
|
||||
settings = self.settings
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import locale
|
|||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from datetime import timezone
|
||||
from datetime import UTC
|
||||
from sys import platform
|
||||
from tempfile import mkdtemp
|
||||
|
||||
|
|
@ -62,10 +62,15 @@ class TestUtils(LoggedTestCase):
|
|||
date = utils.SafeDatetime(year=2012, month=11, day=22)
|
||||
date_hour = utils.SafeDatetime(year=2012, month=11, day=22, hour=22, minute=11)
|
||||
date_hour_z = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=timezone.utc
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=UTC
|
||||
)
|
||||
date_hour_est = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=ZoneInfo("EST")
|
||||
date_hour_wib = utils.SafeDatetime(
|
||||
year=2012,
|
||||
month=11,
|
||||
day=22,
|
||||
hour=22,
|
||||
minute=11,
|
||||
tzinfo=ZoneInfo("Asia/Jakarta"),
|
||||
)
|
||||
date_hour_sec = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, second=10
|
||||
|
|
@ -77,16 +82,16 @@ class TestUtils(LoggedTestCase):
|
|||
hour=22,
|
||||
minute=11,
|
||||
second=10,
|
||||
tzinfo=timezone.utc,
|
||||
tzinfo=UTC,
|
||||
)
|
||||
date_hour_sec_est = utils.SafeDatetime(
|
||||
date_hour_sec_wib = utils.SafeDatetime(
|
||||
year=2012,
|
||||
month=11,
|
||||
day=22,
|
||||
hour=22,
|
||||
minute=11,
|
||||
second=10,
|
||||
tzinfo=ZoneInfo("EST"),
|
||||
tzinfo=ZoneInfo("Asia/Jakarta"),
|
||||
)
|
||||
date_hour_sec_frac_z = utils.SafeDatetime(
|
||||
year=2012,
|
||||
|
|
@ -96,7 +101,7 @@ class TestUtils(LoggedTestCase):
|
|||
minute=11,
|
||||
second=10,
|
||||
microsecond=123000,
|
||||
tzinfo=timezone.utc,
|
||||
tzinfo=UTC,
|
||||
)
|
||||
dates = {
|
||||
"2012-11-22": date,
|
||||
|
|
@ -108,10 +113,10 @@ class TestUtils(LoggedTestCase):
|
|||
"22.11.2012": date,
|
||||
"22.11.2012 22:11": date_hour,
|
||||
"2012-11-22T22:11Z": date_hour_z,
|
||||
"2012-11-22T22:11-0500": date_hour_est,
|
||||
"2012-11-22T22:11+0700": date_hour_wib,
|
||||
"2012-11-22 22:11:10": date_hour_sec,
|
||||
"2012-11-22T22:11:10Z": date_hour_sec_z,
|
||||
"2012-11-22T22:11:10-0500": date_hour_sec_est,
|
||||
"2012-11-22T22:11:10+0700": date_hour_sec_wib,
|
||||
"2012-11-22T22:11:10.123Z": date_hour_sec_frac_z,
|
||||
}
|
||||
|
||||
|
|
|
|||
12
pelican/themes/simple/templates/index.html
vendored
12
pelican/themes/simple/templates/index.html
vendored
|
|
@ -11,11 +11,13 @@
|
|||
<section>{{ article.summary }}</section>
|
||||
<footer>
|
||||
<p>Published: <time datetime="{{ article.date.isoformat() }}"> {{ article.locale_date }} </time></p>
|
||||
<address>By
|
||||
{% for author in article.authors %}
|
||||
<a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
|
||||
{% endfor %}
|
||||
</address>
|
||||
{%- if article.authors %}
|
||||
<address>By
|
||||
{% for author in article.authors %}
|
||||
<a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
|
||||
{% endfor %}
|
||||
</address>
|
||||
{%- endif %}
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
|
|
|||
2
pelican/themes/simple/templates/page.html
vendored
2
pelican/themes/simple/templates/page.html
vendored
|
|
@ -20,7 +20,7 @@
|
|||
{% import 'translations.html' as translations with context %}
|
||||
{{ translations.translations_for(page) }}
|
||||
|
||||
{{ page.content }}
|
||||
{% block page_content %}{{ page.content }}{% endblock page_content %}
|
||||
|
||||
{% if page.modified %}
|
||||
<footer>
|
||||
|
|
|
|||
|
|
@ -446,13 +446,13 @@ def tumblr2fields(api_key, blogname):
|
|||
slug = post.get("slug") or slugify(title, regex_subs=subs)
|
||||
tags = post.get("tags")
|
||||
timestamp = post.get("timestamp")
|
||||
date = SafeDatetime.fromtimestamp(
|
||||
int(timestamp), tz=datetime.timezone.utc
|
||||
).strftime("%Y-%m-%d %H:%M:%S%z")
|
||||
date = SafeDatetime.fromtimestamp(int(timestamp), tz=datetime.UTC).strftime(
|
||||
"%Y-%m-%d %H:%M:%S%z"
|
||||
)
|
||||
slug = (
|
||||
SafeDatetime.fromtimestamp(
|
||||
int(timestamp), tz=datetime.timezone.utc
|
||||
).strftime("%Y-%m-%d-")
|
||||
SafeDatetime.fromtimestamp(int(timestamp), tz=datetime.UTC).strftime(
|
||||
"%Y-%m-%d-"
|
||||
)
|
||||
+ slug
|
||||
)
|
||||
post_format = post.get("format")
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ ssh_upload: publish
|
|||
|
||||
{% set upload = upload + ["sftp_upload"] %}
|
||||
sftp_upload: publish
|
||||
printf 'put -r $(OUTPUTDIR)/*' | sftp $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||
printf 'put -r $(OUTPUTDIR)/*' | sftp -P $(SSH_PORT) $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||
|
||||
{% set upload = upload + ["rsync_upload"] %}
|
||||
rsync_upload: publish
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class URLWrapper:
|
|||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return self.name or ""
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{type(self).__name__} {self._name!r}>"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ classifiers = [
|
|||
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
|
|
@ -27,10 +26,10 @@ classifiers = [
|
|||
"Topic :: Text Processing :: Markup :: HTML",
|
||||
"Topic :: Text Processing :: Markup :: reStructuredText",
|
||||
]
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"blinker>=1.7.0",
|
||||
"docutils>=0.20.1",
|
||||
"docutils>=0.22.0",
|
||||
"feedgenerator>=2.1.0",
|
||||
"jinja2>=3.1.2",
|
||||
"ordered-set>=4.1.0",
|
||||
|
|
@ -59,6 +58,30 @@ pelican-plugins = "pelican.plugins._utils:list_plugins"
|
|||
pelican-quickstart = "pelican.tools.pelican_quickstart:main"
|
||||
pelican-themes = "pelican.tools.pelican_themes:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"BeautifulSoup4>=4.13.3",
|
||||
"jinja2>=3.1.2",
|
||||
"lxml>=4.9.3",
|
||||
"markdown>=3.5.1",
|
||||
"typogrify>=2.1.0",
|
||||
"sphinx>=9.0.0",
|
||||
"sphinxext-opengraph>=0.9.0",
|
||||
"furo==2025.12.19",
|
||||
"livereload>=2.6.3",
|
||||
"psutil>=5.9.6",
|
||||
"pygments>=2.16.1,<2.20.0",
|
||||
"pytest>=7.4.3",
|
||||
"pytest-cov>=4.1.0",
|
||||
"pytest-sugar>=0.9.7",
|
||||
"pytest-xdist>=3.4.0",
|
||||
"tox>=4.11.3",
|
||||
"invoke>=2.2.0",
|
||||
# ruff version should match the one in .pre-commit-config.yaml
|
||||
"ruff==0.12.7",
|
||||
"tomli>=2.0.1; python_version < \"3.11\"",
|
||||
]
|
||||
|
||||
[tool.autopub]
|
||||
project-name = "Pelican"
|
||||
git-username = "botpub"
|
||||
|
|
@ -76,30 +99,6 @@ docserve = "invoke docserve"
|
|||
lint = "invoke lint"
|
||||
test = "invoke tests"
|
||||
|
||||
[tool.pdm.dev-dependencies]
|
||||
dev = [
|
||||
"BeautifulSoup4>=4.13.3",
|
||||
"jinja2>=3.1.2",
|
||||
"lxml>=4.9.3",
|
||||
"markdown>=3.5.1",
|
||||
"typogrify>=2.1.0",
|
||||
"sphinx>=7.1.2",
|
||||
"sphinxext-opengraph>=0.9.0",
|
||||
"furo==2025.9.25",
|
||||
"livereload>=2.6.3",
|
||||
"psutil>=5.9.6",
|
||||
"pygments>=2.16.1,<2.20.0",
|
||||
"pytest>=7.4.3",
|
||||
"pytest-cov>=4.1.0",
|
||||
"pytest-sugar>=0.9.7",
|
||||
"pytest-xdist>=3.4.0",
|
||||
"tox>=4.11.3",
|
||||
"invoke>=2.2.0",
|
||||
# ruff version should match the one in .pre-commit-config.yaml
|
||||
"ruff==0.12.7",
|
||||
"tomli>=2.0.1; python_version < \"3.11\"",
|
||||
]
|
||||
|
||||
[tool.pdm.build]
|
||||
source-includes = [
|
||||
"CONTRIBUTING.rst",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
sphinx
|
||||
sphinxext-opengraph
|
||||
furo==2023.9.10
|
||||
furo==2025.12.19
|
||||
livereload
|
||||
matplotlib
|
||||
tomli;python_version<"3.11"
|
||||
|
|
|
|||
3
tasks.py
3
tasks.py
|
|
@ -3,7 +3,6 @@ from pathlib import Path
|
|||
from shutil import which
|
||||
|
||||
from invoke import task
|
||||
from livereload import Server
|
||||
|
||||
PKG_NAME = "pelican"
|
||||
PKG_PATH = Path(PKG_NAME)
|
||||
|
|
@ -30,6 +29,8 @@ def docbuild(c):
|
|||
@task(docbuild)
|
||||
def docserve(c):
|
||||
"""Serve docs at http://localhost:$DOCS_PORT/ (default port is 8000)"""
|
||||
from livereload import Server # noqa: PLC0415
|
||||
|
||||
server = Server()
|
||||
server.watch("docs/conf.py", lambda: docbuild(c))
|
||||
server.watch("CONTRIBUTING.rst", lambda: docbuild(c))
|
||||
|
|
|
|||
3
tox.ini
3
tox.ini
|
|
@ -1,9 +1,8 @@
|
|||
[tox]
|
||||
envlist = py{3.10,3.11,3.12,3.13,3.14},docs
|
||||
envlist = py{3.11,3.12,3.13,3.14},docs
|
||||
|
||||
[testenv]
|
||||
basepython =
|
||||
py3.10: python3.10
|
||||
py3.11: python3.11
|
||||
py3.12: python3.12
|
||||
py3.13: python3.13
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue