Skip to content

Commit 626999b

Browse files
committed
Make doctests run in date module
This needed to fake the "now" time in the doctests to reproduce results. Note that this also fixes some errors in Range parsing discovered during test creation.
1 parent 0ac2471 commit 626999b

File tree

1 file changed

+78
-28
lines changed

1 file changed

+78
-28
lines changed

roundup/date.py

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
(?P<n>\.)? # .
4040
(((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d?(\.\d+)?))?)? # hh:mm:ss
4141
(?P<o>[\d\smywd\-+]+)? # offset
42+
(?P<tz>[+-]\d{4})? # time-zone offset
4243
$''', re.VERBOSE)
4344
serialised_date_re = re.compile(r'''
4445
(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d?(\.\d+)?)
@@ -158,6 +159,19 @@ def _local_to_utc(y,m,d,H,M,S,tz):
158159
y,m,d,H,M,S = TZ.localize(dt).utctimetuple()[:6]
159160
return (y,m,d,H,M,S)
160161

162+
def test_ini(t):
163+
""" Monkey-patch to make doctest think it's always time t:
164+
"""
165+
u = Date.now
166+
d = datetime.datetime.strptime (t, '%Y-%m-%d.%H:%M:%S.%f')
167+
Date.now = lambda x : d
168+
return u
169+
170+
def test_fin(u):
171+
""" Undo monkey patch above
172+
"""
173+
Date.now = u
174+
161175
class Date:
162176
'''
163177
As strings, date-and-time stamps are specified with the date in
@@ -166,7 +180,7 @@ class Date:
166180
and are fairly readable when printed. An example of a valid stamp is
167181
"2000-06-24.13:03:59". We'll call this the "full date format". When
168182
Timestamp objects are printed as strings, they appear in the full date
169-
format with the time always given in GMT. The full date format is
183+
format with the time always given in UTC. The full date format is
170184
always exactly 19 characters long.
171185
172186
For user input, some partial forms are also permitted: the whole time
@@ -197,40 +211,46 @@ class Date:
197211
2000-08-04 (rather than trying to decide whether 1m 10d means 38 or 40
198212
or 41 days). Example usage::
199213
214+
make doctest think it's always 2000-06-26.00:34:02:
215+
>>> u = test_ini('2000-06-26.00:34:02.0')
216+
200217
>>> Date(".")
201-
<Date 2000-06-26.00:34:02>
218+
<Date 2000-06-26.00:34:02.000>
202219
>>> _.local(-5)
203-
"2000-06-25.19:34:02"
220+
<Date 2000-06-25.19:34:02.000>
204221
>>> Date(". + 2d")
205-
<Date 2000-06-28.00:34:02>
222+
<Date 2000-06-28.00:34:02.000>
206223
>>> Date("1997-04-17", -5)
207-
<Date 1997-04-17.00:00:00>
224+
<Date 1997-04-17.05:00:00.000>
208225
>>> Date("01-25", -5)
209-
<Date 2000-01-25.00:00:00>
226+
<Date 2000-01-25.05:00:00.000>
210227
>>> Date("08-13.22:13", -5)
211-
<Date 2000-08-14.03:13:00>
228+
<Date 2000-08-14.03:13:00.000>
212229
>>> Date("14:25", -5)
213-
<Date 2000-06-25.19:25:00>
230+
<Date 2000-06-26.19:25:00.000>
214231
215232
The date format 'yyyymmddHHMMSS' (year, month, day, hour,
216233
minute, second) is the serialisation format returned by the serialise()
217234
method, and is accepted as an argument on instatiation.
218235
219236
The date class handles basic arithmetic::
220237
238+
>>> x=test_ini('2004-04-06.22:04:20.766830')
221239
>>> d1=Date('.')
222240
>>> d1
223-
<Date 2004-04-06.22:04:20.766830>
241+
<Date 2004-04-06.22:04:20.767>
224242
>>> d2=Date('2003-07-01')
225243
>>> d2
226-
<Date 2003-07-01.00:00:0.000000>
244+
<Date 2003-07-01.00:00:00.000>
227245
>>> d1-d2
228246
<Interval + 280d 22:04:20>
229247
>>> i1=_
230248
>>> d2+i1
231-
<Date 2004-04-06.22:04:20.000000>
249+
<Date 2004-04-06.22:04:20.000>
232250
>>> d1-i1
233-
<Date 2003-07-01.00:00:0.000000>
251+
<Date 2003-07-01.00:00:00.000>
252+
253+
>>> test_fin(u)
234254
'''
235255

236256
def __init__(self, spec='.', offset=0, add_granularity=False,
@@ -281,6 +301,11 @@ def __init__(self, spec='.', offset=0, add_granularity=False,
281301
except:
282302
raise ValueError, 'Unknown spec %r' % (spec,)
283303

304+
def now(self):
305+
""" To be able to override for testing
306+
"""
307+
return datetime.datetime.utcnow()
308+
284309
def set(self, spec, offset=0, date_re=date_re,
285310
serialised_re=serialised_date_re, add_granularity=False):
286311
''' set the date to the value in spec
@@ -298,9 +323,9 @@ def set(self, spec, offset=0, date_re=date_re,
298323
# not serialised data, try usual format
299324
m = date_re.match(spec)
300325
if m is None:
301-
raise ValueError, self._('Not a date spec: '
302-
'"yyyy-mm-dd", "mm-dd", "HH:MM", "HH:MM:SS" or '
303-
'"yyyy-mm-dd.HH:MM:SS.SSS"')
326+
raise ValueError, self._('Not a date spec: %r '
327+
'("yyyy-mm-dd", "mm-dd", "HH:MM", "HH:MM:SS" or '
328+
'"yyyy-mm-dd.HH:MM:SS.SSS")' % spec)
304329

305330
info = m.groupdict()
306331

@@ -324,7 +349,7 @@ def set(self, spec, offset=0, date_re=date_re,
324349
raise ValueError(self._('Could not determine granularity'))
325350

326351
# get the current date as our default
327-
dt = datetime.datetime.utcnow()
352+
dt = self.now()
328353
y,m,d,H,M,S,x,x,x = dt.timetuple()
329354
S += dt.microsecond/1000000.
330355

@@ -603,10 +628,13 @@ class Interval:
603628
"0:04:33" means four minutes and 33 seconds
604629
605630
Example usage:
631+
make doctest think it's always 2000-06-26.00:34:02:
632+
>>> u = test_ini('2000-06-26.00:34:02.0')
633+
606634
>>> Interval(" 3w 1 d 2:00")
607635
<Interval + 22d 2:00>
608636
>>> Date(". + 2d") + Interval("- 3w")
609-
<Date 2000-06-07.00:34:02>
637+
<Date 2000-06-07.00:34:02.000>
610638
>>> Interval('1:59:59') + Interval('00:00:01')
611639
<Interval + 2:00>
612640
>>> Interval('2:00') + Interval('- 00:00:01')
@@ -615,10 +643,16 @@ class Interval:
615643
<Interval + 6m>
616644
>>> Interval('1:00')/2
617645
<Interval + 0:30>
646+
647+
[number of days between 2000-06-26.00:34:02 and 2003-03-18
618648
>>> Interval('2003-03-18')
619-
<Interval + [number of days between now and 2003-03-18]>
649+
<Interval - 995d>
650+
651+
[number of days between 2000-06-26.00:34:02 and 2003-03-14
620652
>>> Interval('-4d 2003-03-18')
621-
<Interval + [number of days between now and 2003-03-14]>
653+
<Interval - 991d>
654+
655+
>>> test_fin(u)
622656
623657
Interval arithmetic is handled in a couple of special ways, trying
624658
to cater for the most common cases. Fundamentally, Intervals which
@@ -1011,24 +1045,40 @@ class Range:
10111045
10121046
Examples (consider local time is Sat Mar 8 22:07:48 EET 2003)::
10131047
1014-
>>> Range("from 2-12 to 4-2")
1048+
make doctest think it's always 2000-06-26.00:34:02:
1049+
>>> u = test_ini('2003-03-08.20:07:48.0')
1050+
1051+
>>> Range("from 2-12 to 4-2", Date)
10151052
<Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
10161053
1017-
>>> Range("18:00 TO +2m")
1054+
>>> Range("18:00 to +2m", Date)
10181055
<Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
10191056
1020-
>>> Range("12:00")
1057+
>>> Range("tO +3d", Date)
1058+
<Range from None to 2003-03-11.20:07:48>
1059+
1060+
>>> Range("12:00 to", Date)
10211061
<Range from 2003-03-08.12:00:00 to None>
10221062
1023-
>>> Range("tO +3d")
1024-
<Range from None to 2003-03-11.20:07:48>
1063+
>>> Range("12:00;", Date)
1064+
<Range from 2003-03-08.12:00:00 to None>
10251065
1026-
>>> Range("2002-11-10; 2002-12-12")
1066+
>>> Range("2002-11-10; 2002-12-12", Date)
10271067
<Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
10281068
1029-
>>> Range("; 20:00 +1d")
1069+
>>> Range("; 20:00 +1d", Date)
10301070
<Range from None to 2003-03-09.20:00:00>
10311071
1072+
Granularity tests:
1073+
1074+
>>> Range("12:00", Date)
1075+
<Range from 2003-03-08.12:00:00 to 2003-03-08.12:00:59>
1076+
1077+
>>> Range("2003-03-08", Date)
1078+
<Range from 2003-03-08.00:00:00 to 2003-03-08.23:59:59>
1079+
1080+
>>> test_fin(u)
1081+
10321082
"""
10331083
def __init__(self, spec, Type, allow_granularity=True, **params):
10341084
"""Initializes Range of type <Type> from given <spec> string.
@@ -1041,8 +1091,8 @@ def __init__(self, spec, Type, allow_granularity=True, **params):
10411091
class instance.
10421092
"""
10431093
self.range_type = Type
1044-
re_range = r'(?:^|from(.+?))(?:to(.+?)$|$)'
1045-
re_geek_range = r'(?:^|(.+?));(?:(.+?)$|$)'
1094+
re_range = r'^(?:from)?(.+?)?to(.+?)?$'
1095+
re_geek_range = r'^(.+?)?;(.+?)?$'
10461096
# Check which syntax to use
10471097
if ';' in spec:
10481098
# Geek

0 commit comments

Comments
 (0)