From 79b6404d68729d6f8c2279a3fc4ba95f0643501a Mon Sep 17 00:00:00 2001 From: Tatamis <80774326+Tatamis@users.noreply.github.com> Date: Thu, 17 Sep 2026 14:23:26 +0300 Subject: [PATCH] Don't crash on a blank PO-Revision-Date/POT-Creation-Date header Fixes #1219. Some tools (e.g. Poedit) leave these headers blank instead of eliding them or using the 'YEAR-MO-DA HO:MI+ZONE' placeholder. _parse_datetime_header() passed the blank value straight to datetime.strptime(), raising ValueError('time data '' does not match format...') and crashing pybabel on any such file, as reported. Treat a blank (or whitespace-only) value the same as an unset header: return None, matching the existing precedent a few lines up for the Language header ('if the header's value is an empty string, which is what some tools generate'). --- babel/messages/catalog.py | 7 ++++++- tests/messages/test_catalog.py | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py index 5e6c28255..040cc95a4 100644 --- a/babel/messages/catalog.py +++ b/babel/messages/catalog.py @@ -103,7 +103,12 @@ def _has_python_brace_format(string: str) -> bool: return field_name_seen -def _parse_datetime_header(value: str) -> datetime.datetime: +def _parse_datetime_header(value: str) -> datetime.datetime | None: + # Some tools (e.g. Poedit) leave the header's value blank instead of + # eliding the header, or leaving the "YEAR-MO-DA HO:MI+ZONE" placeholder. + if not value.strip(): + return None + match = re.match(r'^(?P.*?)(?P[+-]\d{4})?$', value) dt = datetime.datetime.strptime(match.group('datetime'), '%Y-%m-%d %H:%M') diff --git a/tests/messages/test_catalog.py b/tests/messages/test_catalog.py index 7c730d325..a13bb58b8 100644 --- a/tests/messages/test_catalog.py +++ b/tests/messages/test_catalog.py @@ -15,6 +15,8 @@ import pickle from io import StringIO +import pytest + from babel.dates import UTC, format_datetime from babel.messages import catalog, pofile from babel.util import FixedOffsetTimezone @@ -556,6 +558,14 @@ def test_datetime_parsing(): assert val2.tzinfo is None +@pytest.mark.parametrize('value', ['', ' ']) +def test_datetime_parsing_blank_value_returns_none(value): + # Some tools (e.g. Poedit) leave the header blank instead of eliding + # it or using the "YEAR-MO-DA HO:MI+ZONE" placeholder; this used to + # raise ValueError from strptime instead of being treated as unset. + assert catalog._parse_datetime_header(value) is None + + def test_update_catalog_comments(): # Based on https://web.archive.org/web/20100710131029/http://babel.edgewall.org/attachment/ticket/163/cat-update-comments.py