Commit 09d2cf4d by Filippo Valsorda Committed by Xavier Antoviaque

Add string decoding support and tests to xblock.mixin.DateTuple

parent 30a96ddf
......@@ -3,17 +3,50 @@ Mixin defining common Studio functionality
"""
import datetime
import dateutil.parser
import logging
import time
from pytz import UTC
from xblock.fields import Scope, Field, Integer, XBlockMixin
log = logging.getLogger(__name__)
class DateTuple(Field):
"""
Field that stores datetime objects as time tuples
"""
# See note below about not defaulting these
CURRENT_YEAR = datetime.datetime.now(UTC).year
PREVENT_DEFAULT_DAY_MON_SEED1 = datetime.datetime(CURRENT_YEAR, 1, 1, tzinfo=UTC)
PREVENT_DEFAULT_DAY_MON_SEED2 = datetime.datetime(CURRENT_YEAR, 2, 2, tzinfo=UTC)
MUTABLE = False
def _parse_date_wo_default_month_day(self, field):
"""
Parse the field as an iso string but prevent dateutils from defaulting the day or month while
allowing it to default the other fields.
"""
# It's not trivial to replace dateutil b/c parsing timezones as Z, +03:30, -400 is hard in python
# however, we don't want dateutil to default the month or day (but some tests at least expect
# us to default year); so, we'll see if dateutil uses the defaults for these the hard way
result = dateutil.parser.parse(field, default=self.PREVENT_DEFAULT_DAY_MON_SEED1)
result_other = dateutil.parser.parse(field, default=self.PREVENT_DEFAULT_DAY_MON_SEED2)
if result != result_other:
log.warning("Field {0} is missing month or day".format(self._name, field))
return None
if result.tzinfo is None:
result = result.replace(tzinfo=UTC)
return result
def from_json(self, value):
return datetime.datetime(*value[0:6])
if value is None:
return None
return datetime.datetime(*value[0:6]).replace(tzinfo=UTC)
def to_json(self, value):
if value is None:
......@@ -22,13 +55,24 @@ class DateTuple(Field):
return list(value.timetuple())
def enforce_type(self, value):
if isinstance(value, datetime.datetime) or value is None:
if value == "" or value is None:
return None
if isinstance(value, datetime.datetime):
if value.tzinfo is None:
value = value.replace(tzinfo=UTC)
return value
if isinstance(value, (tuple, time.struct_time)):
return datetime.datetime(*value[0:6])
if isinstance(value, tuple):
return datetime.datetime(*value[0:6]).replace(tzinfo=UTC)
if isinstance(value, time.struct_time):
return datetime.datetime.fromtimestamp(time.mktime(value), UTC)
if isinstance(value, basestring):
return self._parse_date_wo_default_month_day(value)
raise TypeError("Value should be datetime, a timetuple or None, not {}".format(type(value)))
raise TypeError("Value should be datetime, timetuple, str or None, not {}".format(type(value)))
class CmsBlockMixin(XBlockMixin):
......
import unittest
import datetime
import time
from pytz import UTC
from cms.lib.xblock.mixin import DateTuple
class DateTupleTest(unittest.TestCase):
datetuple = DateTuple()
def test_from_json(self):
'''Test conversion from iso compatible date strings to struct_time'''
self.assertEqual(
DateTupleTest.datetuple.from_json((2014, 5, 9, 21, 1, 27)),
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC))
self.assertIsNone(DateTupleTest.datetuple.from_json(None))
def test_enforce_type(self):
self.assertEqual(DateTupleTest.datetuple.enforce_type(
(2014, 5, 9, 21, 1, 27)),
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC))
self.assertEqual(DateTupleTest.datetuple.enforce_type(
time.struct_time((2014, 5, 9, 21, 1, 27, 0, 0, 0))),
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC))
self.assertEqual(DateTupleTest.datetuple.enforce_type(
datetime.datetime(2014, 5, 9, 21, 1, 27)),
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC))
self.assertEqual(DateTupleTest.datetuple.enforce_type(
"2013-01-01T00:00:00Z"),
datetime.datetime(2013, 1, 1, 00, 00, 00, tzinfo=UTC))
self.assertEqual(DateTupleTest.datetuple.enforce_type(
"2013-01-01 11:44:22"),
datetime.datetime(2013, 1, 1, 11, 44, 22, tzinfo=UTC))
self.assertEqual(DateTupleTest.datetuple.enforce_type(
"2012-12-31T23:59"),
datetime.datetime(2012, 12, 31, 23, 59, 00, tzinfo=UTC))
self.assertIsNone(DateTupleTest.datetuple.enforce_type(None))
self.assertIsNone(DateTupleTest.datetuple.enforce_type(""))
def test_to_json(self):
self.assertEqual(DateTupleTest.datetuple.to_json(
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC))[:6],
[2014, 5, 9, 21, 1, 27])
self.assertIsNone(DateTupleTest.datetuple.to_json(None))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment