Package horizons :: Package util :: Package python :: Module decorators
[hide private]
[frames] | no frames]

Source Code for Module horizons.util.python.decorators

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  """Save general python function decorators here""" 
 23   
 24  import functools 
 25  import time 
 26  from typing import Any, Dict, Tuple 
 27   
 28  FuncArgs = Tuple[Any, ...] 
 29  FuncKwargsTuple = Tuple[Tuple[str, Any]] 
 30   
 31   
32 -class cachedfunction:
33 """Decorator that caches a function's return value each time it is called. 34 If called later with the same arguments, the cached value is returned, and 35 not re-evaluated. 36 """
37 - def __init__(self, func):
38 self.func = func 39 self.cache = {} # type: Dict[Tuple[FuncArgs, FuncKwargsTuple], Any]
40
41 - def __call__(self, *args, **kwargs):
42 # dicts are not hashable, convert kwargs to a tuple 43 kwargs_tuple = tuple(sorted(kwargs.items())) 44 45 try: 46 return self.cache[(args, kwargs_tuple)] 47 except KeyError: 48 self.cache[(args, kwargs_tuple)] = value = self.func(*args, **kwargs) 49 return value 50 except TypeError: 51 assert False, "Supplied invalid argument to cache decorator"
52 53
54 -class cachedmethod:
55 """Same as cachedfunction, but works also for methods. Results are saved per instance"""
56 - def __init__(self, func):
57 self.cache = {} # type: Dict[Tuple[Any, FuncArgs, FuncKwargsTuple], Any] 58 self.func = func
59
60 - def __get__(self, instance, cls=None):
61 self.instance = instance 62 return self
63
64 - def __call__(self, *args, **kwargs):
65 # dicts are not hashable, convert kwargs to a tuple 66 kwargs_tuple = tuple(sorted(kwargs.items())) 67 68 instance = self.instance 69 70 try: 71 return self.cache[(instance, args, kwargs_tuple)] 72 except KeyError: 73 self.cache[(instance, args, kwargs_tuple)] = value = self.func(instance, *args, **kwargs) 74 return value 75 except TypeError: 76 assert False, "Supplied invalid argument to cache decorator"
77 78
79 -def temporary_cachedmethod(timeout):
80 """ 81 Same as cachedproperty, but cached values only remain valid for a certain duration 82 @param timeout: number of seconds to cache the value for 83 """ 84 class _temporary_cachedmethod(cachedmethod): 85 def __init__(self, func, timeout): 86 super().__init__(func) 87 self.timeout = timeout 88 self.cache_dates = {} # type: Dict[Tuple[Any, FuncArgs, FuncKwargsTuple], Any]
89 90 def __call__(self, *args, **kwargs): 91 key = self.instance, args, tuple(sorted(kwargs.items())) 92 93 # check for expiration 94 if key in self.cache_dates: 95 if self.cache_dates[key] + self.timeout < time.time(): 96 # expired 97 del self.cache[key] 98 del self.cache_dates[key] 99 return self(*args, **kwargs) 100 else: 101 self.cache_dates[key] = time.time() # new entry 102 103 return super().__call__(*args, **kwargs) 104 105 return functools.partial(_temporary_cachedmethod, timeout=timeout) 106 107 # cachedproperty taken from http://code.activestate.com/recipes/576563-cached-property/ 108 # Licensed under MIT 109 # A cached property is a read-only property that is calculated on demand and automatically cached. 110 # If the value has already been calculated, the cached value is returned. 111 112
113 -def cachedproperty(f):
114 """returns a cached property that is calculated by function f""" 115 def get(self): 116 try: 117 return self._property_cache[f] 118 except AttributeError: 119 self._property_cache = {} 120 x = self._property_cache[f] = f(self) 121 return x 122 except KeyError: 123 x = self._property_cache[f] = f(self) 124 return x
125 126 return property(get) 127