2424the storage methods themselves.
2525"""
2626
27- from collections .abc import MutableMapping
27+ from collections .abc import Collection , Mapping , MutableMapping
2828from typing import Any , Iterable , Tuple
2929
3030Key = Any
3737ItemIter = Iterable [Item ]
3838
3939
40- # TODO: Wishful thinking: Define store type so the type is defined by it's methods, not by subclassing.
41- class Persister (MutableMapping ):
42- """ Acts as a MutableMapping abc, but disabling the clear method, and computing __len__ by counting keys"""
40+ class KvCollection (Collection ):
41+
42+ def __contains__ (self , k : Key ) -> bool :
43+ """
44+ Check if collection of keys contains k.
45+ Note: This method actually fetches the contents for k, returning False if there's a key error trying to do so
46+ Therefore it may not be efficient, and in most cases, a method specific to the case should be used.
47+ :return: True if k is in the collection, and False if not
48+ """
49+ try :
50+ self .__getitem__ (k )
51+ return True
52+ except KeyError :
53+ return False
4354
44- def __len__ (self ):
55+ def __len__ (self ) -> int :
56+ """
57+ Number of elements in collection of keys.
58+ Note: This method iterates over all elements of the collection and counts them.
59+ Therefore it is not efficient, and in most cases should be overridden with a more efficient version.
60+ :return: The number (int) of elements in the collection of keys.
61+ """
62+ # TODO: some other means to more quickly count files?
63+ # Note: Found that sum(1 for _ in self.__iter__()) was slower for small, slightly faster for big inputs.
4564 count = 0
4665 for _ in self .__iter__ ():
4766 count += 1
4867 return count
4968
69+ def head (self ):
70+ return next (iter (self .items ()))
71+
72+
73+ class KvReader (KvCollection , Mapping ):
74+ """Acts as a Mapping abc, but with default __len__ (implemented by counting keys)
75+ and head method to get the first (k, v) item of the store"""
76+ pass
77+
78+
79+ Reader = KvReader # alias
80+
81+
82+ # TODO: Wishful thinking: Define store type so the type is defined by it's methods, not by subclassing.
83+ class Persister (Reader , MutableMapping ):
84+ """ Acts as a MutableMapping abc, but disabling the clear method, and computing __len__ by counting keys"""
85+
5086 def clear (self ):
5187 raise NotImplementedError ('''
5288 The clear method was overridden to make dangerous difficult.
@@ -58,6 +94,9 @@ def clear(self):
5894 pass''' )
5995
6096
97+ KvPersister = Persister # alias with explict name
98+
99+
61100# TODO: Make identity_func "identifiable". If we use the following one, we can use == to detect it's use,
62101# TODO: ... but there may be a way to annotate, register, or type any identity function so it can be detected.
63102def identity_func (x ):
@@ -211,6 +250,9 @@ def head(self) -> Item:
211250 def __setitem__ (self , k : Key , v : Val ):
212251 return self .store .__setitem__ (self ._id_of_key (k ), self ._data_of_obj (v ))
213252
253+ # def update(self, *args, **kwargs):
254+ # return self.store.update(*args, **kwargs)
255+
214256 # Delete ####################################################################
215257 def __delitem__ (self , k : Key ):
216258 return self .store .__delitem__ (self ._id_of_key (k ))
@@ -230,6 +272,21 @@ def __repr__(self):
230272 return self .store .__repr__ ()
231273
232274
275+ KvStore = Store # alias with explict name
276+
277+
278+ def has_kv_store_interface (o ):
279+ """Check if object has the KvStore interface (that is, has the kv wrapper methods
280+ Args:
281+ o: object (class or instance)
282+
283+ Returns: True if kv has the four key (in/out) and value (in/out) transformation methods
284+
285+ """
286+ return hasattr (o , '_id_of_key' ) and hasattr (o , '_key_of_id' ) \
287+ and hasattr (o , '_data_of_obj' ) and hasattr (o , '_obj_of_data' )
288+
289+
233290from abc import ABCMeta , abstractmethod
234291from py2store .errors import KeyValidationError
235292
0 commit comments