*** empty log message ***
[pli.git] / pli / pattern / store / store.py
blob17c375c5f0e8e9e92703cfb9bfd938f6d556d7af
1 #=======================================================================
3 __version__ = '''0.0.49'''
4 __sub_version__ = '''20041031230609'''
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()
130 def gettypenames(self):
132 this will return a list of type names supported by the store.
134 return self._store_types.keys()
135 def gettypes(self):
137 this will return the types supported by the store.
139 return self._store_types.values()
140 def itertypenames(self):
142 this will iterate through the type names supported by the store.
144 for n in self._store_types.iterkeys():
145 yield n
146 def itertypes(self):
148 this will iterate through the types supported by the store.
150 for n in self._store_types.itervalues():
151 yield n
155 #-----------------------------------------------------------------------
156 # Store mix-ins...
157 #--------------------------------------------------------WeakrefStore---
158 class WeakrefStore(BaseStore):
161 def __init__(self, name, *p, **n):
164 super(WeakrefStore, self).__init__(name, *p, **n)
165 self._store_data = weakref.WeakValueDictionary()
168 #---------------------------------------------------AttrTypeBaseStore---
169 class AttrTypeBaseStore(BaseStore):
171 mix-in/class. this provides access to stored object types through atributes.
173 # this if set will check the attr name compliance with the python
174 # variable name syntax...
175 __check_type_name_format__ = True
176 ## __check_type_name_format__ = False
177 # this will define a pattern against which the attribute name is to
178 # be checked...
179 __type_name_format__ = re.compile('[_a-zA-Z][_a-zA-Z\d]*$')
181 # NOTE: if this is both an AttributeBaseStore and na
182 # AttrTypeBaseStore the name will get checked twice, and I
183 # see no beautifull way out of this....
184 ## def __setitem__(self, key, value):
185 ## '''
186 ## '''
187 ## if hasattr(self, '__check_type_name_format__') and self.__check_type_name_format__ and \
188 ## re.match(self.__type_name_format__, key) is None:
189 ## raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % key
190 ## super(AttrTypeBaseStore, self).__setitem__(key, value)
191 def __getattr__(self, name):
194 if name in ('_store_types',):
195 return object.__getattribute__(self, '_store_types')
196 if name in self._store_types:
197 return self._store_types[name]
198 try:
199 return super(AttrTypeBaseStore, self).__getattr__(name)
200 except AttributeError:
201 # XXX is this correct....
202 raise AttributeError, 'object "%s" has no attribute "%s"' % (self, name)
203 def add_object_type(self, otype):
206 name = self.__typenameformat___ % otype.__name__
207 if hasattr(self, '__check_type_name_format__') and self.__check_type_name_format__ and \
208 re.match(self.__type_name_format__, name) is None:
209 raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % name
210 super(AttrTypeBaseStore, self).add_object_type(otype)
213 #--------------------------------------------------------RPCBaseStore---
214 # this is here for the RPC interface...
215 class RPCBaseStore(BaseStore):
217 mix-in/class. this provides rpc methods for stored object data access.
219 def get_object_data(self, key, *attrs):
222 obj = self[key]
223 res = {}
224 for attr in attrs:
225 try:
226 ##!!! do type checking....
227 res[attr] = getattr(obj, attr)
228 except:
229 # this might not be good for a generic version...
230 res[attr] = ''
231 return res
232 def add_object(self, key, obj):
234 this will add an object to store...
236 self.__setitem__(key, obj)
237 def update_object(self, key, data):
239 this will update a set of attributes of an object.
241 if hasattr(self[key], 'update'):
242 ##!!! check...
243 return self[key].update(data)
244 else:
245 obj = self[key]
246 for attr in data:
247 return setattr(obj, attr, data[attr])
248 def remove_object(self, key):
251 self.__delitem__(key)
254 #---------------------------------------------------GroupingBaseStore---
255 class GroupingBaseStore(BaseStore):
257 mix-in/class. this provides grouping behavior for stored objects...
259 def __init__(self):
262 raise NotImplementedError, 'not yet done...'
265 #--------------------------------------------------AttributeBaseStore---
266 class AttributeBaseStore(BaseStore):
268 mix-in/class. this provides access to stored objects through store attributes.
270 # this if set will check the attr name compliance with the python
271 # variable name syntax...
272 __check_key_format__ = True
273 # this will define a pattern against which the attribute name is to
274 # be checked...
275 __key_format__ = re.compile('[_a-zA-Z][_a-zA-Z\d]*$')
277 # NOTE: if this is both an AttributeBaseStore and na
278 # AttrTypeBaseStore the name will get checked twice, and I
279 # see no beautifull way out of this....
280 def __setitem__(self, key, value):
283 if hasattr(self, '__check_key_format__') and self.__check_key_format__ and \
284 re.match(self.__key_format__, key) is None:
285 raise NameError, 'stored objects name must comply with python variable naming rules (got: "%s").' % key
286 super(AttributeBaseStore, self).__setitem__(key, value)
287 def __getattr__(self, name):
290 try:
291 return super(AttributeBaseStore, self).__getattr__(name)
292 except:
293 return self[name]
296 #--------------------------------------------------------WrapperStore---
297 class WrapperBaseStore(BaseStore):
299 mix-in/class. this provides access to wrapped/proxied stored objects.
301 # this will define a wrapper object (
302 # format:
303 # <wrapper>(<obj>) -> <wrapped>
304 __wrapper__ = None
306 def __getitem__(self, key):
309 return self.__wrapper__(super(WrapperStore, self).__getitem__(key))
310 def itervalues(self):
313 for val in super(WrapperStore, self).itervalues():
314 yield self.__wrapper__(val)
315 def iteritems(self):
318 for key, val in super(WrapperStore, self).iteritems():
319 yield key, self.__wrapper__(val)
320 def values(self):
323 return [ self.__wrapper__(val) for val in super(WrapperStore, self).values() ]
326 #-----------------------------------------------AttributeWrapperStore---
327 class AttributeWrapperStore(AttributeBaseStore, WrapperBaseStore):
329 mix-in/class. this provides access to wrapped/proxied stored objects through store attributes.
334 #=======================================================================
335 # vim:set ts=4 sw=4 nowrap :