*** empty log message ***
[pli.git] / pli / pattern / store / store.py
blob92db53879e99e9d07172f513039b2c14f5727826
1 #=======================================================================
3 __version__ = '''0.0.49'''
4 __sub_version__ = '''20041014151353'''
5 __copyright__ = '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 import time
11 import re
12 import weakref
14 import pli.pattern.mixin.mapping as mapping
17 #-----------------------------------------------------------------------
18 #---------------------------------------------------isstorecompatible---
19 def isstorecompatible(obj):
20 '''
21 this will test general store interface compatibility...
22 '''
23 return issubclass(type(obj), BaseStore) or type(obj) == type({})
26 #--------------------------------------------------------isstoredtype---
27 def isstoredtype(store, name):
28 '''
29 this will return True if the name is a stored type is store.
30 '''
31 return name in store._store_types
35 #-----------------------------------------------------------------------
36 #-----------------------------------------------------------BaseStore---
37 # TODO add onStoreLoad, onStoreSave and onStoreReload events!!
38 # the handlers of these will accept the store instance as an
39 # argument...
40 # TODO rename to MappingBaseStore...
42 class BaseStore(mapping.Mapping, mapping.BasicMappingProxy):
43 ##class BaseStore(mapping.MappingWithMethods, mapping.BasicMappingProxy):
44 '''
45 '''
46 # if this is true strict object type checking will be enabled...
47 __stricttypes__ = False
48 # if this is true there will be no abbility to "recreate" an object
49 # using the add_object method.
50 __strictnames__ = True
51 # this will define the format used to generate a type attribute
52 # name... (attrname = __typenameformat___ % <type>.__name__)
53 __typenameformat___ = '%s'
55 __source_attr__ = '_store_data'
57 def __init__(self, name, *p, **n):
58 '''
59 '''
60 self.__name__ = name
61 self._store_types = {}
62 self._store_data = {}
63 ## super(BaseStore, self).__init__(name)
64 # dict minimal methods:
65 ## def __getitem__(self, key):
66 ## '''
67 ## '''
68 ## return self._store_data[key]
69 def __setitem__(self, key, obj):
70 '''
71 '''
72 if type(obj).__name__ not in self._store_types:
73 if not self.__stricttypes__:
74 # add objects' type...
75 self.add_object_type(type(obj))
76 else:
77 raise TypeError, 'can\'t add object "' + str(obj) + '" to store "' + str(self) + '": unregistred type.'
78 # add the object
79 if self.__strictnames__ and key in self._store_data:
80 raise TypeError, 'an object with the id "%s" already exists.' % key
81 ## self._store_data[key] = obj
82 super(BaseStore, self).__setitem__(key, obj)
83 ## def __delitem__(self, key):
84 ## '''
85 ## '''
86 ## del self._store_data[key]
87 ## def __iter__(self):
88 ## '''
89 ## '''
90 ## return self._store_data.__iter__()
91 # dict secondary methods:
92 # NOTE: might be good to un comment these...
93 ## def __contains__(self, key):
94 ## '''
95 ## '''
96 ## return key in self._store_data
97 ## def iterkeys(self):
98 ## '''
99 ## '''
100 ## return self._store_data.iterkeys()
101 ## def itervalues(self):
102 ## '''
103 ## '''
104 ## return self._store_data.itervalues()
105 ## def iteritems(self):
106 ## '''
107 ## '''
108 ## return self._store_data.iteritems()
109 ## def keys(self):
110 ## '''
111 ## '''
112 ## return self._store_data.keys()
113 ## def values(self):
114 ## '''
115 ## '''
116 ## return self._store_data.values()
117 # BaseStore specific methods...
118 def add_object_type(self, otype):
121 self._store_types[self.__typenameformat___ % otype.__name__] = otype
122 ##!!! REMOVE THIS !!!##
123 def get_types(self):
126 print '''WARNING: the pli.pattern.store.BaseStore.get_types method will be shortly removed!
127 use the itertypenames, itertypes methods instead!'''
128 return self._store_types.keys()
129 def gettypenames(self):
131 this will return a list of type names supported by the store.
133 return self._store_types.keys()
134 def gettypes(self):
136 this will return the types supported by the store.
138 return self._store_types.values()
139 def itertypenames(self):
141 this will iterate through the type names supported by the store.
143 for n in self._store_types.iterkeys():
144 yield n
145 def itertypes(self):
147 this will iterate through the types supported by the store.
149 for n in self._store_types.itervalues():
150 yield n
154 #-----------------------------------------------------------------------
155 # Store mix-ins...
156 #--------------------------------------------------------WeakrefStore---
157 class WeakrefStore(BaseStore):
160 def __init__(self, name, *p, **n):
163 super(WeakrefStore, self).__init__(name, *p, **n)
164 self._store_data = weakref.WeakValueDictionary()
167 #---------------------------------------------------AttrTypeBaseStore---
168 class AttrTypeBaseStore(BaseStore):
170 mix-in/class. this provides access to stored object types through atributes.
172 # this if set will check the attr name compliance with the python
173 # variable name syntax...
174 __check_type_name_format__ = True
175 ## __check_type_name_format__ = False
176 # this will define a pattern against which the attribute name is to
177 # be checked...
178 __type_name_format__ = re.compile('[_a-zA-Z][_a-zA-Z\d]*$')
180 # NOTE: if this is both an AttributeBaseStore and na
181 # AttrTypeBaseStore the name will get checked twice, and I
182 # see no beautifull way out of this....
183 ## def __setitem__(self, key, value):
184 ## '''
185 ## '''
186 ## if hasattr(self, '__check_type_name_format__') and self.__check_type_name_format__ and \
187 ## re.match(self.__type_name_format__, key) is None:
188 ## raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % key
189 ## super(AttrTypeBaseStore, self).__setitem__(key, value)
190 def __getattr__(self, name):
193 if name in ('_store_types',):
194 return object.__getattribute__(self, '_store_types')
195 if name in self._store_types:
196 return self._store_types[name]
197 try:
198 return super(AttrTypeBaseStore, self).__getattr__(name)
199 except AttributeError:
200 # XXX is this correct....
201 raise AttributeError, 'object "%s" has no attribute "%s"' % (self, name)
202 def add_object_type(self, otype):
205 name = self.__typenameformat___ % otype.__name__
206 if hasattr(self, '__check_type_name_format__') and self.__check_type_name_format__ and \
207 re.match(self.__type_name_format__, name) is None:
208 raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % key
209 super(AttrTypeBaseStore, self).add_object_type(otype)
212 #--------------------------------------------------------RPCBaseStore---
213 # this is here for the RPC interface...
214 class RPCBaseStore(BaseStore):
216 mix-in/class. this provides rpc methods for stored object data access.
218 def get_object_data(self, key, *attrs):
221 obj = self[key]
222 res = {}
223 for attr in attrs:
224 try:
225 ##!!! do type checking....
226 res[attr] = getattr(obj, attr)
227 except:
228 # this might not be good for a generic version...
229 res[attr] = ''
230 return res
231 def add_object(self, key, obj):
233 this will add an object to store...
235 self.__setitem__(key, obj)
236 def update_object(self, key, data):
238 this will update a set of attributes of an object.
240 if hasattr(self[key], 'update'):
241 ##!!! check...
242 return self[key].update(data)
243 else:
244 obj = self[key]
245 for attr in data:
246 return setattr(obj, attr, data[attr])
247 def remove_object(self, key):
250 self.__delitem__(key)
253 #---------------------------------------------------GroupingBaseStore---
254 class GroupingBaseStore(BaseStore):
256 mix-in/class. this provides grouping behavior for stored objects...
258 def __init__(self):
261 raise NotImplementedError, 'not yet done...'
264 #--------------------------------------------------AttributeBaseStore---
265 class AttributeBaseStore(BaseStore):
267 mix-in/class. this provides access to stored objects through store attributes.
269 # this if set will check the attr name compliance with the python
270 # variable name syntax...
271 __check_key_format__ = True
272 # this will define a pattern against which the attribute name is to
273 # be checked...
274 __key_format__ = re.compile('[_a-zA-Z][_a-zA-Z\d]*$')
276 # NOTE: if this is both an AttributeBaseStore and na
277 # AttrTypeBaseStore the name will get checked twice, and I
278 # see no beautifull way out of this....
279 def __setitem__(self, key, value):
282 if hasattr(self, '__check_key_format__') and self.__check_key_format__ and \
283 re.match(self.__key_format__, key) is None:
284 raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % key
285 super(AttributeBaseStore, self).__setitem__(key, value)
286 def __getattr__(self, name):
289 try:
290 return super(AttributeBaseStore, self).__getattr__(name)
291 except:
292 return self[name]
295 #--------------------------------------------------------WrapperStore---
296 class WrapperBaseStore(BaseStore):
298 mix-in/class. this provides access to wrapped/proxied stored objects.
300 # this will define a wrapper object (
301 # format:
302 # <wrapper>(<obj>) -> <wrapped>
303 __wrapper__ = None
305 def __getitem__(self, key):
308 return self.__wrapper__(super(WrapperStore, self).__getitem__(key))
309 def itervalues(self):
312 for val in super(WrapperStore, self).itervalues():
313 yield self.__wrapper__(val)
314 def iteritems(self):
317 for key, val in super(WrapperStore, self).iteritems():
318 yield key, self.__wrapper__(val)
319 def values(self):
322 return [ self.__wrapper__(val) for val in super(WrapperStore, self).values() ]
325 #-----------------------------------------------AttributeWrapperStore---
326 class AttributeWrapperStore(AttributeBaseStore, WrapperBaseStore):
328 mix-in/class. this provides access to wrapped/proxied stored objects through store attributes.
333 #=======================================================================
334 # vim:set ts=4 sw=4 nowrap :