From 528014b150d98a40059faaae971548b4e8c25cd2 Mon Sep 17 00:00:00 2001 From: willthong Date: Fri, 21 Jul 2023 21:18:39 +0100 Subject: [PATCH] Fixes #2958. Replaces pytz dependency with zoneinfo. --- RELEASE.md | 3 +++ pelican/contents.py | 19 ++++++++++++++----- pelican/tools/pelican_quickstart.py | 23 ++++++++++++++--------- pelican/utils.py | 18 ++++++++++++------ pyproject.toml | 2 +- 5 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..28c07394 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,3 @@ +Release type: minor + +Replace `pytz` with native alternatives. diff --git a/pelican/contents.py b/pelican/contents.py index c979dd0a..6df6e57c 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -7,7 +7,13 @@ import re from html import unescape from urllib.parse import unquote, urljoin, urlparse, urlunparse -import pytz +from datetime import timezone + +try: + import zoneinfo +except ModuleNotFoundError: + import backports.zoneinfo + from pelican.plugins import signals from pelican.settings import DEFAULT_CONFIG @@ -120,9 +126,12 @@ class Content: self.date_format = self.date_format[1] # manage timezone - default_timezone = settings.get('TIMEZONE', 'UTC') - timezone = getattr(self, 'timezone', default_timezone) - self.timezone = pytz.timezone(timezone) + default_timezone = settings.get("TIMEZONE", "UTC") + timezone = getattr(self, "timezone", default_timezone) + try: + self.timezone = zoneinfo.ZoneInfo(timezone) + except NameError: + self.timezone = backports.zoneinfo.ZoneInfo(timezone) if hasattr(self, 'date'): self.date = set_date_tzinfo(self.date, timezone) @@ -525,7 +534,7 @@ class Article(Content): if self.date.tzinfo is None: now = datetime.datetime.now() else: - now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc) + now = datetime.datetime.utcnow().replace(tzinfo=timezone.utc) if self.date > now: self.status = 'draft' diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py index 2d5629ef..fbacd8c1 100755 --- a/pelican/tools/pelican_quickstart.py +++ b/pelican/tools/pelican_quickstart.py @@ -7,7 +7,10 @@ from typing import Mapping from jinja2 import Environment, FileSystemLoader -import pytz +try: + import zoneinfo +except ModuleNotFoundError: + import backports.zoneinfo try: import readline # NOQA @@ -17,8 +20,8 @@ except ImportError: try: import tzlocal _DEFAULT_TIMEZONE = tzlocal.get_localzone().zone -except ImportError: - _DEFAULT_TIMEZONE = 'Europe/Rome' +except ModuleNotFoundError: + _DEFAULT_TIMEZONE = "Europe/Rome" from pelican import __version__ @@ -158,16 +161,18 @@ def ask(question, answer=str, default=None, length=None): def ask_timezone(question, default, tzurl): """Prompt for time zone and validate input""" - lower_tz = [tz.lower() for tz in pytz.all_timezones] + try: + tz_dict = {tz.lower(): tz for tz in zoneinfo.available_timezones()} + except NameError: + tz_dict = {tz.lower(): tz for tz in backports.zoneinfo.available_timezones()} while True: r = ask(question, str, default) - r = r.strip().replace(' ', '_').lower() - if r in lower_tz: - r = pytz.all_timezones[lower_tz.index(r)] + r = r.strip().replace(" ", "_").lower() + if r in tz_dict.keys(): + r = tz_dict[r] break else: - print('Please enter a valid time zone:\n' - ' (check [{}])'.format(tzurl)) + print("Please enter a valid time zone:\n" " (check [{}])".format(tzurl)) return r diff --git a/pelican/utils.py b/pelican/utils.py index de6ef9bf..aa9fbdc6 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -18,10 +18,12 @@ from operator import attrgetter import dateutil.parser +try: + import zoneinfo +except ModuleNotFoundError: + import backports.zoneinfo from markupsafe import Markup -import pytz - logger = logging.getLogger(__name__) @@ -919,10 +921,14 @@ class FileSystemWatcher: def set_date_tzinfo(d, tz_name=None): """Set the timezone for dates that don't have tzinfo""" if tz_name and not d.tzinfo: - tz = pytz.timezone(tz_name) - d = tz.localize(d) - return SafeDatetime(d.year, d.month, d.day, d.hour, d.minute, d.second, - d.microsecond, d.tzinfo) + try: + timezone = zoneinfo.ZoneInfo(tz_name) + except NameError: + timezone = backports.zoneinfo.ZoneInfo(tz_name) + d = d.replace(tzinfo=timezone) + return SafeDatetime( + d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, d.tzinfo + ) return d diff --git a/pyproject.toml b/pyproject.toml index eb3a8f52..48f6c5f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,10 +37,10 @@ feedgenerator = ">=1.9" jinja2 = ">=2.7" pygments = ">=2.6" python-dateutil = ">=2.8" -pytz = ">=2020.1" rich = ">=10.1" unidecode = ">=1.1" markdown = {version = ">=3.1", optional = true} +backports-zoneinfo = {version = "^0.2.1", python = "<3.9"} [tool.poetry.dev-dependencies] BeautifulSoup4 = "^4.9"