diff -Nru isodate-0.5.1/CHANGES.txt isodate-0.5.4/CHANGES.txt --- isodate-0.5.1/CHANGES.txt 2014-11-06 19:16:17.000000000 +0000 +++ isodate-0.5.4/CHANGES.txt 2015-08-05 22:56:24.000000000 +0000 @@ -2,6 +2,14 @@ CHANGES ======= +0.5.4 (2015-08-06) +------------------ + +- Fix parsing of Periods (Fabien Bochu) +- Make Duration objects hashable (Geoffrey Fairchild) +- Add multiplication to duration (Reinoud Elhorst) + + 0.5.1 (2014-11-07) ------------------ diff -Nru isodate-0.5.1/debian/changelog isodate-0.5.4/debian/changelog --- isodate-0.5.1/debian/changelog 2015-07-22 17:15:03.000000000 +0000 +++ isodate-0.5.4/debian/changelog 2015-10-01 12:41:23.000000000 +0000 @@ -1,8 +1,8 @@ -isodate (0.5.1-2build1) wily; urgency=medium +isodate (0.5.4-1) unstable; urgency=medium - * No-change rebuild for python3.5 transition + * New upstream release (0.5.4). - -- Steve Langasek Wed, 22 Jul 2015 17:15:03 +0000 + -- Maximiliano Curia Thu, 01 Oct 2015 14:41:23 +0200 isodate (0.5.1-2) unstable; urgency=medium diff -Nru isodate-0.5.1/debian/control isodate-0.5.4/debian/control --- isodate-0.5.1/debian/control 2015-07-22 17:15:03.000000000 +0000 +++ isodate-0.5.4/debian/control 2015-10-01 12:41:23.000000000 +0000 @@ -1,8 +1,7 @@ Source: isodate Section: python Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian Python Modules Team +Maintainer: Debian Python Modules Team Uploaders: Maximiliano Curia Build-Depends: debhelper (>= 9), dh-python, @@ -11,8 +10,7 @@ Standards-Version: 3.9.6 Homepage: https://pypi.python.org/pypi/isodate Vcs-Git: git://anonscm.debian.org/python-modules/packages/isodate.git -Vcs-Browser: http://anonscm.debian.org/gitweb/?p=python-modules/packages/isodate.git -XS-Testsuite: autopkgtest +Vcs-Browser: http://anonscm.debian.org/cgit/python-modules/packages/isodate.git Package: python-isodate Architecture: all diff -Nru isodate-0.5.1/debian/watch isodate-0.5.4/debian/watch --- isodate-0.5.1/debian/watch 2015-04-28 16:10:43.000000000 +0000 +++ isodate-0.5.4/debian/watch 2015-10-01 12:41:23.000000000 +0000 @@ -1,4 +1,3 @@ version=3 -opts="filenamemangle=s/#.*//" \ - http://pypi.python.org/pypi/isodate/ \ - https://pypi.python.org/packages/source/i/isodate/isodate-(\d.+)\.tar\.gz#.* +opts=uversionmangle=s/(rc|a|b|c)/~$1/ \ +https://pypi.debian.net/isodate/isodate-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) diff -Nru isodate-0.5.1/PKG-INFO isodate-0.5.4/PKG-INFO --- isodate-0.5.1/PKG-INFO 2014-11-06 19:18:49.000000000 +0000 +++ isodate-0.5.4/PKG-INFO 2015-08-05 22:56:38.000000000 +0000 @@ -1,7 +1,7 @@ Metadata-Version: 1.1 Name: isodate -Version: 0.5.1 -Summary: An ISO 8601 date/time/duration parser and formater +Version: 0.5.4 +Summary: An ISO 8601 date/time/duration parser and formatter Home-page: http://cheeseshop.python.org/pypi/isodate Author: Gerhard Weis Author-email: gerhard.weis@proclos.com @@ -10,19 +10,19 @@ ISO 8601 date/time parser ========================= - .. image:: https://travis-ci.org/gweis/isodate.png?branch=master + .. image:: https://travis-ci.org/gweis/isodate.svg?branch=master :target: https://travis-ci.org/gweis/isodate :alt: Travis-CI - .. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master + .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master :target: https://coveralls.io/r/gweis/isodate?branch=master :alt: Coveralls - .. image:: https://pypip.in/v/isodate/badge.png + .. image:: https://pypip.in/version/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: Latest Version - .. image:: https://pypip.in/d/isodate/badge.png - :target: https://pypi.python.org/pypi//isodate/ + .. image:: https://pypip.in/download/isodate/badge.svg + :target: https://pypi.python.org/pypi/isodate/ :alt: Downloads - .. image:: https://pypip.in/license/isodate/badge.png + .. image:: https://pypip.in/license/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: License @@ -68,7 +68,7 @@ which can be used almost like a *timedelta* object (with some limitations). However, a *Duration* object can be converted into a *timedelta* object. - There are also ISO formating methods for all supported data types. Each + There are also ISO formatting methods for all supported data types. Each *xxx_isoformat* method accepts a format parameter. The default format is always the ISO 8601 expanded format. This is the same format used by *datetime.isoformat*: @@ -129,6 +129,14 @@ CHANGES ======= + 0.5.4 (2015-08-06) + ------------------ + + - Fix parsing of Periods (Fabien Bochu) + - Make Duration objects hashable (Geoffrey Fairchild) + - Add multiplication to duration (Reinoud Elhorst) + + 0.5.1 (2014-11-07) ------------------ diff -Nru isodate-0.5.1/README.rst isodate-0.5.4/README.rst --- isodate-0.5.1/README.rst 2014-02-27 02:10:14.000000000 +0000 +++ isodate-0.5.4/README.rst 2015-05-18 18:27:00.000000000 +0000 @@ -2,19 +2,19 @@ ISO 8601 date/time parser ========================= -.. image:: https://travis-ci.org/gweis/isodate.png?branch=master +.. image:: https://travis-ci.org/gweis/isodate.svg?branch=master :target: https://travis-ci.org/gweis/isodate :alt: Travis-CI -.. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master +.. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master :target: https://coveralls.io/r/gweis/isodate?branch=master :alt: Coveralls -.. image:: https://pypip.in/v/isodate/badge.png +.. image:: https://pypip.in/version/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: Latest Version -.. image:: https://pypip.in/d/isodate/badge.png - :target: https://pypi.python.org/pypi//isodate/ +.. image:: https://pypip.in/download/isodate/badge.svg + :target: https://pypi.python.org/pypi/isodate/ :alt: Downloads -.. image:: https://pypip.in/license/isodate/badge.png +.. image:: https://pypip.in/license/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: License @@ -60,7 +60,7 @@ which can be used almost like a *timedelta* object (with some limitations). However, a *Duration* object can be converted into a *timedelta* object. -There are also ISO formating methods for all supported data types. Each +There are also ISO formatting methods for all supported data types. Each *xxx_isoformat* method accepts a format parameter. The default format is always the ISO 8601 expanded format. This is the same format used by *datetime.isoformat*: diff -Nru isodate-0.5.1/setup.cfg isodate-0.5.4/setup.cfg --- isodate-0.5.1/setup.cfg 2014-11-06 19:18:49.000000000 +0000 +++ isodate-0.5.4/setup.cfg 2015-08-05 22:56:38.000000000 +0000 @@ -1,5 +1,5 @@ [egg_info] -tag_date = 0 tag_build = tag_svn_revision = 0 +tag_date = 0 diff -Nru isodate-0.5.1/setup.py isodate-0.5.4/setup.py --- isodate-0.5.1/setup.py 2014-11-06 19:18:42.000000000 +0000 +++ isodate-0.5.4/setup.py 2015-08-05 22:56:15.000000000 +0000 @@ -46,7 +46,7 @@ return open(os.path.join(os.path.dirname(__file__), *rnames)).read() setup(name='isodate', - version='0.5.1', + version='0.5.4', packages=['isodate', 'isodate.tests'], package_dir={'': 'src'}, @@ -56,7 +56,7 @@ # PyPI metadata author='Gerhard Weis', author_email='gerhard.weis@proclos.com', - description='An ISO 8601 date/time/duration parser and formater', + description='An ISO 8601 date/time/duration parser and formatter', license='BSD', # keywords = '', url='http://cheeseshop.python.org/pypi/isodate', diff -Nru isodate-0.5.1/src/isodate/duration.py isodate-0.5.4/src/isodate/duration.py --- isodate-0.5.1/src/isodate/duration.py 2014-11-06 18:27:25.000000000 +0000 +++ isodate-0.5.4/src/isodate/duration.py 2015-08-05 22:34:35.000000000 +0000 @@ -134,6 +134,13 @@ self.tdelta.days, self.tdelta.seconds, self.tdelta.microseconds, self.years, self.months) + def __hash__(self): + ''' + Return a hash of this instance so that it can be used in, for + example, dicts and sets. + ''' + return hash((self.tdelta, self.months, self.years)) + def __neg__(self): """ A simple unary minus. @@ -159,8 +166,8 @@ newduration.tdelta = self.tdelta + other.tdelta return newduration if isinstance(other, (date, datetime)): - if (not(float(self.years).is_integer() - and float(self.months).is_integer())): + if (not(float(self.years).is_integer() and + float(self.months).is_integer())): raise ValueError('fractional years or months not supported' ' for date calculations') newmonth = other.month + self.months @@ -185,8 +192,8 @@ newduration.tdelta = self.tdelta + other return newduration if isinstance(other, (date, datetime)): - if (not(float(self.years).is_integer() - and float(self.months).is_integer())): + if (not(float(self.years).is_integer() and + float(self.months).is_integer())): raise ValueError('fractional years or months not supported' ' for date calculations') newmonth = other.month + self.months @@ -202,6 +209,27 @@ raise TypeError('unsupported operand type(s) for +: %s and %s' % (other.__class__, self.__class__)) + def __mul__(self, other): + if isinstance(other, int): + newduration = Duration( + years=self.years * other, + months=self.months * other) + newduration.tdelta = self.tdelta * other + return newduration + raise TypeError('unsupported operand type(s) for +: %s and %s' % + (self.__class__, other.__class__)) + + def __rmul__(self, other): + + if isinstance(other, int): + newduration = Duration( + years=self.years * other, + months=self.months * other) + newduration.tdelta = self.tdelta * other + return newduration + raise TypeError('unsupported operand type(s) for +: %s and %s' % + (other.__class__, self.__class__)) + def __sub__(self, other): ''' It is possible to subtract Duration and timedelta objects from Duration @@ -226,8 +254,8 @@ ''' # print '__rsub__:', self, other if isinstance(other, (date, datetime)): - if (not(float(self.years).is_integer() - and float(self.months).is_integer())): + if (not(float(self.years).is_integer() and + float(self.months).is_integer())): raise ValueError('fractional years or months not supported' ' for date calculations') newmonth = other.month - self.months @@ -258,8 +286,8 @@ if not isinstance(other, Duration): return NotImplemented if (((self.years * 12 + self.months) == - (other.years * 12 + other.months) - and self.tdelta == other.tdelta)): + (other.years * 12 + other.months) and + self.tdelta == other.tdelta)): return True return False @@ -268,15 +296,15 @@ If the years, month part or the timedelta part is not equal, then the two Durations are considered not equal. ''' - if ((isinstance(other, timedelta) - and self.years == 0 - and self.months == 0)): + if ((isinstance(other, timedelta) and + self.years == 0 and + self.months == 0)): return self.tdelta != other if not isinstance(other, Duration): return NotImplemented if (((self.years * 12 + self.months) != - (other.years * 12 + other.months) - or self.tdelta != other.tdelta)): + (other.years * 12 + other.months) or + self.tdelta != other.tdelta)): return True return False diff -Nru isodate-0.5.1/src/isodate/__init__.py isodate-0.5.4/src/isodate/__init__.py --- isodate-0.5.1/src/isodate/__init__.py 2014-02-27 00:15:30.000000000 +0000 +++ isodate-0.5.4/src/isodate/__init__.py 2015-04-01 04:44:00.000000000 +0000 @@ -54,17 +54,17 @@ from isodate.isostrf import D_DEFAULT, D_WEEK, D_ALT_EXT, D_ALT_BAS from isodate.isostrf import D_ALT_BAS_ORD, D_ALT_EXT_ORD -__all__ = (parse_date, date_isoformat, parse_time, time_isoformat, - parse_datetime, datetime_isoformat, parse_duration, - duration_isoformat, ISO8601Error, parse_tzinfo, - tz_isoformat, UTC, FixedOffset, LOCAL, Duration, - strftime, DATE_BAS_COMPLETE, DATE_BAS_ORD_COMPLETE, - DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE, DATE_CENTURY, - DATE_EXT_COMPLETE, DATE_EXT_ORD_COMPLETE, DATE_EXT_WEEK, - DATE_EXT_WEEK_COMPLETE, DATE_MONTH, DATE_YEAR, - TIME_BAS_COMPLETE, TIME_BAS_MINUTE, TIME_EXT_COMPLETE, - TIME_EXT_MINUTE, TIME_HOUR, TZ_BAS, TZ_EXT, TZ_HOUR, - DT_BAS_COMPLETE, DT_EXT_COMPLETE, DT_BAS_ORD_COMPLETE, - DT_EXT_ORD_COMPLETE, DT_BAS_WEEK_COMPLETE, - DT_EXT_WEEK_COMPLETE, D_DEFAULT, D_WEEK, D_ALT_EXT, - D_ALT_BAS, D_ALT_BAS_ORD, D_ALT_EXT_ORD) +__all__ = ['parse_date', 'date_isoformat', 'parse_time', 'time_isoformat', + 'parse_datetime', 'datetime_isoformat', 'parse_duration', + 'duration_isoformat', 'ISO8601Error', 'parse_tzinfo', + 'tz_isoformat', 'UTC', 'FixedOffset', 'LOCAL', 'Duration', + 'strftime', 'DATE_BAS_COMPLETE', 'DATE_BAS_ORD_COMPLETE', + 'DATE_BAS_WEEK', 'DATE_BAS_WEEK_COMPLETE', 'DATE_CENTURY', + 'DATE_EXT_COMPLETE', 'DATE_EXT_ORD_COMPLETE', 'DATE_EXT_WEEK', + 'DATE_EXT_WEEK_COMPLETE', 'DATE_MONTH', 'DATE_YEAR', + 'TIME_BAS_COMPLETE', 'TIME_BAS_MINUTE', 'TIME_EXT_COMPLETE', + 'TIME_EXT_MINUTE', 'TIME_HOUR', 'TZ_BAS', 'TZ_EXT', 'TZ_HOUR', + 'DT_BAS_COMPLETE', 'DT_EXT_COMPLETE', 'DT_BAS_ORD_COMPLETE', + 'DT_EXT_ORD_COMPLETE', 'DT_BAS_WEEK_COMPLETE', + 'DT_EXT_WEEK_COMPLETE', 'D_DEFAULT', 'D_WEEK', 'D_ALT_EXT', + 'D_ALT_BAS', 'D_ALT_BAS_ORD', 'D_ALT_EXT_ORD'] diff -Nru isodate-0.5.1/src/isodate/isoduration.py isodate-0.5.4/src/isodate/isoduration.py --- isodate-0.5.1/src/isodate/isoduration.py 2014-11-06 18:27:25.000000000 +0000 +++ isodate-0.5.4/src/isodate/isoduration.py 2015-04-01 04:44:00.000000000 +0000 @@ -41,7 +41,8 @@ ISO8601_PERIOD_REGEX = re.compile( r"^(?P[+-])?" - r"P(?P[0-9]+([,.][0-9]+)?Y)?" + r"P(?!\b)" + r"(?P[0-9]+([,.][0-9]+)?Y)?" r"(?P[0-9]+([,.][0-9]+)?M)?" r"(?P[0-9]+([,.][0-9]+)?W)?" r"(?P[0-9]+([,.][0-9]+)?D)?" @@ -136,11 +137,11 @@ ''' # TODO: implement better decision for negative Durations. # should be done in Duration class in consistent way with timedelta. - if (((isinstance(tduration, Duration) - and (tduration.years < 0 or tduration.months < 0 - or tduration.tdelta < timedelta(0))) - or (isinstance(tduration, timedelta) - and (tduration < timedelta(0))))): + if (((isinstance(tduration, Duration) and + (tduration.years < 0 or tduration.months < 0 or + tduration.tdelta < timedelta(0))) or + (isinstance(tduration, timedelta) and + (tduration < timedelta(0))))): ret = '-' else: ret = '' diff -Nru isodate-0.5.1/src/isodate/isotime.py isodate-0.5.4/src/isodate/isotime.py --- isodate-0.5.1/src/isodate/isotime.py 2014-02-27 00:24:39.000000000 +0000 +++ isodate-0.5.4/src/isodate/isotime.py 2015-04-01 04:44:00.000000000 +0000 @@ -71,25 +71,25 @@ # hh:mm:ss.ss ... extended format TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2}):" r"(?P[0-9]{2}):" - r"(?P[0-9]{2}([,.][0-9]+)?)" - + TZ_REGEX)) + r"(?P[0-9]{2}" + r"([,.][0-9]+)?)" + TZ_REGEX)) # hhmmss.ss ... basic format TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2})" r"(?P[0-9]{2})" - r"(?P[0-9]{2}([,.][0-9]+)?)" - + TZ_REGEX)) + r"(?P[0-9]{2}" + r"([,.][0-9]+)?)" + TZ_REGEX)) # 2. reduced accuracy: # hh:mm.mm ... extended format TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2}):" - r"(?P[0-9]{2}([,.][0-9]+)?)" - + TZ_REGEX)) + r"(?P[0-9]{2}" + r"([,.][0-9]+)?)" + TZ_REGEX)) # hhmm.mm ... basic format TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2})" - r"(?P[0-9]{2}([,.][0-9]+)?)" - + TZ_REGEX)) + r"(?P[0-9]{2}" + r"([,.][0-9]+)?)" + TZ_REGEX)) # hh.hh ... basic format - TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2}([,.][0-9]+)?)" - + TZ_REGEX)) + TIME_REGEX_CACHE.append(re.compile(r"T?(?P[0-9]{2}" + r"([,.][0-9]+)?)" + TZ_REGEX)) return TIME_REGEX_CACHE diff -Nru isodate-0.5.1/src/isodate/tests/test_duration.py isodate-0.5.4/src/isodate/tests/test_duration.py --- isodate-0.5.1/src/isodate/tests/test_duration.py 2014-11-06 18:27:25.000000000 +0000 +++ isodate-0.5.4/src/isodate/tests/test_duration.py 2015-08-05 22:34:35.000000000 +0000 @@ -231,6 +231,31 @@ # date(2001, 2, 14)), ) +# A list of test cases of multiplications of durations +# are compared against a given expected result. +DATE_MUL_TEST_CASES = ( + (Duration(years=1, months=1), + 3, + Duration(years=3, months=3)), + (Duration(years=1, months=1), + -3, + Duration(years=-3, months=-3)), + (3, + Duration(years=1, months=1), + Duration(years=3, months=3)), + (-3, + Duration(years=1, months=1), + Duration(years=-3, months=-3)), + (5, + Duration(years=2, minutes=40), + Duration(years=10, hours=3, minutes=20)), + (-5, + Duration(years=2, minutes=40), + Duration(years=-10, hours=-3, minutes=-20)), + (7, + Duration(years=1, months=2, weeks=40), + Duration(years=8, months=2, weeks=280))) + class DurationTest(unittest.TestCase): ''' @@ -263,6 +288,16 @@ 'raise exception') self.assertRaises(TypeError, operator.add, 'raise exception', Duration(years=1, months=1, weeks=5)) + self.assertRaises(TypeError, operator.mul, + Duration(years=1, months=1, weeks=5), + 'raise exception') + self.assertRaises(TypeError, operator.mul, 'raise exception', + Duration(years=1, months=1, weeks=5)) + self.assertRaises(TypeError, operator.mul, + Duration(years=1, months=1, weeks=5), + 3.14) + self.assertRaises(TypeError, operator.mul, 3.14, + Duration(years=1, months=1, weeks=5)) def test_parseerror(self): ''' @@ -272,13 +307,30 @@ def test_repr(self): ''' - Test __repr__ and __str__ for Duration obqects. + Test __repr__ and __str__ for Duration objects. ''' dur = Duration(10, 10, years=10, months=10) self.assertEqual('10 years, 10 months, 10 days, 0:00:10', str(dur)) self.assertEqual('isodate.duration.Duration(10, 10, 0,' ' years=10, months=10)', repr(dur)) + def test_hash(self): + ''' + Test __hash__ for Duration objects. + ''' + dur1 = Duration(10, 10, years=10, months=10) + dur2 = Duration(9, 9, years=9, months=9) + dur3 = Duration(10, 10, years=10, months=10) + self.assertNotEqual(hash(dur1), hash(dur2)) + self.assertNotEqual(id(dur1), id(dur2)) + self.assertEqual(hash(dur1), hash(dur3)) + self.assertNotEqual(id(dur1), id(dur3)) + durSet = set() + durSet.add(dur1) + durSet.add(dur2) + durSet.add(dur3) + self.assertEqual(len(durSet), 2) + def test_neg(self): ''' Test __neg__ for Duration objects. @@ -498,6 +550,28 @@ return unittest.TestLoader().loadTestsFromTestCase(TestDateCalc) +def create_datemultestcase(operand1, operand2, expectation): + """ + Create a TestCase class for a specific test. + + This allows having a separate TestCase for each test tuple from the + DATE_CALC_TEST_CASES list, so that a failed test won't stop other tests. + """ + + class TestDateMul(unittest.TestCase): + ''' + A test case template test addition operators for Duration objects. + ''' + + def test_mul(self): + ''' + Test operator *. + ''' + self.assertEqual(operand1 * operand2, expectation) + + return unittest.TestLoader().loadTestsFromTestCase(TestDateMul) + + def test_suite(): ''' Return a test suite containing all test defined above. @@ -513,6 +587,8 @@ suite.addTest(create_datetestcase(*testdata)) for testdata in DATE_CALC_TEST_CASES: suite.addTest(create_datecalctestcase(*testdata)) + for testdata in DATE_MUL_TEST_CASES: + suite.addTest(create_datemultestcase(*testdata)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(DurationTest)) return suite diff -Nru isodate-0.5.1/src/isodate.egg-info/PKG-INFO isodate-0.5.4/src/isodate.egg-info/PKG-INFO --- isodate-0.5.1/src/isodate.egg-info/PKG-INFO 2014-11-06 19:18:49.000000000 +0000 +++ isodate-0.5.4/src/isodate.egg-info/PKG-INFO 2015-08-05 22:56:38.000000000 +0000 @@ -1,7 +1,7 @@ Metadata-Version: 1.1 Name: isodate -Version: 0.5.1 -Summary: An ISO 8601 date/time/duration parser and formater +Version: 0.5.4 +Summary: An ISO 8601 date/time/duration parser and formatter Home-page: http://cheeseshop.python.org/pypi/isodate Author: Gerhard Weis Author-email: gerhard.weis@proclos.com @@ -10,19 +10,19 @@ ISO 8601 date/time parser ========================= - .. image:: https://travis-ci.org/gweis/isodate.png?branch=master + .. image:: https://travis-ci.org/gweis/isodate.svg?branch=master :target: https://travis-ci.org/gweis/isodate :alt: Travis-CI - .. image:: https://coveralls.io/repos/gweis/isodate/badge.png?branch=master + .. image:: https://coveralls.io/repos/gweis/isodate/badge.svg?branch=master :target: https://coveralls.io/r/gweis/isodate?branch=master :alt: Coveralls - .. image:: https://pypip.in/v/isodate/badge.png + .. image:: https://pypip.in/version/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: Latest Version - .. image:: https://pypip.in/d/isodate/badge.png - :target: https://pypi.python.org/pypi//isodate/ + .. image:: https://pypip.in/download/isodate/badge.svg + :target: https://pypi.python.org/pypi/isodate/ :alt: Downloads - .. image:: https://pypip.in/license/isodate/badge.png + .. image:: https://pypip.in/license/isodate/badge.svg :target: https://pypi.python.org/pypi/isodate/ :alt: License @@ -68,7 +68,7 @@ which can be used almost like a *timedelta* object (with some limitations). However, a *Duration* object can be converted into a *timedelta* object. - There are also ISO formating methods for all supported data types. Each + There are also ISO formatting methods for all supported data types. Each *xxx_isoformat* method accepts a format parameter. The default format is always the ISO 8601 expanded format. This is the same format used by *datetime.isoformat*: @@ -129,6 +129,14 @@ CHANGES ======= + 0.5.4 (2015-08-06) + ------------------ + + - Fix parsing of Periods (Fabien Bochu) + - Make Duration objects hashable (Geoffrey Fairchild) + - Add multiplication to duration (Reinoud Elhorst) + + 0.5.1 (2014-11-07) ------------------