Guest User

Untitled

a guest
Feb 25th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.58 KB | None | 0 0
  1. import collections
  2. import json
  3. import os
  4. import pathlib
  5. import functools
  6.  
  7. class StoreDoesNotExistError(Exception):
  8. """
  9. Exception raised when specified store does not exist
  10. """
  11. pass
  12.  
  13. def guard_loaded(fn):
  14.  
  15. @functools.wraps(fn)
  16. def wrapper(self, *args, **kwargs):
  17. if not self._is_loaded:
  18. self.load()
  19. return fn(self, *args, **kwargs)
  20. return wrapper
  21.  
  22. class OnDiskMapping(collections.MutableMapping):
  23. _file_name = None
  24.  
  25. def __init__(self, file_dir: str, file_name: str = None, should_create: bool = True):
  26. self._file_dir = os.path.expanduser(file_dir)
  27. if file_name:
  28. self._file_name = file_name
  29. else:
  30. if not self._file_name:
  31. raise ValueError('File name for store not specified')
  32. self._file_path = os.path.join(self._file_dir, self._file_name)
  33. self._store = dict()
  34. self._dirty = False
  35. self._should_create = should_create
  36. self._is_loaded = True
  37.  
  38. def load(self):
  39. if self.exists():
  40. pass
  41. else:
  42. if self._should_create:
  43. pathlib.Path(self._file_dir).mkdir(exist_ok=True, parents=True)
  44. else:
  45. raise StoreDoesNotExistError('Store does not exist at {}'.format(self._file_path))
  46. try:
  47. with open(self._file_path, 'r+') as f:
  48. try:
  49. data = json.load(f)
  50. except json.JSONDecodeError:
  51. raise ValueError('Unable to deserialize on-disk mapping')
  52. self._store.update(data)
  53. except IOError:
  54. with open(self._file_path, 'w+') as f:
  55. try:
  56. json.dump(self._store, f)
  57. except ValueError:
  58. raise ValueError('Unable to serialize on-disk mapping')
  59. self._is_loaded = True
  60.  
  61. def save(self):
  62. if self._dirty:
  63. with open(self._file_path, 'w') as f:
  64. try:
  65. json.dump(self._store, f)
  66. except ValueError:
  67. raise ValueError('Unable to serialize on-disk mapping')
  68. self._dirty = False
  69.  
  70. @guard_loaded
  71. def __setitem__(self, key, value):
  72. self._store[key] = value
  73. self._dirty = True
  74.  
  75. @guard_loaded
  76. def __getitem__(self, key):
  77. return self._store[key]
  78.  
  79. @guard_loaded
  80. def __delitem__(self, key):
  81. del self._store[key]
  82. self._dirty = True
  83.  
  84. @guard_loaded
  85. def __iter__(self):
  86. return (key for key, value in self._store.values())
  87.  
  88. @guard_loaded
  89. def __len__(self):
  90. return len(self._store)
  91.  
  92. def exists(self):
  93. return os.path.isfile(self._file_path)
  94.  
  95. @guard_loaded
  96. def clear(self):
  97. self._store = {}
  98. self._dirty = True
  99.  
  100. def __eq__(self, other):
  101. if isinstance(other, self.__class__):
  102. other = other._store
  103. elif isinstance(other, collections.MutableMapping):
  104. pass
  105. else:
  106. return NotImplemented
  107. return dict(self._store) == dict(other)
  108.  
  109. def __enter__(self):
  110. self.load()
  111. return self
  112.  
  113. def __exit__(self, exc_type, exc_val, exc_tb):
  114. self.save()
  115.  
  116. def __del__(self):
  117. if os.path.isfile(self._file_path):
  118. os.remove(self._file_path)
  119. del self
  120.  
  121. @guard_loaded
  122. def copy(self):
  123. store = OnDiskMapping(self._file_dir, self._file_name, self._should_create)
  124. store.update(self._store)
  125. return store
  126.  
  127. def __repr__(self):
  128. return '%s(%r)' % (self.__class__.__name__, dict(self.items()))
Add Comment
Please, Sign In to add comment