mirror of
https://github.com/python/cpython.git
synced 2025-12-09 02:35:14 +00:00
Remove caching of TimeRE (and thus LocaleTime) instance. Error was being
caught when executing test_strptime, test_logging, and test_time in that order when the testing of "%c" occured. Suspect the cache was not being recreated (the test passed when test_logging was forced to re-establish the locale).
This commit is contained in:
parent
98741af170
commit
175ddb5b30
2 changed files with 23 additions and 48 deletions
|
|
@ -27,19 +27,15 @@ __all__ = ['strptime']
|
||||||
|
|
||||||
def _getlang():
|
def _getlang():
|
||||||
# Figure out what the current language is set to.
|
# Figure out what the current language is set to.
|
||||||
current_lang = locale.getlocale(locale.LC_TIME)[0]
|
return locale.getlocale(locale.LC_TIME)
|
||||||
if current_lang:
|
|
||||||
return current_lang
|
|
||||||
else:
|
|
||||||
current_lang = locale.getdefaultlocale()[0]
|
|
||||||
if current_lang:
|
|
||||||
return current_lang
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
class LocaleTime(object):
|
class LocaleTime(object):
|
||||||
"""Stores and handles locale-specific information related to time.
|
"""Stores and handles locale-specific information related to time.
|
||||||
|
|
||||||
|
This is not thread-safe! Attributes are lazily calculated and no
|
||||||
|
precaution is taken to check to see if the locale information has changed
|
||||||
|
since the creation of the instance in use.
|
||||||
|
|
||||||
ATTRIBUTES (all read-only after instance creation! Instance variables that
|
ATTRIBUTES (all read-only after instance creation! Instance variables that
|
||||||
store the values have mangled names):
|
store the values have mangled names):
|
||||||
f_weekday -- full weekday names (7-item list)
|
f_weekday -- full weekday names (7-item list)
|
||||||
|
|
@ -103,7 +99,10 @@ class LocaleTime(object):
|
||||||
raise TypeError("timezone names must contain 2 items")
|
raise TypeError("timezone names must contain 2 items")
|
||||||
else:
|
else:
|
||||||
self.__timezone = self.__pad(timezone, False)
|
self.__timezone = self.__pad(timezone, False)
|
||||||
|
if lang:
|
||||||
self.__lang = lang
|
self.__lang = lang
|
||||||
|
else:
|
||||||
|
self.__lang = _getlang()
|
||||||
|
|
||||||
def __pad(self, seq, front):
|
def __pad(self, seq, front):
|
||||||
# Add '' to seq to either front (is True), else the back.
|
# Add '' to seq to either front (is True), else the back.
|
||||||
|
|
@ -196,13 +195,7 @@ class LocaleTime(object):
|
||||||
LC_time = property(__get_LC_time, __set_nothing,
|
LC_time = property(__get_LC_time, __set_nothing,
|
||||||
doc="Format string for locale's time representation ('%X' format)")
|
doc="Format string for locale's time representation ('%X' format)")
|
||||||
|
|
||||||
def __get_lang(self):
|
lang = property(lambda self: self.__lang, __set_nothing,
|
||||||
# Fetch self.lang.
|
|
||||||
if not self.__lang:
|
|
||||||
self.__calc_lang()
|
|
||||||
return self.__lang
|
|
||||||
|
|
||||||
lang = property(__get_lang, __set_nothing,
|
|
||||||
doc="Language used for instance")
|
doc="Language used for instance")
|
||||||
|
|
||||||
def __calc_weekday(self):
|
def __calc_weekday(self):
|
||||||
|
|
@ -295,11 +288,6 @@ class LocaleTime(object):
|
||||||
time_zones.append(time.tzname[0])
|
time_zones.append(time.tzname[0])
|
||||||
self.__timezone = self.__pad(time_zones, 0)
|
self.__timezone = self.__pad(time_zones, 0)
|
||||||
|
|
||||||
def __calc_lang(self):
|
|
||||||
# Set self.__lang by using __getlang().
|
|
||||||
self.__lang = _getlang()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TimeRE(dict):
|
class TimeRE(dict):
|
||||||
"""Handle conversion from format directives to regexes."""
|
"""Handle conversion from format directives to regexes."""
|
||||||
|
|
@ -406,28 +394,12 @@ class TimeRE(dict):
|
||||||
"""Return a compiled re object for the format string."""
|
"""Return a compiled re object for the format string."""
|
||||||
return re_compile(self.pattern(format), IGNORECASE)
|
return re_compile(self.pattern(format), IGNORECASE)
|
||||||
|
|
||||||
# Cached TimeRE; probably only need one instance ever so cache it for performance
|
|
||||||
_locale_cache = TimeRE()
|
|
||||||
# Cached regex objects; same reason as for TimeRE cache
|
|
||||||
_regex_cache = dict()
|
|
||||||
|
|
||||||
def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
|
def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
|
||||||
"""Return a time struct based on the input data and the format string."""
|
"""Return a time struct based on the input data and the format string."""
|
||||||
global _locale_cache
|
time_re = TimeRE()
|
||||||
global _regex_cache
|
locale_time = time_re.locale_time
|
||||||
locale_time = _locale_cache.locale_time
|
format_regex = time_re.compile(format)
|
||||||
# If the language changes, caches are invalidated, so clear them
|
|
||||||
if locale_time.lang != _getlang():
|
|
||||||
_locale_cache = TimeRE()
|
|
||||||
_regex_cache.clear()
|
|
||||||
format_regex = _regex_cache.get(format)
|
|
||||||
if not format_regex:
|
|
||||||
# Limit regex cache size to prevent major bloating of the module;
|
|
||||||
# The value 5 is arbitrary
|
|
||||||
if len(_regex_cache) > 5:
|
|
||||||
_regex_cache.clear()
|
|
||||||
format_regex = _locale_cache.compile(format)
|
|
||||||
_regex_cache[format] = format_regex
|
|
||||||
found = format_regex.match(data_string)
|
found = format_regex.match(data_string)
|
||||||
if not found:
|
if not found:
|
||||||
raise ValueError("time data did not match format: data=%s fmt=%s" %
|
raise ValueError("time data did not match format: data=%s fmt=%s" %
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ from test import test_support
|
||||||
|
|
||||||
import _strptime
|
import _strptime
|
||||||
|
|
||||||
|
class getlang_Tests(unittest.TestCase):
|
||||||
|
"""Test _getlang"""
|
||||||
|
def test_basic(self):
|
||||||
|
self.failUnlessEqual(_strptime._getlang(), locale.getlocale(locale.LC_TIME))
|
||||||
|
|
||||||
class LocaleTime_Tests(unittest.TestCase):
|
class LocaleTime_Tests(unittest.TestCase):
|
||||||
"""Tests for _strptime.LocaleTime."""
|
"""Tests for _strptime.LocaleTime."""
|
||||||
|
|
||||||
|
|
@ -89,11 +94,9 @@ class LocaleTime_Tests(unittest.TestCase):
|
||||||
"empty strings")
|
"empty strings")
|
||||||
|
|
||||||
def test_lang(self):
|
def test_lang(self):
|
||||||
# Make sure lang is set
|
# Make sure lang is set to what _getlang() returns
|
||||||
self.failUnless(self.LT_ins.lang in (locale.getdefaultlocale()[0],
|
# Assuming locale has not changed between now and when self.LT_ins was created
|
||||||
locale.getlocale(locale.LC_TIME)[0],
|
self.failUnlessEqual(self.LT_ins.lang, _strptime._getlang())
|
||||||
''),
|
|
||||||
"Setting of lang failed")
|
|
||||||
|
|
||||||
def test_by_hand_input(self):
|
def test_by_hand_input(self):
|
||||||
# Test passed-in initialization value checks
|
# Test passed-in initialization value checks
|
||||||
|
|
@ -410,15 +413,15 @@ class CalculationTests(unittest.TestCase):
|
||||||
self.failUnless(result.tm_wday == self.time_tuple.tm_wday,
|
self.failUnless(result.tm_wday == self.time_tuple.tm_wday,
|
||||||
"Calculation of day of the week failed;"
|
"Calculation of day of the week failed;"
|
||||||
"%s != %s" % (result.tm_wday, self.time_tuple.tm_wday))
|
"%s != %s" % (result.tm_wday, self.time_tuple.tm_wday))
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test_support.run_unittest(
|
test_support.run_unittest(
|
||||||
|
getlang_Tests,
|
||||||
LocaleTime_Tests,
|
LocaleTime_Tests,
|
||||||
TimeRETests,
|
TimeRETests,
|
||||||
StrptimeTests,
|
StrptimeTests,
|
||||||
Strptime12AMPMTests,
|
Strptime12AMPMTests,
|
||||||
JulianTests,
|
JulianTests,
|
||||||
CalculationTests
|
CalculationTests,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue