dircache.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import time
  2. from collections.abc import MutableMapping
  3. from functools import lru_cache
  4. class DirCache(MutableMapping):
  5. """
  6. Caching of directory listings, in a structure like::
  7. {"path0": [
  8. {"name": "path0/file0",
  9. "size": 123,
  10. "type": "file",
  11. ...
  12. },
  13. {"name": "path0/file1",
  14. },
  15. ...
  16. ],
  17. "path1": [...]
  18. }
  19. Parameters to this class control listing expiry or indeed turn
  20. caching off
  21. """
  22. def __init__(
  23. self,
  24. use_listings_cache=True,
  25. listings_expiry_time=None,
  26. max_paths=None,
  27. **kwargs,
  28. ):
  29. """
  30. Parameters
  31. ----------
  32. use_listings_cache: bool
  33. If False, this cache never returns items, but always reports KeyError,
  34. and setting items has no effect
  35. listings_expiry_time: int or float (optional)
  36. Time in seconds that a listing is considered valid. If None,
  37. listings do not expire.
  38. max_paths: int (optional)
  39. The number of most recent listings that are considered valid; 'recent'
  40. refers to when the entry was set.
  41. """
  42. self._cache = {}
  43. self._times = {}
  44. if max_paths:
  45. self._q = lru_cache(max_paths + 1)(lambda key: self._cache.pop(key, None))
  46. self.use_listings_cache = use_listings_cache
  47. self.listings_expiry_time = listings_expiry_time
  48. self.max_paths = max_paths
  49. def __getitem__(self, item):
  50. if self.listings_expiry_time is not None:
  51. if self._times.get(item, 0) - time.time() < -self.listings_expiry_time:
  52. del self._cache[item]
  53. if self.max_paths:
  54. self._q(item)
  55. return self._cache[item] # maybe raises KeyError
  56. def clear(self):
  57. self._cache.clear()
  58. def __len__(self):
  59. return len(self._cache)
  60. def __contains__(self, item):
  61. try:
  62. self[item]
  63. return True
  64. except KeyError:
  65. return False
  66. def __setitem__(self, key, value):
  67. if not self.use_listings_cache:
  68. return
  69. if self.max_paths:
  70. self._q(key)
  71. self._cache[key] = value
  72. if self.listings_expiry_time is not None:
  73. self._times[key] = time.time()
  74. def __delitem__(self, key):
  75. del self._cache[key]
  76. def __iter__(self):
  77. entries = list(self._cache)
  78. return (k for k in entries if k in self)
  79. def __reduce__(self):
  80. return (
  81. DirCache,
  82. (self.use_listings_cache, self.listings_expiry_time, self.max_paths),
  83. )