Drop support for EOL Python 3.8

This commit is contained in:
Hugo van Kemenade 2024-12-21 15:53:13 +02:00
commit 714a3d53a1
9 changed files with 22 additions and 40 deletions

View file

@ -17,8 +17,6 @@ jobs:
os: [ubuntu, macos, windows] os: [ubuntu, macos, windows]
python: ["3.10", "3.11", "3.12", "3.13"] python: ["3.10", "3.11", "3.12", "3.13"]
include: include:
- os: ubuntu
python: "3.8"
- os: ubuntu - os: ubuntu
python: "3.9" python: "3.9"

View file

@ -6,7 +6,7 @@ import os
import re import re
from datetime import timezone from datetime import timezone
from html import unescape from html import unescape
from typing import Any, Dict, Optional, Set, Tuple from typing import Any, Optional
from urllib.parse import ParseResult, unquote, urljoin, urlparse, urlunparse from urllib.parse import ParseResult, unquote, urljoin, urlparse, urlunparse
try: try:
@ -47,7 +47,7 @@ class Content:
""" """
default_template: Optional[str] = None default_template: Optional[str] = None
mandatory_properties: Tuple[str, ...] = () mandatory_properties: tuple[str, ...] = ()
@deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0)) @deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0))
def filename(): def filename():
@ -56,10 +56,10 @@ class Content:
def __init__( def __init__(
self, self,
content: str, content: str,
metadata: Optional[Dict[str, Any]] = None, metadata: Optional[dict[str, Any]] = None,
settings: Optional[Settings] = None, settings: Optional[Settings] = None,
source_path: Optional[str] = None, source_path: Optional[str] = None,
context: Optional[Dict[Any, Any]] = None, context: Optional[dict[Any, Any]] = None,
): ):
if metadata is None: if metadata is None:
metadata = {} metadata = {}
@ -226,7 +226,7 @@ class Content:
) )
@property @property
def url_format(self) -> Dict[str, Any]: def url_format(self) -> dict[str, Any]:
"""Returns the URL, formatted with the proper values""" """Returns the URL, formatted with the proper values"""
metadata = copy.copy(self.metadata) metadata = copy.copy(self.metadata)
path = self.metadata.get("path", self.get_relative_source_path()) path = self.metadata.get("path", self.get_relative_source_path())
@ -397,7 +397,7 @@ class Content:
hrefs = self._get_intrasite_link_regex() hrefs = self._get_intrasite_link_regex()
return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content) return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content)
def get_static_links(self) -> Set[str]: def get_static_links(self) -> set[str]:
static_links = set() static_links = set()
hrefs = self._get_intrasite_link_regex() hrefs = self._get_intrasite_link_regex()
for m in hrefs.finditer(self._content): for m in hrefs.finditer(self._content):

View file

@ -7,7 +7,7 @@ from collections import defaultdict
from functools import partial from functools import partial
from itertools import chain, groupby from itertools import chain, groupby
from operator import attrgetter from operator import attrgetter
from typing import List, Optional, Set from typing import Optional
from jinja2 import ( from jinja2 import (
BaseLoader, BaseLoader,
@ -158,8 +158,8 @@ class Generator:
return False return False
def get_files( def get_files(
self, paths, exclude: Optional[List[str]] = None, extensions=None self, paths, exclude: Optional[list[str]] = None, extensions=None
) -> Set[str]: ) -> set[str]:
"""Return a list of files to use, based on rules """Return a list of files to use, based on rules
:param paths: the list pf paths to search (relative to self.path) :param paths: the list pf paths to search (relative to self.path)
@ -253,7 +253,7 @@ class Generator:
# return the name of the class for logging purposes # return the name of the class for logging purposes
return self.__class__.__name__ return self.__class__.__name__
def _check_disabled_readers(self, paths, exclude: Optional[List[str]]) -> None: def _check_disabled_readers(self, paths, exclude: Optional[list[str]]) -> None:
"""Log warnings for files that would have been processed by disabled readers.""" """Log warnings for files that would have been processed by disabled readers."""
for fil in self.get_files( for fil in self.get_files(
paths, exclude=exclude, extensions=self.readers.disabled_extensions paths, exclude=exclude, extensions=self.readers.disabled_extensions

View file

@ -9,7 +9,7 @@ import sys
from os.path import isabs from os.path import isabs
from pathlib import Path from pathlib import Path
from types import ModuleType from types import ModuleType
from typing import Any, Dict, Optional from typing import Any, Optional
from pelican.log import LimitFilter from pelican.log import LimitFilter
@ -24,7 +24,7 @@ def load_source(name: str, path: str) -> ModuleType:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
Settings = Dict[str, Any] Settings = dict[str, Any]
DEFAULT_THEME = os.path.join( DEFAULT_THEME = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "themes", "notmyidea" os.path.dirname(os.path.abspath(__file__)), "themes", "notmyidea"

View file

@ -1,5 +1,4 @@
import os import os
import sys
from shutil import copy, rmtree from shutil import copy, rmtree
from tempfile import mkdtemp from tempfile import mkdtemp
from unittest.mock import MagicMock from unittest.mock import MagicMock
@ -1528,18 +1527,9 @@ class TestStaticGenerator(unittest.TestCase):
self.generator.generate_context() self.generator.generate_context()
self.generator.generate_output(None) self.generator.generate_output(None)
self.assertTrue(os.path.islink(self.endfile)) self.assertTrue(os.path.islink(self.endfile))
self.assertEqual(
# os.path.realpath is broken on Windows before python3.8 for symlinks. os.path.realpath(self.endfile), os.path.realpath(self.startfile)
# This is a (ugly) workaround. )
# see: https://bugs.python.org/issue9949
if os.name == "nt" and sys.version_info < (3, 8):
def get_real_path(path):
return os.readlink(path) if os.path.islink(path) else path
else:
get_real_path = os.path.realpath
self.assertEqual(get_real_path(self.endfile), get_real_path(self.startfile))
def test_delete_existing_file_before_mkdir(self): def test_delete_existing_file_before_mkdir(self):
with open(self.startfile, "w") as f: with open(self.startfile, "w") as f:

View file

@ -3,7 +3,7 @@
import argparse import argparse
import locale import locale
import os import os
from typing import Mapping from collections.abc import Mapping
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader

View file

@ -11,7 +11,7 @@ import shutil
import sys import sys
import traceback import traceback
import urllib import urllib
from collections.abc import Hashable from collections.abc import Collection, Generator, Hashable, Iterable, Sequence
from contextlib import contextmanager from contextlib import contextmanager
from functools import partial from functools import partial
from html import entities from html import entities
@ -22,10 +22,6 @@ from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
Callable, Callable,
Collection,
Generator,
Iterable,
Sequence,
) )
import dateutil.parser import dateutil.parser
@ -133,8 +129,9 @@ class DateFormatter:
def __call__(self, date: datetime.datetime, date_format: str) -> str: def __call__(self, date: datetime.datetime, date_format: str) -> str:
# on OSX, encoding from LC_CTYPE determines the unicode output in PY3 # on OSX, encoding from LC_CTYPE determines the unicode output in PY3
# make sure it's same as LC_TIME # make sure it's same as LC_TIME
with temporary_locale(self.locale, locale.LC_TIME), temporary_locale( with (
self.locale, locale.LC_CTYPE temporary_locale(self.locale, locale.LC_TIME),
temporary_locale(self.locale, locale.LC_CTYPE),
): ):
formatted = strftime(date, date_format) formatted = strftime(date, date_format)

View file

@ -14,7 +14,6 @@ classifiers = [
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
@ -28,7 +27,7 @@ classifiers = [
"Topic :: Text Processing :: Markup :: HTML", "Topic :: Text Processing :: Markup :: HTML",
"Topic :: Text Processing :: Markup :: reStructuredText", "Topic :: Text Processing :: Markup :: reStructuredText",
] ]
requires-python = ">=3.8.1,<4.0" requires-python = ">=3.9,<4.0"
dependencies = [ dependencies = [
"blinker>=1.7.0", "blinker>=1.7.0",
"docutils>=0.20.1", "docutils>=0.20.1",
@ -39,7 +38,6 @@ dependencies = [
"python-dateutil>=2.8.2", "python-dateutil>=2.8.2",
"rich>=13.6.0", "rich>=13.6.0",
"unidecode>=1.3.7", "unidecode>=1.3.7",
"backports-zoneinfo>=0.2.1; python_version < \"3.9\"",
"watchfiles>=0.21.0", "watchfiles>=0.21.0",
"tzdata; sys_platform == 'win32'", "tzdata; sys_platform == 'win32'",
] ]

View file

@ -1,9 +1,8 @@
[tox] [tox]
envlist = py{3.8,3.9,3.10,3.11,3.12,3.13},docs envlist = py{3.9,3.10,3.11,3.12,3.13},docs
[testenv] [testenv]
basepython = basepython =
py3.8: python3.8
py3.9: python3.9 py3.9: python3.9
py3.10: python3.10 py3.10: python3.10
py3.11: python3.11 py3.11: python3.11