|
import time |
|
from collections.abc import MutableMapping |
|
from functools import lru_cache |
|
|
|
|
|
class DirCache(MutableMapping): |
|
""" |
|
Caching of directory listings, in a structure like:: |
|
|
|
{"path0": [ |
|
{"name": "path0/file0", |
|
"size": 123, |
|
"type": "file", |
|
... |
|
}, |
|
{"name": "path0/file1", |
|
}, |
|
... |
|
], |
|
"path1": [...] |
|
} |
|
|
|
Parameters to this class control listing expiry or indeed turn |
|
caching off |
|
""" |
|
|
|
def __init__( |
|
self, |
|
use_listings_cache=True, |
|
listings_expiry_time=None, |
|
max_paths=None, |
|
**kwargs, |
|
): |
|
""" |
|
|
|
Parameters |
|
---------- |
|
use_listings_cache: bool |
|
If False, this cache never returns items, but always reports KeyError, |
|
and setting items has no effect |
|
listings_expiry_time: int or float (optional) |
|
Time in seconds that a listing is considered valid. If None, |
|
listings do not expire. |
|
max_paths: int (optional) |
|
The number of most recent listings that are considered valid; 'recent' |
|
refers to when the entry was set. |
|
""" |
|
self._cache = {} |
|
self._times = {} |
|
if max_paths: |
|
self._q = lru_cache(max_paths + 1)(lambda key: self._cache.pop(key, None)) |
|
self.use_listings_cache = use_listings_cache |
|
self.listings_expiry_time = listings_expiry_time |
|
self.max_paths = max_paths |
|
|
|
def __getitem__(self, item): |
|
if self.listings_expiry_time is not None: |
|
if self._times.get(item, 0) - time.time() < -self.listings_expiry_time: |
|
del self._cache[item] |
|
if self.max_paths: |
|
self._q(item) |
|
return self._cache[item] |
|
|
|
def clear(self): |
|
self._cache.clear() |
|
|
|
def __len__(self): |
|
return len(self._cache) |
|
|
|
def __contains__(self, item): |
|
try: |
|
self[item] |
|
return True |
|
except KeyError: |
|
return False |
|
|
|
def __setitem__(self, key, value): |
|
if not self.use_listings_cache: |
|
return |
|
if self.max_paths: |
|
self._q(key) |
|
self._cache[key] = value |
|
if self.listings_expiry_time is not None: |
|
self._times[key] = time.time() |
|
|
|
def __delitem__(self, key): |
|
del self._cache[key] |
|
|
|
def __iter__(self): |
|
entries = list(self._cache) |
|
|
|
return (k for k in entries if k in self) |
|
|
|
def __reduce__(self): |
|
return ( |
|
DirCache, |
|
(self.use_listings_cache, self.listings_expiry_time, self.max_paths), |
|
) |
|
|