From e32a87ada4f78ba42713972e0dc6523440057111 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 6 Aug 2003 21:17:09 +0000 Subject: Re-introduction of caching. Not thread-safe against the changing of locale in the middle of executing time.strptime . Added new tests for caching mechanism; taken from 2.4 branch and tweaked appropriately. --- Lib/_strptime.py | 22 +++++++++++++++++++--- Lib/test/test_strptime.py | 41 +++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/Lib/_strptime.py b/Lib/_strptime.py index ed8ed35..02eacce 100644 --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -397,12 +397,28 @@ class TimeRE(dict): """Return a compiled re object for the format string.""" 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"): """Return a time struct based on the input data and the format string.""" - time_re = TimeRE() - locale_time = time_re.locale_time - format_regex = time_re.compile(format) + global _locale_cache + global _regex_cache + locale_time = _locale_cache.locale_time + # 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) if not found: raise ValueError("time data did not match format: data=%s fmt=%s" % diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py index 183ec56..ee24b72 100644 --- a/Lib/test/test_strptime.py +++ b/Lib/test/test_strptime.py @@ -417,6 +417,46 @@ class CalculationTests(unittest.TestCase): self.failUnless(result.tm_wday == self.time_tuple.tm_wday, "Calculation of day of the week failed;" "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday)) + +class CacheTests(unittest.TestCase): + """Test that caching works properly.""" + + def test_time_re_recreation(self): + # Make sure cache is recreated when current locale does not match what + # cached object was created with. + _strptime.strptime("10", "%d") + _strptime._locale_cache.locale_time = _strptime.LocaleTime(lang="Ni") + original_time_re = id(_strptime._locale_cache) + _strptime.strptime("10", "%d") + self.failIfEqual(original_time_re, id(_strptime._locale_cache)) + + def test_regex_cleanup(self): + # Make sure cached regexes are discarded when cache becomes "full". + try: + del _strptime._regex_cache['%d'] + except KeyError: + pass + bogus_key = 0 + while len(_strptime._regex_cache) <= 5: + _strptime._regex_cache[bogus_key] = None + bogus_key += 1 + _strptime.strptime("10", "%d") + self.failUnlessEqual(len(_strptime._regex_cache), 1) + + def test_new_localetime(self): + # A new LocaleTime instance should be created when a new TimeRE object + # is created. + _strptime._locale_cache.locale_time = _strptime.LocaleTime(lang="Ni") + locale_time_id = id(_strptime._locale_cache.locale_time) + locale_time_lang = _strptime._locale_cache.locale_time.lang + _strptime.strptime("10", "%d") + self.failIfEqual(locale_time_id, + id(_strptime._locale_cache.locale_time)) + self.failIfEqual(locale_time_lang, + _strptime._locale_cache.locale_time.lang) + + + def test_main(): test_support.run_unittest( getlang_Tests, @@ -426,6 +466,7 @@ def test_main(): Strptime12AMPMTests, JulianTests, CalculationTests, + CacheTests ) diff --git a/Misc/NEWS b/Misc/NEWS index 45bf3e5..cc3dcd8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,10 @@ Library - Bug #782369: fix memory leak in array module. +- Caching in _strptime.py has been re-introduced. This leads to a large + performance boost at the cost of being thread-safe from locale changes + while executing time.strptime() . + IDLE ---- -- cgit v0.12