cache.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # -*- coding: utf-8 -*-
  2. """
  3. cache module
  4. 文件缓存
  5. """
  6. from os import path, stat
  7. from pickle import dump, load
  8. from time import time
  9. from logging import getLogger, Logger # noqa: F401
  10. class Cache(dict):
  11. """
  12. using file to Cache data as dictionary
  13. """
  14. def __init__(self, path, logger=None, sync=False):
  15. # type: (str, Logger | None, bool) -> None
  16. self.__data = {}
  17. self.__filename = path
  18. self.__sync = sync
  19. self.__time = time()
  20. self.__changed = False
  21. self.__logger = (logger or getLogger()).getChild("Cache")
  22. self.load()
  23. @property
  24. def time(self):
  25. """
  26. 缓存修改时间
  27. """
  28. return self.__time
  29. def load(self, file=None):
  30. """
  31. load data from path
  32. """
  33. if not file:
  34. file = self.__filename
  35. self.__logger.debug("load cache data from %s", file)
  36. if path.isfile(file):
  37. with open(self.__filename, "rb") as data:
  38. try:
  39. self.__data = load(data)
  40. self.__time = stat(file).st_mtime
  41. return self
  42. except ValueError:
  43. pass
  44. except Exception as e:
  45. self.__logger.warning(e)
  46. else:
  47. self.__logger.info("cache file not exist")
  48. self.__data = {}
  49. self.__time = time()
  50. self.__changed = True
  51. return self
  52. def data(self, key=None, default=None):
  53. # type: (str | None, Any | None) -> dict | Any
  54. """
  55. 获取当前字典或者制定得键值
  56. """
  57. if self.__sync:
  58. self.load()
  59. if key is None:
  60. return self.__data
  61. else:
  62. return self.__data.get(key, default)
  63. def sync(self):
  64. """Sync the write buffer with the cache files and clear the buffer."""
  65. if self.__changed:
  66. with open(self.__filename, "wb") as data:
  67. dump(self.__data, data)
  68. self.__logger.debug("save cache data to %s", self.__filename)
  69. self.__time = time()
  70. self.__changed = False
  71. return self
  72. def close(self):
  73. """Sync the write buffer, then close the cache.
  74. If a closed :class:`FileCache` object's methods are called, a
  75. :exc:`ValueError` will be raised.
  76. """
  77. self.sync()
  78. del self.__data
  79. del self.__filename
  80. del self.__time
  81. self.__sync = False
  82. def __update(self):
  83. self.__changed = True
  84. if self.__sync:
  85. self.sync()
  86. else:
  87. self.__time = time()
  88. def clear(self):
  89. if self.data() is not None:
  90. self.__data = {}
  91. self.__update()
  92. def __setitem__(self, key, value):
  93. if self.data(key) != value:
  94. self.__data[key] = value
  95. self.__update()
  96. def __delitem__(self, key):
  97. if key in self.data():
  98. del self.__data[key]
  99. self.__update()
  100. def __getitem__(self, key):
  101. return self.data(key)
  102. def __iter__(self):
  103. for key in self.data():
  104. yield key
  105. def __len__(self):
  106. return len(self.data())
  107. def __contains__(self, key):
  108. return key in self.data()
  109. def __str__(self):
  110. return self.data().__str__()
  111. def __del__(self):
  112. self.close()