Merge branch 'main' into patch-4

This commit is contained in:
Justin Mayer 2026-04-13 17:47:21 +02:00 committed by GitHub
commit 688a2a9a24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 101 additions and 65 deletions

View file

@ -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

View file

@ -9,7 +9,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
python: "3.10"
python: "3.11"
# Build HTML & PDF formats
formats:

View file

@ -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"]

View file

@ -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"

View file

@ -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:

View file

@ -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

View file

@ -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,
}

View file

@ -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 %}

View file

@ -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>

View file

@ -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")

View file

@ -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

View file

@ -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}>"

View file

@ -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",

View file

@ -1,6 +1,5 @@
sphinx
sphinxext-opengraph
furo==2023.9.10
furo==2025.12.19
livereload
matplotlib
tomli;python_version<"3.11"

View file

@ -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))

View file

@ -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