Skip to content
Browse files

test the iso8601 package and add a licensing exception

  • Loading branch information...
1 parent 8f06c0a commit ef7b467900f8c511b6774baab9619f666e9ce04b @mcdonc mcdonc committed Feb 4, 2012
Showing with 170 additions and 25 deletions.
  1. +3 −0 LICENSE.txt
  2. +28 −4 colander/iso8601.py
  3. +2 −0 colander/tests/__init__.py
  4. +33 −21 colander/{tests.py → tests/test_colander.py}
  5. +104 −0 colander/tests/test_iso8601.py
View
3 LICENSE.txt
@@ -39,3 +39,6 @@ License
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
+This package uses code from the "pyiso8601" package by Michael Twomey,
+licensed under the MIT license. See the source file named "iso8601.py" for
+copyright information and license text.
View
32 colander/iso8601.py
@@ -1,13 +1,35 @@
-"""ISO 8601 date time string parsing
+"""
+Copyright (c) 2007 Michael Twomey
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ISO 8601 date time string parsing
Basic usage:
>>> import iso8601
>>> iso8601.parse_date("2007-01-25T12:00:00Z")
datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
>>>
-
"""
+
from datetime import datetime, timedelta, tzinfo
import re
@@ -16,11 +38,13 @@
__all__ = ["parse_date", "ParseError", "Utc", "FixedOffset"]
# Adapted from http://delete.me.uk/2005/03/iso8601.html
-ISO8601_REGEX = re.compile(r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
+ISO8601_REGEX = re.compile(
+ r"(?P<year>[0-9]{4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
r"((?P<separator>.)(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2})(:(?P<second>[0-9]{2})(\.(?P<fraction>[0-9]+))?)?"
r"(?P<timezone>Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"
)
-TIMEZONE_REGEX = re.compile("(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})")
+TIMEZONE_REGEX = re.compile(
+ "(?P<prefix>[+-])(?P<hours>[0-9]{2}).(?P<minutes>[0-9]{2})")
class ParseError(Exception):
"""Raised when there is a problem parsing a date string"""
View
2 colander/tests/__init__.py
@@ -0,0 +1,2 @@
+# package
+fixture = 1
View
54 colander/tests.py → colander/tests/test_colander.py
@@ -1,6 +1,6 @@
# -*- coding:utf-8 -*-
import unittest
-from .compat import text_, text_type
+from colander.compat import text_, text_type
def invalid_exc(func, *arg, **kw):
from colander import Invalid
@@ -1244,7 +1244,7 @@ def _makeOne(self, package=None):
def test_zope_dottedname_style_resolve_absolute(self):
typ = self._makeOne()
result = typ._zope_dottedname_style(None,
- 'colander.tests.TestGlobalObject')
+ 'colander.tests.test_colander.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_zope_dottedname_style_irrresolveable_absolute(self):
@@ -1256,14 +1256,18 @@ def test__zope_dottedname_style_resolve_relative(self):
import colander
typ = self._makeOne(package=colander)
node = DummySchemaNode(None)
- result = typ._zope_dottedname_style(node, '.tests.TestGlobalObject')
+ result = typ._zope_dottedname_style(
+ node,
+ '.tests.test_colander.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__zope_dottedname_style_resolve_relative_leading_dots(self):
import colander
typ = self._makeOne(package=colander.tests)
node = DummySchemaNode(None)
- result = typ._zope_dottedname_style(node, '..tests.TestGlobalObject')
+ result = typ._zope_dottedname_style(
+ node,
+ '..tests.test_colander.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__zope_dottedname_style_resolve_relative_is_dot(self):
@@ -1301,36 +1305,40 @@ def test__zope_dottedname_style_resolveable_relative(self):
def test__zope_dottedname_style_irresolveable_absolute(self):
typ = self._makeOne()
- self.assertRaises(ImportError,
- typ._zope_dottedname_style, None, 'colander.fudge.bar')
+ self.assertRaises(
+ ImportError,
+ typ._zope_dottedname_style, None, 'colander.fudge.bar')
def test__zope_dottedname_style_resolveable_absolute(self):
typ = self._makeOne()
- result = typ._zope_dottedname_style(None,
- 'colander.tests.TestGlobalObject')
+ result = typ._zope_dottedname_style(
+ None,
+ 'colander.tests.test_colander.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_resolve_absolute(self):
typ = self._makeOne()
result = typ._pkg_resources_style(None,
- 'colander.tests:TestGlobalObject')
+ 'colander.tests.test_colander:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_irrresolveable_absolute(self):
typ = self._makeOne()
self.assertRaises(ImportError, typ._pkg_resources_style, None,
- 'colander.tests:nonexisting')
+ 'colander.tests.test_colander:nonexisting')
def test__pkg_resources_style_resolve_relative_startswith_colon(self):
import colander.tests
typ = self._makeOne(package=colander.tests)
- result = typ._pkg_resources_style(None, ':TestGlobalObject')
- self.assertEqual(result, self.__class__)
+ result = typ._pkg_resources_style(None, ':fixture')
+ self.assertEqual(result, 1)
def test__pkg_resources_style_resolve_relative_startswith_dot(self):
import colander
typ = self._makeOne(package=colander)
- result = typ._pkg_resources_style(None, '.tests:TestGlobalObject')
+ result = typ._pkg_resources_style(
+ None,
+ '.tests.test_colander:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test__pkg_resources_style_resolve_relative_is_dot(self):
@@ -1374,13 +1382,17 @@ def test_deserialize_notastring(self):
def test_deserialize_using_pkgresources_style(self):
typ = self._makeOne()
node = DummySchemaNode(None)
- result = typ.deserialize(node, 'colander.tests:TestGlobalObject')
+ result = typ.deserialize(
+ node,
+ 'colander.tests.test_colander:TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_deserialize_using_zope_dottedname_style(self):
typ = self._makeOne()
node = DummySchemaNode(None)
- result = typ.deserialize(node, 'colander.tests.TestGlobalObject')
+ result = typ.deserialize(
+ node,
+ 'colander.tests.test_colander.TestGlobalObject')
self.assertEqual(result, self.__class__)
def test_deserialize_style_raises(self):
@@ -1425,12 +1437,12 @@ def _today(self):
return datetime.date.today()
def test_ctor_default_tzinfo_None(self):
- from . import iso8601
+ from .. import iso8601
typ = self._makeOne()
self.assertEqual(typ.default_tzinfo.__class__, iso8601.Utc)
def test_ctor_default_tzinfo_non_None(self):
- from . import iso8601
+ from .. import iso8601
tzinfo = iso8601.FixedOffset(1, 0, 'myname')
typ = self._makeOne(default_tzinfo=tzinfo)
self.assertEqual(typ.default_tzinfo, tzinfo)
@@ -1476,7 +1488,7 @@ def test_serialize_with_none_tzinfo_naive_datetime(self):
self.assertEqual(result, dt.isoformat())
def test_serialize_with_tzware_datetime(self):
- from . import iso8601
+ from .. import iso8601
typ = self._makeOne()
dt = self._dt()
tzinfo = iso8601.FixedOffset(1, 0, 'myname')
@@ -1488,7 +1500,7 @@ def test_serialize_with_tzware_datetime(self):
def test_deserialize_date(self):
import datetime
- from . import iso8601
+ from .. import iso8601
date = self._today()
typ = self._makeOne()
formatted = date.isoformat()
@@ -1520,7 +1532,7 @@ def test_deserialize_empty(self):
self.assertEqual(result, colander.null)
def test_deserialize_success(self):
- from . import iso8601
+ from .. import iso8601
typ = self._makeOne()
dt = self._dt()
tzinfo = iso8601.FixedOffset(1, 0, 'myname')
@@ -1531,7 +1543,7 @@ def test_deserialize_success(self):
self.assertEqual(result.isoformat(), iso)
def test_deserialize_naive_with_default_tzinfo(self):
- from . import iso8601
+ from .. import iso8601
tzinfo = iso8601.FixedOffset(1, 0, 'myname')
typ = self._makeOne(default_tzinfo=tzinfo)
dt = self._dt()
View
104 colander/tests/test_iso8601.py
@@ -0,0 +1,104 @@
+import unittest
+import datetime
+
+class Test_Utc(unittest.TestCase):
+ def _makeOne(self):
+ from ..iso8601 import Utc
+ return Utc()
+
+ def test_utcoffset(self):
+ from ..iso8601 import ZERO
+ inst = self._makeOne()
+ result = inst.utcoffset(None)
+ self.assertEqual(result, ZERO)
+
+ def test_tzname(self):
+ inst = self._makeOne()
+ result = inst.tzname(None)
+ self.assertEqual(result, "UTC")
+
+ def test_dst(self):
+ from ..iso8601 import ZERO
+ inst = self._makeOne()
+ result = inst.dst(None)
+ self.assertEqual(result, ZERO)
+
+class Test_FixedOffset(unittest.TestCase):
+ def _makeOne(self):
+ from ..iso8601 import FixedOffset
+ return FixedOffset(1, 30, 'oneandahalf')
+
+ def test_utcoffset(self):
+ inst = self._makeOne()
+ result = inst.utcoffset(None)
+ self.assertEqual(result, datetime.timedelta(hours=1, minutes=30))
+
+ def test_tzname(self):
+ inst = self._makeOne()
+ result = inst.tzname(None)
+ self.assertEqual(result, 'oneandahalf')
+
+ def test_dst(self):
+ from ..iso8601 import ZERO
+ inst = self._makeOne()
+ result = inst.dst(None)
+ self.assertEqual(result, ZERO)
+
+ def test___repr__(self):
+ inst = self._makeOne()
+ result = inst.__repr__()
+ self.assertEqual(result, "<FixedOffset 'oneandahalf'>")
+
+class Test_parse_timezone(unittest.TestCase):
+ def _callFUT(self, tzstring):
+ from ..iso8601 import parse_timezone
+ return parse_timezone(tzstring)
+
+ def test_default_Z(self):
+ from ..iso8601 import UTC
+ result = self._callFUT('Z')
+ self.assertEqual(result, UTC)
+
+ def test_default_None(self):
+ from ..iso8601 import UTC
+ result = self._callFUT(None)
+ self.assertEqual(result, UTC)
+
+ def test_positive(self):
+ tzstring = "+01:00"
+ result = self._callFUT(tzstring)
+ self.assertEqual(result.utcoffset(None),
+ datetime.timedelta(hours=1, minutes=0))
+
+ def test_negative(self):
+ tzstring = "-01:00"
+ result = self._callFUT(tzstring)
+ self.assertEqual(result.utcoffset(None),
+ datetime.timedelta(hours=-1, minutes=0))
+
+class Test_parse_date(unittest.TestCase):
+ def _callFUT(self, datestring):
+ from ..iso8601 import parse_date
+ return parse_date(datestring)
+
+ def test_notastring(self):
+ from ..iso8601 import ParseError
+ self.assertRaises(ParseError, self._callFUT, None)
+
+ def test_cantparse(self):
+ from ..iso8601 import ParseError
+ self.assertRaises(ParseError, self._callFUT, 'garbage')
+
+ def test_normal(self):
+ from ..iso8601 import UTC
+ result = self._callFUT("2007-01-25T12:00:00Z")
+ self.assertEqual(result,
+ datetime.datetime(2007, 1, 25, 12, 0, tzinfo=UTC))
+
+ def test_fraction(self):
+ from ..iso8601 import UTC
+ result = self._callFUT("2007-01-25T12:00:00.123Z")
+ self.assertEqual(result,
+ datetime.datetime(2007, 1, 25, 12, 0, 0, 123000,
+ tzinfo=UTC))
+

0 comments on commit ef7b467

Please sign in to comment.
Something went wrong with that request. Please try again.