Commits

Matthew Schinckel  committed f467aed

Make the tests all run better.
More py3k support.

  • Participants
  • Parent commits 9ed168d

Comments (0)

Files changed (4)

File timedelta/fields.py

 COLUMN_TYPES["django.db.backends.postgresql_psycopg2"] = "interval"
 COLUMN_TYPES["django.contrib.gis.db.backends.postgis"] = "interval"
 
-class TimedeltaField(models.Field):
+class TimedeltaField(six.with_metaclass(models.SubfieldBase, models.Field)):
     """
     Store a datetime.timedelta as an INTERVAL in postgres, or a 
     CHAR(20) in other database backends.
     """
-    __metaclass__ = models.SubfieldBase
     _south_introspects = True
     
     description = "A datetime.timedelta object"

File timedelta/forms.py

 from django import forms
 from django.utils.translation import ugettext_lazy as _
+from django.utils import six
 
 import datetime
 from collections import defaultdict
 from .helpers import parse
 
 class TimedeltaFormField(forms.Field):
+    
     default_error_messages = {
         'invalid':_('Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"')
     }
         defaults = {'widget':forms.Select(choices=choices)}
         defaults.update(kwargs)
         super(TimedeltaChoicesField, self).__init__(*args, **defaults)
+
+
+def test_clean():
+    """
+    >>> t = TimedeltaFormField()
+    >>> t.clean('1 day')
+    datetime.timedelta(1)
+    >>> t.clean('1 day, 0:00:00')
+    datetime.timedelta(1)
+    >>> t.clean('1 day, 8:42:42.342')
+    datetime.timedelta(1, 31362, 342000)
+    >>> t.clean('3 days, 8:42:42.342161')
+    datetime.timedelta(3, 31362, 342161)
+    >>> try:
+    ...  t.clean('3 days, 8:42:42.3.42161')
+    ... except forms.ValidationError as arg:
+    ...  six.print_(arg.messages[0])
+    Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"
+    >>> t.clean('5 day, 8:42:42')
+    datetime.timedelta(5, 31362)
+    >>> t.clean('1 days')
+    datetime.timedelta(1)
+    >>> t.clean('1 second')
+    datetime.timedelta(0, 1)
+    >>> t.clean('1 sec')
+    datetime.timedelta(0, 1)
+    >>> t.clean('10 seconds')
+    datetime.timedelta(0, 10)
+    >>> t.clean('30 seconds')
+    datetime.timedelta(0, 30)
+    >>> t.clean('1 minute, 30 seconds')
+    datetime.timedelta(0, 90)
+    >>> t.clean('2.5 minutes')
+    datetime.timedelta(0, 150)
+    >>> t.clean('2 minutes, 30 seconds')
+    datetime.timedelta(0, 150)
+    >>> t.clean('.5 hours')
+    datetime.timedelta(0, 1800)
+    >>> t.clean('30 minutes')
+    datetime.timedelta(0, 1800)
+    >>> t.clean('1 hour')
+    datetime.timedelta(0, 3600)
+    >>> t.clean('5.5 hours')
+    datetime.timedelta(0, 19800)
+    >>> t.clean('1 day, 1 hour, 30 mins')
+    datetime.timedelta(1, 5400)
+    >>> t.clean('8 min')
+    datetime.timedelta(0, 480)
+    >>> t.clean('3 days, 12 hours')
+    datetime.timedelta(3, 43200)
+    >>> t.clean('3.5 day')
+    datetime.timedelta(3, 43200)
+    >>> t.clean('1 week')
+    datetime.timedelta(7)
+    >>> t.clean('2 weeks, 2 days')
+    datetime.timedelta(16)
+    >>> try:
+    ...  t.clean(six.u('2 we\xe8k, 2 days'))
+    ... except forms.ValidationError as arg:
+    ...  six.print_(arg.messages[0])
+    Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"
+    """
+    pass

File timedelta/helpers.py

     '1 day, 2 hours, 3 minutes, 4 seconds'
     >>> nice_repr(td(days=1, seconds=1), "minimal")
     '1d, 1s'
+    >>> nice_repr(datetime.timedelta(days=1))
+    '1 day'
+    >>> nice_repr(datetime.timedelta(days=0))
+    ''
+    >>> nice_repr(datetime.timedelta(seconds=1))
+    '1 second'
+    >>> nice_repr(datetime.timedelta(seconds=10))
+    '10 seconds'
+    >>> nice_repr(datetime.timedelta(seconds=30))
+    '30 seconds'
+    >>> nice_repr(datetime.timedelta(seconds=60))
+    '1 minute'
+    >>> nice_repr(datetime.timedelta(seconds=150))
+    '2 minutes, 30 seconds'
+    >>> nice_repr(datetime.timedelta(seconds=1800))
+    '30 minutes'
+    >>> nice_repr(datetime.timedelta(seconds=3600))
+    '1 hour'
+    >>> nice_repr(datetime.timedelta(seconds=3601))
+    '1 hour, 1 second'
+    >>> nice_repr(datetime.timedelta(seconds=19800))
+    '5 hours, 30 minutes'
+    >>> nice_repr(datetime.timedelta(seconds=91800))
+    '1 day, 1 hour, 30 minutes'
+    >>> nice_repr(datetime.timedelta(seconds=302400))
+    '3 days, 12 hours'
     """
     
     assert isinstance(timedelta, datetime.timedelta), "First argument must be a timedelta."
     Traceback (most recent call last):
     ...
     TypeError: '' is not a valid time interval
+    >>> parse("1.5 days")
+    datetime.timedelta(1, 43200)
+    >>> parse("3 weeks")
+    datetime.timedelta(21)
+    >>> parse("4.2 hours")
+    datetime.timedelta(0, 15120)
+    >>> parse(".5 hours")
+    datetime.timedelta(0, 1800)
+    >>> parse(" hours")
+    Traceback (most recent call last):
+        ...
+    TypeError: ' hours' is not a valid time interval
+    >>> parse("1 hour, 5 mins")
+    datetime.timedelta(0, 3900)
     
+    >>> parse("-2 days")
+    datetime.timedelta(-2)
+    >>> parse("-1 day 0:00:01")
+    datetime.timedelta(-1, 1)
+    >>> parse("-1 day, -1:01:01")
+    datetime.timedelta(-2, 82739)
+    >>> parse("-1 weeks, 2 days, -3 hours, 4 minutes, -5 seconds")
+    datetime.timedelta(-5, 11045)
     """
     if string == "":
         raise TypeError("'%s' is not a valid time interval" % string)
     # This is the format we get from sometimes Postgres, sqlite,
     # and from serialization
-    d = re.match(r'^((?P<days>\d+) days?,? )?(?P<hours>\d+):'
+    d = re.match(r'^((?P<days>[-+]?\d+) days?,? )?(?P<sign>[-+]?)(?P<hours>\d+):'
                  r'(?P<minutes>\d+)(:(?P<seconds>\d+(\.\d+)?))?$',
                  six.text_type(string))
-    if d: 
+    if d:
         d = d.groupdict(0)
+        if d['sign'] == '-':
+            for k in 'hours', 'minutes', 'seconds':
+                d[k] = '-' + d[k]
+        d.pop('sign', None)
     else:
         # This is the more flexible format
         d = re.match(
-                     r'^((?P<weeks>((\d*\.\d+)|\d+))\W*w((ee)?(k(s)?)?)(,)?\W*)?'
-                     r'((?P<days>((\d*\.\d+)|\d+))\W*d(ay(s)?)?(,)?\W*)?'
-                     r'((?P<hours>((\d*\.\d+)|\d+))\W*h(ou)?(r(s)?)?(,)?\W*)?'
-                     r'((?P<minutes>((\d*\.\d+)|\d+))\W*m(in(ute)?(s)?)?(,)?\W*)?'
-                     r'((?P<seconds>((\d*\.\d+)|\d+))\W*s(ec(ond)?(s)?)?)?\W*$',
+                     r'^((?P<weeks>-?((\d*\.\d+)|\d+))\W*w((ee)?(k(s)?)?)(,)?\W*)?'
+                     r'((?P<days>-?((\d*\.\d+)|\d+))\W*d(ay(s)?)?(,)?\W*)?'
+                     r'((?P<hours>-?((\d*\.\d+)|\d+))\W*h(ou)?(r(s)?)?(,)?\W*)?'
+                     r'((?P<minutes>-?((\d*\.\d+)|\d+))\W*m(in(ute)?(s)?)?(,)?\W*)?'
+                     r'((?P<seconds>-?((\d*\.\d+)|\d+))\W*s(ec(ond)?(s)?)?)?\W*$',
                      six.text_type(string))
         if not d:
             raise TypeError("'%s' is not a valid time interval" % string)
     2
     >>> divide(td(32), 16)
     datetime.timedelta(2)
+    >>> divide(datetime.timedelta(1), datetime.timedelta(hours=6))
+    4
+    >>> divide(datetime.timedelta(2), datetime.timedelta(3))
+    0
+    >>> divide(datetime.timedelta(8), datetime.timedelta(3), as_float=True)
+    2.6666666666666665
+    >>> divide(datetime.timedelta(8), 2.0)
+    datetime.timedelta(4)
+    >>> divide(datetime.timedelta(8), 2, as_float=True)
+    Traceback (most recent call last):
+        ...
+    AssertionError: as_float=True is inappropriate when dividing timedelta by a number.
+    
     """
     assert isinstance(obj1, datetime.timedelta), "First argument must be a timedelta."
     assert isinstance(obj2, (datetime.timedelta, int, float, Decimal)), "Second argument must be a timedelta or number"
     datetime.timedelta(0)
     >>> modulo(td(15), 4 * 3600 * 24)
     datetime.timedelta(3)
+    
+    >>> modulo(5, td(1))
+    Traceback (most recent call last):
+        ...
+    AssertionError: First argument must be a timedelta.
+    >>> modulo(td(1), 2.8)
+    Traceback (most recent call last):
+        ...
+    AssertionError: Second argument must be a timedelta or int.
     """
     assert isinstance(obj1, datetime.timedelta), "First argument must be a timedelta."
     assert isinstance(obj2, (datetime.timedelta, int)), "Second argument must be a timedelta or int."
 def percentage(obj1, obj2):
     """
     What percentage of obj2 is obj1? We want the answer as a float.
+    >>> percentage(datetime.timedelta(4), datetime.timedelta(2))
+    200.0
     >>> percentage(datetime.timedelta(2), datetime.timedelta(4))
     50.0
     """
 
 def decimal_percentage(obj1, obj2):
     """
+    >>> decimal_percentage(datetime.timedelta(4), datetime.timedelta(2))
+    Decimal('200.0')
     >>> decimal_percentage(datetime.timedelta(2), datetime.timedelta(4))
     Decimal('50.0')
     """
     Allows for the multiplication of timedeltas by float values.
     >>> multiply(datetime.timedelta(seconds=20), 1.5)
     datetime.timedelta(0, 30)
+    >>> multiply(datetime.timedelta(1), 2.5)
+    datetime.timedelta(2, 43200)
+    >>> multiply(datetime.timedelta(1), 3)
+    datetime.timedelta(3)
+    >>> multiply(datetime.timedelta(1), Decimal("5.5"))
+    datetime.timedelta(5, 43200)
+    >>> multiply(datetime.date.today(), 2.5)
+    Traceback (most recent call last):
+        ...
+    AssertionError: First argument must be a timedelta.
+    >>> multiply(datetime.timedelta(1), "2")
+    Traceback (most recent call last):
+        ...
+    AssertionError: Second argument must be a number.
     """
     
     assert isinstance(obj, datetime.timedelta), "First argument must be a timedelta."
     datetime.datetime(2012, 1, 1, 9, 45)
     >>> round_to_nearest(datetime.datetime(2012, 1, 1, 9, 43), datetime.timedelta(minutes=1))
     datetime.datetime(2012, 1, 1, 9, 43)
+    
+    >>> td = datetime.timedelta(minutes=30)
+    >>> round_to_nearest(datetime.timedelta(minutes=0), td)
+    datetime.timedelta(0)
+    >>> round_to_nearest(datetime.timedelta(minutes=14), td)
+    datetime.timedelta(0)
+    >>> round_to_nearest(datetime.timedelta(minutes=15), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(minutes=29), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(minutes=30), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(minutes=42), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(hours=7, minutes=22), td)
+    datetime.timedelta(0, 27000)
+
+    >>> td = datetime.timedelta(minutes=15)
+    >>> round_to_nearest(datetime.timedelta(minutes=0), td)
+    datetime.timedelta(0)
+    >>> round_to_nearest(datetime.timedelta(minutes=14), td)
+    datetime.timedelta(0, 900)
+    >>> round_to_nearest(datetime.timedelta(minutes=15), td)
+    datetime.timedelta(0, 900)
+    >>> round_to_nearest(datetime.timedelta(minutes=29), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(minutes=30), td)
+    datetime.timedelta(0, 1800)
+    >>> round_to_nearest(datetime.timedelta(minutes=42), td)
+    datetime.timedelta(0, 2700)
+    >>> round_to_nearest(datetime.timedelta(hours=7, minutes=22), td)
+    datetime.timedelta(0, 26100)
+
+    >>> td = datetime.timedelta(minutes=30)
+    >>> round_to_nearest(datetime.datetime(2010,1,1,9,22), td)
+    datetime.datetime(2010, 1, 1, 9, 30)
+    >>> round_to_nearest(datetime.datetime(2010,1,1,9,32), td)
+    datetime.datetime(2010, 1, 1, 9, 30)
+    >>> round_to_nearest(datetime.datetime(2010,1,1,9,42), td)
+    datetime.datetime(2010, 1, 1, 9, 30)
+
+    >>> round_to_nearest(datetime.time(0,20), td)
+    datetime.time(0, 30)
+    
+    TODO: test with tzinfo (non-naive) datetimes/times.
     """
     
     assert isinstance(obj, (datetime.datetime, datetime.timedelta, datetime.time)), "First argument must be datetime, time or timedelta."

File timedelta/tests.py

+from unittest import TestCase
+import datetime
+import doctest
+
+from django.core.exceptions import ValidationError
 from django.db import models
-from django.core.exceptions import ValidationError
 from django.utils import six
 
-from unittest import TestCase
-
-import datetime
-
-from .forms import TimedeltaFormField
 from .fields import TimedeltaField
-from .widgets import TimedeltaWidget
-from .helpers import *
-
-UNICODE = {
-    'u': '' if six.PY3 else 'u'
-}
-
-class TimedeltaWidgetTest(TestCase):
-    def test_render(self):
-        """
-        >>> t = TimedeltaWidget()
-        >>> t.render('', datetime.timedelta(days=1), {})
-        %(u)s'<input type="text" name="" value="1 day" />'
-        >>> t.render('', datetime.timedelta(days=0), {})
-        %(u)s'<input type="text" name="" />'
-        >>> t.render('', datetime.timedelta(seconds=1), {})
-        %(u)s'<input type="text" name="" value="1 second" />'
-        >>> t.render('', datetime.timedelta(seconds=10), {})
-        %(u)s'<input type="text" name="" value="10 seconds" />'
-        >>> t.render('', datetime.timedelta(seconds=30), {})
-        %(u)s'<input type="text" name="" value="30 seconds" />'
-        >>> t.render('', datetime.timedelta(seconds=60), {})
-        %(u)s'<input type="text" name="" value="1 minute" />'
-        >>> t.render('', datetime.timedelta(seconds=150), {})
-        %(u)s'<input type="text" name="" value="2 minutes, 30 seconds" />'
-        >>> t.render('', datetime.timedelta(seconds=1800), {})
-        %(u)s'<input type="text" name="" value="30 minutes" />'
-        >>> t.render('', datetime.timedelta(seconds=3600), {})
-        %(u)s'<input type="text" name="" value="1 hour" />'
-        >>> t.render('', datetime.timedelta(seconds=3601), {})
-        %(u)s'<input type="text" name="" value="1 hour, 1 second" />'
-        >>> t.render('', datetime.timedelta(seconds=19800), {})
-        %(u)s'<input type="text" name="" value="5 hours, 30 minutes" />'
-        >>> t.render('', datetime.timedelta(seconds=91800), {})
-        %(u)s'<input type="text" name="" value="1 day, 1 hour, 30 minutes" />'
-        >>> t.render('', datetime.timedelta(seconds=302400), {})
-        %(u)s'<input type="text" name="" value="3 days, 12 hours" />'
-        """ % UNICODE
+import timedelta.helpers
+import timedelta.forms
+import timedelta.widgets
 
 class MinMaxTestModel(models.Model):
     min = TimedeltaField(min_value=datetime.timedelta(1))
         self.assertRaises(ValidationError, test.full_clean)
         test.minmax = datetime.timedelta(6, hours=23, minutes=59, seconds=59)
         test.full_clean()
+    
+    def test_load_from_db(self):
+        obj = MinMaxTestModel.objects.create(min='2 days', max='2 minutes', minmax='3 days')
+        self.assertEquals(datetime.timedelta(2), obj.min)
+        self.assertEquals(datetime.timedelta(0, 120), obj.max)
+        self.assertEquals(datetime.timedelta(3), obj.minmax)
+        
+        obj = MinMaxTestModel.objects.get()
+        self.assertEquals(datetime.timedelta(2), obj.min)
+        self.assertEquals(datetime.timedelta(0, 120), obj.max)
+        self.assertEquals(datetime.timedelta(3), obj.minmax)
 
-class TimedeltaFormFieldTest(TestCase):
-    def test_clean(self):
-        """
-        >>> t = TimedeltaFormField()
-        >>> t.clean('1 day')
-        datetime.timedelta(1)
-        >>> t.clean('1 day, 0:00:00')
-        datetime.timedelta(1)
-        >>> t.clean('1 day, 8:42:42.342')
-        datetime.timedelta(1, 31362, 342000)
-        >>> t.clean('3 days, 8:42:42.342161')
-        datetime.timedelta(3, 31362, 342161)
-        >>> t.clean('3 days, 8:42:42.3.42161')
-        Traceback (most recent call last):
-        ValidationError: ['Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"']
-        >>> t.clean('5 day, 8:42:42')
-        datetime.timedelta(5, 31362)
-        >>> t.clean('1 days')
-        datetime.timedelta(1)
-        >>> t.clean('1 second')
-        datetime.timedelta(0, 1)
-        >>> t.clean('1 sec')
-        datetime.timedelta(0, 1)
-        >>> t.clean('10 seconds')
-        datetime.timedelta(0, 10)
-        >>> t.clean('30 seconds')
-        datetime.timedelta(0, 30)
-        >>> t.clean('1 minute, 30 seconds')
-        datetime.timedelta(0, 90)
-        >>> t.clean('2.5 minutes')
-        datetime.timedelta(0, 150)
-        >>> t.clean('2 minutes, 30 seconds')
-        datetime.timedelta(0, 150)
-        >>> t.clean('.5 hours')
-        datetime.timedelta(0, 1800)
-        >>> t.clean('30 minutes')
-        datetime.timedelta(0, 1800)
-        >>> t.clean('1 hour')
-        datetime.timedelta(0, 3600)
-        >>> t.clean('5.5 hours')
-        datetime.timedelta(0, 19800)
-        >>> t.clean('1 day, 1 hour, 30 mins')
-        datetime.timedelta(1, 5400)
-        >>> t.clean('8 min')
-        datetime.timedelta(0, 480)
-        >>> t.clean('3 days, 12 hours')
-        datetime.timedelta(3, 43200)
-        >>> t.clean('3.5 day')
-        datetime.timedelta(3, 43200)
-        >>> t.clean('1 week')
-        datetime.timedelta(7)
-        >>> t.clean('2 weeks, 2 days')
-        datetime.timedelta(16)
-        >>> t.clean(six.u('2 we\xe8k, 2 days'))
-        Traceback (most recent call last):
-            ...
-        ValidationError: [%(u)s'Enter a valid time span: e.g. "3 days, 4 hours, 2 minutes"']
-        """ % UNICODE
-    
-
-class TimedeltaHelpersTest(TestCase):
-    def test_parse(self):
-        """
-        >>> parse('1 day')
-        datetime.timedelta(1)
-        >>> parse('2 days')
-        datetime.timedelta(2)
-        >>> parse("1.5 days")
-        datetime.timedelta(1, 43200)
-        >>> parse("3 weeks")
-        datetime.timedelta(21)
-        >>> parse("4.2 hours")
-        datetime.timedelta(0, 15120)
-        >>> parse(".5 hours")
-        datetime.timedelta(0, 1800)
-        >>> parse(" hours")
-        Traceback (most recent call last):
-            ...
-        TypeError: ' hours' is not a valid time interval
-        >>> parse("1 hour, 5 mins")
-        datetime.timedelta(0, 3900)
-        """
-    
-    def test_multiply(self):
-        """
-        >>> multiply(datetime.timedelta(1), 2.5)
-        datetime.timedelta(2, 43200)
-        >>> multiply(datetime.timedelta(1), 3)
-        datetime.timedelta(3)
-        >>> multiply(datetime.timedelta(1), Decimal("5.5"))
-        datetime.timedelta(5, 43200)
-        >>> multiply(datetime.date.today(), 2.5)
-        Traceback (most recent call last):
-            ...
-        AssertionError: First argument must be a timedelta.
-        >>> multiply(datetime.timedelta(1), "2")
-        Traceback (most recent call last):
-            ...
-        AssertionError: Second argument must be a number.
-        """
-    def test_divide(self):
-        """
-        >>> divide(datetime.timedelta(1), datetime.timedelta(hours=6))
-        4
-        >>> divide(datetime.timedelta(2), datetime.timedelta(3))
-        0
-        >>> divide(datetime.timedelta(8), datetime.timedelta(3), as_float=True)
-        2.6666666666666665
-        >>> divide(datetime.timedelta(8), 2.0)
-        datetime.timedelta(4)
-        >>> divide(datetime.timedelta(8), 2, as_float=True)
-        Traceback (most recent call last):
-            ...
-        AssertionError: as_float=True is inappropriate when dividing timedelta by a number.
-        """
-    
-    def test_percentage(self):
-        """
-        >>> percentage(datetime.timedelta(4), datetime.timedelta(2))
-        200.0
-        >>> percentage(datetime.timedelta(2), datetime.timedelta(4))
-        50.0
-        
-        """
-    
-    def test_decimal_percentage(self):
-        """
-        >>> decimal_percentage(datetime.timedelta(4), datetime.timedelta(2))
-        Decimal('200.0')
-        >>> decimal_percentage(datetime.timedelta(2), datetime.timedelta(4))
-        Decimal('50.0')
-        
-        """
-    
-    
-    def test_round_to_nearest(self):
-        """
-        >>> td = datetime.timedelta(minutes=30)
-        >>> round_to_nearest(datetime.timedelta(minutes=0), td)
-        datetime.timedelta(0)
-        >>> round_to_nearest(datetime.timedelta(minutes=14), td)
-        datetime.timedelta(0)
-        >>> round_to_nearest(datetime.timedelta(minutes=15), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(minutes=29), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(minutes=30), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(minutes=42), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(hours=7, minutes=22), td)
-        datetime.timedelta(0, 27000)
-        
-        >>> td = datetime.timedelta(minutes=15)
-        >>> round_to_nearest(datetime.timedelta(minutes=0), td)
-        datetime.timedelta(0)
-        >>> round_to_nearest(datetime.timedelta(minutes=14), td)
-        datetime.timedelta(0, 900)
-        >>> round_to_nearest(datetime.timedelta(minutes=15), td)
-        datetime.timedelta(0, 900)
-        >>> round_to_nearest(datetime.timedelta(minutes=29), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(minutes=30), td)
-        datetime.timedelta(0, 1800)
-        >>> round_to_nearest(datetime.timedelta(minutes=42), td)
-        datetime.timedelta(0, 2700)
-        >>> round_to_nearest(datetime.timedelta(hours=7, minutes=22), td)
-        datetime.timedelta(0, 26100)
-
-        >>> td = datetime.timedelta(minutes=30)
-        >>> round_to_nearest(datetime.datetime(2010,1,1,9,22), td)
-        datetime.datetime(2010, 1, 1, 9, 30)
-        >>> round_to_nearest(datetime.datetime(2010,1,1,9,32), td)
-        datetime.datetime(2010, 1, 1, 9, 30)
-        >>> round_to_nearest(datetime.datetime(2010,1,1,9,42), td)
-        datetime.datetime(2010, 1, 1, 9, 30)
-
-        >>> round_to_nearest(datetime.time(0,20), td)
-        datetime.time(0, 30)
-        
-        TODO: test with tzinfo (non-naive) datetimes/times.
-        """
-    
-    def test_decimal_hours(self):
-        """
-        >>> decimal_hours(datetime.timedelta(hours=5, minutes=30))
-        Decimal('5.5')
-        >>> decimal_hours(datetime.timedelta(hours=5))
-        Decimal('5')
-        >>> decimal_hours(datetime.timedelta(hours=9, minutes=20))
-        Decimal('9.333333333333333333333333333')
-        """
+def load_tests(loader, tests, ignore):
+    tests.addTests(doctest.DocTestSuite(timedelta.helpers))
+    tests.addTests(doctest.DocTestSuite(timedelta.forms))
+    return tests