"""Uses the ``shelve`` OS level API to CRUD binary data."""__author__='Paul Landes'fromtypingimportAny,Iterable,Optional,Listfromdataclassesimportdataclass,fieldimportloggingimportitertoolsasitfrompathlibimportPathimportshelveasshfromzensols.util.tempfileimporttempfilefromzensols.persistimportpersisted,CloseableStashlogger=logging.getLogger(__name__)
[docs]@dataclassclassShelveStash(CloseableStash):"""Stash that uses Python's shelve library to store key/value pairs in DBM databases. """path:Path=field()"""A file to be created to store and/or load for the data storage."""writeback:bool=field(default=True)"""The writeback parameter given to ``shelve``."""auto_close:bool=field(default=True)"""If ``True``, close the shelve for each operation."""def__post_init__(self):self.is_open=False
@property@persisted('_real_path')defreal_path(self)->Path:"""The path the shelve API created on this file system. This is provided since :obj:`path` does *not* take in to account that some (G)DBM implementations add an extension and others do not This differes across libraries compiled against the Python interpreter and platorm. """ext=ShelveStash.get_extension()ext=''ifextisNoneelsef'.{ext}'returnself.path.parent/f'{self.path.name}{ext}'@property@persisted('_shelve')defshelve(self):"""Return an opened shelve mod:`shelve` object. """iflogger.isEnabledFor(logging.DEBUG):exists:bool=self.real_path.exists()logger.debug(f'creating shelve data, exists: {exists}')ifnotself.is_open:self.path.parent.mkdir(parents=True,exist_ok=True)fname=str(self.path.absolute())inst=sh.open(fname,writeback=self.writeback)self.is_open=Truereturninstdef_assert_auto_close(self):ifself.auto_close:self.close()
[docs]defdelete(self,name:str=None):"Delete the shelve data file."iflogger.isEnabledFor(logging.DEBUG):logger.debug(f'deleting: {name}')ifnameisNone:self.clear()else:delself.shelve[name]
[docs]defclose(self):"Close the shelve object, which is needed for data consistency."ifself.is_open:logger.debug('closing shelve data')try:self.shelve.close()self._shelve.clear()exceptException:self.is_open=False
[docs]defclear(self):self.close()iflogger.isEnabledFor(logging.DEBUG):logger.debug(f'clearing shelve data if exists: {self.real_path}')ifself.real_path.exists():self.real_path.unlink()
[docs]classshelve(object):"""Object used with a ``with`` scope that creates the closes a shelve object. For example, the following opens a file ``path``, sets a temporary variable ``stash``, prints all the data from the shelve, and then closes it: Example:: with shelve(path) as stash: for id, val in stash, 30: print(f'{id}: {val}') """