diff --git a/CHANGES.rst b/CHANGES.rst index c7a1da8..5d06033 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,8 @@ Changelog 1.5.3 (unreleased) ------------------ -- Nothing changed yet. +- Implement new deserializer for datetime fields. + [mbaechtold] 1.5.2 (2015-07-13) diff --git a/README.rst b/README.rst index 8250739..dc1fc68 100644 --- a/README.rst +++ b/README.rst @@ -34,6 +34,10 @@ Actually tested and supported fields needs a datetime.date or datetime.datetime object, or a string in the following format "%Y-%m-%d" +- Datetime + needs a datetime.datetime object, or a string in the + format "'%Y-%m-%d %H:%M:%S" + Default pipelines ================= diff --git a/transmogrify/dexterity/converters.py b/transmogrify/dexterity/converters.py index 569ea00..5b0e315 100644 --- a/transmogrify/dexterity/converters.py +++ b/transmogrify/dexterity/converters.py @@ -1,5 +1,6 @@ from .interfaces import IDeserializer from .interfaces import ISerializer +from DateTime import DateTime from datetime import datetime from plone.app.textfield.interfaces import IRichText from plone.app.textfield.value import RichTextValue @@ -11,6 +12,7 @@ from zope.interface import implementer from zope.schema.interfaces import ICollection from zope.schema.interfaces import IDate +from zope.schema.interfaces import IDatetime from zope.schema.interfaces import IField from zope.schema.interfaces import IFromUnicode from zope.schema.interfaces import IObject @@ -382,6 +384,33 @@ def __call__(self, value, filestore, item, return value +@implementer(IDeserializer) +@adapter(IDatetime) +class DatetimeDeserializer(object): + + def __init__(self, field): + self.field = field + + def __call__(self, value, filestore, item, + disable_constraints=False, logger=None): + if isinstance(value, basestring): + value = DateTime(value).asdatetime() + try: + self.field.validate(value) + except Exception as e: + if not disable_constraints: + raise e + else: + if logger: + logger( + "%s is invalid in %s: %s" % ( + self.field.__name__, + item['_path'], + e) + ) + return value + + @implementer(ISerializer) @adapter(IField) class DefaultSerializer(object): diff --git a/transmogrify/dexterity/converters.zcml b/transmogrify/dexterity/converters.zcml index 09bfcc2..97d1406 100644 --- a/transmogrify/dexterity/converters.zcml +++ b/transmogrify/dexterity/converters.zcml @@ -16,6 +16,7 @@ + diff --git a/transmogrify/dexterity/testing.py b/transmogrify/dexterity/testing.py index d3257c1..6b8cf05 100644 --- a/transmogrify/dexterity/testing.py +++ b/transmogrify/dexterity/testing.py @@ -2,6 +2,7 @@ from collective.transmogrifier.interfaces import ISectionBlueprint from collective.transmogrifier.sections.tests import SampleSource from datetime import date +from datetime import datetime from ftw.builder.testing import BUILDER_LAYER from ftw.builder.testing import functional_session_factory from ftw.builder.testing import set_builder_session_factory @@ -72,6 +73,10 @@ class ITestSchema(form.Schema): title=u'test_date', ) + test_datetime = schema.Datetime( + title=u'test_datetime', + ) + fancy_text = RichText( title=u"Fancy text", ) @@ -131,6 +136,7 @@ def __init__(self, transmogrifier, name, options, previous): 'data': zptlogo, 'filename': 'zptlogo.gif'}, test_date='2010-10-12', + test_datetime='2010-10-12 17:59:59', fieldnotchanged='nochange', ), dict(_path='/two', @@ -142,6 +148,7 @@ def __init__(self, transmogrifier, name, options, previous): test_file=zptlogo, _filename="testlogo.gif", test_date=date(2010, 0o1, 0o1, ), + test_datetime=datetime(2010, 0o1, 0o1, 17, 59, 59), fieldnotchanged='nochange', ), ) diff --git a/transmogrify/dexterity/tests/schemaupdater.txt b/transmogrify/dexterity/tests/schemaupdater.txt index 6db3d20..8ff47cf 100644 --- a/transmogrify/dexterity/tests/schemaupdater.txt +++ b/transmogrify/dexterity/tests/schemaupdater.txt @@ -70,6 +70,14 @@ DateFields: >>> two.test_date datetime.date(2010, 1, 1) +DatetimeFields: + + >>> spam.test_datetime + datetime.datetime(2010, 10, 12, 17, 59, 59) + + >>> two.test_datetime + datetime.datetime(2010, 1, 1, 17, 59, 59) + Won't touch already existing values >>> transmogrifier = Transmogrifier(portal) diff --git a/transmogrify/dexterity/tests/testconverters.py b/transmogrify/dexterity/tests/testconverters.py index 819ae0b..48aa5ed 100644 --- a/transmogrify/dexterity/tests/testconverters.py +++ b/transmogrify/dexterity/tests/testconverters.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from datetime import datetime from ftw.builder import Builder from ftw.builder import create from plone.app.textfield import RichText @@ -9,6 +10,7 @@ from z3c.relationfield.relation import RelationValue from z3c.relationfield.schema import RelationChoice from z3c.relationfield.schema import RelationList +from zope.schema import Datetime import pprint import unittest import zope.testing @@ -195,3 +197,21 @@ def test_filestore(self): "x-application/cow", "Content type from dict should override default") self.assertEqual(rtv.encoding, "latin-1") + + +class TestDatetimeDeserializer(unittest.TestCase): + + layer = TRANSMOGRIFY_DEXTERITY_FUNCTIONAL_TESTING + + def setUp(test): + test.pp = pprint.PrettyPrinter(indent=4) + # TODO: This should read the zcml instead + zope.component.provideAdapter(converters.DatetimeDeserializer) + + def test_datetime_deserializer(self): + deserializer = IDeserializer(Datetime()) + value = deserializer('2015-12-31 17:59:59', None, None) + self.assertEqual( + datetime(2015, 12, 31, 17, 59, 59), + value + )