Commit 534792d0 authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #14290 -- Made format localization faster by caching the format modules....

Fixed #14290 -- Made format localization faster by caching the format modules. Thanks, Teemu Kurppa and Anssi Kääriäinen for the report and initial patches.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13898 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 9c402f0e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -58,6 +58,11 @@ def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'):

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    # Handle the common case first, saves 30-40% in performance when s
    # is an instance of unicode. This function gets called often in that
    # setting.
    if isinstance(s, unicode):
        return s
    if strings_only and is_protected_type(s):
        return s
    try:
+50 −30
Original line number Diff line number Diff line
@@ -7,34 +7,41 @@ from django.utils.importlib import import_module
from django.utils.encoding import smart_str
from django.utils import dateformat, numberformat, datetime_safe

def get_format_modules(reverse=False):
# format_cache is a mapping from (format_type, lang) to the format string.
# By using the cache, it is possible to avoid running get_format_modules
# repeatedly.
_format_cache = {}
_format_modules_cache = {}

def iter_format_modules(lang):
    """
    Returns an iterator over the format modules found in the project and Django
    Does the heavy lifting of finding format modules.
    """
    modules = []
    if not check_for_language(get_language()) or not settings.USE_L10N:
        return modules
    locale = to_locale(get_language())
    if check_for_language(lang) or settings.USE_L10N:
        format_locations = ['django.conf.locale.%s']
        if settings.FORMAT_MODULE_PATH:
        format_locations = [settings.FORMAT_MODULE_PATH + '.%s']
    else:
        format_locations = []
    format_locations.append('django.conf.locale.%s')
            format_locations.append(settings.FORMAT_MODULE_PATH + '.%s')
            format_locations.reverse()
        locale = to_locale(lang)
        locales = set((locale, locale.split('_')[0]))
        for location in format_locations:
        for l in (locale, locale.split('_')[0]):
            for loc in locales:
                try:
                mod = import_module('.formats', location % l)
                    yield import_module('.formats', location % loc)
                except ImportError:
                    pass
            else:
                # Don't return duplicates
                if mod not in modules:
                    modules.append(mod)

def get_format_modules(reverse=False):
    """
    Returns an iterator over the format modules found
    """
    lang = get_language()
    modules = _format_modules_cache.setdefault(lang, list(iter_format_modules(lang)))
    if reverse:
        modules.reverse()
    return modules

def get_format(format_type):
def get_format(format_type, lang=None):
    """
    For a specific format type, returns the format for the current
    language (locale), defaults to the format in the settings.
@@ -42,11 +49,20 @@ def get_format(format_type):
    """
    format_type = smart_str(format_type)
    if settings.USE_L10N:
        if lang is None:
            lang = get_language()
        cache_key = (format_type, lang)
        try:
            return _format_cache[cache_key] or getattr(settings, format_type)
        except KeyError:
            for module in get_format_modules():
                try:
                return getattr(module, format_type)
                    val = getattr(module, format_type)
                    _format_cache[cache_key] = val
                    return val
                except AttributeError:
                    pass
            _format_cache[cache_key] = None
    return getattr(settings, format_type)

def date_format(value, format=None):
@@ -66,12 +82,16 @@ def number_format(value, decimal_pos=None):
    """
    Formats a numeric value using localization settings
    """
    if settings.USE_L10N:
        lang = get_language()
    else:
        lang = None
    return numberformat.format(
        value,
        get_format('DECIMAL_SEPARATOR'),
        get_format('DECIMAL_SEPARATOR', lang),
        decimal_pos,
        get_format('NUMBER_GROUPING'),
        get_format('THOUSAND_SEPARATOR'),
        get_format('NUMBER_GROUPING', lang),
        get_format('THOUSAND_SEPARATOR', lang),
    )

def localize(value):
@@ -97,7 +117,7 @@ def localize_input(value, default=None):
    """
    if isinstance(value, (decimal.Decimal, float, int)):
        return number_format(value)
    if isinstance(value, datetime.datetime):
    elif isinstance(value, datetime.datetime):
        value = datetime_safe.new_datetime(value)
        format = smart_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
        return value.strftime(format)
+9 −3
Original line number Diff line number Diff line
from django.conf import settings
from django.utils.safestring import mark_safe


def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
    """
@@ -11,15 +13,20 @@ def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
    * thousand_sep: Thousand separator symbol (for example ",")

    """
    use_grouping = settings.USE_L10N and \
        settings.USE_THOUSAND_SEPARATOR and grouping
    # Make the common case fast:
    if isinstance(number, int) and not use_grouping and not decimal_pos:
        return mark_safe(unicode(number))
    # sign
    if float(number) < 0:
        sign = '-'
    else:
        sign = ''
    # decimal part
    str_number = unicode(number)
    if str_number[0] == '-':
        str_number = str_number[1:]
    # decimal part
    if '.' in str_number:
        int_part, dec_part = str_number.split('.')
        if decimal_pos:
@@ -30,13 +37,12 @@ def format(number, decimal_sep, decimal_pos, grouping=0, thousand_sep=''):
        dec_part = dec_part + ('0' * (decimal_pos - len(dec_part)))
    if dec_part: dec_part = decimal_sep + dec_part
    # grouping
    if settings.USE_L10N and settings.USE_THOUSAND_SEPARATOR and grouping:
    if use_grouping:
        int_part_gd = ''
        for cnt, digit in enumerate(int_part[::-1]):
            if cnt and not cnt % grouping:
                int_part_gd += thousand_sep
            int_part_gd += digit
        int_part = int_part_gd[::-1]

    return sign + int_part + dec_part
+0 −0

Empty file added.

+0 −0

Empty file added.

Loading