From 7f2bc2a23b6e8c8f0865cb293942a560a06d74e0 Mon Sep 17 00:00:00 2001
From: Stefan hr Berder
Date: Sun, 16 Feb 2014 12:51:52 +0100
Subject: [PATCH] change date metadata parsing to dateutil.parser
---
docs/getting_started.rst | 2 ++
pelican/tests/test_utils.py | 32 +++++++++++++++++++++++++++---
pelican/utils.py | 39 +++++--------------------------------
setup.py | 2 +-
4 files changed, 37 insertions(+), 38 deletions(-)
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
index 6655d8d6..8ee37162 100644
--- a/docs/getting_started.rst
+++ b/docs/getting_started.rst
@@ -130,6 +130,8 @@ automatically installed without any action on your part:
utilities
* `MarkupSafe `_, for a markup safe
string implementation
+* `python-dateutil `_, to read
+ the date metadata
If you want the following optional packages, you will need to install them
manually via ``pip``:
diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py
index f6f96a1c..9047593f 100644
--- a/pelican/tests/test_utils.py
+++ b/pelican/tests/test_utils.py
@@ -41,6 +41,12 @@ class TestUtils(LoggedTestCase):
date = datetime.datetime(year=2012, month=11, day=22)
date_hour = datetime.datetime(
year=2012, month=11, day=22, hour=22, minute=11)
+ date_hour_z = datetime.datetime(
+ year=2012, month=11, day=22, hour=22, minute=11,
+ tzinfo=pytz.timezone('UTC'))
+ date_hour_est = datetime.datetime(
+ year=2012, month=11, day=22, hour=22, minute=11,
+ tzinfo=pytz.timezone('EST'))
date_hour_sec = datetime.datetime(
year=2012, month=11, day=22, hour=22, minute=11, second=10)
date_hour_sec_z = datetime.datetime(
@@ -61,22 +67,42 @@ class TestUtils(LoggedTestCase):
'22/11/2012': date,
'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-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.123Z': date_hour_sec_frac_z,
}
+ # examples from http://www.w3.org/TR/NOTE-datetime
+ iso_8601_date = datetime.datetime(year=1997, month=7, day=16)
+ iso_8601_date_hour_tz = datetime.datetime(
+ year=1997, month=7, day=16, hour=19, minute=20,
+ tzinfo=pytz.timezone('CET'))
+ iso_8601_date_hour_sec_tz = datetime.datetime(
+ year=1997, month=7, day=16, hour=19, minute=20, second=30,
+ tzinfo=pytz.timezone('CET'))
+ iso_8601_date_hour_sec_ms_tz = datetime.datetime(
+ year=1997, month=7, day=16, hour=19, minute=20, second=30,
+ microsecond=450000, tzinfo=pytz.timezone('CET'))
+ iso_8601 = {
+ '1997-07-16': iso_8601_date,
+ '1997-07-16T19:20+01:00': iso_8601_date_hour_tz,
+ '1997-07-16T19:20:30+01:00': iso_8601_date_hour_sec_tz,
+ '1997-07-16T19:20:30.45+01:00': iso_8601_date_hour_sec_ms_tz,
+ }
+
# invalid ones
invalid_dates = ['2010-110-12', 'yay']
- if version_info < (3, 2):
- dates.pop('2012-11-22T22:11:10-0500')
- invalid_dates.append('2012-11-22T22:11:10-0500')
for value, expected in dates.items():
self.assertEqual(utils.get_date(value), expected, value)
+ for value, expected in iso_8601.items():
+ self.assertEqual(utils.get_date(value), expected, value)
+
for item in invalid_dates:
self.assertRaises(ValueError, utils.get_date, item)
diff --git a/pelican/utils.py b/pelican/utils.py
index 822e50e9..c5aacaa3 100644
--- a/pelican/utils.py
+++ b/pelican/utils.py
@@ -15,7 +15,7 @@ import traceback
from collections import Hashable
from contextlib import contextmanager
-from datetime import datetime
+import dateutil.parser
from functools import partial
from itertools import groupby
from jinja2 import Markup
@@ -181,39 +181,10 @@ def get_date(string):
If no format matches the given date, raise a ValueError.
"""
string = re.sub(' +', ' ', string)
- formats = [
- # ISO 8601
- '%Y',
- '%Y-%m',
- '%Y-%m-%d',
- '%Y-%m-%dT%H:%M%z',
- '%Y-%m-%dT%H:%MZ',
- '%Y-%m-%dT%H:%M',
- '%Y-%m-%dT%H:%M:%S%z',
- '%Y-%m-%dT%H:%M:%SZ',
- '%Y-%m-%dT%H:%M:%S',
- '%Y-%m-%dT%H:%M:%S.%f%z',
- '%Y-%m-%dT%H:%M:%S.%fZ',
- '%Y-%m-%dT%H:%M:%S.%f',
- # end ISO 8601 forms
- '%Y-%m-%d %H:%M',
- '%Y-%m-%d %H:%M:%S',
- '%Y/%m/%d %H:%M',
- '%Y/%m/%d',
- '%d-%m-%Y',
- '%d.%m.%Y %H:%M',
- '%d.%m.%Y',
- '%d/%m/%Y',
- ]
- for date_format in formats:
- try:
- date = datetime.strptime(string, date_format)
- except ValueError:
- continue
- if date_format.endswith('Z'):
- date = date.replace(tzinfo=pytz.timezone('UTC'))
- return date
- raise ValueError('{0!r} is not a valid date'.format(string))
+ try:
+ return dateutil.parser.parse(string)
+ except (TypeError, ValueError):
+ raise ValueError('{0!r} is not a valid date'.format(string))
@contextmanager
diff --git a/setup.py b/setup.py
index f56a7c41..e989d549 100755
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
from setuptools import setup
requires = ['feedgenerator >= 1.6', 'jinja2 >= 2.7', 'pygments', 'docutils',
- 'pytz >= 0a', 'blinker', 'unidecode', 'six']
+ 'pytz >= 0a', 'blinker', 'unidecode', 'six', 'python-dateutil']
entry_points = {
'console_scripts': [