test the iso8601 package and add a licensing exception
This commit is contained in:
@@ -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.
|
||||
|
@@ -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 @@ from .compat import string_types
|
||||
__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"""
|
||||
|
2
colander/tests/__init__.py
Normal file
2
colander/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# package
|
||||
fixture = 1
|
@@ -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 @@ class TestGlobalObject(unittest.TestCase):
|
||||
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 @@ class TestGlobalObject(unittest.TestCase):
|
||||
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 @@ class TestGlobalObject(unittest.TestCase):
|
||||
|
||||
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 @@ class TestGlobalObject(unittest.TestCase):
|
||||
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 @@ class TestDateTime(unittest.TestCase):
|
||||
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 @@ class TestDateTime(unittest.TestCase):
|
||||
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 @@ class TestDateTime(unittest.TestCase):
|
||||
|
||||
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 @@ class TestDateTime(unittest.TestCase):
|
||||
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 @@ class TestDateTime(unittest.TestCase):
|
||||
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()
|
104
colander/tests/test_iso8601.py
Normal file
104
colander/tests/test_iso8601.py
Normal file
@@ -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))
|
||||
|
Reference in New Issue
Block a user