Guest User

Untitled

a guest
Feb 25th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.51 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.  
  23. class OnDiskCollection(collections.MutableSequence):
  24. _file_name = None
  25.  
  26. def __init__(self, file_dir: str, file_name: str = None, should_create: bool = True):
  27. super(OnDiskCollection, self).__init__()
  28. self._file_dir = os.path.expanduser(file_dir)
  29. if file_name:
  30. self._file_name = file_name
  31. else:
  32. if not self._file_name:
  33. raise ValueError('File name for store not specified')
  34. self._file_path = os.path.join(self._file_dir, self._file_name)
  35. self._collection = list()
  36. self._dirty = False
  37. self._should_create = should_create
  38. self._is_loaded = False
  39.  
  40. @guard_loaded
  41. def __repr__(self):
  42. return "<{0} {1}>".format(self.__class__.__name__, self._collection)
  43.  
  44. @guard_loaded
  45. def __len__(self):
  46. """List length"""
  47. return len(self._collection)
  48.  
  49. @guard_loaded
  50. def __getitem__(self, ii):
  51. """Get a list item"""
  52. return self._collection[ii]
  53.  
  54. @guard_loaded
  55. def __delitem__(self, ii):
  56. """Delete an item"""
  57. del self._collection[ii]
  58. self._dirty = True
  59.  
  60. @guard_loaded
  61. def __setitem__(self, ii, val):
  62. self._collection[ii] = val
  63. self._dirty = True
  64.  
  65. @guard_loaded
  66. def __str__(self):
  67. return str(self._collection)
  68.  
  69. @guard_loaded
  70. def __eq__(self, other):
  71. if isinstance(other, self.__class__):
  72. other = other._collection
  73. elif isinstance(other, collections.MutableSequence):
  74. pass
  75. else:
  76. return NotImplemented
  77. return dict(self._collection) == dict(other)
  78.  
  79. @guard_loaded
  80. def insert(self, ii, val):
  81. self._collection.insert(ii, val)
  82. self._dirty = True
  83.  
  84. def exists(self):
  85. return os.path.isfile(self._file_path)
  86.  
  87. def load(self):
  88. if self.exists():
  89. pass
  90. else:
  91. if self._should_create:
  92. pathlib.Path(self._file_dir).mkdir(exist_ok=True, parents=True)
  93. else:
  94. raise StoreDoesNotExistError('Store does not exist at {}'.format(self._file_path))
  95. try:
  96. with open(self._file_path, 'r+') as f:
  97. try:
  98. data = json.load(f)
  99. except json.JSONDecodeError:
  100. raise ValueError('Unable to deserialize on-disk collection')
  101. self._collection.extend(data)
  102. except IOError:
  103. with open(self._file_path, 'w+') as f:
  104. try:
  105. json.dump(self._collection, f)
  106. except ValueError:
  107. raise ValueError('Unable to serialize on-disk collection')
  108. self._is_loaded = True
  109.  
  110. def save(self):
  111. if self._dirty:
  112. with open(self._file_path, 'w') as f:
  113. try:
  114. json.dump(self._collection, f)
  115. except ValueError:
  116. raise ValueError('Unable to serialize on-disk collection')
  117. self._dirty = False
  118.  
  119. def __enter__(self):
  120. self.load()
  121. return self
  122.  
  123. def __exit__(self, exc_type, exc_val, exc_tb):
  124. self.save()
Add Comment
Please, Sign In to add comment