1 #=======================================================================
3 __version__
= '''0.1.19'''
4 __sub_version__
= '''20050902235933'''
5 __copyright__
= '''(c) Alex A. Naanou 2003'''
8 this module defines a number of utilities and objects to assist advanced
9 usage of standard python types.
12 #-----------------------------------------------------------------------
14 import pli
.pattern
.mixin
.mapping
as mapping
17 #-----------------------------------------------------------------------
18 # TODO create a logic proxy, with adapters....
19 # UNION(*p), INTERSECTION(*n), ...
21 #------------------------------------------------------------_Compare---
22 class _Compare(object):
25 def __init__(self
, eq
):
27 def __cmp__(self
, other
):
29 def __eq__(self
, other
):
31 def __ne__(self
, other
):
33 def __gt__(self
, other
):
35 def __ge__(self
, other
):
37 def __lt__(self
, other
):
39 def __le__(self
, other
):
42 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43 # this will compare to any value as equel (almost oposite to None)
44 Any
= ANY
= _Compare(0)
46 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47 # this is bigger than any value...
50 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51 # this is smaller than any value...
52 MINIMUM
= _Compare(-1)
56 #-----------------------------------------------------------------------
57 # this is to define basic pattern combination mathematics.
59 # Pab = Pa | Pb -- Pab is a pattern that will match either Pa
70 class Pattern(object):
74 def __eq__(self
, other
):
78 def __ne__(self
, other
):
82 def __gt__(self
, other
):
86 def __ge__(self
, other
):
90 def __lt__(self
, other
):
94 def __le__(self
, other
):
102 #--------------------------------------------------------------oftype---
103 class oftype(Pattern
):
105 this will create an object that can be used as a predicate to test type,
106 and it will copare True to objects of that type.
108 def __init__(self
, *types
, **n
):
113 self
.__doc
__ = n
['doc']
114 def __call__(self
, other
):
116 test if the the other object object is of type.
118 return isinstance(other
, self
._types
) is True
120 def __ne__(self
, other
):
121 return not isinstance(other
, self
._types
) is True
122 def __gt__(self
, other
):
124 def __ge__(self
, other
):
126 def __lt__(self
, other
):
128 def __le__(self
, other
):
131 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132 # simple type predicates...
134 isfloat
= oftype(float)
135 iscomplex
= oftype(complex)
138 isunicode
= oftype(unicode)
140 islist
= oftype(list)
141 istuple
= oftype(tuple)
142 isdict
= oftype(dict)
144 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145 # general type groups predicates...
146 isnumber
= oftype(int, float, complex)
147 isstring
= oftype(str, unicode)
148 issequence
= oftype(list, tuple)
150 isiterabletype
= oftype(str, unicode, list, tuple, dict)
154 ###-----------------------------------------------------------------------
155 ##class isLike(Pattern):
158 ## def __init__(self, *types, **n):
161 ## self._types = types
163 ## self.__doc__ = n['doc']
164 ## def __call__(self, other):
166 ## test if the the other object object is of type.
168 ## return isinstance(other, self._types) is True
170 ## def __ne__(self, other):
171 ## return not isinstance(other, self._types) is True
172 ## def __gt__(self, other):
174 ## def __ge__(self, other):
176 ## def __lt__(self, other):
178 ## def __le__(self, other):
182 #-----------------------------------------------------------------------
183 #-------------------------------------------------------dictcopyunite---
184 def dictcopyunite(*members
):
193 #---------------------------------------------------AbstractDictChainMixin---
194 # TODO split this into several mix-ins....
195 # NOTE: this was not designed to be used directly...
196 class AbstractDictChainMixin(mapping
.Mapping
):
199 # mapping interface...
200 def __getitem__(self
, name
):
203 for m
in self
.__iterchainmembers
__():
206 raise KeyError, 'key "%s" is not present in any of the members.' % name
207 def __setitem__(self
, name
, value
):
212 raise TypeError, 'can\'t add values to an AbstractDictChainMixin object.'
213 def __delitem__(self
, name
):
216 raise TypeError, 'can\'t delete values from an AbstractDictChainMixin object.'
217 def __contains__(self
, name
):
220 for m
in self
.__iterchainmembers
__():
228 for m
in self
.__iterchainmembers
__():
233 # AbstractDictChainMixin specific extension interface...
234 ## def __iterchainmembers__(self):
236 ## this will yield dicts, elements of the chain.
238 ## raise NotImplementedError
239 # AbstractDictChainMixin specific methods...
242 this will return a dict copy of the DictUnion object.
244 return dict(self
.items())
247 #-----------------------------------------------------------DictUnion---
248 # XXX might be good to combine this and DictChain... (this will be
249 # quite easy using the itermembers instead of self._members)
250 class DictUnion(AbstractDictChainMixin
):
252 this is a dict like object, that acts as a union of its members but
253 without modifieng its members in any way.
255 this is similar to a sequential update of all members, but retains
256 the container information for each item, and does not have the
257 overhead of creating a new resulting dict.
259 NOTE: because of the nature of dicts, the later added members (unite)
260 have higher priority than the former.
261 NOTE: the members added in one call (be it __init__, unite or tailunite)
262 have descending priority -- first highest last lowest.
263 NOTE: due to ints nature this object is *live*, e.g. it emidiatly
264 reflects all modifications to its members as they are modified.
268 def __init__(self
, *members
):
271 members
= list(members
)
273 self
._members
= tuple(members
)
274 # AbstractDictChainMixin specific extension interface...
275 def __iterchainmembers__(self
):
278 for m
in self
._members
:
280 # the DictUnion specific interface...
281 # XXX should these depend on __iterchainmembers__ or directly on
283 def unite(self
, *others
):
285 add members to the union object.
287 NOTE: this method will add members to the top of the pririty
290 others
= list(others
)
292 self
._members
= tuple(others
) + self
._members
293 def tailunite(self
, *others
):
295 this is the same as unite but adds low priority members (to the
296 botom of the priority stack).
298 others
= list(others
)
300 self
._members
= self
._members
+ tuple(others
)
301 def memberindex(self
, obj
):
304 return list(self
._members
).index(obj
)
305 def removemember(self
, obj
):
308 if obj
in self
._members
:
309 self
._members
= tuple(list(self
._members
).remove(obj
))
311 raise TypeError, '%s does not contain %s as a member.' % (self
, obj
)
312 def clearmembers(self
):
320 def popmember(self
, index
=0):
323 NOTE: this by default will remove the highest priority member.
325 m
= list(self
._members
)
327 self
._members
= tuple(m
)
329 itermembers
= __iterchainmembers__
330 def getcontainerof(self
, name
):
333 for m
in self
._members
:
336 raise KeyError, '%s does not contain "%s"' % (self
, name
)
337 def getallcontainersof(self
, name
):
341 for m
in self
._members
:
345 raise KeyError, '%s does not contain "%s"' % (self
, name
)
349 #---------------------------------------------------WritableDictUnion---
351 # get the last occurance...
353 # get the first occurance...
356 # if key is not contained in union, add it to the last member...
357 WRITE_NEW_TO_LAST
= 0
358 # if key is not contained in union, add it to the first member...
359 WRITE_NEW_TO_FIRST
= 2
360 # if the key is present in the union more than once, override the last
362 WRITE_TO_LAST_OWNER
= 0
363 # if the key is present in the union more than once, override the first
365 WRITE_TO_FIRST_OWNER
= 4
366 # write to local (temporary) dict...
367 # NOTE: if this is set, other write opts will be ignored...
372 # delete the last occurance of key...
374 # delete the first occurance of key...
376 # enable ocal key delete...
378 # disable deletion of anything but local keys...
379 DELETE_LOCAL_ONLY
= 128
381 DELETE_DISABLED
= 256
383 class WritableDictUnion(DictUnion
):
386 __modify_props__
= GET_LOCAL_FIRST \
387 | WRITE_NEW_TO_FIRST \
388 | WRITE_TO_FIRST_OWNER \
392 def __init__(self
, *members
):
395 super(WritableDictUnion
, self
).__init
__(*members
)
397 def __getitem__(self
, name
):
400 props
= getattr(self
, '__modify_props__', 0)
401 if props
& GET_LOCAL_FIRST
:
402 return self
._locals
.get(name
, super(WritableDictUnion
, self
).__getitem
__(name
))
404 return super(WritableDictUnion
, self
).__getitem
__(name
)
406 if name
in self
._locals
:
407 return self
._locals
[name
]
409 def __setitem__(self
, name
, value
):
412 props
= getattr(self
, '__modify_props__', 0)
413 if props
& WRITE_DISABLED
:
414 raise TypeError, 'can\'t add values to a dict union object (writing is disabled).'
415 elif props
& WRITE_LOCAL
:
416 self
._locals
[name
] = value
419 if props
& WRITE_TO_FIRST_OWNER
:
420 self
.getallcontainersof(name
)[0][name
] = value
422 self
.getallcontainersof(name
)[-1][name
] = value
424 if props
& WRITE_NEW_TO_FIRST
:
425 self
.members()[0][name
] = value
427 self
.members()[-1][name
] = value
428 def __contains__(self
, name
):
431 if name
in self
._locals
or super(WritableDictUnion
, self
).__contains
__(name
):
434 def __delitem__(self
, name
):
437 props
= getattr(self
, '__modify_props__', 0)
438 if props
& DELETE_DISABLED
:
439 raise TypeError, 'can\'t delete items (deletion is disabled).'
440 if props
& DELETE_LOCAL
and name
in self
._locals
:
441 del self
._locals
[name
]
442 elif not props
& DELETE_LOCAL_ONLY
:
443 if props
& DELETE_FIRST
:
444 del self
.getallcontainersof(name
)[0][name
]
446 del self
.getallcontainersof(name
)[-1][name
]
448 raise TypeError, 'can\'t delete from contained dicts.'
453 props
= getattr(self
, '__modify_props__', 0)
454 if props
& GET_LOCAL_FIRST
:
455 for k
in self
._locals
:
458 for k
in super(WritableDictUnion
, self
).__iter
__():
462 if not props
& GET_LOCAL_FIRST
:
463 for k
in self
._locals
:
469 #-------------------------------------------------------DictTypeUnion---
470 # WARNING: this is not done!
471 class DictTypeUnion(DictUnion
, dict):
473 this is a diriviation from dict that can contain oun data.
479 #------------------------------------------------------BasicDictChain---
480 class BasicDictChain(AbstractDictChainMixin
, mapping
.DictLike
):
483 NOTE: this class was designed as a basic base class (atleast the
484 __iterchainmembers__ method should be overloaded).
485 NOTE: do not forget to call the original __iterchainmembers__.
486 NOTE: this, if used as is will not differ from a dict.
488 def __init__(self
, *p
, **n
):
492 super(BasicDictChain
, self
).__init
__(*p
, **n
)
493 def __setitem__(self
, name
, value
):
496 self
._dct
_data
[name
] = value
497 def __delitem__(self
, name
):
500 del self
._dct
_data
[name
]
501 def __iterchainmembers__(self
):
508 #-----------------------------------------------------------------------
509 #---------------------------------------------------------ObjectUnion---
511 # TODO split to various mix-ins...
512 ##class BasicObjectUnion(object):
513 class ObjectUnion(object):
515 this represents the union of the attr of several objects.
517 def __init__(self
, *members
):
520 members
= list(members
)
522 self
._members
= tuple(members
)
524 def __getattr__(self
, name
):
527 for o
in self
._members
:
529 return getattr(o
, name
)
530 ## # Q: which is faster, this or the "if hasattr..."???
532 ## return getattr(o, name)
533 ## except AttributeError:
535 raise AttributeError, name
536 ## def __setattr__(self, name, value):
539 ## raise TypeError, 'ca\'t write attributes of a ObjectUnion object.'
540 ## def __delattr__(self, name, value):
544 def __hasattr__(self
, name
):
547 for o
in self
._members
:
551 # interface methods...
555 #=======================================================================
556 if __name__
== '__main__':
558 d1
= {'c':'!!!!!', 'b':'x'}
560 D
= WritableDictUnion(d0
, d1
)
572 #=======================================================================
573 # vim:set ts=4 sw=4 nowrap :