Commits

Brian Kearns committed 72e79a8

clean up datetime argument handling, improve tests

  • Participants
  • Parent commits fe56756

Comments (0)

Files changed (2)

File lib_pypy/datetime.py

 
 import time as _time
 import math as _math
+import decimal as _decimal
 
 MINYEAR = 1
 MAXYEAR = 9999
         return offset
     raise ValueError("%s()=%d, must be in -1439..1439" % (name, offset))
 
+def _check_int_field(value):
+    if not isinstance(value, (int, long, _decimal.Decimal)):
+        raise TypeError('integer argument expected')
+    return int(value)
+
 def _check_date_fields(year, month, day):
-    for value in [year, day]:
-        if not isinstance(value, (int, long)):
-            raise TypeError('int expected')
+    year = _check_int_field(year)
+    month = _check_int_field(month)
+    day = _check_int_field(day)
     if not MINYEAR <= year <= MAXYEAR:
         raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year)
     if not 1 <= month <= 12:
     dim = _days_in_month(year, month)
     if not 1 <= day <= dim:
         raise ValueError('day must be in 1..%d' % dim, day)
+    return year, month, day
 
 def _check_time_fields(hour, minute, second, microsecond):
-    for value in [hour, minute, second, microsecond]:
-        if not isinstance(value, (int, long)):
-            raise TypeError('int expected')
+    hour = _check_int_field(hour)
+    minute = _check_int_field(minute)
+    second = _check_int_field(second)
+    microsecond = _check_int_field(microsecond)
     if not 0 <= hour <= 23:
         raise ValueError('hour must be in 0..23', hour)
     if not 0 <= minute <= 59:
         raise ValueError('second must be in 0..59', second)
     if not 0 <= microsecond <= 999999:
         raise ValueError('microsecond must be in 0..999999', microsecond)
+    return hour, minute, second, microsecond
 
 def _check_tzinfo_arg(tz):
     if tz is not None and not isinstance(tz, tzinfo):
             self = object.__new__(cls)
             self.__setstate(year)
             return self
-        _check_date_fields(year, month, day)
+        year, month, day = _check_date_fields(year, month, day)
         self = object.__new__(cls)
         self._year = year
         self._month = month
             month = self._month
         if day is None:
             day = self._day
-        _check_date_fields(year, month, day)
+        year, month, day = _check_date_fields(year, month, day)
         return date(year, month, day)
 
     # Comparisons of date objects with other.
         second, microsecond (default to zero)
         tzinfo (default to None)
         """
-        self = object.__new__(cls)
         if isinstance(hour, str):
             # Pickle support
+            self = object.__new__(cls)
             self.__setstate(hour, minute or None)
             return self
+        hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
         _check_tzinfo_arg(tzinfo)
-        _check_time_fields(hour, minute, second, microsecond)
+        self = object.__new__(cls)
         self._hour = hour
         self._minute = minute
         self._second = second
             microsecond = self.microsecond
         if tzinfo is True:
             tzinfo = self.tzinfo
-        _check_time_fields(hour, minute, second, microsecond)
+        hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
         _check_tzinfo_arg(tzinfo)
         return time(hour, minute, second, microsecond, tzinfo)
 
             self = date.__new__(cls, year[:4])
             self.__setstate(year, month)
             return self
+        year, month, day = _check_date_fields(year, month, day)
+        hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
         _check_tzinfo_arg(tzinfo)
-        _check_time_fields(hour, minute, second, microsecond)
-        self = date.__new__(cls, year, month, day)
-        # XXX This duplicates __year, __month, __day for convenience :-(
+        self = object.__new__(cls)
         self._year = year
         self._month = month
         self._day = day
             microsecond = self.microsecond
         if tzinfo is True:
             tzinfo = self.tzinfo
-        _check_date_fields(year, month, day)
-        _check_time_fields(hour, minute, second, microsecond)
+        year, month, day = _check_date_fields(year, month, day)
+        hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
         _check_tzinfo_arg(tzinfo)
         return datetime(year, month, day, hour, minute, second,
                           microsecond, tzinfo)

File pypy/module/test_lib_pypy/test_datetime.py

     dt = datetime.datetime.utcfromtimestamp(0)
     assert isinstance(dt.microsecond, int)
 
+def test_default_args():
+    with py.test.raises(TypeError):
+        datetime.datetime()
+    with py.test.raises(TypeError):
+        datetime.datetime(10)
+    with py.test.raises(TypeError):
+        datetime.datetime(10, 10)
+    datetime.datetime(10, 10, 10)
 
-def test_integer_args():
+def test_check_arg_types():
+    import decimal
+    i10 = 10
+    l10 = 10L
+    d10 = decimal.Decimal(10)
+    d11 = decimal.Decimal(10.9)
+    assert datetime.datetime(i10, i10, i10, i10, i10, i10, i10) == \
+           datetime.datetime(l10, l10, l10, l10, l10, l10, l10) == \
+           datetime.datetime(d10, d10, d10, d10, d10, d10, d10) == \
+           datetime.datetime(d11, d11, d11, d11, d11, d11, d11)
+
+    with py.test.raises(TypeError):
+        datetime.datetime(10., 10, 10)
+    with py.test.raises(TypeError):
+        datetime.datetime(10, 10., 10)
     with py.test.raises(TypeError):
         datetime.datetime(10, 10, 10.)
     with py.test.raises(TypeError):
+        datetime.datetime(10, 10, 10, 10.)
+    with py.test.raises(TypeError):
         datetime.datetime(10, 10, 10, 10, 10.)
     with py.test.raises(TypeError):
         datetime.datetime(10, 10, 10, 10, 10, 10.)
+    with py.test.raises(TypeError):
+        datetime.datetime(10, 10, 10, 10, 10, 10, 10.)
 
 def test_utcnow_microsecond():
     dt = datetime.datetime.utcnow()