Commit 7f6b4f86 authored by Brett Cannon's avatar Brett Cannon

Make sure time.strptime only accepts strings (and document the fact like

strftime). Already didn't accept bytes but make the check earlier. This also
lifts the limitation of requiring ASCII.

Closes issue #5236. Thanks Tennessee Leeuwenburg.
parent d687887b
......@@ -358,15 +358,17 @@ The module defines the following functions and data items:
.. function:: strptime(string[, format])
Parse a string representing a time according to a format. The return value is
a :class:`struct_time` as returned by :func:`gmtime` or :func:`localtime`.
Parse a string representing a time according to a format. The return value
is a :class:`struct_time` as returned by :func:`gmtime` or
:func:`localtime`.
The *format* parameter uses the same directives as those used by
:func:`strftime`; it defaults to ``"%a %b %d %H:%M:%S %Y"`` which matches the
formatting returned by :func:`ctime`. If *string* cannot be parsed according to
*format*, or if it has excess data after parsing, :exc:`ValueError` is raised.
The default values used to fill in any missing data when more accurate values
cannot be inferred are ``(1900, 1, 1, 0, 0, 0, 0, 1, -1)``.
formatting returned by :func:`ctime`. If *string* cannot be parsed according
to *format*, or if it has excess data after parsing, :exc:`ValueError` is
raised. The default values used to fill in any missing data when more
accurate values cannot be inferred are ``(1900, 1, 1, 0, 0, 0, 0, 1, -1)``.
Both *string* and *format* must be strings.
For example:
......
......@@ -262,7 +262,7 @@ class TimeRE(dict):
def compile(self, format):
"""Return a compiled re object for the format string."""
return re_compile(self.pattern(format), IGNORECASE | ASCII)
return re_compile(self.pattern(format), IGNORECASE)
_cache_lock = _thread_allocate_lock()
# DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock
......@@ -294,8 +294,15 @@ def _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon):
def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
"""Return a time struct based on the input string and the format string."""
for index, arg in enumerate([data_string, format]):
if not isinstance(arg, str):
msg = "strptime() argument {} must be str, not {}"
raise TypeError(msg.format(arg, index))
global _TimeRE_cache, _regex_cache
with _cache_lock:
if _getlang() != _TimeRE_cache.locale_time.lang:
_TimeRE_cache = TimeRE()
_regex_cache.clear()
......
......@@ -116,6 +116,11 @@ class TimeTestCase(unittest.TestCase):
self.fail("conversion specifier %r failed with '%s' input." %
(format, strf_output))
def test_strptime_bytes(self):
# Make sure only strings are accepted as arguments to strptime.
self.assertRaises(TypeError, time.strptime, b'2009', "%Y")
self.assertRaises(TypeError, time.strptime, '2009', b'%Y')
def test_asctime(self):
time.asctime(time.gmtime(self.t))
self.assertRaises(TypeError, time.asctime, 0)
......
......@@ -411,6 +411,7 @@ John J. Lee
Inyeol Lee
Thomas Lee
Christopher Lee
Tennessee Leeuwenburg
Luc Lefebvre
Kip Lehman
Joerg Lehmann
......
......@@ -43,6 +43,9 @@ Core and Builtins
Library
-------
- Issue #5236: Change time.strptime() to only take strings. Didn't work with
bytes already but the failure was non-obvious.
- Issue #5177: Multiprocessing's SocketListener class now uses
socket.SO_REUSEADDR on all connections so that the user no longer needs
to wait 120 seconds for the socket to expire.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment