We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Mitigate the risk of revision counter also being in 'default' Redis cache
The revision counter goes into the 'default' cache.  This adds the risk of people clearing the default cache and also wiping out the revision counter — even if there's a way to restore it, we might want to prevent removal in the first place. This concern was raised in https://github.com/translate/pootle/issues/3500#issuecomment-73204160


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pootle/core/models.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2013-2015 Evernote Corporation
5 #
6 # This file is part of Pootle.
7 #
8 # Pootle is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 
23 from .cache import get_cache
24 from .mixins import TreeItem
25 
26 
27 cache = get_cache()
28 
29 
30 class Revision(object):
31     """Wrapper around the revision counter stored in Redis."""
32 
33     CACHE_KEY = 'pootle:revision'
34     INITIAL = 0
35 
36     @classmethod
37     def initialize(cls, force=False):
38         """Initializes the revision with `cls.INITIAL`.
39 
40         :param force: whether to overwrite the number if there's a
41             revision already set or not.
42         :return: `True` if the initial value was set, `False` otherwise.
43         """
44         if force:
45             return cls.set(cls.INITIAL)
46 
47         return cls.add(cls.INITIAL)
48 
49     @classmethod
50     def get(cls):
51         """Gets the current revision number.
52 
53         :return: The current revision number, or the initial number if
54             there's no revision stored yet.
55         """
56         return cache.get(cls.CACHE_KEY, cls.INITIAL)
57 
58     @classmethod
59     def set(cls, value):
60         """Sets the revision number to `value`, regardless of whether
61         there's a value previously set or not.
62 
63         :return: `True` if the value was set, `False` otherwise.
64         """
65         return cache.set(cls.CACHE_KEY, value, None)
66 
67     @classmethod
68     def add(cls, value):
69         """Sets the revision number to `value`, only if there's no
70         revision already set.
71 
72         :return: `True` if the value was set, `False` otherwise.
73         """
74         return cache.add(cls.CACHE_KEY, value, None)
75 
76     @classmethod
77     def incr(cls):
78         """Increments the revision number.
79 
80         :return: the new revision number after incrementing it, or the
81             initial number if there's no revision stored yet.
82         """
83         try:
84             return cache.incr(cls.CACHE_KEY)
85         except ValueError:
86             return cls.INITIAL
87 
88 
89 class VirtualResource(TreeItem):
90     """An object representing a virtual resource.
91 
92     A virtual resource doesn't live in the DB and has a unique
93     `pootle_path` of its own. It's a simple collection of actual
94     resources.
95 
96     For instance, this can be used in projects to have cross-language
97     references.
98 
99     Don't use this object as-is, rather subclass it and adapt the
100     implementation details for each context.
101     """
102     def __init__(self, resources, pootle_path, *args, **kwargs):
103         self.resources = resources  #: Collection of underlying resources
104         self.pootle_path = pootle_path
105 
106         super(VirtualResource, self).__init__(*args, **kwargs)
107 
108     def __unicode__(self):
109         return self.pootle_path
110 
111     ### TreeItem
112 
113     def get_children(self):
114         return self.resources
115 
116     def get_cachekey(self):
117         return self.pootle_path
118 
119     ### /TreeItem
120
```

Path: `pootle/core/cache.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2013-2015 Evernote Corporation
5 #
6 # This file is part of Pootle.
7 #
8 # Pootle is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, see <http://www.gnu.org/licenses/>.
20 
21 
22 from django.core.cache import caches, cache as default_cache
23 from django.core.cache.backends.base import InvalidCacheBackendError
24 
25 
26 def make_method_key(model, method, key):
27     """Creates a cache key for model's `method` method.
28 
29     :param model: A model instance
30     :param method: Method name to cache
31     :param key: a unique key to identify the object to be cached
32     """
33     prefix = 'method-cache'
34 
35     if isinstance(model, basestring):
36         name = model
37     else:
38         name = (model.__name__ if hasattr(model, '__name__')
39                                else model.__class__.__name__)
40 
41     key = key if not isinstance(key, dict) else make_key(**key)
42     return u':'.join([prefix, name, method, key])
43 
44 
45 def make_key(*args, **kwargs):
46     """Creates a cache key with key-value pairs from a dict."""
47     return ':'.join([
48         '%s=%s' % (k, v) for k, v in sorted(kwargs.iteritems())
49     ])
50 
51 
52 def get_cache(cache=None):
53     """Return ``cache`` or the 'default' cache if ``cache`` is not specified or
54     ``cache`` is not configured.
55 
56     :param cache: The name of the requested cache.
57     """
58     try:
59         return caches[cache]
60     except InvalidCacheBackendError:
61         return default_cache
62
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pootle/core/cache.py b/pootle/core/cache.py
--- a/pootle/core/cache.py
+++ b/pootle/core/cache.py
@@ -19,8 +19,13 @@
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 
+from django.conf import settings
 from django.core.cache import caches, cache as default_cache
 from django.core.cache.backends.base import InvalidCacheBackendError
+from django.core.exceptions import ImproperlyConfigured
+
+
+PERSISTENT_STORES = ('redis', 'stats')
 
 
 def make_method_key(model, method, key):
@@ -56,6 +61,17 @@
     :param cache: The name of the requested cache.
     """
     try:
+        # Check for proper Redis persistent backends
+        # FIXME: this logic needs to be a system sanity check
+        if (cache in PERSISTENT_STORES and
+            (cache not in settings.CACHES or
+            'RedisCache' not in settings.CACHES[cache]['BACKEND'] or
+            settings.CACHES[cache].get('TIMEOUT', '') != None)):
+            raise ImproperlyConfigured(
+                'Pootle requires a Redis-backed caching backend for %r '
+                'with `TIMEOUT: None`. Please review your settings.' % cache
+            )
+
         return caches[cache]
     except InvalidCacheBackendError:
         return default_cache
diff --git a/pootle/core/models.py b/pootle/core/models.py
--- a/pootle/core/models.py
+++ b/pootle/core/models.py
@@ -24,7 +24,7 @@
 from .mixins import TreeItem
 
 
-cache = get_cache()
+cache = get_cache('redis')
 
 
 class Revision(object):

{"golden_diff": "diff --git a/pootle/core/cache.py b/pootle/core/cache.py\n--- a/pootle/core/cache.py\n+++ b/pootle/core/cache.py\n@@ -19,8 +19,13 @@\n # along with this program; if not, see <http://www.gnu.org/licenses/>.\n \n \n+from django.conf import settings\n from django.core.cache import caches, cache as default_cache\n from django.core.cache.backends.base import InvalidCacheBackendError\n+from django.core.exceptions import ImproperlyConfigured\n+\n+\n+PERSISTENT_STORES = ('redis', 'stats')\n \n \n def make_method_key(model, method, key):\n@@ -56,6 +61,17 @@\n     :param cache: The name of the requested cache.\n     \"\"\"\n     try:\n+        # Check for proper Redis persistent backends\n+        # FIXME: this logic needs to be a system sanity check\n+        if (cache in PERSISTENT_STORES and\n+            (cache not in settings.CACHES or\n+            'RedisCache' not in settings.CACHES[cache]['BACKEND'] or\n+            settings.CACHES[cache].get('TIMEOUT', '') != None)):\n+            raise ImproperlyConfigured(\n+                'Pootle requires a Redis-backed caching backend for %r '\n+                'with `TIMEOUT: None`. Please review your settings.' % cache\n+            )\n+\n         return caches[cache]\n     except InvalidCacheBackendError:\n         return default_cache\ndiff --git a/pootle/core/models.py b/pootle/core/models.py\n--- a/pootle/core/models.py\n+++ b/pootle/core/models.py\n@@ -24,7 +24,7 @@\n from .mixins import TreeItem\n \n \n-cache = get_cache()\n+cache = get_cache('redis')\n \n \n class Revision(object):\n", "issue": "Mitigate the risk of revision counter also being in 'default' Redis cache\nThe revision counter goes into the 'default' cache.  This adds the risk of people clearing the default cache and also wiping out the revision counter \u2014 even if there's a way to restore it, we might want to prevent removal in the first place. This concern was raised in https://github.com/translate/pootle/issues/3500#issuecomment-73204160\n\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2013-2015 Evernote Corporation\n#\n# This file is part of Pootle.\n#\n# Pootle is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# translate is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with translate; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nfrom .cache import get_cache\nfrom .mixins import TreeItem\n\n\ncache = get_cache()\n\n\nclass Revision(object):\n    \"\"\"Wrapper around the revision counter stored in Redis.\"\"\"\n\n    CACHE_KEY = 'pootle:revision'\n    INITIAL = 0\n\n    @classmethod\n    def initialize(cls, force=False):\n        \"\"\"Initializes the revision with `cls.INITIAL`.\n\n        :param force: whether to overwrite the number if there's a\n            revision already set or not.\n        :return: `True` if the initial value was set, `False` otherwise.\n        \"\"\"\n        if force:\n            return cls.set(cls.INITIAL)\n\n        return cls.add(cls.INITIAL)\n\n    @classmethod\n    def get(cls):\n        \"\"\"Gets the current revision number.\n\n        :return: The current revision number, or the initial number if\n            there's no revision stored yet.\n        \"\"\"\n        return cache.get(cls.CACHE_KEY, cls.INITIAL)\n\n    @classmethod\n    def set(cls, value):\n        \"\"\"Sets the revision number to `value`, regardless of whether\n        there's a value previously set or not.\n\n        :return: `True` if the value was set, `False` otherwise.\n        \"\"\"\n        return cache.set(cls.CACHE_KEY, value, None)\n\n    @classmethod\n    def add(cls, value):\n        \"\"\"Sets the revision number to `value`, only if there's no\n        revision already set.\n\n        :return: `True` if the value was set, `False` otherwise.\n        \"\"\"\n        return cache.add(cls.CACHE_KEY, value, None)\n\n    @classmethod\n    def incr(cls):\n        \"\"\"Increments the revision number.\n\n        :return: the new revision number after incrementing it, or the\n            initial number if there's no revision stored yet.\n        \"\"\"\n        try:\n            return cache.incr(cls.CACHE_KEY)\n        except ValueError:\n            return cls.INITIAL\n\n\nclass VirtualResource(TreeItem):\n    \"\"\"An object representing a virtual resource.\n\n    A virtual resource doesn't live in the DB and has a unique\n    `pootle_path` of its own. It's a simple collection of actual\n    resources.\n\n    For instance, this can be used in projects to have cross-language\n    references.\n\n    Don't use this object as-is, rather subclass it and adapt the\n    implementation details for each context.\n    \"\"\"\n    def __init__(self, resources, pootle_path, *args, **kwargs):\n        self.resources = resources  #: Collection of underlying resources\n        self.pootle_path = pootle_path\n\n        super(VirtualResource, self).__init__(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.pootle_path\n\n    ### TreeItem\n\n    def get_children(self):\n        return self.resources\n\n    def get_cachekey(self):\n        return self.pootle_path\n\n    ### /TreeItem\n", "path": "pootle/core/models.py"}, {"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2013-2015 Evernote Corporation\n#\n# This file is part of Pootle.\n#\n# Pootle is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\n\nfrom django.core.cache import caches, cache as default_cache\nfrom django.core.cache.backends.base import InvalidCacheBackendError\n\n\ndef make_method_key(model, method, key):\n    \"\"\"Creates a cache key for model's `method` method.\n\n    :param model: A model instance\n    :param method: Method name to cache\n    :param key: a unique key to identify the object to be cached\n    \"\"\"\n    prefix = 'method-cache'\n\n    if isinstance(model, basestring):\n        name = model\n    else:\n        name = (model.__name__ if hasattr(model, '__name__')\n                               else model.__class__.__name__)\n\n    key = key if not isinstance(key, dict) else make_key(**key)\n    return u':'.join([prefix, name, method, key])\n\n\ndef make_key(*args, **kwargs):\n    \"\"\"Creates a cache key with key-value pairs from a dict.\"\"\"\n    return ':'.join([\n        '%s=%s' % (k, v) for k, v in sorted(kwargs.iteritems())\n    ])\n\n\ndef get_cache(cache=None):\n    \"\"\"Return ``cache`` or the 'default' cache if ``cache`` is not specified or\n    ``cache`` is not configured.\n\n    :param cache: The name of the requested cache.\n    \"\"\"\n    try:\n        return caches[cache]\n    except InvalidCacheBackendError:\n        return default_cache\n", "path": "pootle/core/cache.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2013-2015 Evernote Corporation\n#\n# This file is part of Pootle.\n#\n# Pootle is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# translate is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with translate; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nfrom .cache import get_cache\nfrom .mixins import TreeItem\n\n\ncache = get_cache('redis')\n\n\nclass Revision(object):\n    \"\"\"Wrapper around the revision counter stored in Redis.\"\"\"\n\n    CACHE_KEY = 'pootle:revision'\n    INITIAL = 0\n\n    @classmethod\n    def initialize(cls, force=False):\n        \"\"\"Initializes the revision with `cls.INITIAL`.\n\n        :param force: whether to overwrite the number if there's a\n            revision already set or not.\n        :return: `True` if the initial value was set, `False` otherwise.\n        \"\"\"\n        if force:\n            return cls.set(cls.INITIAL)\n\n        return cls.add(cls.INITIAL)\n\n    @classmethod\n    def get(cls):\n        \"\"\"Gets the current revision number.\n\n        :return: The current revision number, or the initial number if\n            there's no revision stored yet.\n        \"\"\"\n        return cache.get(cls.CACHE_KEY, cls.INITIAL)\n\n    @classmethod\n    def set(cls, value):\n        \"\"\"Sets the revision number to `value`, regardless of whether\n        there's a value previously set or not.\n\n        :return: `True` if the value was set, `False` otherwise.\n        \"\"\"\n        return cache.set(cls.CACHE_KEY, value, None)\n\n    @classmethod\n    def add(cls, value):\n        \"\"\"Sets the revision number to `value`, only if there's no\n        revision already set.\n\n        :return: `True` if the value was set, `False` otherwise.\n        \"\"\"\n        return cache.add(cls.CACHE_KEY, value, None)\n\n    @classmethod\n    def incr(cls):\n        \"\"\"Increments the revision number.\n\n        :return: the new revision number after incrementing it, or the\n            initial number if there's no revision stored yet.\n        \"\"\"\n        try:\n            return cache.incr(cls.CACHE_KEY)\n        except ValueError:\n            return cls.INITIAL\n\n\nclass VirtualResource(TreeItem):\n    \"\"\"An object representing a virtual resource.\n\n    A virtual resource doesn't live in the DB and has a unique\n    `pootle_path` of its own. It's a simple collection of actual\n    resources.\n\n    For instance, this can be used in projects to have cross-language\n    references.\n\n    Don't use this object as-is, rather subclass it and adapt the\n    implementation details for each context.\n    \"\"\"\n    def __init__(self, resources, pootle_path, *args, **kwargs):\n        self.resources = resources  #: Collection of underlying resources\n        self.pootle_path = pootle_path\n\n        super(VirtualResource, self).__init__(*args, **kwargs)\n\n    def __unicode__(self):\n        return self.pootle_path\n\n    ### TreeItem\n\n    def get_children(self):\n        return self.resources\n\n    def get_cachekey(self):\n        return self.pootle_path\n\n    ### /TreeItem\n", "path": "pootle/core/models.py"}, {"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2013-2015 Evernote Corporation\n#\n# This file is part of Pootle.\n#\n# Pootle is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\n\nfrom django.conf import settings\nfrom django.core.cache import caches, cache as default_cache\nfrom django.core.cache.backends.base import InvalidCacheBackendError\nfrom django.core.exceptions import ImproperlyConfigured\n\n\nPERSISTENT_STORES = ('redis', 'stats')\n\n\ndef make_method_key(model, method, key):\n    \"\"\"Creates a cache key for model's `method` method.\n\n    :param model: A model instance\n    :param method: Method name to cache\n    :param key: a unique key to identify the object to be cached\n    \"\"\"\n    prefix = 'method-cache'\n\n    if isinstance(model, basestring):\n        name = model\n    else:\n        name = (model.__name__ if hasattr(model, '__name__')\n                               else model.__class__.__name__)\n\n    key = key if not isinstance(key, dict) else make_key(**key)\n    return u':'.join([prefix, name, method, key])\n\n\ndef make_key(*args, **kwargs):\n    \"\"\"Creates a cache key with key-value pairs from a dict.\"\"\"\n    return ':'.join([\n        '%s=%s' % (k, v) for k, v in sorted(kwargs.iteritems())\n    ])\n\n\ndef get_cache(cache=None):\n    \"\"\"Return ``cache`` or the 'default' cache if ``cache`` is not specified or\n    ``cache`` is not configured.\n\n    :param cache: The name of the requested cache.\n    \"\"\"\n    try:\n        # Check for proper Redis persistent backends\n        # FIXME: this logic needs to be a system sanity check\n        if (cache in PERSISTENT_STORES and\n            (cache not in settings.CACHES or\n            'RedisCache' not in settings.CACHES[cache]['BACKEND'] or\n            settings.CACHES[cache].get('TIMEOUT', '') != None)):\n            raise ImproperlyConfigured(\n                'Pootle requires a Redis-backed caching backend for %r '\n                'with `TIMEOUT: None`. Please review your settings.' % cache\n            )\n\n        return caches[cache]\n    except InvalidCacheBackendError:\n        return default_cache\n", "path": "pootle/core/cache.py"}]}