Skip to content

Commit 9cd39b1

Browse files
paulmonpganssle
authored andcommitted
bpo-37552: Skip failing tests in strptime/strftime with UCRT version 17763.615 (#14460)
A bug in MSVC UCRT version 17763.615 (which has been fixed in newer versions) is causing test failures in some strptime/strftime tests when the default code page is c65001. This change selectively skips the tests affected by this.
1 parent 1b38922 commit 9cd39b1

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

Lib/test/support/__init__.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import glob
1515
import importlib
1616
import importlib.util
17+
import locale
1718
import logging.handlers
1819
import nntplib
1920
import os
@@ -92,7 +93,7 @@
9293
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
9394
"requires_IEEE_754", "skip_unless_xattr", "requires_zlib",
9495
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
95-
"check__all__", "skip_unless_bind_unix_socket",
96+
"check__all__", "skip_unless_bind_unix_socket", "skip_if_buggy_ucrt_strfptime",
9697
"ignore_warnings",
9798
# sys
9899
"is_jython", "is_android", "check_impl_detail", "unix_shell",
@@ -2501,6 +2502,27 @@ def skip_unless_symlink(test):
25012502
msg = "Requires functional symlink implementation"
25022503
return test if ok else unittest.skip(msg)(test)
25032504

2505+
_buggy_ucrt = None
2506+
def skip_if_buggy_ucrt_strfptime(test):
2507+
"""
2508+
Skip decorator for tests that use buggy strptime/strftime
2509+
2510+
If the UCRT bugs are present time.localtime().tm_zone will be
2511+
an empty string, otherwise we assume the UCRT bugs are fixed
2512+
2513+
See bpo-37552 [Windows] strptime/strftime return invalid
2514+
results with UCRT version 17763.615
2515+
"""
2516+
global _buggy_ucrt
2517+
if _buggy_ucrt is None:
2518+
if(sys.platform == 'win32' and
2519+
locale.getdefaultlocale()[1] == 'cp65001' and
2520+
time.localtime().tm_zone == ''):
2521+
_buggy_ucrt = True
2522+
else:
2523+
_buggy_ucrt = False
2524+
return unittest.skip("buggy MSVC UCRT strptime/strftime")(test) if _buggy_ucrt else test
2525+
25042526
class PythonSymlink:
25052527
"""Creates a symlink for the current Python executable"""
25062528
def __init__(self, link=None):

Lib/test/test_strptime.py

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import sys
99
from test import support
10+
from test.support import skip_if_buggy_ucrt_strfptime
1011
from datetime import date as datetime_date
1112

1213
import _strptime
@@ -135,6 +136,7 @@ def test_pattern_escaping(self):
135136
"%s does not have re characters escaped properly" %
136137
pattern_string)
137138

139+
@skip_if_buggy_ucrt_strfptime
138140
def test_compile(self):
139141
# Check that compiled regex is correct
140142
found = self.time_re.compile(r"%A").match(self.locale_time.f_weekday[6])
@@ -365,6 +367,7 @@ def test_bad_offset(self):
365367
_strptime._strptime("-01:3030", "%z")
366368
self.assertEqual("Inconsistent use of : in -01:3030", str(err.exception))
367369

370+
@skip_if_buggy_ucrt_strfptime
368371
def test_timezone(self):
369372
# Test timezone directives.
370373
# When gmtime() is used with %Z, entire result of strftime() is empty.
@@ -489,6 +492,7 @@ class CalculationTests(unittest.TestCase):
489492
def setUp(self):
490493
self.time_tuple = time.gmtime()
491494

495+
@skip_if_buggy_ucrt_strfptime
492496
def test_julian_calculation(self):
493497
# Make sure that when Julian is missing that it is calculated
494498
format_string = "%Y %m %d %H %M %S %w %Z"
@@ -498,6 +502,7 @@ def test_julian_calculation(self):
498502
"Calculation of tm_yday failed; %s != %s" %
499503
(result.tm_yday, self.time_tuple.tm_yday))
500504

505+
@skip_if_buggy_ucrt_strfptime
501506
def test_gregorian_calculation(self):
502507
# Test that Gregorian date can be calculated from Julian day
503508
format_string = "%Y %H %M %S %w %j %Z"
@@ -512,6 +517,7 @@ def test_gregorian_calculation(self):
512517
self.time_tuple.tm_year, self.time_tuple.tm_mon,
513518
self.time_tuple.tm_mday))
514519

520+
@skip_if_buggy_ucrt_strfptime
515521
def test_day_of_week_calculation(self):
516522
# Test that the day of the week is calculated as needed
517523
format_string = "%Y %m %d %H %S %j %Z"

Lib/test/test_time.py

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
except ImportError:
1515
_testcapi = None
1616

17+
from test.support import skip_if_buggy_ucrt_strfptime
1718

1819
# Max year is only limited by the size of C int.
1920
SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
@@ -250,6 +251,7 @@ def test_default_values_for_zero(self):
250251
result = time.strftime("%Y %m %d %H %M %S %w %j", (2000,)+(0,)*8)
251252
self.assertEqual(expected, result)
252253

254+
@skip_if_buggy_ucrt_strfptime
253255
def test_strptime(self):
254256
# Should be able to go round-trip from strftime to strptime without
255257
# raising an exception.
@@ -672,6 +674,7 @@ class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear, unittest.TestCase):
672674

673675

674676
class TestPytime(unittest.TestCase):
677+
@skip_if_buggy_ucrt_strfptime
675678
@unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support")
676679
def test_localtime_timezone(self):
677680

0 commit comments

Comments
 (0)