Commits

Matthew Schinckel committed 9c44505

A whole stack of testing

Comments (0)

Files changed (2)

timedelta/helpers.py

 
 import re
 import datetime
+from decimal import Decimal
+from numbers import Number
 
 def nice_repr(timedelta, display="long"):
     """
     '1d, 1s'
     """
     
+    assert isinstance(timedelta, datetime.timedelta), "First argument must be a timedelta."
+    
     result = ""
     
     weeks = timedelta.days / 7
     
     values = [weeks, days, hours, minutes, seconds]
     
-    for i in range(4):
+    for i in range(len(values)):
         if values[i]:
             if values[i] == 1 and len(words[i]) > 1:
                 result += "%i%s, " % (values[i], words[i].rstrip('s'))
 def parse(string):
     """
     Parse a string into a timedelta object.
+    
+    >>> parse("1 day")
+    datetime.timedelta(1)
+    >>> parse("2 days")
+    datetime.timedelta(2)
     """
     # This is the format we sometimes get from Postgres.
     d = re.match(r'((?P<days>\d+) days )?(?P<hours>\d+):'
     else:
         # This is the more flexible format
         d = re.match(
-                     r'^((?P<weeks>\d+)\W*w((ee)?k(s)?)(,)?\W*)?'
-                     r'((?P<days>\d+)\W*d(ay(s)?)?(,)?\W*)?'
-                     r'((?P<hours>\d+)\W*h(ou)?r(s)?(,)?\W*)?'
-                     r'((?P<minutes>\d+)\W*m(in(ute)?)?(s)?(,)?\W*)?'
-                     r'((?P<seconds>\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*$',
                      str(string))
         if not d:
-            raise TypeError("%s is not a valid time interval" % string)
+            raise TypeError("'%s' is not a valid time interval" % string)
         d = d.groupdict()
     
-    return datetime.timedelta(**dict(( (k, int(v)) for k,v in d.items() 
+    return datetime.timedelta(**dict(( (k, float(v)) for k,v in d.items() 
         if v is not None )))
 
 
 def divide(obj1, obj2, float=False):
     """
-    Allows for the division of timedeltas by other timedeltas.
-    
-    >>> divide(datetime.timedelta(1), datetime.timedelta(hours=6))
-    4
-    >>> divide(datetime.timedelta(2), datetime.timedelta(3))
-    0
+    Allows for the division of timedeltas by other timedeltas, or by
+    floats/Decimals
     """
-    assert isinstance(obj1, datetime.timedelta)
-    assert isinstance(obj2, datetime.timedelta)
+    assert isinstance(obj1, datetime.timedelta), "First argument must be a timedelta."
+    assert isinstance(obj2, (datetime.timedelta, Number, Decimal)), "Second argument must be a timedelta or number"
     
     sec1 = obj1.days * 86400 + obj1.seconds
-    sec2 = obj2.days * 86400 + obj2.seconds
-    if float:
-        sec1 *= 1.0
-    return sec1 / sec2
+    if isinstance(obj2, datetime.timedelta):
+        sec2 = obj2.days * 86400 + obj2.seconds
+        if float:
+            sec1 *= 1.0
+        return sec1 / sec2
+    else:
+        if float:
+            assert None, "float=True is inappropriate when dividing timedelta by a number."
+        secs = sec1 / obj2
+        if isinstance(secs, Decimal):
+            secs = float(secs)
+        return datetime.timedelta(seconds=secs)
 
 def percentage(obj1, obj2):
     """
+    What percentage of obj2 is obj1? We want the answer as a float.
     >>> percentage(datetime.timedelta(2), datetime.timedelta(4))
     50.0
     """
+    assert isinstance(obj1, datetime.timedelta), "First argument must be a timedelta."
+    assert isinstance(obj2, datetime.timedelta), "Second argument must be a timedelta."
+    
     return divide(obj1 * 100, obj2, float=True)
 
 def multiply(obj, val):
     Allows for the multiplication of timedeltas by float values.
     """
     
-    assert isinstance(obj, datetime.timedelta)
+    assert isinstance(obj, datetime.timedelta), "First argument must be a timedelta."
+    assert isinstance(val, (Number, Decimal)), "Second argument must be a number."
     
     sec = obj.days * 86400 + obj.seconds
     sec *= val
+    if isinstance(sec, Decimal):
+        sec = float(sec)
     return datetime.timedelta(seconds=sec)
 
 
     The obj is rounded to the nearest whole number of timedeltas.
     
     obj can be a timedelta, datetime or time object.
+    """
     
-    >>> 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)
-    """
+    assert isinstance(obj, (datetime.datetime, datetime.timedelta, datetime.time)), "First argument must be datetime, time or timedelta."
+    assert isinstance(timedelta, datetime.timedelta), "Second argument must be a timedelta."
     
     time_only = False
     if isinstance(obj, datetime.timedelta):
     elif isinstance(obj, datetime.datetime):
         counter = datetime.datetime.combine(obj.date(), datetime.time(0, tzinfo=obj.tzinfo))
     elif isinstance(obj, datetime.time):
-        counter = datetime.datetime.combine(datetime.date.today(obj.tzinfo), datetime.time(0, tzinfo=obj.tzinfo))
+        counter = datetime.datetime.combine(datetime.date.today(), datetime.time(0, tzinfo=obj.tzinfo))
         obj = datetime.datetime.combine(datetime.date.today(), obj)
         time_only = True
     

timedelta/tests.py

 import datetime
 from forms import TimedeltaFormField
 from widgets import TimedeltaWidget
+from helpers import *
 
 class TimedeltaWidgetTest(TestCase):
     def test_render(self):
         datetime.timedelta(7)
         >>> t.clean('2 weeks, 2 days')
         datetime.timedelta(16)
-        """
+        """
+
+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), float=True)
+        2.6666666666666665
+        >>> divide(datetime.timedelta(8), 2.0)
+        datetime.timedelta(4)
+        >>> divide(datetime.timedelta(8), 2, float=True)
+        Traceback (most recent call last):
+            ...
+        AssertionError: float=True is inappropriate when dividing timedelta by a number.
+        """
+    
+    def percentage(self):
+        """
+        >>> percentage(datetime.timedelta(4), datetime.timedelta(2))
+        200.0
+        >>> percentage(datetime.timedelta(2), datetime.timedelta(4))
+        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.
+        """
+    
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.