From 3916cfbaff3b0b41d977a5efb6a9d9b41b067d90 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Mon, 14 May 2007 11:56:20 +0000 Subject: [PATCH] unicode: Replaced all implicit uses of _() from builtins with explicitly importing ugettext and aliasing it to _. Refs #2920. git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5230 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/filterspecs.py | 1 + .../contrib/admin/templatetags/admin_list.py | 2 +- django/contrib/admin/views/auth.py | 1 + django/contrib/admin/views/decorators.py | 2 +- django/contrib/admin/views/doc.py | 1 + django/contrib/admin/views/main.py | 1 + django/contrib/auth/models.py | 2 +- django/contrib/auth/views.py | 1 + django/contrib/comments/views/karma.py | 1 + django/core/validators.py | 72 +++++++++---------- django/db/models/fields/__init__.py | 14 ++-- django/db/models/fields/related.py | 2 +- django/db/models/manipulators.py | 1 + django/oldforms/__init__.py | 2 +- django/template/__init__.py | 1 + django/utils/translation/trans_real.py | 10 +-- tests/regressiontests/templates/tests.py | 2 +- 17 files changed, 62 insertions(+), 54 deletions(-) diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py index 1aef670598..5fa1d82dfa 100644 --- a/django/contrib/admin/filterspecs.py +++ b/django/contrib/admin/filterspecs.py @@ -8,6 +8,7 @@ certain test -- e.g. being a DateField or ForeignKey. from django.db import models from django.utils.encoding import smart_unicode +from django.utils.translation import ugettext as _ import datetime class FilterSpec(object): diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index b79060db5f..22ffc282a4 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -6,7 +6,7 @@ from django.db import models from django.utils import dateformat from django.utils.html import escape from django.utils.text import capfirst -from django.utils.translation import get_date_formats, get_partial_date_formats +from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _ from django.utils.encoding import smart_unicode, smart_str from django.template import Library import datetime diff --git a/django/contrib/admin/views/auth.py b/django/contrib/admin/views/auth.py index c6ad0c3a95..0c8104831b 100644 --- a/django/contrib/admin/views/auth.py +++ b/django/contrib/admin/views/auth.py @@ -6,6 +6,7 @@ from django import oldforms, template from django.shortcuts import render_to_response, get_object_or_404 from django.http import HttpResponseRedirect from django.utils.html import escape +from django.utils.translation import ugettext as _ def user_add_stage(request): if not request.user.has_perm('auth.change_user'): diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py index 2a5b7335cd..9ae0170b54 100644 --- a/django/contrib/admin/views/decorators.py +++ b/django/contrib/admin/views/decorators.py @@ -3,7 +3,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.contrib.auth import authenticate, login from django.shortcuts import render_to_response -from django.utils.translation import ugettext_lazy +from django.utils.translation import ugettext_lazy, ugettext as _ import base64, datetime, md5 import cPickle as pickle diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py index 6adfb57c92..8d79f49e0c 100644 --- a/django/contrib/admin/views/doc.py +++ b/django/contrib/admin/views/doc.py @@ -9,6 +9,7 @@ from django.http import Http404, get_host from django.core import urlresolvers from django.contrib.admin import utils from django.contrib.sites.models import Site +from django.utils.translation import ugettext as _ import inspect, os, re # Exclude methods starting with these strings from documentation diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index ca74ec73ff..576fd101f8 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -13,6 +13,7 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect from django.utils.html import escape from django.utils.text import capfirst, get_text_list from django.utils.encoding import smart_unicode +from django.utils.translation import ugettext as _ import operator from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index e684c0294d..6137b52baf 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -2,7 +2,7 @@ from django.core import validators from django.core.exceptions import ImproperlyConfigured from django.db import backend, connection, models from django.contrib.contenttypes.models import ContentType -from django.utils.translation import ugettext_lazy +from django.utils.translation import ugettext_lazy, ugettext as _ import datetime def check_password(raw_password, enc_password): diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py index 77350b9a8f..141f710bfd 100644 --- a/django/contrib/auth/views.py +++ b/django/contrib/auth/views.py @@ -7,6 +7,7 @@ from django.contrib.sites.models import Site from django.http import HttpResponseRedirect from django.contrib.auth.decorators import login_required from django.contrib.auth import REDIRECT_FIELD_NAME +from django.utils.translation import ugettext as _ def login(request, template_name='registration/login.html'): "Displays the login form and handles the login action." diff --git a/django/contrib/comments/views/karma.py b/django/contrib/comments/views/karma.py index 8c18523feb..c6ad301dee 100644 --- a/django/contrib/comments/views/karma.py +++ b/django/contrib/comments/views/karma.py @@ -2,6 +2,7 @@ from django.http import Http404 from django.shortcuts import render_to_response from django.template import RequestContext from django.contrib.comments.models import Comment, KarmaScore +from django.utils.translation import ugettext as _ def vote(request, comment_id, vote): """ diff --git a/django/core/validators.py b/django/core/validators.py index b9c9f7fa08..42bf59439f 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -10,7 +10,7 @@ form field is required. import urllib2 from django.conf import settings -from django.utils.translation import ugettext, ugettext_lazy, ungettext +from django.utils.translation import ugettext as _, ugettext_lazy, ungettext from django.utils.functional import Promise, lazy import re @@ -61,30 +61,30 @@ class CriticalValidationError(Exception): def isAlphaNumeric(field_data, all_data): if not alnum_re.search(field_data): - raise ValidationError, ugettext("This value must contain only letters, numbers and underscores.") + raise ValidationError, _("This value must contain only letters, numbers and underscores.") def isAlphaNumericURL(field_data, all_data): if not alnumurl_re.search(field_data): - raise ValidationError, ugettext("This value must contain only letters, numbers, underscores, dashes or slashes.") + raise ValidationError, _("This value must contain only letters, numbers, underscores, dashes or slashes.") def isSlug(field_data, all_data): if not slug_re.search(field_data): - raise ValidationError, ugettext("This value must contain only letters, numbers, underscores or hyphens.") + raise ValidationError, _("This value must contain only letters, numbers, underscores or hyphens.") def isLowerCase(field_data, all_data): if field_data.lower() != field_data: - raise ValidationError, ugettext("Uppercase letters are not allowed here.") + raise ValidationError, _("Uppercase letters are not allowed here.") def isUpperCase(field_data, all_data): if field_data.upper() != field_data: - raise ValidationError, ugettext("Lowercase letters are not allowed here.") + raise ValidationError, _("Lowercase letters are not allowed here.") def isCommaSeparatedIntegerList(field_data, all_data): for supposed_int in field_data.split(','): try: int(supposed_int) except ValueError: - raise ValidationError, ugettext("Enter only digits separated by commas.") + raise ValidationError, _("Enter only digits separated by commas.") def isCommaSeparatedEmailList(field_data, all_data): """ @@ -96,32 +96,32 @@ def isCommaSeparatedEmailList(field_data, all_data): try: isValidEmail(supposed_email.strip(), '') except ValidationError: - raise ValidationError, ugettext("Enter valid e-mail addresses separated by commas.") + raise ValidationError, _("Enter valid e-mail addresses separated by commas.") def isValidIPAddress4(field_data, all_data): if not ip4_re.search(field_data): - raise ValidationError, ugettext("Please enter a valid IP address.") + raise ValidationError, _("Please enter a valid IP address.") def isNotEmpty(field_data, all_data): if field_data.strip() == '': - raise ValidationError, ugettext("Empty values are not allowed here.") + raise ValidationError, _("Empty values are not allowed here.") def isOnlyDigits(field_data, all_data): if not field_data.isdigit(): - raise ValidationError, ugettext("Non-numeric characters aren't allowed here.") + raise ValidationError, _("Non-numeric characters aren't allowed here.") def isNotOnlyDigits(field_data, all_data): if field_data.isdigit(): - raise ValidationError, ugettext("This value can't be comprised solely of digits.") + raise ValidationError, _("This value can't be comprised solely of digits.") def isInteger(field_data, all_data): # This differs from isOnlyDigits because this accepts the negative sign if not integer_re.search(field_data): - raise ValidationError, ugettext("Enter a whole number.") + raise ValidationError, _("Enter a whole number.") def isOnlyLetters(field_data, all_data): if not field_data.isalpha(): - raise ValidationError, ugettext("Only alphabetical characters are allowed here.") + raise ValidationError, _("Only alphabetical characters are allowed here.") def _isValidDate(date_string): """ @@ -136,30 +136,30 @@ def _isValidDate(date_string): # This check is needed because strftime is used when saving the date # value to the database, and strftime requires that the year be >=1900. if year < 1900: - raise ValidationError, ugettext('Year must be 1900 or later.') + raise ValidationError, _('Year must be 1900 or later.') try: date(year, month, day) except ValueError, e: - msg = ugettext('Invalid date: %s') % ugettext(str(e)) + msg = _('Invalid date: %s') % _(str(e)) raise ValidationError, msg def isValidANSIDate(field_data, all_data): if not ansi_date_re.search(field_data): - raise ValidationError, ugettext('Enter a valid date in YYYY-MM-DD format.') + raise ValidationError, _('Enter a valid date in YYYY-MM-DD format.') _isValidDate(field_data) def isValidANSITime(field_data, all_data): if not ansi_time_re.search(field_data): - raise ValidationError, ugettext('Enter a valid time in HH:MM format.') + raise ValidationError, _('Enter a valid time in HH:MM format.') def isValidANSIDatetime(field_data, all_data): if not ansi_datetime_re.search(field_data): - raise ValidationError, ugettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.') + raise ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') _isValidDate(field_data.split()[0]) def isValidEmail(field_data, all_data): if not email_re.search(field_data): - raise ValidationError, ugettext('Enter a valid e-mail address.') + raise ValidationError, _('Enter a valid e-mail address.') def isValidImage(field_data, all_data): """ @@ -171,22 +171,22 @@ def isValidImage(field_data, all_data): try: content = field_data['content'] except TypeError: - raise ValidationError, ugettext("No file was submitted. Check the encoding type on the form.") + raise ValidationError, _("No file was submitted. Check the encoding type on the form.") try: Image.open(StringIO(content)) except IOError: # Python Imaging Library doesn't recognize it as an image - raise ValidationError, ugettext("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") + raise ValidationError, _("Upload a valid image. The file you uploaded was either not an image or a corrupted image.") def isValidImageURL(field_data, all_data): uc = URLMimeTypeCheck(('image/jpeg', 'image/gif', 'image/png')) try: uc(field_data, all_data) except URLMimeTypeCheck.InvalidContentType: - raise ValidationError, ugettext("The URL %s does not point to a valid image.") % field_data + raise ValidationError, _("The URL %s does not point to a valid image.") % field_data def isValidPhone(field_data, all_data): if not phone_re.search(field_data): - raise ValidationError, ugettext('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data + raise ValidationError, _('Phone numbers must be in XXX-XXX-XXXX format. "%s" is invalid.') % field_data def isValidQuicktimeVideoURL(field_data, all_data): "Checks that the given URL is a video that can be played by QuickTime (qt, mpeg)" @@ -194,11 +194,11 @@ def isValidQuicktimeVideoURL(field_data, all_data): try: uc(field_data, all_data) except URLMimeTypeCheck.InvalidContentType: - raise ValidationError, ugettext("The URL %s does not point to a valid QuickTime video.") % field_data + raise ValidationError, _("The URL %s does not point to a valid QuickTime video.") % field_data def isValidURL(field_data, all_data): if not url_re.search(field_data): - raise ValidationError, ugettext("A valid URL is required.") + raise ValidationError, _("A valid URL is required.") def isValidHTML(field_data, all_data): import urllib, urllib2 @@ -212,14 +212,14 @@ def isValidHTML(field_data, all_data): return from xml.dom.minidom import parseString error_messages = [e.firstChild.wholeText for e in parseString(u.read()).getElementsByTagName('messages')[0].getElementsByTagName('msg')] - raise ValidationError, ugettext("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) + raise ValidationError, _("Valid HTML is required. Specific errors are:\n%s") % "\n".join(error_messages) def isWellFormedXml(field_data, all_data): from xml.dom.minidom import parseString try: parseString(field_data) except Exception, e: # Naked except because we're not sure what will be thrown - raise ValidationError, ugettext("Badly formed XML: %s") % str(e) + raise ValidationError, _("Badly formed XML: %s") % str(e) def isWellFormedXmlFragment(field_data, all_data): isWellFormedXml('%s' % field_data, all_data) @@ -249,7 +249,7 @@ def isValidUSState(field_data, all_data): "Checks that the given string is a valid two-letter U.S. state abbreviation" states = ['AA', 'AE', 'AK', 'AL', 'AP', 'AR', 'AS', 'AZ', 'CA', 'CO', 'CT', 'DC', 'DE', 'FL', 'FM', 'GA', 'GU', 'HI', 'IA', 'ID', 'IL', 'IN', 'KS', 'KY', 'LA', 'MA', 'MD', 'ME', 'MH', 'MI', 'MN', 'MO', 'MP', 'MS', 'MT', 'NC', 'ND', 'NE', 'NH', 'NJ', 'NM', 'NV', 'NY', 'OH', 'OK', 'OR', 'PA', 'PR', 'PW', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VA', 'VI', 'VT', 'WA', 'WI', 'WV', 'WY'] if field_data.upper() not in states: - raise ValidationError, ugettext("Enter a valid U.S. state abbreviation.") + raise ValidationError, _("Enter a valid U.S. state abbreviation.") def hasNoProfanities(field_data, all_data): """ @@ -364,11 +364,11 @@ class NumberIsInRange(object): self.lower, self.upper = lower, upper if not error_message: if lower and upper: - self.error_message = ugettext("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} + self.error_message = _("This value must be between %(lower)s and %(upper)s.") % {'lower': lower, 'upper': upper} elif lower: - self.error_message = ugettext("This value must be at least %s.") % lower + self.error_message = _("This value must be at least %s.") % lower elif upper: - self.error_message = ugettext("This value must be no more than %s.") % upper + self.error_message = _("This value must be no more than %s.") % upper else: self.error_message = error_message @@ -404,7 +404,7 @@ class IsAPowerOf(object): from math import log val = log(int(field_data)) / log(self.power_of) if val != int(val): - raise ValidationError, ugettext("This value must be a power of %s.") % self.power_of + raise ValidationError, _("This value must be a power of %s.") % self.power_of class IsValidFloat(object): def __init__(self, max_digits, decimal_places): @@ -415,7 +415,7 @@ class IsValidFloat(object): try: float(data) except ValueError: - raise ValidationError, ugettext("Please enter a valid decimal number.") + raise ValidationError, _("Please enter a valid decimal number.") # Negative floats require more space to input. max_allowed_length = data.startswith('-') and (self.max_digits + 2) or (self.max_digits + 1) if len(data) > max_allowed_length: @@ -504,10 +504,10 @@ class URLMimeTypeCheck(object): try: info = urllib2.urlopen(field_data).info() except (urllib2.HTTPError, urllib2.URLError): - raise URLMimeTypeCheck.CouldNotRetrieve, ugettext("Could not retrieve anything from %s.") % field_data + raise URLMimeTypeCheck.CouldNotRetrieve, _("Could not retrieve anything from %s.") % field_data content_type = info['content-type'] if content_type not in self.mime_type_list: - raise URLMimeTypeCheck.InvalidContentType, ugettext("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { + raise URLMimeTypeCheck.InvalidContentType, _("The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'.") % { 'url': field_data, 'contenttype': content_type} class RelaxNGCompact(object): diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index aa3596403e..5003f0e389 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -8,7 +8,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.utils.functional import curry from django.utils.itercompat import tee from django.utils.text import capfirst -from django.utils.translation import ugettext, ugettext_lazy +from django.utils.translation import ugettext_lazy, ugettext as _ from django.utils.encoding import smart_unicode import datetime, os, time @@ -40,7 +40,7 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data): return if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val(): return - raise validators.ValidationError, ugettext("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name} + raise validators.ValidationError, _("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name} # A guide to Field parameters: # @@ -367,7 +367,7 @@ class AutoField(Field): try: return int(value) except (TypeError, ValueError): - raise validators.ValidationError, ugettext("This value must be an integer.") + raise validators.ValidationError, _("This value must be an integer.") def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): if not rel: @@ -402,7 +402,7 @@ class BooleanField(Field): if value in (True, False): return value if value in ('t', 'True', '1'): return True if value in ('f', 'False', '0'): return False - raise validators.ValidationError, ugettext("This value must be either True or False.") + raise validators.ValidationError, _("This value must be either True or False.") def get_manipulator_field_objs(self): return [oldforms.CheckboxField] @@ -457,7 +457,7 @@ class DateField(Field): try: return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) except ValueError: - raise validators.ValidationError, ugettext('Enter a valid date in YYYY-MM-DD format.') + raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') def get_db_prep_lookup(self, lookup_type, value): if lookup_type == 'range': @@ -526,7 +526,7 @@ class DateTimeField(DateField): try: return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3]) except ValueError: - raise validators.ValidationError, ugettext('Enter a valid date/time in YYYY-MM-DD HH:MM format.') + raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM format.') def get_db_prep_save(self, value): # Casts dates into string format for entry into database. @@ -751,7 +751,7 @@ class NullBooleanField(Field): if value in ('None'): return None if value in ('t', 'True', '1'): return True if value in ('f', 'False', '0'): return False - raise validators.ValidationError, ugettext("This value must be either None, True or False.") + raise validators.ValidationError, _("This value must be either None, True or False.") def get_manipulator_field_objs(self): return [oldforms.NullBooleanField] diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 93b0608fc6..95aa66a1ef 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -3,7 +3,7 @@ from django.db.models import signals, get_model from django.db.models.fields import AutoField, Field, IntegerField, get_ul_class from django.db.models.related import RelatedObject from django.utils.text import capfirst -from django.utils.translation import ugettext_lazy, string_concat, ungettext +from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ from django.utils.functional import curry from django.utils.encoding import smart_unicode from django.core import validators diff --git a/django/db/models/manipulators.py b/django/db/models/manipulators.py index 10e581720b..c3e5292198 100644 --- a/django/db/models/manipulators.py +++ b/django/db/models/manipulators.py @@ -8,6 +8,7 @@ from django.utils.functional import curry from django.utils.datastructures import DotExpandedDict from django.utils.text import capfirst from django.utils.encoding import smart_str +from django.utils.translation import ugettext as _ import types def add_manipulators(sender): diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index 6edfd7059d..d802f33468 100644 --- a/django/oldforms/__init__.py +++ b/django/oldforms/__init__.py @@ -584,7 +584,7 @@ class NullBooleanField(SelectField): "This SelectField provides 'Yes', 'No' and 'Unknown', mapping results to True, False or None" def __init__(self, field_name, is_required=False, validator_list=None): if validator_list is None: validator_list = [] - SelectField.__init__(self, field_name, choices=[('1', _('Unknown')), ('2', _('Yes')), ('3', _('No'))], + SelectField.__init__(self, field_name, choices=[('1', ugettext('Unknown')), ('2', ugettext('Yes')), ('3', ugettext('No'))], is_required=is_required, validator_list=validator_list) def render(self, data): diff --git a/django/template/__init__.py b/django/template/__init__.py index ae2243b47e..b9349e64cd 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -61,6 +61,7 @@ from django.template.context import Context, RequestContext, ContextPopException from django.utils.functional import curry from django.utils.text import smart_split from django.utils.encoding import smart_unicode, smart_str +from django.utils.translation import ugettext as _ __all__ = ('Template', 'Context', 'RequestContext', 'compile_string') diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 2b8e8fa448..a78a0f9af9 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -380,9 +380,9 @@ def get_date_formats(): one, the formats provided in the settings will be used. """ from django.conf import settings - date_format = _('DATE_FORMAT') - datetime_format = _('DATETIME_FORMAT') - time_format = _('TIME_FORMAT') + date_format = ugettext('DATE_FORMAT') + datetime_format = ugettext('DATETIME_FORMAT') + time_format = ugettext('TIME_FORMAT') if date_format == 'DATE_FORMAT': date_format = settings.DATE_FORMAT if datetime_format == 'DATETIME_FORMAT': @@ -398,8 +398,8 @@ def get_partial_date_formats(): one, the formats provided in the settings will be used. """ from django.conf import settings - year_month_format = _('YEAR_MONTH_FORMAT') - month_day_format = _('MONTH_DAY_FORMAT') + year_month_format = ugettext('YEAR_MONTH_FORMAT') + month_day_format = ugettext('MONTH_DAY_FORMAT') if year_month_format == 'YEAR_MONTH_FORMAT': year_month_format = settings.YEAR_MONTH_FORMAT if month_day_format == 'MONTH_DAY_FORMAT': diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index c995ebd955..da1ad4f427 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -8,7 +8,7 @@ if __name__ == '__main__': from django import template from django.template import loader -from django.utils.translation import activate, deactivate, install +from django.utils.translation import activate, deactivate, install, ugettext as _ from django.utils.tzinfo import LocalTimezone from datetime import datetime, timedelta from unicode import unicode_tests