1 | n/a | """PyUnit testing against strptime""" |
---|
2 | n/a | |
---|
3 | n/a | import unittest |
---|
4 | n/a | import time |
---|
5 | n/a | import locale |
---|
6 | n/a | import re |
---|
7 | n/a | import os |
---|
8 | n/a | from test import support |
---|
9 | n/a | from datetime import date as datetime_date |
---|
10 | n/a | |
---|
11 | n/a | import _strptime |
---|
12 | n/a | |
---|
13 | n/a | class getlang_Tests(unittest.TestCase): |
---|
14 | n/a | """Test _getlang""" |
---|
15 | n/a | def test_basic(self): |
---|
16 | n/a | self.assertEqual(_strptime._getlang(), locale.getlocale(locale.LC_TIME)) |
---|
17 | n/a | |
---|
18 | n/a | class LocaleTime_Tests(unittest.TestCase): |
---|
19 | n/a | """Tests for _strptime.LocaleTime. |
---|
20 | n/a | |
---|
21 | n/a | All values are lower-cased when stored in LocaleTime, so make sure to |
---|
22 | n/a | compare values after running ``lower`` on them. |
---|
23 | n/a | |
---|
24 | n/a | """ |
---|
25 | n/a | |
---|
26 | n/a | def setUp(self): |
---|
27 | n/a | """Create time tuple based on current time.""" |
---|
28 | n/a | self.time_tuple = time.localtime() |
---|
29 | n/a | self.LT_ins = _strptime.LocaleTime() |
---|
30 | n/a | |
---|
31 | n/a | def compare_against_time(self, testing, directive, tuple_position, |
---|
32 | n/a | error_msg): |
---|
33 | n/a | """Helper method that tests testing against directive based on the |
---|
34 | n/a | tuple_position of time_tuple. Uses error_msg as error message. |
---|
35 | n/a | |
---|
36 | n/a | """ |
---|
37 | n/a | strftime_output = time.strftime(directive, self.time_tuple).lower() |
---|
38 | n/a | comparison = testing[self.time_tuple[tuple_position]] |
---|
39 | n/a | self.assertIn(strftime_output, testing, |
---|
40 | n/a | "%s: not found in tuple" % error_msg) |
---|
41 | n/a | self.assertEqual(comparison, strftime_output, |
---|
42 | n/a | "%s: position within tuple incorrect; %s != %s" % |
---|
43 | n/a | (error_msg, comparison, strftime_output)) |
---|
44 | n/a | |
---|
45 | n/a | def test_weekday(self): |
---|
46 | n/a | # Make sure that full and abbreviated weekday names are correct in |
---|
47 | n/a | # both string and position with tuple |
---|
48 | n/a | self.compare_against_time(self.LT_ins.f_weekday, '%A', 6, |
---|
49 | n/a | "Testing of full weekday name failed") |
---|
50 | n/a | self.compare_against_time(self.LT_ins.a_weekday, '%a', 6, |
---|
51 | n/a | "Testing of abbreviated weekday name failed") |
---|
52 | n/a | |
---|
53 | n/a | def test_month(self): |
---|
54 | n/a | # Test full and abbreviated month names; both string and position |
---|
55 | n/a | # within the tuple |
---|
56 | n/a | self.compare_against_time(self.LT_ins.f_month, '%B', 1, |
---|
57 | n/a | "Testing against full month name failed") |
---|
58 | n/a | self.compare_against_time(self.LT_ins.a_month, '%b', 1, |
---|
59 | n/a | "Testing against abbreviated month name failed") |
---|
60 | n/a | |
---|
61 | n/a | def test_am_pm(self): |
---|
62 | n/a | # Make sure AM/PM representation done properly |
---|
63 | n/a | strftime_output = time.strftime("%p", self.time_tuple).lower() |
---|
64 | n/a | self.assertIn(strftime_output, self.LT_ins.am_pm, |
---|
65 | n/a | "AM/PM representation not in tuple") |
---|
66 | n/a | if self.time_tuple[3] < 12: position = 0 |
---|
67 | n/a | else: position = 1 |
---|
68 | n/a | self.assertEqual(self.LT_ins.am_pm[position], strftime_output, |
---|
69 | n/a | "AM/PM representation in the wrong position within the tuple") |
---|
70 | n/a | |
---|
71 | n/a | def test_timezone(self): |
---|
72 | n/a | # Make sure timezone is correct |
---|
73 | n/a | timezone = time.strftime("%Z", self.time_tuple).lower() |
---|
74 | n/a | if timezone: |
---|
75 | n/a | self.assertTrue(timezone in self.LT_ins.timezone[0] or |
---|
76 | n/a | timezone in self.LT_ins.timezone[1], |
---|
77 | n/a | "timezone %s not found in %s" % |
---|
78 | n/a | (timezone, self.LT_ins.timezone)) |
---|
79 | n/a | |
---|
80 | n/a | def test_date_time(self): |
---|
81 | n/a | # Check that LC_date_time, LC_date, and LC_time are correct |
---|
82 | n/a | # the magic date is used so as to not have issues with %c when day of |
---|
83 | n/a | # the month is a single digit and has a leading space. This is not an |
---|
84 | n/a | # issue since strptime still parses it correctly. The problem is |
---|
85 | n/a | # testing these directives for correctness by comparing strftime |
---|
86 | n/a | # output. |
---|
87 | n/a | magic_date = (1999, 3, 17, 22, 44, 55, 2, 76, 0) |
---|
88 | n/a | strftime_output = time.strftime("%c", magic_date) |
---|
89 | n/a | self.assertEqual(time.strftime(self.LT_ins.LC_date_time, magic_date), |
---|
90 | n/a | strftime_output, "LC_date_time incorrect") |
---|
91 | n/a | strftime_output = time.strftime("%x", magic_date) |
---|
92 | n/a | self.assertEqual(time.strftime(self.LT_ins.LC_date, magic_date), |
---|
93 | n/a | strftime_output, "LC_date incorrect") |
---|
94 | n/a | strftime_output = time.strftime("%X", magic_date) |
---|
95 | n/a | self.assertEqual(time.strftime(self.LT_ins.LC_time, magic_date), |
---|
96 | n/a | strftime_output, "LC_time incorrect") |
---|
97 | n/a | LT = _strptime.LocaleTime() |
---|
98 | n/a | LT.am_pm = ('', '') |
---|
99 | n/a | self.assertTrue(LT.LC_time, "LocaleTime's LC directives cannot handle " |
---|
100 | n/a | "empty strings") |
---|
101 | n/a | |
---|
102 | n/a | def test_lang(self): |
---|
103 | n/a | # Make sure lang is set to what _getlang() returns |
---|
104 | n/a | # Assuming locale has not changed between now and when self.LT_ins was created |
---|
105 | n/a | self.assertEqual(self.LT_ins.lang, _strptime._getlang()) |
---|
106 | n/a | |
---|
107 | n/a | |
---|
108 | n/a | class TimeRETests(unittest.TestCase): |
---|
109 | n/a | """Tests for TimeRE.""" |
---|
110 | n/a | |
---|
111 | n/a | def setUp(self): |
---|
112 | n/a | """Construct generic TimeRE object.""" |
---|
113 | n/a | self.time_re = _strptime.TimeRE() |
---|
114 | n/a | self.locale_time = _strptime.LocaleTime() |
---|
115 | n/a | |
---|
116 | n/a | def test_pattern(self): |
---|
117 | n/a | # Test TimeRE.pattern |
---|
118 | n/a | pattern_string = self.time_re.pattern(r"%a %A %d") |
---|
119 | n/a | self.assertTrue(pattern_string.find(self.locale_time.a_weekday[2]) != -1, |
---|
120 | n/a | "did not find abbreviated weekday in pattern string '%s'" % |
---|
121 | n/a | pattern_string) |
---|
122 | n/a | self.assertTrue(pattern_string.find(self.locale_time.f_weekday[4]) != -1, |
---|
123 | n/a | "did not find full weekday in pattern string '%s'" % |
---|
124 | n/a | pattern_string) |
---|
125 | n/a | self.assertTrue(pattern_string.find(self.time_re['d']) != -1, |
---|
126 | n/a | "did not find 'd' directive pattern string '%s'" % |
---|
127 | n/a | pattern_string) |
---|
128 | n/a | |
---|
129 | n/a | def test_pattern_escaping(self): |
---|
130 | n/a | # Make sure any characters in the format string that might be taken as |
---|
131 | n/a | # regex syntax is escaped. |
---|
132 | n/a | pattern_string = self.time_re.pattern(r"\d+") |
---|
133 | n/a | self.assertIn(r"\\d\+", pattern_string, |
---|
134 | n/a | "%s does not have re characters escaped properly" % |
---|
135 | n/a | pattern_string) |
---|
136 | n/a | |
---|
137 | n/a | def test_compile(self): |
---|
138 | n/a | # Check that compiled regex is correct |
---|
139 | n/a | found = self.time_re.compile(r"%A").match(self.locale_time.f_weekday[6]) |
---|
140 | n/a | self.assertTrue(found and found.group('A') == self.locale_time.f_weekday[6], |
---|
141 | n/a | "re object for '%A' failed") |
---|
142 | n/a | compiled = self.time_re.compile(r"%a %b") |
---|
143 | n/a | found = compiled.match("%s %s" % (self.locale_time.a_weekday[4], |
---|
144 | n/a | self.locale_time.a_month[4])) |
---|
145 | n/a | self.assertTrue(found, |
---|
146 | n/a | "Match failed with '%s' regex and '%s' string" % |
---|
147 | n/a | (compiled.pattern, "%s %s" % (self.locale_time.a_weekday[4], |
---|
148 | n/a | self.locale_time.a_month[4]))) |
---|
149 | n/a | self.assertTrue(found.group('a') == self.locale_time.a_weekday[4] and |
---|
150 | n/a | found.group('b') == self.locale_time.a_month[4], |
---|
151 | n/a | "re object couldn't find the abbreviated weekday month in " |
---|
152 | n/a | "'%s' using '%s'; group 'a' = '%s', group 'b' = %s'" % |
---|
153 | n/a | (found.string, found.re.pattern, found.group('a'), |
---|
154 | n/a | found.group('b'))) |
---|
155 | n/a | for directive in ('a','A','b','B','c','d','G','H','I','j','m','M','p', |
---|
156 | n/a | 'S','u','U','V','w','W','x','X','y','Y','Z','%'): |
---|
157 | n/a | compiled = self.time_re.compile("%" + directive) |
---|
158 | n/a | found = compiled.match(time.strftime("%" + directive)) |
---|
159 | n/a | self.assertTrue(found, "Matching failed on '%s' using '%s' regex" % |
---|
160 | n/a | (time.strftime("%" + directive), |
---|
161 | n/a | compiled.pattern)) |
---|
162 | n/a | |
---|
163 | n/a | def test_blankpattern(self): |
---|
164 | n/a | # Make sure when tuple or something has no values no regex is generated. |
---|
165 | n/a | # Fixes bug #661354 |
---|
166 | n/a | test_locale = _strptime.LocaleTime() |
---|
167 | n/a | test_locale.timezone = (frozenset(), frozenset()) |
---|
168 | n/a | self.assertEqual(_strptime.TimeRE(test_locale).pattern("%Z"), '', |
---|
169 | n/a | "with timezone == ('',''), TimeRE().pattern('%Z') != ''") |
---|
170 | n/a | |
---|
171 | n/a | def test_matching_with_escapes(self): |
---|
172 | n/a | # Make sure a format that requires escaping of characters works |
---|
173 | n/a | compiled_re = self.time_re.compile(r"\w+ %m") |
---|
174 | n/a | found = compiled_re.match(r"\w+ 10") |
---|
175 | n/a | self.assertTrue(found, r"Escaping failed of format '\w+ 10'") |
---|
176 | n/a | |
---|
177 | n/a | def test_locale_data_w_regex_metacharacters(self): |
---|
178 | n/a | # Check that if locale data contains regex metacharacters they are |
---|
179 | n/a | # escaped properly. |
---|
180 | n/a | # Discovered by bug #1039270 . |
---|
181 | n/a | locale_time = _strptime.LocaleTime() |
---|
182 | n/a | locale_time.timezone = (frozenset(("utc", "gmt", |
---|
183 | n/a | "Tokyo (standard time)")), |
---|
184 | n/a | frozenset("Tokyo (daylight time)")) |
---|
185 | n/a | time_re = _strptime.TimeRE(locale_time) |
---|
186 | n/a | self.assertTrue(time_re.compile("%Z").match("Tokyo (standard time)"), |
---|
187 | n/a | "locale data that contains regex metacharacters is not" |
---|
188 | n/a | " properly escaped") |
---|
189 | n/a | |
---|
190 | n/a | def test_whitespace_substitution(self): |
---|
191 | n/a | # When pattern contains whitespace, make sure it is taken into account |
---|
192 | n/a | # so as to not allow subpatterns to end up next to each other and |
---|
193 | n/a | # "steal" characters from each other. |
---|
194 | n/a | pattern = self.time_re.pattern('%j %H') |
---|
195 | n/a | self.assertFalse(re.match(pattern, "180")) |
---|
196 | n/a | self.assertTrue(re.match(pattern, "18 0")) |
---|
197 | n/a | |
---|
198 | n/a | |
---|
199 | n/a | class StrptimeTests(unittest.TestCase): |
---|
200 | n/a | """Tests for _strptime.strptime.""" |
---|
201 | n/a | |
---|
202 | n/a | def setUp(self): |
---|
203 | n/a | """Create testing time tuple.""" |
---|
204 | n/a | self.time_tuple = time.gmtime() |
---|
205 | n/a | |
---|
206 | n/a | def test_ValueError(self): |
---|
207 | n/a | # Make sure ValueError is raised when match fails or format is bad |
---|
208 | n/a | self.assertRaises(ValueError, _strptime._strptime_time, data_string="%d", |
---|
209 | n/a | format="%A") |
---|
210 | n/a | for bad_format in ("%", "% ", "%e"): |
---|
211 | n/a | try: |
---|
212 | n/a | _strptime._strptime_time("2005", bad_format) |
---|
213 | n/a | except ValueError: |
---|
214 | n/a | continue |
---|
215 | n/a | except Exception as err: |
---|
216 | n/a | self.fail("'%s' raised %s, not ValueError" % |
---|
217 | n/a | (bad_format, err.__class__.__name__)) |
---|
218 | n/a | else: |
---|
219 | n/a | self.fail("'%s' did not raise ValueError" % bad_format) |
---|
220 | n/a | |
---|
221 | n/a | # Ambiguous or incomplete cases using ISO year/week/weekday directives |
---|
222 | n/a | # 1. ISO week (%V) is specified, but the year is specified with %Y |
---|
223 | n/a | # instead of %G |
---|
224 | n/a | with self.assertRaises(ValueError): |
---|
225 | n/a | _strptime._strptime("1999 50", "%Y %V") |
---|
226 | n/a | # 2. ISO year (%G) and ISO week (%V) are specified, but weekday is not |
---|
227 | n/a | with self.assertRaises(ValueError): |
---|
228 | n/a | _strptime._strptime("1999 51", "%G %V") |
---|
229 | n/a | # 3. ISO year (%G) and weekday are specified, but ISO week (%V) is not |
---|
230 | n/a | for w in ('A', 'a', 'w', 'u'): |
---|
231 | n/a | with self.assertRaises(ValueError): |
---|
232 | n/a | _strptime._strptime("1999 51","%G %{}".format(w)) |
---|
233 | n/a | # 4. ISO year is specified alone (e.g. time.strptime('2015', '%G')) |
---|
234 | n/a | with self.assertRaises(ValueError): |
---|
235 | n/a | _strptime._strptime("2015", "%G") |
---|
236 | n/a | # 5. Julian/ordinal day (%j) is specified with %G, but not %Y |
---|
237 | n/a | with self.assertRaises(ValueError): |
---|
238 | n/a | _strptime._strptime("1999 256", "%G %j") |
---|
239 | n/a | |
---|
240 | n/a | |
---|
241 | n/a | def test_strptime_exception_context(self): |
---|
242 | n/a | # check that this doesn't chain exceptions needlessly (see #17572) |
---|
243 | n/a | with self.assertRaises(ValueError) as e: |
---|
244 | n/a | _strptime._strptime_time('', '%D') |
---|
245 | n/a | self.assertIs(e.exception.__suppress_context__, True) |
---|
246 | n/a | # additional check for IndexError branch (issue #19545) |
---|
247 | n/a | with self.assertRaises(ValueError) as e: |
---|
248 | n/a | _strptime._strptime_time('19', '%Y %') |
---|
249 | n/a | self.assertIs(e.exception.__suppress_context__, True) |
---|
250 | n/a | |
---|
251 | n/a | def test_unconverteddata(self): |
---|
252 | n/a | # Check ValueError is raised when there is unconverted data |
---|
253 | n/a | self.assertRaises(ValueError, _strptime._strptime_time, "10 12", "%m") |
---|
254 | n/a | |
---|
255 | n/a | def helper(self, directive, position): |
---|
256 | n/a | """Helper fxn in testing.""" |
---|
257 | n/a | strf_output = time.strftime("%" + directive, self.time_tuple) |
---|
258 | n/a | strp_output = _strptime._strptime_time(strf_output, "%" + directive) |
---|
259 | n/a | self.assertTrue(strp_output[position] == self.time_tuple[position], |
---|
260 | n/a | "testing of '%s' directive failed; '%s' -> %s != %s" % |
---|
261 | n/a | (directive, strf_output, strp_output[position], |
---|
262 | n/a | self.time_tuple[position])) |
---|
263 | n/a | |
---|
264 | n/a | def test_year(self): |
---|
265 | n/a | # Test that the year is handled properly |
---|
266 | n/a | for directive in ('y', 'Y'): |
---|
267 | n/a | self.helper(directive, 0) |
---|
268 | n/a | # Must also make sure %y values are correct for bounds set by Open Group |
---|
269 | n/a | for century, bounds in ((1900, ('69', '99')), (2000, ('00', '68'))): |
---|
270 | n/a | for bound in bounds: |
---|
271 | n/a | strp_output = _strptime._strptime_time(bound, '%y') |
---|
272 | n/a | expected_result = century + int(bound) |
---|
273 | n/a | self.assertTrue(strp_output[0] == expected_result, |
---|
274 | n/a | "'y' test failed; passed in '%s' " |
---|
275 | n/a | "and returned '%s'" % (bound, strp_output[0])) |
---|
276 | n/a | |
---|
277 | n/a | def test_month(self): |
---|
278 | n/a | # Test for month directives |
---|
279 | n/a | for directive in ('B', 'b', 'm'): |
---|
280 | n/a | self.helper(directive, 1) |
---|
281 | n/a | |
---|
282 | n/a | def test_day(self): |
---|
283 | n/a | # Test for day directives |
---|
284 | n/a | self.helper('d', 2) |
---|
285 | n/a | |
---|
286 | n/a | def test_hour(self): |
---|
287 | n/a | # Test hour directives |
---|
288 | n/a | self.helper('H', 3) |
---|
289 | n/a | strf_output = time.strftime("%I %p", self.time_tuple) |
---|
290 | n/a | strp_output = _strptime._strptime_time(strf_output, "%I %p") |
---|
291 | n/a | self.assertTrue(strp_output[3] == self.time_tuple[3], |
---|
292 | n/a | "testing of '%%I %%p' directive failed; '%s' -> %s != %s" % |
---|
293 | n/a | (strf_output, strp_output[3], self.time_tuple[3])) |
---|
294 | n/a | |
---|
295 | n/a | def test_minute(self): |
---|
296 | n/a | # Test minute directives |
---|
297 | n/a | self.helper('M', 4) |
---|
298 | n/a | |
---|
299 | n/a | def test_second(self): |
---|
300 | n/a | # Test second directives |
---|
301 | n/a | self.helper('S', 5) |
---|
302 | n/a | |
---|
303 | n/a | def test_fraction(self): |
---|
304 | n/a | # Test microseconds |
---|
305 | n/a | import datetime |
---|
306 | n/a | d = datetime.datetime(2012, 12, 20, 12, 34, 56, 78987) |
---|
307 | n/a | tup, frac = _strptime._strptime(str(d), format="%Y-%m-%d %H:%M:%S.%f") |
---|
308 | n/a | self.assertEqual(frac, d.microsecond) |
---|
309 | n/a | |
---|
310 | n/a | def test_weekday(self): |
---|
311 | n/a | # Test weekday directives |
---|
312 | n/a | for directive in ('A', 'a', 'w', 'u'): |
---|
313 | n/a | self.helper(directive,6) |
---|
314 | n/a | |
---|
315 | n/a | def test_julian(self): |
---|
316 | n/a | # Test julian directives |
---|
317 | n/a | self.helper('j', 7) |
---|
318 | n/a | |
---|
319 | n/a | def test_timezone(self): |
---|
320 | n/a | # Test timezone directives. |
---|
321 | n/a | # When gmtime() is used with %Z, entire result of strftime() is empty. |
---|
322 | n/a | # Check for equal timezone names deals with bad locale info when this |
---|
323 | n/a | # occurs; first found in FreeBSD 4.4. |
---|
324 | n/a | strp_output = _strptime._strptime_time("UTC", "%Z") |
---|
325 | n/a | self.assertEqual(strp_output.tm_isdst, 0) |
---|
326 | n/a | strp_output = _strptime._strptime_time("GMT", "%Z") |
---|
327 | n/a | self.assertEqual(strp_output.tm_isdst, 0) |
---|
328 | n/a | time_tuple = time.localtime() |
---|
329 | n/a | strf_output = time.strftime("%Z") #UTC does not have a timezone |
---|
330 | n/a | strp_output = _strptime._strptime_time(strf_output, "%Z") |
---|
331 | n/a | locale_time = _strptime.LocaleTime() |
---|
332 | n/a | if time.tzname[0] != time.tzname[1] or not time.daylight: |
---|
333 | n/a | self.assertTrue(strp_output[8] == time_tuple[8], |
---|
334 | n/a | "timezone check failed; '%s' -> %s != %s" % |
---|
335 | n/a | (strf_output, strp_output[8], time_tuple[8])) |
---|
336 | n/a | else: |
---|
337 | n/a | self.assertTrue(strp_output[8] == -1, |
---|
338 | n/a | "LocaleTime().timezone has duplicate values and " |
---|
339 | n/a | "time.daylight but timezone value not set to -1") |
---|
340 | n/a | |
---|
341 | n/a | def test_bad_timezone(self): |
---|
342 | n/a | # Explicitly test possibility of bad timezone; |
---|
343 | n/a | # when time.tzname[0] == time.tzname[1] and time.daylight |
---|
344 | n/a | tz_name = time.tzname[0] |
---|
345 | n/a | if tz_name.upper() in ("UTC", "GMT"): |
---|
346 | n/a | self.skipTest('need non-UTC/GMT timezone') |
---|
347 | n/a | |
---|
348 | n/a | with support.swap_attr(time, 'tzname', (tz_name, tz_name)), \ |
---|
349 | n/a | support.swap_attr(time, 'daylight', 1), \ |
---|
350 | n/a | support.swap_attr(time, 'tzset', lambda: None): |
---|
351 | n/a | time.tzname = (tz_name, tz_name) |
---|
352 | n/a | time.daylight = 1 |
---|
353 | n/a | tz_value = _strptime._strptime_time(tz_name, "%Z")[8] |
---|
354 | n/a | self.assertEqual(tz_value, -1, |
---|
355 | n/a | "%s lead to a timezone value of %s instead of -1 when " |
---|
356 | n/a | "time.daylight set to %s and passing in %s" % |
---|
357 | n/a | (time.tzname, tz_value, time.daylight, tz_name)) |
---|
358 | n/a | |
---|
359 | n/a | def test_date_time(self): |
---|
360 | n/a | # Test %c directive |
---|
361 | n/a | for position in range(6): |
---|
362 | n/a | self.helper('c', position) |
---|
363 | n/a | |
---|
364 | n/a | def test_date(self): |
---|
365 | n/a | # Test %x directive |
---|
366 | n/a | for position in range(0,3): |
---|
367 | n/a | self.helper('x', position) |
---|
368 | n/a | |
---|
369 | n/a | def test_time(self): |
---|
370 | n/a | # Test %X directive |
---|
371 | n/a | for position in range(3,6): |
---|
372 | n/a | self.helper('X', position) |
---|
373 | n/a | |
---|
374 | n/a | def test_percent(self): |
---|
375 | n/a | # Make sure % signs are handled properly |
---|
376 | n/a | strf_output = time.strftime("%m %% %Y", self.time_tuple) |
---|
377 | n/a | strp_output = _strptime._strptime_time(strf_output, "%m %% %Y") |
---|
378 | n/a | self.assertTrue(strp_output[0] == self.time_tuple[0] and |
---|
379 | n/a | strp_output[1] == self.time_tuple[1], |
---|
380 | n/a | "handling of percent sign failed") |
---|
381 | n/a | |
---|
382 | n/a | def test_caseinsensitive(self): |
---|
383 | n/a | # Should handle names case-insensitively. |
---|
384 | n/a | strf_output = time.strftime("%B", self.time_tuple) |
---|
385 | n/a | self.assertTrue(_strptime._strptime_time(strf_output.upper(), "%B"), |
---|
386 | n/a | "strptime does not handle ALL-CAPS names properly") |
---|
387 | n/a | self.assertTrue(_strptime._strptime_time(strf_output.lower(), "%B"), |
---|
388 | n/a | "strptime does not handle lowercase names properly") |
---|
389 | n/a | self.assertTrue(_strptime._strptime_time(strf_output.capitalize(), "%B"), |
---|
390 | n/a | "strptime does not handle capword names properly") |
---|
391 | n/a | |
---|
392 | n/a | def test_defaults(self): |
---|
393 | n/a | # Default return value should be (1900, 1, 1, 0, 0, 0, 0, 1, 0) |
---|
394 | n/a | defaults = (1900, 1, 1, 0, 0, 0, 0, 1, -1) |
---|
395 | n/a | strp_output = _strptime._strptime_time('1', '%m') |
---|
396 | n/a | self.assertTrue(strp_output == defaults, |
---|
397 | n/a | "Default values for strptime() are incorrect;" |
---|
398 | n/a | " %s != %s" % (strp_output, defaults)) |
---|
399 | n/a | |
---|
400 | n/a | def test_escaping(self): |
---|
401 | n/a | # Make sure all characters that have regex significance are escaped. |
---|
402 | n/a | # Parentheses are in a purposeful order; will cause an error of |
---|
403 | n/a | # unbalanced parentheses when the regex is compiled if they are not |
---|
404 | n/a | # escaped. |
---|
405 | n/a | # Test instigated by bug #796149 . |
---|
406 | n/a | need_escaping = r".^$*+?{}\[]|)(" |
---|
407 | n/a | self.assertTrue(_strptime._strptime_time(need_escaping, need_escaping)) |
---|
408 | n/a | |
---|
409 | n/a | def test_feb29_on_leap_year_without_year(self): |
---|
410 | n/a | time.strptime("Feb 29", "%b %d") |
---|
411 | n/a | |
---|
412 | n/a | def test_mar1_comes_after_feb29_even_when_omitting_the_year(self): |
---|
413 | n/a | self.assertLess( |
---|
414 | n/a | time.strptime("Feb 29", "%b %d"), |
---|
415 | n/a | time.strptime("Mar 1", "%b %d")) |
---|
416 | n/a | |
---|
417 | n/a | class Strptime12AMPMTests(unittest.TestCase): |
---|
418 | n/a | """Test a _strptime regression in '%I %p' at 12 noon (12 PM)""" |
---|
419 | n/a | |
---|
420 | n/a | def test_twelve_noon_midnight(self): |
---|
421 | n/a | eq = self.assertEqual |
---|
422 | n/a | eq(time.strptime('12 PM', '%I %p')[3], 12) |
---|
423 | n/a | eq(time.strptime('12 AM', '%I %p')[3], 0) |
---|
424 | n/a | eq(_strptime._strptime_time('12 PM', '%I %p')[3], 12) |
---|
425 | n/a | eq(_strptime._strptime_time('12 AM', '%I %p')[3], 0) |
---|
426 | n/a | |
---|
427 | n/a | |
---|
428 | n/a | class JulianTests(unittest.TestCase): |
---|
429 | n/a | """Test a _strptime regression that all julian (1-366) are accepted""" |
---|
430 | n/a | |
---|
431 | n/a | def test_all_julian_days(self): |
---|
432 | n/a | eq = self.assertEqual |
---|
433 | n/a | for i in range(1, 367): |
---|
434 | n/a | # use 2004, since it is a leap year, we have 366 days |
---|
435 | n/a | eq(_strptime._strptime_time('%d 2004' % i, '%j %Y')[7], i) |
---|
436 | n/a | |
---|
437 | n/a | class CalculationTests(unittest.TestCase): |
---|
438 | n/a | """Test that strptime() fills in missing info correctly""" |
---|
439 | n/a | |
---|
440 | n/a | def setUp(self): |
---|
441 | n/a | self.time_tuple = time.gmtime() |
---|
442 | n/a | |
---|
443 | n/a | def test_julian_calculation(self): |
---|
444 | n/a | # Make sure that when Julian is missing that it is calculated |
---|
445 | n/a | format_string = "%Y %m %d %H %M %S %w %Z" |
---|
446 | n/a | result = _strptime._strptime_time(time.strftime(format_string, self.time_tuple), |
---|
447 | n/a | format_string) |
---|
448 | n/a | self.assertTrue(result.tm_yday == self.time_tuple.tm_yday, |
---|
449 | n/a | "Calculation of tm_yday failed; %s != %s" % |
---|
450 | n/a | (result.tm_yday, self.time_tuple.tm_yday)) |
---|
451 | n/a | |
---|
452 | n/a | def test_gregorian_calculation(self): |
---|
453 | n/a | # Test that Gregorian date can be calculated from Julian day |
---|
454 | n/a | format_string = "%Y %H %M %S %w %j %Z" |
---|
455 | n/a | result = _strptime._strptime_time(time.strftime(format_string, self.time_tuple), |
---|
456 | n/a | format_string) |
---|
457 | n/a | self.assertTrue(result.tm_year == self.time_tuple.tm_year and |
---|
458 | n/a | result.tm_mon == self.time_tuple.tm_mon and |
---|
459 | n/a | result.tm_mday == self.time_tuple.tm_mday, |
---|
460 | n/a | "Calculation of Gregorian date failed;" |
---|
461 | n/a | "%s-%s-%s != %s-%s-%s" % |
---|
462 | n/a | (result.tm_year, result.tm_mon, result.tm_mday, |
---|
463 | n/a | self.time_tuple.tm_year, self.time_tuple.tm_mon, |
---|
464 | n/a | self.time_tuple.tm_mday)) |
---|
465 | n/a | |
---|
466 | n/a | def test_day_of_week_calculation(self): |
---|
467 | n/a | # Test that the day of the week is calculated as needed |
---|
468 | n/a | format_string = "%Y %m %d %H %S %j %Z" |
---|
469 | n/a | result = _strptime._strptime_time(time.strftime(format_string, self.time_tuple), |
---|
470 | n/a | format_string) |
---|
471 | n/a | self.assertTrue(result.tm_wday == self.time_tuple.tm_wday, |
---|
472 | n/a | "Calculation of day of the week failed;" |
---|
473 | n/a | "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday)) |
---|
474 | n/a | |
---|
475 | n/a | if support.is_android: |
---|
476 | n/a | # Issue #26929: strftime() on Android incorrectly formats %V or %G for |
---|
477 | n/a | # the last or the first incomplete week in a year. |
---|
478 | n/a | _ymd_excluded = ((1905, 1, 1), (1906, 12, 31), (2008, 12, 29), |
---|
479 | n/a | (1917, 12, 31)) |
---|
480 | n/a | _formats_excluded = ('%G %V',) |
---|
481 | n/a | else: |
---|
482 | n/a | _ymd_excluded = () |
---|
483 | n/a | _formats_excluded = () |
---|
484 | n/a | |
---|
485 | n/a | def test_week_of_year_and_day_of_week_calculation(self): |
---|
486 | n/a | # Should be able to infer date if given year, week of year (%U or %W) |
---|
487 | n/a | # and day of the week |
---|
488 | n/a | def test_helper(ymd_tuple, test_reason): |
---|
489 | n/a | for year_week_format in ('%Y %W', '%Y %U', '%G %V'): |
---|
490 | n/a | if (year_week_format in self._formats_excluded and |
---|
491 | n/a | ymd_tuple in self._ymd_excluded): |
---|
492 | n/a | return |
---|
493 | n/a | for weekday_format in ('%w', '%u', '%a', '%A'): |
---|
494 | n/a | format_string = year_week_format + ' ' + weekday_format |
---|
495 | n/a | with self.subTest(test_reason, |
---|
496 | n/a | date=ymd_tuple, |
---|
497 | n/a | format=format_string): |
---|
498 | n/a | dt_date = datetime_date(*ymd_tuple) |
---|
499 | n/a | strp_input = dt_date.strftime(format_string) |
---|
500 | n/a | strp_output = _strptime._strptime_time(strp_input, |
---|
501 | n/a | format_string) |
---|
502 | n/a | msg = "%r: %s != %s" % (strp_input, |
---|
503 | n/a | strp_output[7], |
---|
504 | n/a | dt_date.timetuple()[7]) |
---|
505 | n/a | self.assertEqual(strp_output[:3], ymd_tuple, msg) |
---|
506 | n/a | test_helper((1901, 1, 3), "week 0") |
---|
507 | n/a | test_helper((1901, 1, 8), "common case") |
---|
508 | n/a | test_helper((1901, 1, 13), "day on Sunday") |
---|
509 | n/a | test_helper((1901, 1, 14), "day on Monday") |
---|
510 | n/a | test_helper((1905, 1, 1), "Jan 1 on Sunday") |
---|
511 | n/a | test_helper((1906, 1, 1), "Jan 1 on Monday") |
---|
512 | n/a | test_helper((1906, 1, 7), "first Sunday in a year starting on Monday") |
---|
513 | n/a | test_helper((1905, 12, 31), "Dec 31 on Sunday") |
---|
514 | n/a | test_helper((1906, 12, 31), "Dec 31 on Monday") |
---|
515 | n/a | test_helper((2008, 12, 29), "Monday in the last week of the year") |
---|
516 | n/a | test_helper((2008, 12, 22), "Monday in the second-to-last week of the " |
---|
517 | n/a | "year") |
---|
518 | n/a | test_helper((1978, 10, 23), "randomly chosen date") |
---|
519 | n/a | test_helper((2004, 12, 18), "randomly chosen date") |
---|
520 | n/a | test_helper((1978, 10, 23), "year starting and ending on Monday while " |
---|
521 | n/a | "date not on Sunday or Monday") |
---|
522 | n/a | test_helper((1917, 12, 17), "year starting and ending on Monday with " |
---|
523 | n/a | "a Monday not at the beginning or end " |
---|
524 | n/a | "of the year") |
---|
525 | n/a | test_helper((1917, 12, 31), "Dec 31 on Monday with year starting and " |
---|
526 | n/a | "ending on Monday") |
---|
527 | n/a | test_helper((2007, 1, 7), "First Sunday of 2007") |
---|
528 | n/a | test_helper((2007, 1, 14), "Second Sunday of 2007") |
---|
529 | n/a | test_helper((2006, 12, 31), "Last Sunday of 2006") |
---|
530 | n/a | test_helper((2006, 12, 24), "Second to last Sunday of 2006") |
---|
531 | n/a | |
---|
532 | n/a | def test_week_0(self): |
---|
533 | n/a | def check(value, format, *expected): |
---|
534 | n/a | self.assertEqual(_strptime._strptime_time(value, format)[:-1], expected) |
---|
535 | n/a | check('2015 0 0', '%Y %U %w', 2014, 12, 28, 0, 0, 0, 6, 362) |
---|
536 | n/a | check('2015 0 0', '%Y %W %w', 2015, 1, 4, 0, 0, 0, 6, 4) |
---|
537 | n/a | check('2015 1 1', '%G %V %u', 2014, 12, 29, 0, 0, 0, 0, 363) |
---|
538 | n/a | check('2015 0 1', '%Y %U %w', 2014, 12, 29, 0, 0, 0, 0, 363) |
---|
539 | n/a | check('2015 0 1', '%Y %W %w', 2014, 12, 29, 0, 0, 0, 0, 363) |
---|
540 | n/a | check('2015 1 2', '%G %V %u', 2014, 12, 30, 0, 0, 0, 1, 364) |
---|
541 | n/a | check('2015 0 2', '%Y %U %w', 2014, 12, 30, 0, 0, 0, 1, 364) |
---|
542 | n/a | check('2015 0 2', '%Y %W %w', 2014, 12, 30, 0, 0, 0, 1, 364) |
---|
543 | n/a | check('2015 1 3', '%G %V %u', 2014, 12, 31, 0, 0, 0, 2, 365) |
---|
544 | n/a | check('2015 0 3', '%Y %U %w', 2014, 12, 31, 0, 0, 0, 2, 365) |
---|
545 | n/a | check('2015 0 3', '%Y %W %w', 2014, 12, 31, 0, 0, 0, 2, 365) |
---|
546 | n/a | check('2015 1 4', '%G %V %u', 2015, 1, 1, 0, 0, 0, 3, 1) |
---|
547 | n/a | check('2015 0 4', '%Y %U %w', 2015, 1, 1, 0, 0, 0, 3, 1) |
---|
548 | n/a | check('2015 0 4', '%Y %W %w', 2015, 1, 1, 0, 0, 0, 3, 1) |
---|
549 | n/a | check('2015 1 5', '%G %V %u', 2015, 1, 2, 0, 0, 0, 4, 2) |
---|
550 | n/a | check('2015 0 5', '%Y %U %w', 2015, 1, 2, 0, 0, 0, 4, 2) |
---|
551 | n/a | check('2015 0 5', '%Y %W %w', 2015, 1, 2, 0, 0, 0, 4, 2) |
---|
552 | n/a | check('2015 1 6', '%G %V %u', 2015, 1, 3, 0, 0, 0, 5, 3) |
---|
553 | n/a | check('2015 0 6', '%Y %U %w', 2015, 1, 3, 0, 0, 0, 5, 3) |
---|
554 | n/a | check('2015 0 6', '%Y %W %w', 2015, 1, 3, 0, 0, 0, 5, 3) |
---|
555 | n/a | check('2015 1 7', '%G %V %u', 2015, 1, 4, 0, 0, 0, 6, 4) |
---|
556 | n/a | |
---|
557 | n/a | check('2009 0 0', '%Y %U %w', 2008, 12, 28, 0, 0, 0, 6, 363) |
---|
558 | n/a | check('2009 0 0', '%Y %W %w', 2009, 1, 4, 0, 0, 0, 6, 4) |
---|
559 | n/a | check('2009 1 1', '%G %V %u', 2008, 12, 29, 0, 0, 0, 0, 364) |
---|
560 | n/a | check('2009 0 1', '%Y %U %w', 2008, 12, 29, 0, 0, 0, 0, 364) |
---|
561 | n/a | check('2009 0 1', '%Y %W %w', 2008, 12, 29, 0, 0, 0, 0, 364) |
---|
562 | n/a | check('2009 1 2', '%G %V %u', 2008, 12, 30, 0, 0, 0, 1, 365) |
---|
563 | n/a | check('2009 0 2', '%Y %U %w', 2008, 12, 30, 0, 0, 0, 1, 365) |
---|
564 | n/a | check('2009 0 2', '%Y %W %w', 2008, 12, 30, 0, 0, 0, 1, 365) |
---|
565 | n/a | check('2009 1 3', '%G %V %u', 2008, 12, 31, 0, 0, 0, 2, 366) |
---|
566 | n/a | check('2009 0 3', '%Y %U %w', 2008, 12, 31, 0, 0, 0, 2, 366) |
---|
567 | n/a | check('2009 0 3', '%Y %W %w', 2008, 12, 31, 0, 0, 0, 2, 366) |
---|
568 | n/a | check('2009 1 4', '%G %V %u', 2009, 1, 1, 0, 0, 0, 3, 1) |
---|
569 | n/a | check('2009 0 4', '%Y %U %w', 2009, 1, 1, 0, 0, 0, 3, 1) |
---|
570 | n/a | check('2009 0 4', '%Y %W %w', 2009, 1, 1, 0, 0, 0, 3, 1) |
---|
571 | n/a | check('2009 1 5', '%G %V %u', 2009, 1, 2, 0, 0, 0, 4, 2) |
---|
572 | n/a | check('2009 0 5', '%Y %U %w', 2009, 1, 2, 0, 0, 0, 4, 2) |
---|
573 | n/a | check('2009 0 5', '%Y %W %w', 2009, 1, 2, 0, 0, 0, 4, 2) |
---|
574 | n/a | check('2009 1 6', '%G %V %u', 2009, 1, 3, 0, 0, 0, 5, 3) |
---|
575 | n/a | check('2009 0 6', '%Y %U %w', 2009, 1, 3, 0, 0, 0, 5, 3) |
---|
576 | n/a | check('2009 0 6', '%Y %W %w', 2009, 1, 3, 0, 0, 0, 5, 3) |
---|
577 | n/a | check('2009 1 7', '%G %V %u', 2009, 1, 4, 0, 0, 0, 6, 4) |
---|
578 | n/a | |
---|
579 | n/a | |
---|
580 | n/a | class CacheTests(unittest.TestCase): |
---|
581 | n/a | """Test that caching works properly.""" |
---|
582 | n/a | |
---|
583 | n/a | def test_time_re_recreation(self): |
---|
584 | n/a | # Make sure cache is recreated when current locale does not match what |
---|
585 | n/a | # cached object was created with. |
---|
586 | n/a | _strptime._strptime_time("10", "%d") |
---|
587 | n/a | _strptime._strptime_time("2005", "%Y") |
---|
588 | n/a | _strptime._TimeRE_cache.locale_time.lang = "Ni" |
---|
589 | n/a | original_time_re = _strptime._TimeRE_cache |
---|
590 | n/a | _strptime._strptime_time("10", "%d") |
---|
591 | n/a | self.assertIsNot(original_time_re, _strptime._TimeRE_cache) |
---|
592 | n/a | self.assertEqual(len(_strptime._regex_cache), 1) |
---|
593 | n/a | |
---|
594 | n/a | def test_regex_cleanup(self): |
---|
595 | n/a | # Make sure cached regexes are discarded when cache becomes "full". |
---|
596 | n/a | try: |
---|
597 | n/a | del _strptime._regex_cache['%d'] |
---|
598 | n/a | except KeyError: |
---|
599 | n/a | pass |
---|
600 | n/a | bogus_key = 0 |
---|
601 | n/a | while len(_strptime._regex_cache) <= _strptime._CACHE_MAX_SIZE: |
---|
602 | n/a | _strptime._regex_cache[bogus_key] = None |
---|
603 | n/a | bogus_key += 1 |
---|
604 | n/a | _strptime._strptime_time("10", "%d") |
---|
605 | n/a | self.assertEqual(len(_strptime._regex_cache), 1) |
---|
606 | n/a | |
---|
607 | n/a | def test_new_localetime(self): |
---|
608 | n/a | # A new LocaleTime instance should be created when a new TimeRE object |
---|
609 | n/a | # is created. |
---|
610 | n/a | locale_time_id = _strptime._TimeRE_cache.locale_time |
---|
611 | n/a | _strptime._TimeRE_cache.locale_time.lang = "Ni" |
---|
612 | n/a | _strptime._strptime_time("10", "%d") |
---|
613 | n/a | self.assertIsNot(locale_time_id, _strptime._TimeRE_cache.locale_time) |
---|
614 | n/a | |
---|
615 | n/a | def test_TimeRE_recreation_locale(self): |
---|
616 | n/a | # The TimeRE instance should be recreated upon changing the locale. |
---|
617 | n/a | locale_info = locale.getlocale(locale.LC_TIME) |
---|
618 | n/a | try: |
---|
619 | n/a | locale.setlocale(locale.LC_TIME, ('en_US', 'UTF8')) |
---|
620 | n/a | except locale.Error: |
---|
621 | n/a | self.skipTest('test needs en_US.UTF8 locale') |
---|
622 | n/a | try: |
---|
623 | n/a | _strptime._strptime_time('10', '%d') |
---|
624 | n/a | # Get id of current cache object. |
---|
625 | n/a | first_time_re = _strptime._TimeRE_cache |
---|
626 | n/a | try: |
---|
627 | n/a | # Change the locale and force a recreation of the cache. |
---|
628 | n/a | locale.setlocale(locale.LC_TIME, ('de_DE', 'UTF8')) |
---|
629 | n/a | _strptime._strptime_time('10', '%d') |
---|
630 | n/a | # Get the new cache object's id. |
---|
631 | n/a | second_time_re = _strptime._TimeRE_cache |
---|
632 | n/a | # They should not be equal. |
---|
633 | n/a | self.assertIsNot(first_time_re, second_time_re) |
---|
634 | n/a | # Possible test locale is not supported while initial locale is. |
---|
635 | n/a | # If this is the case just suppress the exception and fall-through |
---|
636 | n/a | # to the resetting to the original locale. |
---|
637 | n/a | except locale.Error: |
---|
638 | n/a | self.skipTest('test needs de_DE.UTF8 locale') |
---|
639 | n/a | # Make sure we don't trample on the locale setting once we leave the |
---|
640 | n/a | # test. |
---|
641 | n/a | finally: |
---|
642 | n/a | locale.setlocale(locale.LC_TIME, locale_info) |
---|
643 | n/a | |
---|
644 | n/a | @support.run_with_tz('STD-1DST') |
---|
645 | n/a | def test_TimeRE_recreation_timezone(self): |
---|
646 | n/a | # The TimeRE instance should be recreated upon changing the timezone. |
---|
647 | n/a | oldtzname = time.tzname |
---|
648 | n/a | tm = _strptime._strptime_time(time.tzname[0], '%Z') |
---|
649 | n/a | self.assertEqual(tm.tm_isdst, 0) |
---|
650 | n/a | tm = _strptime._strptime_time(time.tzname[1], '%Z') |
---|
651 | n/a | self.assertEqual(tm.tm_isdst, 1) |
---|
652 | n/a | # Get id of current cache object. |
---|
653 | n/a | first_time_re = _strptime._TimeRE_cache |
---|
654 | n/a | # Change the timezone and force a recreation of the cache. |
---|
655 | n/a | os.environ['TZ'] = 'EST+05EDT,M3.2.0,M11.1.0' |
---|
656 | n/a | time.tzset() |
---|
657 | n/a | tm = _strptime._strptime_time(time.tzname[0], '%Z') |
---|
658 | n/a | self.assertEqual(tm.tm_isdst, 0) |
---|
659 | n/a | tm = _strptime._strptime_time(time.tzname[1], '%Z') |
---|
660 | n/a | self.assertEqual(tm.tm_isdst, 1) |
---|
661 | n/a | # Get the new cache object's id. |
---|
662 | n/a | second_time_re = _strptime._TimeRE_cache |
---|
663 | n/a | # They should not be equal. |
---|
664 | n/a | self.assertIsNot(first_time_re, second_time_re) |
---|
665 | n/a | # Make sure old names no longer accepted. |
---|
666 | n/a | with self.assertRaises(ValueError): |
---|
667 | n/a | _strptime._strptime_time(oldtzname[0], '%Z') |
---|
668 | n/a | with self.assertRaises(ValueError): |
---|
669 | n/a | _strptime._strptime_time(oldtzname[1], '%Z') |
---|
670 | n/a | |
---|
671 | n/a | |
---|
672 | n/a | if __name__ == '__main__': |
---|
673 | n/a | unittest.main() |
---|