Fixed #16123 -- Ensured strptime receive proper string type

strptime generates an UnicodeEncodeError when using a non-ascii
unicode string on Python 2.
This commit is contained in:
Claude Paroz 2013-01-26 20:49:02 +01:00
parent 962f133f72
commit 4b3f7110ae
4 changed files with 18 additions and 7 deletions

View File

@ -9,6 +9,7 @@ import re
from django.forms.widgets import Widget, Select from django.forms.widgets import Widget, Select
from django.utils import datetime_safe from django.utils import datetime_safe
from django.utils.dates import MONTHS from django.utils.dates import MONTHS
from django.utils.encoding import force_str
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.formats import get_format from django.utils.formats import get_format
from django.utils import six from django.utils import six
@ -69,7 +70,7 @@ class SelectDateWidget(Widget):
if settings.USE_L10N: if settings.USE_L10N:
try: try:
input_format = get_format('DATE_INPUT_FORMATS')[0] input_format = get_format('DATE_INPUT_FORMATS')[0]
v = datetime.datetime.strptime(value, input_format) v = datetime.datetime.strptime(force_str(value), input_format)
year_val, month_val, day_val = v.year, v.month, v.day year_val, month_val, day_val = v.year, v.month, v.day
except ValueError: except ValueError:
pass pass

View File

@ -23,7 +23,7 @@ from django.forms.widgets import (TextInput, PasswordInput, HiddenInput,
NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION) SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION)
from django.utils import formats from django.utils import formats
from django.utils.encoding import smart_text, force_text from django.utils.encoding import smart_text, force_str, force_text
from django.utils.ipv6 import clean_ipv6_address from django.utils.ipv6 import clean_ipv6_address
from django.utils import six from django.utils import six
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -395,7 +395,7 @@ class DateField(BaseTemporalField):
return super(DateField, self).to_python(value) return super(DateField, self).to_python(value)
def strptime(self, value, format): def strptime(self, value, format):
return datetime.datetime.strptime(value, format).date() return datetime.datetime.strptime(force_str(value), format).date()
class TimeField(BaseTemporalField): class TimeField(BaseTemporalField):
@ -417,7 +417,7 @@ class TimeField(BaseTemporalField):
return super(TimeField, self).to_python(value) return super(TimeField, self).to_python(value)
def strptime(self, value, format): def strptime(self, value, format):
return datetime.datetime.strptime(value, format).time() return datetime.datetime.strptime(force_str(value), format).time()
class DateTimeField(BaseTemporalField): class DateTimeField(BaseTemporalField):
widget = DateTimeInput widget = DateTimeInput
@ -455,7 +455,7 @@ class DateTimeField(BaseTemporalField):
return from_current_timezone(result) return from_current_timezone(result)
def strptime(self, value, format): def strptime(self, value, format):
return datetime.datetime.strptime(value, format) return datetime.datetime.strptime(force_str(value), format)
class RegexField(CharField): class RegexField(CharField):
def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):

View File

@ -5,7 +5,7 @@ from django.conf import settings
from django.db import models from django.db import models
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.http import Http404 from django.http import Http404
from django.utils.encoding import force_text from django.utils.encoding import force_str, force_text
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils import timezone from django.utils import timezone
@ -673,7 +673,7 @@ def _date_from_string(year, year_format, month='', month_format='', day='', day_
format = delim.join((year_format, month_format, day_format)) format = delim.join((year_format, month_format, day_format))
datestr = delim.join((year, month, day)) datestr = delim.join((year, month, day))
try: try:
return datetime.datetime.strptime(datestr, format).date() return datetime.datetime.strptime(force_str(datestr), format).date()
except ValueError: except ValueError:
raise Http404(_("Invalid date string '%(datestr)s' given format '%(format)s'") % { raise Http404(_("Invalid date string '%(datestr)s' given format '%(format)s'") % {
'datestr': datestr, 'datestr': datestr,

View File

@ -370,6 +370,16 @@ class FieldsTests(SimpleTestCase):
self.assertFalse(f._has_changed(d, '17/09/2007')) self.assertFalse(f._has_changed(d, '17/09/2007'))
self.assertFalse(f._has_changed(d.strftime(format), '17/09/2007')) self.assertFalse(f._has_changed(d.strftime(format), '17/09/2007'))
def test_datefield_strptime(self):
"""Test that field.strptime doesn't raise an UnicodeEncodeError (#16123)"""
f = DateField()
try:
f.strptime('31 мая 2011', '%d-%b-%y')
except Exception as e:
# assertIsInstance or assertRaises cannot be used because UnicodeEncodeError
# is a subclass of ValueError
self.assertEqual(e.__class__, ValueError)
# TimeField ################################################################### # TimeField ###################################################################
def test_timefield_1(self): def test_timefield_1(self):