Commit 9b7455e9 authored by Bouke Haarsma's avatar Bouke Haarsma Committed by Baptiste Mispelon
Browse files

Fixed #21351 -- Replaced memoize with Python's lru_cache.

Replaced the custom, untested memoize with a similar decorator from Python's
3.2 stdlib. Although some minor performance degradation (see ticket), it is
expected that in the long run lru_cache will outperform memoize once it is
implemented in C.

Thanks to EvilDMP for the report and Baptiste Mispelon for the idea of
replacing memoize with lru_cache.
parent 6c5f5b9a
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -4,16 +4,14 @@ import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.storage import default_storage, Storage, FileSystemStorage
from django.utils.functional import empty, memoize, LazyObject
from django.utils.functional import empty, LazyObject
from django.utils.module_loading import import_by_path
from django.utils._os import safe_join
from django.utils import six
from django.utils import six, lru_cache

from django.contrib.staticfiles import utils
from django.contrib.staticfiles.storage import AppStaticStorage

_finders = OrderedDict()


class BaseFinder(object):
    """
@@ -254,7 +252,8 @@ def get_finders():
        yield get_finder(finder_path)


def _get_finder(import_path):
@lru_cache.lru_cache(maxsize=None)
def get_finder(import_path):
    """
    Imports the staticfiles finder class described by import_path, where
    import_path is the full Python path to the class.
@@ -264,4 +263,3 @@ def _get_finder(import_path):
        raise ImproperlyConfigured('Finder "%s" is not a subclass of "%s"' %
                                   (Finder, BaseFinder))
    return Finder()
get_finder = memoize(_get_finder, _finders, 1)
+4 −5
Original line number Diff line number Diff line
@@ -14,8 +14,9 @@ from django.core.management.color import no_style
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
      IntegrityError, DatabaseError)
from django.db.models import get_app_paths
from django.utils import lru_cache
from django.utils.encoding import force_text
from django.utils.functional import cached_property, memoize
from django.utils.functional import cached_property
from django.utils._os import upath
from itertools import product

@@ -164,7 +165,8 @@ class Command(BaseCommand):
                    RuntimeWarning
                )

    def _find_fixtures(self, fixture_label):
    @lru_cache.lru_cache(maxsize=None)
    def find_fixtures(self, fixture_label):
        """
        Finds fixture files for a given label.
        """
@@ -220,9 +222,6 @@ class Command(BaseCommand):

        return fixture_files

    _label_to_fixtures_cache = {}
    find_fixtures = memoize(_find_fixtures, _label_to_fixtures_cache, 2)

    @cached_property
    def fixture_dirs(self):
        """
+8 −15
Original line number Diff line number Diff line
@@ -16,18 +16,14 @@ from django.http import Http404
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import force_str, force_text, iri_to_uri
from django.utils.functional import memoize, lazy
from django.utils.functional import lazy
from django.utils.http import urlquote
from django.utils.module_loading import module_has_submodule
from django.utils.regex_helper import normalize
from django.utils import six
from django.utils import six, lru_cache
from django.utils.translation import get_language


_resolver_cache = {}  # Maps URLconf modules to RegexURLResolver instances.
_ns_resolver_cache = {}  # Maps namespaces to RegexURLResolver instances.
_callable_cache = {}  # Maps view and url pattern names to their view functions.

# SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for
# the current thread (which is the only one we ever access), it is assumed to
# be empty.
@@ -80,6 +76,7 @@ class NoReverseMatch(Exception):
    pass


@lru_cache.lru_cache(maxsize=None)
def get_callable(lookup_view, can_fail=False):
    """
    Convert a string version of a function name to the callable object.
@@ -119,17 +116,17 @@ def get_callable(lookup_view, can_fail=False):
                        "Could not import %s. View does not exist in module %s." %
                        (lookup_view, mod_name))
    return lookup_view
get_callable = memoize(get_callable, _callable_cache, 1)


@lru_cache.lru_cache(maxsize=None)
def get_resolver(urlconf):
    if urlconf is None:
        from django.conf import settings
        urlconf = settings.ROOT_URLCONF
    return RegexURLResolver(r'^/', urlconf)
get_resolver = memoize(get_resolver, _resolver_cache, 1)


@lru_cache.lru_cache(maxsize=None)
def get_ns_resolver(ns_pattern, resolver):
    # Build a namespaced resolver for the given parent urlconf pattern.
    # This makes it possible to have captured parameters in the parent
@@ -137,7 +134,6 @@ def get_ns_resolver(ns_pattern, resolver):
    ns_resolver = RegexURLResolver(ns_pattern,
                                          resolver.url_patterns)
    return RegexURLResolver(r'^/', [ns_resolver])
get_ns_resolver = memoize(get_ns_resolver, _ns_resolver_cache, 2)


def get_mod_func(callback):
@@ -523,12 +519,9 @@ reverse_lazy = lazy(reverse, str)


def clear_url_caches():
    global _resolver_cache
    global _ns_resolver_cache
    global _callable_cache
    _resolver_cache.clear()
    _ns_resolver_cache.clear()
    _callable_cache.clear()
    get_callable.cache_clear()
    get_resolver.cache_clear()
    get_ns_resolver.cache_clear()


def set_script_prefix(prefix):
+1 −1
Original line number Diff line number Diff line
@@ -427,7 +427,7 @@ class TransRealMixin(object):
        trans_real._translations = {}
        trans_real._active = local()
        trans_real._default = None
        trans_real._checked_languages = {}
        trans_real.check_for_language.cache_clear()

    def tearDown(self):
        self.flush_caches()
+5 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ import copy
import operator
from functools import wraps
import sys
import warnings

from django.utils import six
from django.utils.six.moves import copyreg
@@ -24,6 +25,10 @@ def memoize(func, cache, num_args):

    Only the first num_args are considered when creating the key.
    """
    warnings.warn(u"memoize wrapper is deprecated and will be removed in "
                  u"Django 1.9. Use django.utils.lru_cache instead.",
                  PendingDeprecationWarning, 2)

    @wraps(func)
    def wrapper(*args):
        mem_args = args[:num_args]
Loading