(func)
| 91 | assert limit <= 0 or thread_safe, 'memoize() it not thread safe enough to work in limiting and non-thread safe mode' |
| 92 | |
| 93 | def decorator(func): |
| 94 | memory = {} |
| 95 | |
| 96 | if six.PY3: |
| 97 | lock = contextlib.nullcontext() |
| 98 | else: |
| 99 | lock = nullcontext() |
| 100 | lock = threading.Lock() if thread_safe else lock |
| 101 | |
| 102 | if limit: |
| 103 | keys = collections.deque() |
| 104 | |
| 105 | def get(args): |
| 106 | if args not in memory: |
| 107 | with lock: |
| 108 | if args not in memory: |
| 109 | fargs = args[-1] |
| 110 | memory[args] = func(*fargs) |
| 111 | keys.append(args) |
| 112 | if len(keys) > limit: |
| 113 | del memory[keys.popleft()] |
| 114 | return memory[args] |
| 115 | |
| 116 | else: |
| 117 | |
| 118 | def get(args): |
| 119 | if args not in memory: |
| 120 | with lock: |
| 121 | if args not in memory: |
| 122 | fargs = args[-1] |
| 123 | memory.setdefault(args, func(*fargs)) |
| 124 | return memory[args] |
| 125 | |
| 126 | if thread_local: |
| 127 | |
| 128 | @functools.wraps(func) |
| 129 | def wrapper(*args): |
| 130 | th = threading.current_thread() |
| 131 | return get((th.ident, th.name, args)) |
| 132 | |
| 133 | else: |
| 134 | |
| 135 | @functools.wraps(func) |
| 136 | def wrapper(*args): |
| 137 | return get(('', '', args)) |
| 138 | |
| 139 | return wrapper |
| 140 | |
| 141 | return decorator |
| 142 |
nothing calls this directly
no test coverage detected