Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: appengine/findit/lib/cache_decorator.py

Issue 2538373003: [Culprit-Finder] Merge lib/ to libs/. (Closed)
Patch Set: . Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/findit/lib/__init__.py ('k') | appengine/findit/lib/gitiles/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """This module provides a decorator to cache the results of a function.
6
7 Examples:
8 1. Decorate a function:
9 @cache_decorator.Cached()
10 def Test(a):
11 return a + a
12
13 Test('a')
14 Test('a') # Returns the cached 'aa'.
15
16 2. Decorate a method in a class:
17 class Downloader(object):
18 def __init__(self, url, retries):
19 self.url = url
20 self.retries = retries
21
22 @property
23 def identifier(self):
24 return self.url
25
26 @cache_decorator.Cached():
27 def Download(self, path):
28 return urllib2.urlopen(self.url + '/' + path).read()
29
30 d1 = Downloader('http://url', 4)
31 d1.Download('path')
32
33 d2 = Downloader('http://url', 5)
34 d2.Download('path') # Returned the cached downloaded data.
35 """
36
37 import functools
38 import hashlib
39 import inspect
40 import logging
41 import pickle
42
43
44 def _DefaultKeyGenerator(func, args, kwargs):
45 """Generates a key from the function and arguments passed to it.
46
47 Args:
48 func (function): An arbitrary function.
49 args (list): Positional arguments passed to ``func``.
50 kwargs (dict): Keyword arguments passed to ``func``.
51
52 Returns:
53 A string to represent a call to the given function with the given arguments.
54 """
55 params = inspect.getcallargs(func, *args, **kwargs)
56 for var_name in params:
57 if not hasattr(params[var_name], 'identifier'):
58 continue
59
60 if callable(params[var_name].identifier):
61 params[var_name] = params[var_name].identifier()
62 else:
63 params[var_name] = params[var_name].identifier
64
65 return hashlib.md5(pickle.dumps(params)).hexdigest()
66
67
68 def Cached(namespace=None,
69 expire_time=0,
70 key_generator=_DefaultKeyGenerator,
71 cache=None):
72 """Returns a decorator to cache the decorated function's results.
73
74 However, if the function returns None, empty list/dict, empty string, or other
75 value that is evaluated as False, the results won't be cached.
76
77 This decorator is to cache results of different calls to the decorated
78 function, and avoid executing it again if the calls are equivalent. Two calls
79 are equivalent, if the namespace is the same and the keys generated by the
80 ``key_generator`` are the same.
81
82 The usage of this decorator requires that:
83 - If the default key generator is used, parameters passed to the decorated
84 function should be pickleable, or each of the parameter has an identifier
85 property or method which returns pickleable results.
86 - If the default cache is used, the returned results of the decorated
87 function should be pickleable.
88
89 Args:
90 namespace (str): A prefix to the key for the cache. Default to the
91 combination of module name and function name of the decorated function.
92 expire_time (int): Expiration time, relative number of seconds from current
93 time (up to 0 month). Defaults to 0 -- never expire.
94 key_generator (function): A function to generate a key to represent a call
95 to the decorated function. Defaults to :func:`_DefaultKeyGenerator`.
96 cache (Cache): An instance of an implementation of interface `Cache`.
97 Defaults to None.
98
99 Returns:
100 The cached results or the results of a new run of the decorated function.
101 """
102 def GetPrefix(func, namespace):
103 return namespace or '%s.%s' % (func.__module__, func.__name__)
104
105 def Decorator(func):
106 """Decorator to cache a function's results."""
107 @functools.wraps(func)
108 def Wrapped(*args, **kwargs):
109 prefix = GetPrefix(func, namespace)
110 key = '%s-%s' % (prefix, key_generator(func, args, kwargs))
111
112 try:
113 result = cache.Get(key)
114 except Exception: # pragma: no cover.
115 result = None
116 logging.exception(
117 'Failed to get cached data for function %s.%s, args=%s, kwargs=%s',
118 func.__module__, func.__name__, repr(args), repr(kwargs))
119
120 if result is not None:
121 return result
122
123 result = func(*args, **kwargs)
124 if result:
125 try:
126 cache.Set(key, result, expire_time=expire_time)
127 except Exception: # pragma: no cover.
128 logging.exception(
129 'Failed to cache data for function %s.%s, args=%s, kwargs=%s',
130 func.__module__, func.__name__, repr(args), repr(kwargs))
131
132 return result
133
134 return Wrapped
135
136 return Decorator
OLDNEW
« no previous file with comments | « appengine/findit/lib/__init__.py ('k') | appengine/findit/lib/gitiles/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698