Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/glob2/compat.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
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 |