[Python-checkins] r82066 - in sandbox/branches/py3k-datetime: datetime.py test_datetime.py
alexander.belopolsky
python-checkins at python.org
Fri Jun 18 03:25:47 CEST 2010
Author: alexander.belopolsky
Date: Fri Jun 18 03:25:46 2010
New Revision: 82066
Log:
Added 2.7 features
Modified:
sandbox/branches/py3k-datetime/datetime.py
sandbox/branches/py3k-datetime/test_datetime.py
Modified: sandbox/branches/py3k-datetime/datetime.py
==============================================================================
--- sandbox/branches/py3k-datetime/datetime.py (original)
+++ sandbox/branches/py3k-datetime/datetime.py Fri Jun 18 03:25:46 2010
@@ -180,6 +180,7 @@
raise ValueError("year=%d is before 1900; the datetime strftime() "
"methods require year >= 1900" % year)
# Don't call _utcoffset() or tzname() unless actually needed.
+ freplace = None # the string to use for %f
zreplace = None # the string to use for %z
Zreplace = None # the string to use for %Z
@@ -194,7 +195,12 @@
if i < n:
ch = format[i]
i += 1
- if ch == 'z':
+ if ch == 'f':
+ if freplace is None:
+ freplace = '%06d' % getattr(object,
+ 'microsecond', 0)
+ newformat.append(freplace)
+ elif ch == 'z':
if zreplace is None:
zreplace = ""
if hasattr(object, "_utcoffset"):
@@ -570,6 +576,9 @@
s = s + ".%06d" % self.__microseconds
return s
+ def total_seconds(self):
+ return ((self.days * 86400 + self.seconds)*10**6 +
+ self.microseconds).__truediv__(10**6)
days = property(lambda self: self.__days, doc="days")
seconds = property(lambda self: self.__seconds, doc="seconds")
microseconds = property(lambda self: self.__microseconds,
@@ -790,6 +799,11 @@
"Format using strftime()."
return _wrap_strftime(self, fmt, self.timetuple())
+ def __format__(self, fmt):
+ if len(fmt) != 0:
+ return self.strftime(fmt)
+ return str(self)
+
def isoformat(self):
"""Return the date formatted according to ISO.
@@ -1249,6 +1263,11 @@
0, 1, -1)
return _wrap_strftime(self, fmt, timetuple)
+ def __format__(self, fmt):
+ if len(fmt) != 0:
+ return self.strftime(fmt)
+ return str(self)
+
# Timezone functions
def utcoffset(self):
@@ -1587,7 +1606,9 @@
@classmethod
def strptime(cls, date_string, format):
'string, format -> new datetime parsed from a string (like time.strptime()).'
- return cls(*_time.strptime(date_string, format)[0:6])
+ import _strptime
+ tt, us = _strptime._strptime(date_string, format)
+ return cls(*(tt[0:6] + (us,)))
def utcoffset(self):
"""Return the timezone offset in minutes east of UTC (negative west of
Modified: sandbox/branches/py3k-datetime/test_datetime.py
==============================================================================
--- sandbox/branches/py3k-datetime/test_datetime.py (original)
+++ sandbox/branches/py3k-datetime/test_datetime.py Fri Jun 18 03:25:46 2010
@@ -2,19 +2,20 @@
See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases
"""
-
+from __future__ import division
import sys
import pickle
import cPickle
import unittest
+from test import test_support
+
from datetime import MINYEAR, MAXYEAR
from datetime import timedelta
from datetime import tzinfo
from datetime import time
from datetime import date, datetime
-# Before Python 2.3, proto=2 was taken as a synonym for proto=1.
pickle_choices = [(pickler, unpickler, proto)
for pickler in pickle, cPickle
for unpickler in pickle, cPickle
@@ -78,9 +79,9 @@
def __init__(self, offset, name):
self.__offset = offset
self.__name = name
- self.failUnless(issubclass(NotEnough, tzinfo))
+ self.assertTrue(issubclass(NotEnough, tzinfo))
ne = NotEnough(3, "NotByALongShot")
- self.failUnless(isinstance(ne, tzinfo))
+ self.assertIsInstance(ne, tzinfo)
dt = datetime.now()
self.assertRaises(NotImplementedError, ne.tzname, dt)
@@ -89,7 +90,7 @@
def test_normal(self):
fo = FixedOffset(3, "Three")
- self.failUnless(isinstance(fo, tzinfo))
+ self.assertIsInstance(fo, tzinfo)
for dt in datetime.now(), None:
self.assertEqual(fo.utcoffset(dt), timedelta(minutes=3))
self.assertEqual(fo.tzname(dt), "Three")
@@ -100,33 +101,33 @@
# carry no data), but they need to be picklable anyway else
# concrete subclasses can't be pickled.
orig = tzinfo.__new__(tzinfo)
- self.failUnless(type(orig) is tzinfo)
+ self.assertTrue(type(orig) is tzinfo)
for pickler, unpickler, proto in pickle_choices:
- green = pickler.dumps(orig, proto)
- derived = unpickler.loads(green)
- self.failUnless(type(derived) is tzinfo)
+ green = pickler.dumps(orig, proto)
+ derived = unpickler.loads(green)
+ self.assertTrue(type(derived) is tzinfo)
def test_pickling_subclass(self):
# Make sure we can pickle/unpickle an instance of a subclass.
offset = timedelta(minutes=-300)
orig = PicklableFixedOffset(offset, 'cookie')
- self.failUnless(isinstance(orig, tzinfo))
- self.failUnless(type(orig) is PicklableFixedOffset)
+ self.assertIsInstance(orig, tzinfo)
+ self.assertTrue(type(orig) is PicklableFixedOffset)
self.assertEqual(orig.utcoffset(None), offset)
self.assertEqual(orig.tzname(None), 'cookie')
for pickler, unpickler, proto in pickle_choices:
- green = pickler.dumps(orig, proto)
- derived = unpickler.loads(green)
- self.failUnless(isinstance(derived, tzinfo))
- self.failUnless(type(derived) is PicklableFixedOffset)
- self.assertEqual(derived.utcoffset(None), offset)
- self.assertEqual(derived.tzname(None), 'cookie')
+ green = pickler.dumps(orig, proto)
+ derived = unpickler.loads(green)
+ self.assertIsInstance(derived, tzinfo)
+ self.assertTrue(type(derived) is PicklableFixedOffset)
+ self.assertEqual(derived.utcoffset(None), offset)
+ self.assertEqual(derived.tzname(None), 'cookie')
#############################################################################
# Base clase for testing a particular aspect of timedelta, time, date and
# datetime comparisons.
-class HarmlessMixedComparison(unittest.TestCase):
+class HarmlessMixedComparison:
# Test that __eq__ and __ne__ don't complain for mixed-type comparisons.
# Subclasses must define 'theclass', and theclass(1, 1, 1) must be a
@@ -135,16 +136,13 @@
def test_harmless_mixed_comparison(self):
me = self.theclass(1, 1, 1)
- self.failIf(me == ())
- self.failUnless(me != ())
- self.failIf(() == me)
- self.failUnless(() != me)
+ self.assertFalse(me == ())
+ self.assertTrue(me != ())
+ self.assertFalse(() == me)
+ self.assertTrue(() != me)
- self.failUnless(me in [1, 20L, [], me])
- self.failIf(me not in [1, 20L, [], me])
-
- self.failUnless([] in [me, 1, 20L, []])
- self.failIf([] not in [me, 1, 20L, []])
+ self.assertIn(me, [1, 20L, [], me])
+ self.assertIn([], [me, 1, 20L, []])
def test_harmful_mixed_comparison(self):
me = self.theclass(1, 1, 1)
@@ -165,7 +163,7 @@
#############################################################################
# timedelta tests
-class TestTimeDelta(HarmlessMixedComparison):
+class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
theclass = timedelta
@@ -252,7 +250,7 @@
self.assertRaises(TypeError, lambda: a // x)
self.assertRaises(TypeError, lambda: x // a)
- # Divison of int by timedelta doesn't make sense.
+ # Division of int by timedelta doesn't make sense.
# Division by zero doesn't make sense.
for zero in 0, 0L:
self.assertRaises(TypeError, lambda: zero // a)
@@ -265,6 +263,20 @@
self.assertEqual(td.seconds, seconds)
self.assertEqual(td.microseconds, us)
+ def test_total_seconds(self):
+ td = timedelta(days=365)
+ self.assertEqual(td.total_seconds(), 31536000.0)
+ for total_seconds in [123456.789012, -123456.789012, 0.123456, 0, 1e6]:
+ td = timedelta(seconds=total_seconds)
+ self.assertEqual(td.total_seconds(), total_seconds)
+ # Issue8644: Test that td.total_seconds() has the same
+ # accuracy as td / timedelta(seconds=1).
+ for ms in [-1, -2, -123]:
+ td = timedelta(microseconds=ms)
+ self.assertEqual(td.total_seconds(),
+ ((24*3600*td.days + td.seconds)*10**6
+ + td.microseconds)/10**6)
+
def test_carries(self):
t1 = timedelta(days=100,
weeks=-7,
@@ -306,29 +318,29 @@
def test_compare(self):
t1 = timedelta(2, 3, 4)
t2 = timedelta(2, 3, 4)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
+ self.assertTrue(t1 == t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ self.assertTrue(not t1 != t2)
+ self.assertTrue(not t1 < t2)
+ self.assertTrue(not t1 > t2)
self.assertEqual(cmp(t1, t2), 0)
self.assertEqual(cmp(t2, t1), 0)
for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
t2 = timedelta(*args) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
+ self.assertTrue(t1 < t2)
+ self.assertTrue(t2 > t1)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t2 >= t1)
+ self.assertTrue(t1 != t2)
+ self.assertTrue(t2 != t1)
+ self.assertTrue(not t1 == t2)
+ self.assertTrue(not t2 == t1)
+ self.assertTrue(not t1 > t2)
+ self.assertTrue(not t2 < t1)
+ self.assertTrue(not t1 >= t2)
+ self.assertTrue(not t2 <= t1)
self.assertEqual(cmp(t1, t2), -1)
self.assertEqual(cmp(t2, t1), 1)
@@ -376,7 +388,7 @@
# Verify td -> string -> td identity.
s = repr(td)
- self.failUnless(s.startswith('datetime.'))
+ self.assertTrue(s.startswith('datetime.'))
s = s[9:]
td2 = eval(s)
self.assertEqual(td, td2)
@@ -386,10 +398,10 @@
self.assertEqual(td, td2)
def test_resolution_info(self):
- self.assert_(isinstance(timedelta.min, timedelta))
- self.assert_(isinstance(timedelta.max, timedelta))
- self.assert_(isinstance(timedelta.resolution, timedelta))
- self.assert_(timedelta.max > timedelta.min)
+ self.assertIsInstance(timedelta.min, timedelta)
+ self.assertIsInstance(timedelta.max, timedelta)
+ self.assertIsInstance(timedelta.resolution, timedelta)
+ self.assertTrue(timedelta.max > timedelta.min)
self.assertEqual(timedelta.min, timedelta(-999999999))
self.assertEqual(timedelta.max, timedelta(999999999, 24*3600-1, 1e6-1))
self.assertEqual(timedelta.resolution, timedelta(0, 0, 1))
@@ -436,11 +448,42 @@
(-1, 24*3600-1, 999999))
def test_bool(self):
- self.failUnless(timedelta(1))
- self.failUnless(timedelta(0, 1))
- self.failUnless(timedelta(0, 0, 1))
- self.failUnless(timedelta(microseconds=1))
- self.failUnless(not timedelta(0))
+ self.assertTrue(timedelta(1))
+ self.assertTrue(timedelta(0, 1))
+ self.assertTrue(timedelta(0, 0, 1))
+ self.assertTrue(timedelta(microseconds=1))
+ self.assertTrue(not timedelta(0))
+
+ def test_subclass_timedelta(self):
+
+ class T(timedelta):
+ @staticmethod
+ def from_td(td):
+ return T(td.days, td.seconds, td.microseconds)
+
+ def as_hours(self):
+ sum = (self.days * 24 +
+ self.seconds / 3600.0 +
+ self.microseconds / 3600e6)
+ return round(sum)
+
+ t1 = T(days=1)
+ self.assertTrue(type(t1) is T)
+ self.assertEqual(t1.as_hours(), 24)
+
+ t2 = T(days=-1, seconds=-3600)
+ self.assertTrue(type(t2) is T)
+ self.assertEqual(t2.as_hours(), -25)
+
+ t3 = t1 + t2
+ self.assertTrue(type(t3) is timedelta)
+ t4 = T.from_td(t3)
+ self.assertTrue(type(t4) is T)
+ self.assertEqual(t3.days, t4.days)
+ self.assertEqual(t3.seconds, t4.seconds)
+ self.assertEqual(t3.microseconds, t4.microseconds)
+ self.assertEqual(str(t3), str(t4))
+ self.assertEqual(t4.as_hours(), -1)
#############################################################################
# date tests
@@ -478,7 +521,10 @@
dt2 = dt - delta
self.assertEqual(dt2, dt - days)
-class TestDate(HarmlessMixedComparison):
+class SubclassDate(date):
+ sub_var = 1
+
+class TestDate(HarmlessMixedComparison, unittest.TestCase):
# Tests here should pass for both dates and datetimes, except for a
# few tests that TestDateTime overrides.
@@ -495,7 +541,7 @@
self.theclass.today()):
# Verify dt -> string -> date identity.
s = repr(dt)
- self.failUnless(s.startswith('datetime.'))
+ self.assertTrue(s.startswith('datetime.'))
s = s[9:]
dt2 = eval(s)
self.assertEqual(dt, dt2)
@@ -516,8 +562,8 @@
fromord = self.theclass.fromordinal(n)
self.assertEqual(d, fromord)
if hasattr(fromord, "hour"):
- # if we're checking something fancier than a date, verify
- # the extra fields have been zeroed out
+ # if we're checking something fancier than a date, verify
+ # the extra fields have been zeroed out
self.assertEqual(fromord.hour, 0)
self.assertEqual(fromord.minute, 0)
self.assertEqual(fromord.second, 0)
@@ -674,15 +720,16 @@
def test_overflow(self):
tiny = self.theclass.resolution
- dt = self.theclass.min + tiny
- dt -= tiny # no problem
- self.assertRaises(OverflowError, dt.__sub__, tiny)
- self.assertRaises(OverflowError, dt.__add__, -tiny)
-
- dt = self.theclass.max - tiny
- dt += tiny # no problem
- self.assertRaises(OverflowError, dt.__add__, tiny)
- self.assertRaises(OverflowError, dt.__sub__, -tiny)
+ for delta in [tiny, timedelta(1), timedelta(2)]:
+ dt = self.theclass.min + delta
+ dt -= delta # no problem
+ self.assertRaises(OverflowError, dt.__sub__, delta)
+ self.assertRaises(OverflowError, dt.__add__, -delta)
+
+ dt = self.theclass.max - delta
+ dt += delta # no problem
+ self.assertRaises(OverflowError, dt.__add__, delta)
+ self.assertRaises(OverflowError, dt.__sub__, -delta)
def test_fromtimestamp(self):
import time
@@ -695,6 +742,15 @@
self.assertEqual(d.month, month)
self.assertEqual(d.day, day)
+ def test_insane_fromtimestamp(self):
+ # It's possible that some platform maps time_t to double,
+ # and that this test will fail there. This test should
+ # exempt such platforms (provided they return reasonable
+ # results!).
+ for insane in -1e200, 1e200:
+ self.assertRaises(ValueError, self.theclass.fromtimestamp,
+ insane)
+
def test_today(self):
import time
@@ -720,7 +776,7 @@
# It worked or it didn't. If it didn't, assume it's reason #2, and
# let the test pass if they're within half a second of each other.
- self.failUnless(today == todayagain or
+ self.assertTrue(today == todayagain or
abs(todayagain - today) < timedelta(seconds=0.5))
def test_weekday(self):
@@ -799,19 +855,68 @@
def test_strftime(self):
t = self.theclass(2005, 3, 2)
self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05")
+ self.assertEqual(t.strftime(""), "") # SF bug #761337
+ self.assertEqual(t.strftime('x'*1000), 'x'*1000) # SF bug #1556784
self.assertRaises(TypeError, t.strftime) # needs an arg
self.assertRaises(TypeError, t.strftime, "one", "two") # too many args
self.assertRaises(TypeError, t.strftime, 42) # arg wrong type
+ # test that unicode input is allowed (issue 2782)
+ self.assertEqual(t.strftime(u"%m"), "03")
+
# A naive object replaces %z and %Z w/ empty strings.
self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
+ #make sure that invalid format specifiers are handled correctly
+ #self.assertRaises(ValueError, t.strftime, "%e")
+ #self.assertRaises(ValueError, t.strftime, "%")
+ #self.assertRaises(ValueError, t.strftime, "%#")
+
+ #oh well, some systems just ignore those invalid ones.
+ #at least, excercise them to make sure that no crashes
+ #are generated
+ for f in ["%e", "%", "%#"]:
+ try:
+ t.strftime(f)
+ except ValueError:
+ pass
+
+ #check that this standard extension works
+ t.strftime("%f")
+
+
+ def test_format(self):
+ dt = self.theclass(2007, 9, 10)
+ self.assertEqual(dt.__format__(''), str(dt))
+
+ # check that a derived class's __str__() gets called
+ class A(self.theclass):
+ def __str__(self):
+ return 'A'
+ a = A(2007, 9, 10)
+ self.assertEqual(a.__format__(''), 'A')
+
+ # check that a derived class's strftime gets called
+ class B(self.theclass):
+ def strftime(self, format_spec):
+ return 'B'
+ b = B(2007, 9, 10)
+ self.assertEqual(b.__format__(''), str(dt))
+
+ for fmt in ["m:%m d:%d y:%y",
+ "m:%m d:%d y:%y H:%H M:%M S:%S",
+ "%z %Z",
+ ]:
+ self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
+ self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
+ self.assertEqual(b.__format__(fmt), 'B')
+
def test_resolution_info(self):
- self.assert_(isinstance(self.theclass.min, self.theclass))
- self.assert_(isinstance(self.theclass.max, self.theclass))
- self.assert_(isinstance(self.theclass.resolution, timedelta))
- self.assert_(self.theclass.max > self.theclass.min)
+ self.assertIsInstance(self.theclass.min, self.theclass)
+ self.assertIsInstance(self.theclass.max, self.theclass)
+ self.assertIsInstance(self.theclass.resolution, timedelta)
+ self.assertTrue(self.theclass.max > self.theclass.min)
def test_extreme_timedelta(self):
big = self.theclass.max - self.theclass.min
@@ -859,29 +964,29 @@
def test_compare(self):
t1 = self.theclass(2, 3, 4)
t2 = self.theclass(2, 3, 4)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
+ self.assertTrue(t1 == t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ self.assertTrue(not t1 != t2)
+ self.assertTrue(not t1 < t2)
+ self.assertTrue(not t1 > t2)
self.assertEqual(cmp(t1, t2), 0)
self.assertEqual(cmp(t2, t1), 0)
for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
t2 = self.theclass(*args) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
+ self.assertTrue(t1 < t2)
+ self.assertTrue(t2 > t1)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t2 >= t1)
+ self.assertTrue(t1 != t2)
+ self.assertTrue(t2 != t1)
+ self.assertTrue(not t1 == t2)
+ self.assertTrue(not t2 == t1)
+ self.assertTrue(not t1 > t2)
+ self.assertTrue(not t2 < t1)
+ self.assertTrue(not t1 >= t2)
+ self.assertTrue(not t2 <= t1)
self.assertEqual(cmp(t1, t2), -1)
self.assertEqual(cmp(t2, t1), 1)
@@ -910,6 +1015,7 @@
# compare-by-address (which never says "equal" for distinct
# objects).
return 0
+ __hash__ = None # Silence Py3k warning
# This still errors, because date and datetime comparison raise
# TypeError instead of NotImplemented when they don't know what to
@@ -934,15 +1040,15 @@
their = Comparable()
self.assertEqual(cmp(our, their), 0)
self.assertEqual(cmp(their, our), 0)
- self.failUnless(our == their)
- self.failUnless(their == our)
+ self.assertTrue(our == their)
+ self.assertTrue(their == our)
def test_bool(self):
# All dates are considered true.
- self.failUnless(self.theclass.min)
- self.failUnless(self.theclass.max)
+ self.assertTrue(self.theclass.min)
+ self.assertTrue(self.theclass.max)
- def test_srftime_out_of_range(self):
+ def test_strftime_out_of_range(self):
# For nasty technical reasons, we can't handle years before 1900.
cls = self.theclass
self.assertEqual(cls(1900, 1, 1).strftime("%Y"), "1900")
@@ -970,9 +1076,68 @@
base = cls(2000, 2, 29)
self.assertRaises(ValueError, base.replace, year=2001)
+ def test_subclass_date(self):
+
+ class C(self.theclass):
+ theAnswer = 42
+
+ def __new__(cls, *args, **kws):
+ temp = kws.copy()
+ extra = temp.pop('extra')
+ result = self.theclass.__new__(cls, *args, **temp)
+ result.extra = extra
+ return result
+
+ def newmeth(self, start):
+ return start + self.year + self.month
+
+ args = 2003, 4, 14
+
+ dt1 = self.theclass(*args)
+ dt2 = C(*args, **{'extra': 7})
+
+ self.assertEqual(dt2.__class__, C)
+ self.assertEqual(dt2.theAnswer, 42)
+ self.assertEqual(dt2.extra, 7)
+ self.assertEqual(dt1.toordinal(), dt2.toordinal())
+ self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
+
+ def test_pickling_subclass_date(self):
+
+ args = 6, 7, 23
+ orig = SubclassDate(*args)
+ for pickler, unpickler, proto in pickle_choices:
+ green = pickler.dumps(orig, proto)
+ derived = unpickler.loads(green)
+ self.assertEqual(orig, derived)
+
+ def test_backdoor_resistance(self):
+ # For fast unpickling, the constructor accepts a pickle string.
+ # This is a low-overhead backdoor. A user can (by intent or
+ # mistake) pass a string directly, which (if it's the right length)
+ # will get treated like a pickle, and bypass the normal sanity
+ # checks in the constructor. This can create insane objects.
+ # The constructor doesn't want to burn the time to validate all
+ # fields, but does check the month field. This stops, e.g.,
+ # datetime.datetime('1995-03-25') from yielding an insane object.
+ base = '1995-03-25'
+ if not issubclass(self.theclass, datetime):
+ base = base[:4]
+ for month_byte in '9', chr(0), chr(13), '\xff':
+ self.assertRaises(TypeError, self.theclass,
+ base[:2] + month_byte + base[3:])
+ for ord_byte in range(1, 13):
+ # This shouldn't blow up because of the month byte alone. If
+ # the implementation changes to do more-careful checking, it may
+ # blow up because other fields are insane.
+ self.theclass(base[:2] + chr(ord_byte) + base[3:])
+
#############################################################################
# datetime tests
+class SubclassDatetime(datetime):
+ sub_var = 1
+
class TestDateTime(TestDate):
theclass = datetime
@@ -1004,7 +1169,7 @@
self.theclass.now()):
# Verify dt -> string -> datetime identity.
s = repr(dt)
- self.failUnless(s.startswith('datetime.'))
+ self.assertTrue(s.startswith('datetime.'))
s = s[9:]
dt2 = eval(s)
self.assertEqual(dt, dt2)
@@ -1020,6 +1185,7 @@
self.assertEqual(t.isoformat(), "0002-03-02T04:05:01.000123")
self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123")
self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123")
+ self.assertEqual(t.isoformat('\x00'), "0002-03-02\x0004:05:01.000123")
# str is ISO format with the separator forced to a blank.
self.assertEqual(str(t), "0002-03-02 04:05:01.000123")
@@ -1030,6 +1196,32 @@
# str is ISO format with the separator forced to a blank.
self.assertEqual(str(t), "0002-03-02 00:00:00")
+ def test_format(self):
+ dt = self.theclass(2007, 9, 10, 4, 5, 1, 123)
+ self.assertEqual(dt.__format__(''), str(dt))
+
+ # check that a derived class's __str__() gets called
+ class A(self.theclass):
+ def __str__(self):
+ return 'A'
+ a = A(2007, 9, 10, 4, 5, 1, 123)
+ self.assertEqual(a.__format__(''), 'A')
+
+ # check that a derived class's strftime gets called
+ class B(self.theclass):
+ def strftime(self, format_spec):
+ return 'B'
+ b = B(2007, 9, 10, 4, 5, 1, 123)
+ self.assertEqual(b.__format__(''), str(dt))
+
+ for fmt in ["m:%m d:%d y:%y",
+ "m:%m d:%d y:%y H:%H M:%M S:%S",
+ "%z %Z",
+ ]:
+ self.assertEqual(dt.__format__(fmt), dt.strftime(fmt))
+ self.assertEqual(a.__format__(fmt), dt.strftime(fmt))
+ self.assertEqual(b.__format__(fmt), 'B')
+
def test_more_ctime(self):
# Test fields that TestDate doesn't touch.
import time
@@ -1051,7 +1243,7 @@
dt2 = self.theclass(2002, 3, 1, 10, 0, 0)
dt3 = self.theclass(2002, 3, 1, 9, 0, 0)
self.assertEqual(dt1, dt3)
- self.assert_(dt2 > dt3)
+ self.assertTrue(dt2 > dt3)
# Make sure comparison doesn't forget microseconds, and isn't done
# via comparing a float timestamp (an IEEE double doesn't have enough
@@ -1062,7 +1254,18 @@
us = timedelta(microseconds=1)
dt2 = dt1 + us
self.assertEqual(dt2 - dt1, us)
- self.assert_(dt1 < dt2)
+ self.assertTrue(dt1 < dt2)
+
+ def test_strftime_with_bad_tzname_replace(self):
+ # verify ok if tzinfo.tzname().replace() returns a non-string
+ class MyTzInfo(FixedOffset):
+ def tzname(self, dt):
+ class MyStr(str):
+ def replace(self, *args):
+ return None
+ return MyStr('name')
+ t = self.theclass(2005, 3, 2, 0, 0, 0, 0, MyTzInfo(3, 'name'))
+ self.assertRaises(TypeError, t.strftime, '%Z')
def test_bad_constructor_arguments(self):
# bad years
@@ -1216,6 +1419,14 @@
self.assertEqual(b.month, 2)
self.assertEqual(b.day, 7)
+ def test_pickling_subclass_datetime(self):
+ args = 6, 7, 23, 20, 59, 1, 64**2
+ orig = SubclassDatetime(*args)
+ for pickler, unpickler, proto in pickle_choices:
+ green = pickler.dumps(orig, proto)
+ derived = unpickler.loads(green)
+ self.assertEqual(orig, derived)
+
def test_more_compare(self):
# The test_compare() inherited from TestDate covers the error cases.
# We just want to test lexicographic ordering on the members datetime
@@ -1223,12 +1434,12 @@
args = [2000, 11, 29, 20, 58, 16, 999998]
t1 = self.theclass(*args)
t2 = self.theclass(*args)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
+ self.assertTrue(t1 == t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ self.assertTrue(not t1 != t2)
+ self.assertTrue(not t1 < t2)
+ self.assertTrue(not t1 > t2)
self.assertEqual(cmp(t1, t2), 0)
self.assertEqual(cmp(t2, t1), 0)
@@ -1236,18 +1447,18 @@
newargs = args[:]
newargs[i] = args[i] + 1
t2 = self.theclass(*newargs) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
+ self.assertTrue(t1 < t2)
+ self.assertTrue(t2 > t1)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t2 >= t1)
+ self.assertTrue(t1 != t2)
+ self.assertTrue(t2 != t1)
+ self.assertTrue(not t1 == t2)
+ self.assertTrue(not t2 == t1)
+ self.assertTrue(not t1 > t2)
+ self.assertTrue(not t2 < t1)
+ self.assertTrue(not t1 >= t2)
+ self.assertTrue(not t2 <= t1)
self.assertEqual(cmp(t1, t2), -1)
self.assertEqual(cmp(t2, t1), 1)
@@ -1277,6 +1488,40 @@
got = self.theclass.utcfromtimestamp(ts)
self.verify_field_equality(expected, got)
+ def test_microsecond_rounding(self):
+ # Test whether fromtimestamp "rounds up" floats that are less
+ # than one microsecond smaller than an integer.
+ self.assertEquals(self.theclass.fromtimestamp(0.9999999),
+ self.theclass.fromtimestamp(1))
+
+ def test_insane_fromtimestamp(self):
+ # It's possible that some platform maps time_t to double,
+ # and that this test will fail there. This test should
+ # exempt such platforms (provided they return reasonable
+ # results!).
+ for insane in -1e200, 1e200:
+ self.assertRaises(ValueError, self.theclass.fromtimestamp,
+ insane)
+
+ def test_insane_utcfromtimestamp(self):
+ # It's possible that some platform maps time_t to double,
+ # and that this test will fail there. This test should
+ # exempt such platforms (provided they return reasonable
+ # results!).
+ for insane in -1e200, 1e200:
+ self.assertRaises(ValueError, self.theclass.utcfromtimestamp,
+ insane)
+ @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps")
+ def test_negative_float_fromtimestamp(self):
+ # The result is tz-dependent; at least test that this doesn't
+ # fail (like it did before bug 1646728 was fixed).
+ self.theclass.fromtimestamp(-1.05)
+
+ @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps")
+ def test_negative_float_utcfromtimestamp(self):
+ d = self.theclass.utcfromtimestamp(-1.05)
+ self.assertEquals(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000))
+
def test_utcnow(self):
import time
@@ -1289,7 +1534,17 @@
if abs(from_timestamp - from_now) <= tolerance:
break
# Else try again a few times.
- self.failUnless(abs(from_timestamp - from_now) <= tolerance)
+ self.assertTrue(abs(from_timestamp - from_now) <= tolerance)
+
+ def test_strptime(self):
+ import _strptime
+
+ string = '2004-12-01 13:02:47.197'
+ format = '%Y-%m-%d %H:%M:%S.%f'
+ result, frac = _strptime._strptime(string, format)
+ expected = self.theclass(*(result[0:6]+(frac,)))
+ got = self.theclass.strptime(string, format)
+ self.assertEqual(expected, got)
def test_more_timetuple(self):
# This tests fields beyond those tested by the TestDate.test_timetuple.
@@ -1315,9 +1570,9 @@
def test_more_strftime(self):
# This tests fields beyond those tested by the TestDate.test_strftime.
- t = self.theclass(2004, 12, 31, 6, 22, 33)
- self.assertEqual(t.strftime("%m %d %y %S %M %H %j"),
- "12 31 04 33 22 06 366")
+ t = self.theclass(2004, 12, 31, 6, 22, 33, 47)
+ self.assertEqual(t.strftime("%m %d %y %f %S %M %H %j"),
+ "12 31 04 000047 33 22 06 366")
def test_extract(self):
dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
@@ -1393,7 +1648,37 @@
alsobog = AlsoBogus()
self.assertRaises(ValueError, dt.astimezone, alsobog) # also naive
-class TestTime(HarmlessMixedComparison):
+ def test_subclass_datetime(self):
+
+ class C(self.theclass):
+ theAnswer = 42
+
+ def __new__(cls, *args, **kws):
+ temp = kws.copy()
+ extra = temp.pop('extra')
+ result = self.theclass.__new__(cls, *args, **temp)
+ result.extra = extra
+ return result
+
+ def newmeth(self, start):
+ return start + self.year + self.month + self.second
+
+ args = 2003, 4, 14, 12, 13, 41
+
+ dt1 = self.theclass(*args)
+ dt2 = C(*args, **{'extra': 7})
+
+ self.assertEqual(dt2.__class__, C)
+ self.assertEqual(dt2.theAnswer, 42)
+ self.assertEqual(dt2.extra, 7)
+ self.assertEqual(dt1.toordinal(), dt2.toordinal())
+ self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
+ dt1.second - 7)
+
+class SubclassTime(time):
+ sub_var = 1
+
+class TestTime(HarmlessMixedComparison, unittest.TestCase):
theclass = time
@@ -1418,7 +1703,7 @@
# Verify t -> string -> time identity.
s = repr(t)
- self.failUnless(s.startswith('datetime.'))
+ self.assertTrue(s.startswith('datetime.'))
s = s[9:]
t2 = eval(s)
self.assertEqual(t, t2)
@@ -1432,12 +1717,12 @@
args = [1, 2, 3, 4]
t1 = self.theclass(*args)
t2 = self.theclass(*args)
- self.failUnless(t1 == t2)
- self.failUnless(t1 <= t2)
- self.failUnless(t1 >= t2)
- self.failUnless(not t1 != t2)
- self.failUnless(not t1 < t2)
- self.failUnless(not t1 > t2)
+ self.assertTrue(t1 == t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ self.assertTrue(not t1 != t2)
+ self.assertTrue(not t1 < t2)
+ self.assertTrue(not t1 > t2)
self.assertEqual(cmp(t1, t2), 0)
self.assertEqual(cmp(t2, t1), 0)
@@ -1445,18 +1730,18 @@
newargs = args[:]
newargs[i] = args[i] + 1
t2 = self.theclass(*newargs) # this is larger than t1
- self.failUnless(t1 < t2)
- self.failUnless(t2 > t1)
- self.failUnless(t1 <= t2)
- self.failUnless(t2 >= t1)
- self.failUnless(t1 != t2)
- self.failUnless(t2 != t1)
- self.failUnless(not t1 == t2)
- self.failUnless(not t2 == t1)
- self.failUnless(not t1 > t2)
- self.failUnless(not t2 < t1)
- self.failUnless(not t1 >= t2)
- self.failUnless(not t2 <= t1)
+ self.assertTrue(t1 < t2)
+ self.assertTrue(t2 > t1)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t2 >= t1)
+ self.assertTrue(t1 != t2)
+ self.assertTrue(t2 != t1)
+ self.assertTrue(not t1 == t2)
+ self.assertTrue(not t2 == t1)
+ self.assertTrue(not t1 > t2)
+ self.assertTrue(not t2 < t1)
+ self.assertTrue(not t1 >= t2)
+ self.assertTrue(not t2 <= t1)
self.assertEqual(cmp(t1, t2), -1)
self.assertEqual(cmp(t2, t1), 1)
@@ -1553,12 +1838,41 @@
self.assertEqual(t.isoformat(), "00:00:00.100000")
self.assertEqual(t.isoformat(), str(t))
+ def test_1653736(self):
+ # verify it doesn't accept extra keyword arguments
+ t = self.theclass(second=1)
+ self.assertRaises(TypeError, t.isoformat, foo=3)
+
def test_strftime(self):
t = self.theclass(1, 2, 3, 4)
- self.assertEqual(t.strftime('%H %M %S'), "01 02 03")
+ self.assertEqual(t.strftime('%H %M %S %f'), "01 02 03 000004")
# A naive object replaces %z and %Z with empty strings.
self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
+ def test_format(self):
+ t = self.theclass(1, 2, 3, 4)
+ self.assertEqual(t.__format__(''), str(t))
+
+ # check that a derived class's __str__() gets called
+ class A(self.theclass):
+ def __str__(self):
+ return 'A'
+ a = A(1, 2, 3, 4)
+ self.assertEqual(a.__format__(''), 'A')
+
+ # check that a derived class's strftime gets called
+ class B(self.theclass):
+ def strftime(self, format_spec):
+ return 'B'
+ b = B(1, 2, 3, 4)
+ self.assertEqual(b.__format__(''), str(t))
+
+ for fmt in ['%H %M %S',
+ ]:
+ self.assertEqual(t.__format__(fmt), t.strftime(fmt))
+ self.assertEqual(a.__format__(fmt), t.strftime(fmt))
+ self.assertEqual(b.__format__(fmt), 'B')
+
def test_str(self):
self.assertEqual(str(self.theclass(1, 2, 3, 4)), "01:02:03.000004")
self.assertEqual(str(self.theclass(10, 2, 3, 4000)), "10:02:03.004000")
@@ -1580,10 +1894,10 @@
"%s(23, 15)" % name)
def test_resolution_info(self):
- self.assert_(isinstance(self.theclass.min, self.theclass))
- self.assert_(isinstance(self.theclass.max, self.theclass))
- self.assert_(isinstance(self.theclass.resolution, timedelta))
- self.assert_(self.theclass.max > self.theclass.min)
+ self.assertIsInstance(self.theclass.min, self.theclass)
+ self.assertIsInstance(self.theclass.max, self.theclass)
+ self.assertIsInstance(self.theclass.resolution, timedelta)
+ self.assertTrue(self.theclass.max > self.theclass.min)
def test_pickling(self):
args = 20, 59, 16, 64**2
@@ -1593,14 +1907,22 @@
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ def test_pickling_subclass_time(self):
+ args = 20, 59, 16, 64**2
+ orig = SubclassTime(*args)
+ for pickler, unpickler, proto in pickle_choices:
+ green = pickler.dumps(orig, proto)
+ derived = unpickler.loads(green)
+ self.assertEqual(orig, derived)
+
def test_bool(self):
cls = self.theclass
- self.failUnless(cls(1))
- self.failUnless(cls(0, 1))
- self.failUnless(cls(0, 0, 1))
- self.failUnless(cls(0, 0, 0, 1))
- self.failUnless(not cls(0))
- self.failUnless(not cls())
+ self.assertTrue(cls(1))
+ self.assertTrue(cls(0, 1))
+ self.assertTrue(cls(0, 0, 1))
+ self.assertTrue(cls(0, 0, 0, 1))
+ self.assertTrue(not cls(0))
+ self.assertTrue(not cls())
def test_replace(self):
cls = self.theclass
@@ -1627,10 +1949,43 @@
self.assertRaises(ValueError, base.replace, second=100)
self.assertRaises(ValueError, base.replace, microsecond=1000000)
+ def test_subclass_time(self):
+
+ class C(self.theclass):
+ theAnswer = 42
+
+ def __new__(cls, *args, **kws):
+ temp = kws.copy()
+ extra = temp.pop('extra')
+ result = self.theclass.__new__(cls, *args, **temp)
+ result.extra = extra
+ return result
+
+ def newmeth(self, start):
+ return start + self.hour + self.second
+
+ args = 4, 5, 6
+
+ dt1 = self.theclass(*args)
+ dt2 = C(*args, **{'extra': 7})
+
+ self.assertEqual(dt2.__class__, C)
+ self.assertEqual(dt2.theAnswer, 42)
+ self.assertEqual(dt2.extra, 7)
+ self.assertEqual(dt1.isoformat(), dt2.isoformat())
+ self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
+
+ def test_backdoor_resistance(self):
+ # see TestDate.test_backdoor_resistance().
+ base = '2:59.0'
+ for hour_byte in ' ', '9', chr(24), '\xff':
+ self.assertRaises(TypeError, self.theclass,
+ hour_byte + base[1:])
+
# A mixin for classes with a tzinfo= argument. Subclasses must define
# theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever)
# must be legit (which is true for time and datetime).
-class TZInfoBase(unittest.TestCase):
+class TZInfoBase:
def test_argument_passing(self):
cls = self.theclass
@@ -1664,7 +2019,7 @@
def utcoffset(self, dt): pass
b = BetterTry()
t = cls(1, 1, 1, tzinfo=b)
- self.failUnless(t.tzinfo is b)
+ self.assertTrue(t.tzinfo is b)
def test_utc_offset_out_of_bounds(self):
class Edgy(tzinfo):
@@ -1703,9 +2058,9 @@
for t in (cls(1, 1, 1),
cls(1, 1, 1, tzinfo=None),
cls(1, 1, 1, tzinfo=C1())):
- self.failUnless(t.utcoffset() is None)
- self.failUnless(t.dst() is None)
- self.failUnless(t.tzname() is None)
+ self.assertTrue(t.utcoffset() is None)
+ self.assertTrue(t.dst() is None)
+ self.assertTrue(t.tzname() is None)
class C3(tzinfo):
def utcoffset(self, dt): return timedelta(minutes=-1439)
@@ -1790,7 +2145,7 @@
# Testing time objects with a non-None tzinfo.
-class TestTimeTZ(TestTime, TZInfoBase):
+class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase):
theclass = time
def test_empty(self):
@@ -1799,7 +2154,7 @@
self.assertEqual(t.minute, 0)
self.assertEqual(t.second, 0)
self.assertEqual(t.microsecond, 0)
- self.failUnless(t.tzinfo is None)
+ self.assertTrue(t.tzinfo is None)
def test_zones(self):
est = FixedOffset(-300, "EST", 1)
@@ -1814,25 +2169,25 @@
self.assertEqual(t1.tzinfo, est)
self.assertEqual(t2.tzinfo, utc)
self.assertEqual(t3.tzinfo, met)
- self.failUnless(t4.tzinfo is None)
+ self.assertTrue(t4.tzinfo is None)
self.assertEqual(t5.tzinfo, utc)
self.assertEqual(t1.utcoffset(), timedelta(minutes=-300))
self.assertEqual(t2.utcoffset(), timedelta(minutes=0))
self.assertEqual(t3.utcoffset(), timedelta(minutes=60))
- self.failUnless(t4.utcoffset() is None)
+ self.assertTrue(t4.utcoffset() is None)
self.assertRaises(TypeError, t1.utcoffset, "no args")
self.assertEqual(t1.tzname(), "EST")
self.assertEqual(t2.tzname(), "UTC")
self.assertEqual(t3.tzname(), "MET")
- self.failUnless(t4.tzname() is None)
+ self.assertTrue(t4.tzname() is None)
self.assertRaises(TypeError, t1.tzname, "no args")
self.assertEqual(t1.dst(), timedelta(minutes=1))
self.assertEqual(t2.dst(), timedelta(minutes=-2))
self.assertEqual(t3.dst(), timedelta(minutes=3))
- self.failUnless(t4.dst() is None)
+ self.assertTrue(t4.dst() is None)
self.assertRaises(TypeError, t1.dst, "no args")
self.assertEqual(hash(t1), hash(t2))
@@ -1908,7 +2263,7 @@
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
- self.failUnless(isinstance(derived.tzinfo, PicklableFixedOffset))
+ self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
self.assertEqual(derived.tzname(), 'cookie')
@@ -1917,20 +2272,20 @@
cls = self.theclass
t = cls(0, tzinfo=FixedOffset(-300, ""))
- self.failUnless(t)
+ self.assertTrue(t)
t = cls(5, tzinfo=FixedOffset(-300, ""))
- self.failUnless(t)
+ self.assertTrue(t)
t = cls(5, tzinfo=FixedOffset(300, ""))
- self.failUnless(not t)
+ self.assertTrue(not t)
t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, ""))
- self.failUnless(not t)
+ self.assertTrue(not t)
# Mostly ensuring this doesn't overflow internally.
t = cls(0, tzinfo=FixedOffset(23*60 + 59, ""))
- self.failUnless(t)
+ self.assertTrue(t)
# But this should yield a value error -- the utcoffset is bogus.
t = cls(0, tzinfo=FixedOffset(24*60, ""))
@@ -1964,13 +2319,13 @@
# Ensure we can get rid of a tzinfo.
self.assertEqual(base.tzname(), "+100")
base2 = base.replace(tzinfo=None)
- self.failUnless(base2.tzinfo is None)
- self.failUnless(base2.tzname() is None)
+ self.assertTrue(base2.tzinfo is None)
+ self.assertTrue(base2.tzname() is None)
# Ensure we can add one.
base3 = base2.replace(tzinfo=z100)
self.assertEqual(base, base3)
- self.failUnless(base.tzinfo is base3.tzinfo)
+ self.assertTrue(base.tzinfo is base3.tzinfo)
# Out of bounds.
base = cls(1)
@@ -2007,12 +2362,38 @@
# But if they're not identical, it isn't ignored.
t2 = t2.replace(tzinfo=Varies())
- self.failUnless(t1 < t2) # t1's offset counter still going up
+ self.assertTrue(t1 < t2) # t1's offset counter still going up
+
+ def test_subclass_timetz(self):
+
+ class C(self.theclass):
+ theAnswer = 42
+
+ def __new__(cls, *args, **kws):
+ temp = kws.copy()
+ extra = temp.pop('extra')
+ result = self.theclass.__new__(cls, *args, **temp)
+ result.extra = extra
+ return result
+
+ def newmeth(self, start):
+ return start + self.hour + self.second
+
+ args = 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
+
+ dt1 = self.theclass(*args)
+ dt2 = C(*args, **{'extra': 7})
+
+ self.assertEqual(dt2.__class__, C)
+ self.assertEqual(dt2.theAnswer, 42)
+ self.assertEqual(dt2.extra, 7)
+ self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
+ self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.second - 7)
# Testing datetime objects with a non-None tzinfo.
-class TestDateTimeTZ(TestDateTime, TZInfoBase):
+class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
theclass = datetime
def test_trivial(self):
@@ -2037,12 +2418,12 @@
tzinfo=FixedOffset(-1439, ""))
# Make sure those compare correctly, and w/o overflow.
- self.failUnless(t1 < t2)
- self.failUnless(t1 != t2)
- self.failUnless(t2 > t1)
+ self.assertTrue(t1 < t2)
+ self.assertTrue(t1 != t2)
+ self.assertTrue(t2 > t1)
- self.failUnless(t1 == t1)
- self.failUnless(t2 == t2)
+ self.assertTrue(t1 == t1)
+ self.assertTrue(t2 == t2)
# Equal afer adjustment.
t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""))
@@ -2051,21 +2432,21 @@
# Change t1 not to subtract a minute, and t1 should be larger.
t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, ""))
- self.failUnless(t1 > t2)
+ self.assertTrue(t1 > t2)
# Change t1 to subtract 2 minutes, and t1 should be smaller.
t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, ""))
- self.failUnless(t1 < t2)
+ self.assertTrue(t1 < t2)
# Back to the original t1, but make seconds resolve it.
t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
second=1)
- self.failUnless(t1 > t2)
+ self.assertTrue(t1 > t2)
# Likewise, but make microseconds resolve it.
t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""),
microsecond=1)
- self.failUnless(t1 > t2)
+ self.assertTrue(t1 > t2)
# Make t2 naive and it should fail.
t2 = self.theclass.min
@@ -2109,8 +2490,7 @@
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
- self.failUnless(isinstance(derived.tzinfo,
- PicklableFixedOffset))
+ self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
self.assertEqual(derived.tzname(), 'cookie')
@@ -2180,7 +2560,7 @@
tz55 = FixedOffset(-330, "west 5:30")
timeaware = now.time().replace(tzinfo=tz55)
nowaware = self.theclass.combine(now.date(), timeaware)
- self.failUnless(nowaware.tzinfo is tz55)
+ self.assertTrue(nowaware.tzinfo is tz55)
self.assertEqual(nowaware.timetz(), timeaware)
# Can't mix aware and non-aware.
@@ -2199,15 +2579,15 @@
# Adding a delta should preserve tzinfo.
delta = timedelta(weeks=1, minutes=12, microseconds=5678)
nowawareplus = nowaware + delta
- self.failUnless(nowaware.tzinfo is tz55)
+ self.assertTrue(nowaware.tzinfo is tz55)
nowawareplus2 = delta + nowaware
- self.failUnless(nowawareplus2.tzinfo is tz55)
+ self.assertTrue(nowawareplus2.tzinfo is tz55)
self.assertEqual(nowawareplus, nowawareplus2)
# that - delta should be what we started with, and that - what we
# started with should be delta.
diff = nowawareplus - delta
- self.failUnless(diff.tzinfo is tz55)
+ self.assertTrue(diff.tzinfo is tz55)
self.assertEqual(nowaware, diff)
self.assertRaises(TypeError, lambda: delta - nowawareplus)
self.assertEqual(nowawareplus - nowaware, delta)
@@ -2216,7 +2596,7 @@
tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone")
# Attach it to nowawareplus.
nowawareplus = nowawareplus.replace(tzinfo=tzr)
- self.failUnless(nowawareplus.tzinfo is tzr)
+ self.assertTrue(nowawareplus.tzinfo is tzr)
# Make sure the difference takes the timezone adjustments into account.
got = nowaware - nowawareplus
# Expected: (nowaware base - nowaware offset) -
@@ -2243,7 +2623,7 @@
off42 = FixedOffset(42, "42")
another = meth(off42)
again = meth(tz=off42)
- self.failUnless(another.tzinfo is again.tzinfo)
+ self.assertTrue(another.tzinfo is again.tzinfo)
self.assertEqual(another.utcoffset(), timedelta(minutes=42))
# Bad argument with and w/o naming the keyword.
self.assertRaises(TypeError, meth, 16)
@@ -2260,7 +2640,7 @@
utc = FixedOffset(0, "utc", 0)
for dummy in range(3):
now = datetime.now(weirdtz)
- self.failUnless(now.tzinfo is weirdtz)
+ self.assertTrue(now.tzinfo is weirdtz)
utcnow = datetime.utcnow().replace(tzinfo=utc)
now2 = utcnow.astimezone(weirdtz)
if abs(now - now2) < timedelta(seconds=30):
@@ -2281,7 +2661,7 @@
off42 = FixedOffset(42, "42")
another = meth(ts, off42)
again = meth(ts, tz=off42)
- self.failUnless(another.tzinfo is again.tzinfo)
+ self.assertTrue(another.tzinfo is again.tzinfo)
self.assertEqual(another.utcoffset(), timedelta(minutes=42))
# Bad argument with and w/o naming the keyword.
self.assertRaises(TypeError, meth, ts, 16)
@@ -2475,13 +2855,13 @@
# Ensure we can get rid of a tzinfo.
self.assertEqual(base.tzname(), "+100")
base2 = base.replace(tzinfo=None)
- self.failUnless(base2.tzinfo is None)
- self.failUnless(base2.tzname() is None)
+ self.assertTrue(base2.tzinfo is None)
+ self.assertTrue(base2.tzname() is None)
# Ensure we can add one.
base3 = base2.replace(tzinfo=z100)
self.assertEqual(base, base3)
- self.failUnless(base.tzinfo is base3.tzinfo)
+ self.assertTrue(base.tzinfo is base3.tzinfo)
# Out of bounds.
base = cls(2000, 2, 29)
@@ -2494,20 +2874,20 @@
fm5h = FixedOffset(-timedelta(hours=5), "m300")
dt = self.theclass.now(tz=f44m)
- self.failUnless(dt.tzinfo is f44m)
+ self.assertTrue(dt.tzinfo is f44m)
# Replacing with degenerate tzinfo raises an exception.
self.assertRaises(ValueError, dt.astimezone, fnone)
# Ditto with None tz.
self.assertRaises(TypeError, dt.astimezone, None)
# Replacing with same tzinfo makes no change.
x = dt.astimezone(dt.tzinfo)
- self.failUnless(x.tzinfo is f44m)
+ self.assertTrue(x.tzinfo is f44m)
self.assertEqual(x.date(), dt.date())
self.assertEqual(x.time(), dt.time())
# Replacing with different tzinfo does adjust.
got = dt.astimezone(fm5h)
- self.failUnless(got.tzinfo is fm5h)
+ self.assertTrue(got.tzinfo is fm5h)
self.assertEqual(got.utcoffset(), timedelta(hours=-5))
expected = dt - dt.utcoffset() # in effect, convert to UTC
expected += fm5h.utcoffset(dt) # and from there to local time
@@ -2515,7 +2895,7 @@
self.assertEqual(got.date(), expected.date())
self.assertEqual(got.time(), expected.time())
self.assertEqual(got.timetz(), expected.timetz())
- self.failUnless(got.tzinfo is expected.tzinfo)
+ self.assertTrue(got.tzinfo is expected.tzinfo)
self.assertEqual(got, expected)
def test_aware_subtract(self):
@@ -2590,7 +2970,33 @@
# But if they're not identical, it isn't ignored.
t2 = t2.replace(tzinfo=Varies())
- self.failUnless(t1 < t2) # t1's offset counter still going up
+ self.assertTrue(t1 < t2) # t1's offset counter still going up
+
+ def test_subclass_datetimetz(self):
+
+ class C(self.theclass):
+ theAnswer = 42
+
+ def __new__(cls, *args, **kws):
+ temp = kws.copy()
+ extra = temp.pop('extra')
+ result = self.theclass.__new__(cls, *args, **temp)
+ result.extra = extra
+ return result
+
+ def newmeth(self, start):
+ return start + self.hour + self.year
+
+ args = 2002, 12, 31, 4, 5, 6, 500, FixedOffset(-300, "EST", 1)
+
+ dt1 = self.theclass(*args)
+ dt2 = C(*args, **{'extra': 7})
+
+ self.assertEqual(dt2.__class__, C)
+ self.assertEqual(dt2.theAnswer, 42)
+ self.assertEqual(dt2.extra, 7)
+ self.assertEqual(dt1.utcoffset(), dt2.utcoffset())
+ self.assertEqual(dt2.newmeth(-7), dt1.hour + dt1.year - 7)
# Pain to set up DST-aware tzinfo classes.
@@ -2904,45 +3310,51 @@
start += HOUR
fstart += HOUR
-def test_suite():
- allsuites = [unittest.makeSuite(klass, 'test')
- for klass in (TestModule,
- TestTZInfo,
- TestTimeDelta,
- TestDateOnly,
- TestDate,
- TestDateTime,
- TestTime,
- TestTimeTZ,
- TestDateTimeTZ,
- TestTimezoneConversions,
- )
- ]
- return unittest.TestSuite(allsuites)
-def test_main():
- import gc
- import sys
+#############################################################################
+# oddballs
- r = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
- s = test_suite()
- lastrc = None
- while True:
- r.run(s)
- if 1: # change to 0, under a debug build, for some leak detection
- break
- gc.collect()
- if gc.garbage:
- raise SystemError("gc.garbage not empty after test run: %r" %
- gc.garbage)
- if hasattr(sys, 'gettotalrefcount'):
- thisrc = sys.gettotalrefcount()
- print >> sys.stderr, '*' * 10, 'total refs:', thisrc,
- if lastrc:
- print >> sys.stderr, 'delta:', thisrc - lastrc
- else:
- print >> sys.stderr
- lastrc = thisrc
+class Oddballs(unittest.TestCase):
+
+ def test_bug_1028306(self):
+ # Trying to compare a date to a datetime should act like a mixed-
+ # type comparison, despite that datetime is a subclass of date.
+ as_date = date.today()
+ as_datetime = datetime.combine(as_date, time())
+ self.assertTrue(as_date != as_datetime)
+ self.assertTrue(as_datetime != as_date)
+ self.assertTrue(not as_date == as_datetime)
+ self.assertTrue(not as_datetime == as_date)
+ self.assertRaises(TypeError, lambda: as_date < as_datetime)
+ self.assertRaises(TypeError, lambda: as_datetime < as_date)
+ self.assertRaises(TypeError, lambda: as_date <= as_datetime)
+ self.assertRaises(TypeError, lambda: as_datetime <= as_date)
+ self.assertRaises(TypeError, lambda: as_date > as_datetime)
+ self.assertRaises(TypeError, lambda: as_datetime > as_date)
+ self.assertRaises(TypeError, lambda: as_date >= as_datetime)
+ self.assertRaises(TypeError, lambda: as_datetime >= as_date)
+
+ # Neverthelss, comparison should work with the base-class (date)
+ # projection if use of a date method is forced.
+ self.assertTrue(as_date.__eq__(as_datetime))
+ different_day = (as_date.day + 1) % 20 + 1
+ self.assertTrue(not as_date.__eq__(as_datetime.replace(day=
+ different_day)))
+
+ # And date should compare with other subclasses of date. If a
+ # subclass wants to stop this, it's up to the subclass to do so.
+ date_sc = SubclassDate(as_date.year, as_date.month, as_date.day)
+ self.assertEqual(as_date, date_sc)
+ self.assertEqual(date_sc, as_date)
+
+ # Ditto for datetimes.
+ datetime_sc = SubclassDatetime(as_datetime.year, as_datetime.month,
+ as_date.day, 0, 0, 0)
+ self.assertEqual(as_datetime, datetime_sc)
+ self.assertEqual(datetime_sc, as_datetime)
+
+def test_main():
+ test_support.run_unittest(__name__)
if __name__ == "__main__":
test_main()
More information about the Python-checkins
mailing list