Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/glob2/compat.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 # Back-port functools.lru_cache to Python 2 (and <= 3.2) | |
| 2 # {{{ http://code.activestate.com/recipes/578078/ (r6) | |
| 3 | |
| 4 from collections import namedtuple | |
| 5 from functools import update_wrapper | |
| 6 from threading import RLock | |
| 7 | |
| 8 _CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"]) | |
| 9 | |
| 10 class _HashedSeq(list): | |
| 11 __slots__ = 'hashvalue' | |
| 12 | |
| 13 def __init__(self, tup, hash=hash): | |
| 14 self[:] = tup | |
| 15 self.hashvalue = hash(tup) | |
| 16 | |
| 17 def __hash__(self): | |
| 18 return self.hashvalue | |
| 19 | |
| 20 def _make_key(args, kwds, typed, | |
| 21 kwd_mark = (object(),), | |
| 22 fasttypes = set((int, str, frozenset, type(None))), | |
| 23 sorted=sorted, tuple=tuple, type=type, len=len): | |
| 24 'Make a cache key from optionally typed positional and keyword arguments' | |
| 25 key = args | |
| 26 if kwds: | |
| 27 sorted_items = sorted(kwds.items()) | |
| 28 key += kwd_mark | |
| 29 for item in sorted_items: | |
| 30 key += item | |
| 31 if typed: | |
| 32 key += tuple(type(v) for v in args) | |
| 33 if kwds: | |
| 34 key += tuple(type(v) for k, v in sorted_items) | |
| 35 elif len(key) == 1 and type(key[0]) in fasttypes: | |
| 36 return key[0] | |
| 37 return _HashedSeq(key) | |
| 38 | |
| 39 def lru_cache(maxsize=100, typed=False): | |
| 40 """Least-recently-used cache decorator. | |
| 41 | |
| 42 If *maxsize* is set to None, the LRU features are disabled and the cache | |
| 43 can grow without bound. | |
| 44 | |
| 45 If *typed* is True, arguments of different types will be cached separately. | |
| 46 For example, f(3.0) and f(3) will be treated as distinct calls with | |
| 47 distinct results. | |
| 48 | |
| 49 Arguments to the cached function must be hashable. | |
| 50 | |
| 51 View the cache statistics named tuple (hits, misses, maxsize, currsize) with | |
| 52 f.cache_info(). Clear the cache and statistics with f.cache_clear(). | |
| 53 Access the underlying function with f.__wrapped__. | |
| 54 | |
| 55 See: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used | |
| 56 | |
| 57 """ | |
| 58 | |
| 59 # Users should only access the lru_cache through its public API: | |
| 60 # cache_info, cache_clear, and f.__wrapped__ | |
| 61 # The internals of the lru_cache are encapsulated for thread safety and | |
| 62 # to allow the implementation to change (including a possible C version). | |
| 63 | |
| 64 def decorating_function(user_function): | |
| 65 | |
| 66 cache = dict() | |
| 67 stats = [0, 0] # make statistics updateable non-locally | |
| 68 HITS, MISSES = 0, 1 # names for the stats fields | |
| 69 make_key = _make_key | |
| 70 cache_get = cache.get # bound method to lookup key or return None | |
| 71 _len = len # localize the global len() function | |
| 72 lock = RLock() # because linkedlist updates aren't threadsafe | |
| 73 root = [] # root of the circular doubly linked list | |
| 74 root[:] = [root, root, None, None] # initialize by pointing to self | |
| 75 nonlocal_root = [root] # make updateable non-locally | |
| 76 PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields | |
| 77 | |
| 78 if maxsize == 0: | |
| 79 | |
| 80 def wrapper(*args, **kwds): | |
| 81 # no caching, just do a statistics update after a successful call | |
| 82 result = user_function(*args, **kwds) | |
| 83 stats[MISSES] += 1 | |
| 84 return result | |
| 85 | |
| 86 elif maxsize is None: | |
| 87 | |
| 88 def wrapper(*args, **kwds): | |
| 89 # simple caching without ordering or size limit | |
| 90 key = make_key(args, kwds, typed) | |
| 91 result = cache_get(key, root) # root used here as a unique not-found sentinel | |
| 92 if result is not root: | |
| 93 stats[HITS] += 1 | |
| 94 return result | |
| 95 result = user_function(*args, **kwds) | |
| 96 cache[key] = result | |
| 97 stats[MISSES] += 1 | |
| 98 return result | |
| 99 | |
| 100 else: | |
| 101 | |
| 102 def wrapper(*args, **kwds): | |
| 103 # size limited caching that tracks accesses by recency | |
| 104 key = make_key(args, kwds, typed) if kwds or typed else args | |
| 105 with lock: | |
| 106 link = cache_get(key) | |
| 107 if link is not None: | |
| 108 # record recent use of the key by moving it to the front of the list | |
| 109 root, = nonlocal_root | |
| 110 link_prev, link_next, key, result = link | |
| 111 link_prev[NEXT] = link_next | |
| 112 link_next[PREV] = link_prev | |
| 113 last = root[PREV] | |
| 114 last[NEXT] = root[PREV] = link | |
| 115 link[PREV] = last | |
| 116 link[NEXT] = root | |
| 117 stats[HITS] += 1 | |
| 118 return result | |
| 119 result = user_function(*args, **kwds) | |
| 120 with lock: | |
| 121 root, = nonlocal_root | |
| 122 if key in cache: | |
| 123 # getting here means that this same key was added to the | |
| 124 # cache while the lock was released. since the link | |
| 125 # update is already done, we need only return the | |
| 126 # computed result and update the count of misses. | |
| 127 pass | |
| 128 elif _len(cache) >= maxsize: | |
| 129 # use the old root to store the new key and result | |
| 130 oldroot = root | |
| 131 oldroot[KEY] = key | |
| 132 oldroot[RESULT] = result | |
| 133 # empty the oldest link and make it the new root | |
| 134 root = nonlocal_root[0] = oldroot[NEXT] | |
| 135 oldkey = root[KEY] | |
| 136 oldvalue = root[RESULT] | |
| 137 root[KEY] = root[RESULT] = None | |
| 138 # now update the cache dictionary for the new links | |
| 139 del cache[oldkey] | |
| 140 cache[key] = oldroot | |
| 141 else: | |
| 142 # put result in a new link at the front of the list | |
| 143 last = root[PREV] | |
| 144 link = [last, root, key, result] | |
| 145 last[NEXT] = root[PREV] = cache[key] = link | |
| 146 stats[MISSES] += 1 | |
| 147 return result | |
| 148 | |
| 149 def cache_info(): | |
| 150 """Report cache statistics""" | |
| 151 with lock: | |
| 152 return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache)) | |
| 153 | |
| 154 def cache_clear(): | |
| 155 """Clear the cache and cache statistics""" | |
| 156 with lock: | |
| 157 cache.clear() | |
| 158 root = nonlocal_root[0] | |
| 159 root[:] = [root, root, None, None] | |
| 160 stats[:] = [0, 0] | |
| 161 | |
| 162 wrapper.__wrapped__ = user_function | |
| 163 wrapper.cache_info = cache_info | |
| 164 wrapper.cache_clear = cache_clear | |
| 165 return update_wrapper(wrapper, user_function) | |
| 166 | |
| 167 return decorating_function |
