1 #=======================================================================
3 __version__
= '''0.1.21'''
4 __sub_version__
= '''20120704184439'''
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 #-----------------------------------------------------------------------
16 import pli
.pattern
.mixin
.mapping
as mapping
17 import pli
.pattern
.proxy
.utils
as proxyutils
18 import pli
.objutils
as objutils
21 #-----------------------------------------------------------------------
22 #-------------------------------------------------------------Pattern---
23 class Pattern(object):
29 #-------------------------------------------------------------Compare---
30 class Compare(Pattern
):
35 def __init__(self
, eq
, name
=None):
38 self
._name
= self
.__class
__.__name
__
43 create a copy of self.
49 if self
.original
is True:
51 return '<%s object %s>' % (self
._name
, hash(self
))
52 # comparison methods...
53 def __cmp__(self
, other
):
55 def __eq__(self
, other
):
57 def __ne__(self
, other
):
59 def __gt__(self
, other
):
61 def __ge__(self
, other
):
63 def __lt__(self
, other
):
65 def __le__(self
, other
):
68 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
69 # this will compare to any value as equel (almost oposite to None)
70 Any
= ANY
= Compare(0, 'ANY')
72 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73 # this is bigger than any value...
74 MAXIMUM
= Compare(1, 'MAXIMUM')
76 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77 # this is smaller than any value...
78 MINIMUM
= Compare(-1, 'MINIMUM')
81 #-----------------------------------------------------------------AND---
84 AND(A, B[, ..]) == X iff X == A and X == B [and ..]
86 def __init__(self
, A
, B
, *patterns
):
89 self
.patterns
= (A
, B
) + patterns
93 return 'AND(%s)' % ', '.join(repr(p
) for p
in self
.patterns
)
94 # XXX revise comparison order...
95 def __eq__(self
, other
):
96 return False not in [ other
== p
for p
in self
.patterns
]
97 def __ne__(self
, other
):
98 for p
in self
.patterns
:
104 #------------------------------------------------------------------OR---
107 OR(A, B[, ..]) == X iff X == A or X == B [and ..]
109 def __init__(self
, A
, B
, *patterns
):
112 self
.patterns
= (A
, B
) + patterns
116 return 'OR(%s)' % ', '.join(repr(p
) for p
in self
.patterns
)
117 # XXX revise comparison order...
118 def __eq__(self
, other
):
119 for p
in self
.patterns
:
123 def __ne__(self
, other
):
124 return False not in [ other
!= p
for p
in self
.patterns
]
127 #-----------------------------------------------------------------NOT---
130 NOT(A) == X iff A != X
132 def __init__(self
, obj
):
137 return 'NOT(%r)' % self
.obj
138 def __eq__(self
, other
):
139 return not (self
.obj
== other
)
140 def __ne__(self
, other
):
141 return not (self
.obj
!= other
)
144 #------------------------------------------------------------------IN---
145 # NOTE: this looks odd :)
148 IN(A) == X iff A in X
149 IN(A, B) == X iff B == X and A in X
151 def __init__(self
, obj
, container
=ANY
):
153 self
.container
= container
157 return 'IN(%r, %r)' % (self
.obj
, self
.container
)
158 def __eq__(self
, other
):
159 return self
.container
== other
and self
.obj
in other
160 def __ne__(self
, other
):
161 return self
.container
!= other
or self
.obj
not in other
164 #------------------------------------------------------------------AT---
167 AT(A) == X iff A in X and X[ANY] == A
168 AT(A, B) == X iff A in X and X[B] == A
170 NOTE: this works as good as python's containers accept patterns.
171 this mostly amounts to staying clear of using patterns as
172 indexes, thus the first case might not work correctly.
174 def __init__(self
, obj
, position
=ANY
):
176 self
.position
= position
178 return 'AT(%r, %r)' % (self
.obj
, self
.position
)
179 def __eq__(self
, other
):
181 if other
== SEQUENCE
:
182 return self
.obj
in other \
183 and other
[self
.position
] == self
.obj
186 return self
.obj
in other
.values() \
187 and other
[self
.position
] == self
.obj
188 except (KeyError, IndexError):
190 def __ne__(self
, other
):
192 if other
== SEQUENCE
:
193 return self
.obj
not in other \
194 or other
[self
.position
] != self
.obj
196 return self
.obj
not in other
.values() \
197 or other
[self
.position
] != self
.obj
198 except (KeyError, IndexError):
203 #-----------------------------------------------------------------------
205 # TODO add chaining support...
206 # TODO add shadowing support... (via NOTHING, afect chained values)
207 class ErxCONTAINER(Pattern
, mapping
.Mapping
):
210 has the folowing notions:
211 - length, if content is sizable or has length
212 - content/containment
215 ##!!! we need to pass data arround!
216 def __init__(self
, data
=()):
217 ##!!! we need to pass data arround!
218 ## objutils.termsuper(ErxCONTAINER, self).__init__(data)
219 objutils
.termsuper(ErxCONTAINER
, self
).__init
__()
221 # mapping-like interface...
222 # NOTE: this is mainly needed to bypass pythons dict optimizations
223 # thus enabling patterns...
224 def __getitem__(self
, pattern
):
227 # XXX might be good to make this check the obvious first...
231 # XXX should this fail like this??
232 raise KeyError, pattern
233 def __setitem__(self
, pattern
, value
):
237 self
._data
+= (value
,)
238 def __delitem__(self
, pattern
):
242 while pattern
in res
:
244 self
._data
= tuple(res
)
245 ##!!! need raw iter, to iterate and detect content items...
250 if isinstance(e
, CONTENT
):
255 # pattern interface...
256 def __eq__(self
, other
):
259 # NOTE: this will go through content items via .__iter__
263 return len(self
) == len(other
)
264 def __ne__(self
, other
):
267 # XXX is there a better way to do this?
268 return not (self
== other
)
274 ##!!! should this be a view or a container?
275 class ORDERED(ErxCONTAINER
):
277 takes a container as argument and returns a container that also considers
278 the nothion of order.
280 def __eq__(self
, other
):
283 if len(self
) == len(other
):
284 return tuple(self
) == tuple(other
)
286 def __ne__(self
, other
):
292 ##!!! should this be a view or a container?
293 # XXX this should be like OR -- match single elements as well as
294 # sub-sequences... i.e. '==' and 'in' should be equivalent but
295 # strictly prioretized...
296 class CONTENT(ErxCONTAINER
):
298 like a container but matches a part of a container.
304 class VIEW(ErxCONTAINER
):
307 def __init__(self
, pattern
, container
):
310 objutils
.termsuper(VIEW
, self
).__init
__()
311 self
.pattern
= pattern
312 self
.container
= container
314 def __getitem__(self
, pattern
):
318 return self
.container
[AND(pattern
, self
.pattern
)]
320 raise KeyError, pattern
321 def __setitem__(self
, pattern
, value
):
325 self
.container
[AND(pattern
, self
.pattern
)] = value
327 raise KeyError, pattern
328 def __delitem__(self
, pattern
):
331 del self
.container
[AND(pattern
, self
.pattern
)]
335 pattern
= self
.pattern
336 for e
in self
.container
:
341 # XXX this should match the value or item pattern...
342 # XXX need a reliable way to position this at next/prev values... this
343 # must be as independent of container manipulation as possible...
344 # XXX need an efficient way to directly position within a container...
345 # the "visited bag" approach is BAD for very large containers!
346 # one way to do this is to remember a "current" element. but this
347 # will break if it is deleted or modified...
351 def __init__(self
, pattern
, container
, visited
=()):
354 objutils
.termsuper(ITEM
, self
).__init
__()
355 self
.pattern
= pattern
356 self
.container
= container
357 self
.visited
= visited
360 # XXX may be a good idea to combine value with assign a-la
361 # jQuery... actually, might even add delete into the mix -- we
362 # do have a NOTHING pattern don't we?
363 # ...still need some more thought.
367 visited
= self
.visited
368 if len(visited
) == 0:
369 return self
.container
[self
.pattern
]
370 elif len(visited
) == 1:
371 return self
.container
[AND(NOT(self
.visited
[0]), self
.pattern
)]
372 return self
.container
[AND(NOT(OR(*self
.visited
)), self
.pattern
)]
373 ##!!! what should happen of we changed the value or updated the container
374 ##!!! so as this does not have a value anymore?
375 def assign(self
, value
):
379 self
.container
[self
.value
] = value
381 # this means we are not looking at a meaningfull
384 ##!!! is this correct???
385 self
.container
[NOTHING
] = value
392 del self
.container
[self
.value
]
401 visited
= self
.visited
+ (self
.value
,)
402 res
= self
.__class
__(self
.pattern
, self
.container
, visited
)
403 # this is here to break things and to prevent ust to iterate
404 # beyond where we started...
411 visited
= self
.visited
412 # we can't iterate over the beginning...
413 if len(visited
) == 0:
414 raise KeyError, self
.pattern
415 pattern
= self
.pattern
416 container
= self
.container
417 for v
in visited
[::-1]:
418 if v
not in container
:
419 # remove the non-existing elements...
420 visited
= visited
[:-1]
421 # this is to handle the case of we are positioned
422 # somewhere in a chain and all the items we saw before
423 # do not exist any longer...
424 if len(visited
) == 0:
425 raise KeyError, self
.pattern
427 res
= self
.__class
__(pattern
, container
, visited
[:-1])
428 # this is here to break things and to prevent ust to iterate
429 # beyond where we started...
435 # variable length contents...
438 OF(A, N) == X iff A occurs N times in X
440 Pythonism for N of A in Eryx.
442 def __init__(self
, obj
, count
):
443 super(OF
, self
).__init
__()
444 self
.obj
, self
.count
= obj
, count
449 #-----------------------------------------------------------------------
450 # this is to define basic pattern combination mathematics.
452 # Pab = Pa | Pb -- Pab is a pattern that will match either Pa
463 ##class Pattern(object):
467 ## def __eq__(self, other):
471 ## def __ne__(self, other):
475 ## def __gt__(self, other):
479 ## def __ge__(self, other):
483 ## def __lt__(self, other):
487 ## def __le__(self, other):
495 #--------------------------------------------------------------oftype---
496 class OfType(Pattern
):
498 this will create an object that can be used as a predicate to test type,
499 and it will copare True to objects of that type.
501 def __init__(self
, *types
, **n
):
506 self
.__doc
__ = n
['doc']
507 def __call__(self
, other
):
509 test if the the other object object is of type.
511 return isinstance(other
, self
._types
) is True
513 def __ne__(self
, other
):
514 return not self(other
)
515 ## return not isinstance(other, self._types) is True
516 def __gt__(self
, other
):
518 def __ge__(self
, other
):
520 def __lt__(self
, other
):
522 def __le__(self
, other
):
525 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
529 #-------------------------------------------------OfTypeWithPredicate---
530 class OfTypeWithPredicate(OfType
):
533 def __call__(self
, other
):
536 if self
.__predicate
__(other
):
537 return super(OfTypeWithPredicate
, self
).__call
__(other
)
540 # NOTE: this is intended to be oveloaded... (by default it will
541 # break the object...)
542 def __predicate__(self
, other
):
544 this will check the object.
546 must return True or False.
548 raise NotImplementedError
551 #----------------------------------------------OfTypeWithArgPredicate---
552 # WARNING: this might not be compatible with CPythons pickle...
553 class OfTypeWithArgPredicate(OfTypeWithPredicate
):
556 def __init__(self
, *p
, **n
):
559 super(OfTypeWithArgPredicate
, self
).__init
__(*p
, **n
)
561 self
.__predicate
__ = n
['predicate']
563 raise TypeError, 'a predicate must be given.'
565 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
567 ofptype
= OfTypeWithArgPredicate
570 #-----------------------------------------------------------------------
571 # simple type predicates...
572 INT
= isint
= oftype(int)
573 FLOAT
= isfloat
= oftype(float)
574 COMPLEX
= iscomplex
= oftype(complex)
576 STR
= isstr
= oftype(str)
577 UNICODE
= isunicode
= oftype(unicode)
579 LIST
= islist
= oftype(list)
580 TUPLE
= istuple
= oftype(tuple)
581 DICT
= isdict
= oftype(dict)
582 SET
= isset
= oftype(set)
584 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
585 # other odd predicates :)
586 ODD
= isodd
= ofptype(int, long, predicate
=lambda o
: o
%2 != 0)
587 EVEN
= iseven
= ofptype(int, long, predicate
=lambda o
: o
%2 == 0)
590 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
591 # general type groups predicates...
592 NUMBER
= isnumber
= oftype(int, float, complex)
594 STRING
= isstring
= oftype(str, unicode)
596 SEQUENCE
= issequence
= oftype(list, tuple)
597 CONTAINER
= iscontainer
= oftype(list, tuple, dict, set)
599 ITERABLETYPE
= isiterabletype
= oftype(str, unicode, list, tuple, dict, set)
602 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
603 IDENT
= isident
= ofptype(str, unicode, predicate
=lambda o
: len(o
) > 0 \
604 and False not in [ c
.isalnum() \
605 for c
in o
.split('_') ] \
609 ###-----------------------------------------------------------------------
610 ##class isLike(Pattern):
613 ## def __init__(self, *types, **n):
616 ## self._types = types
618 ## self.__doc__ = n['doc']
619 ## def __call__(self, other):
621 ## test if the the other object object is of type.
623 ## return isinstance(other, self._types) is True
625 ## def __ne__(self, other):
626 ## return not isinstance(other, self._types) is True
627 ## def __gt__(self, other):
629 ## def __ge__(self, other):
631 ## def __lt__(self, other):
633 ## def __le__(self, other):
638 #-----------------------------------------------------------------------
639 #-------------------------------------------------------dictcopyunite---
640 def dictcopyunite(*members
):
649 #---------------------------------------------------AbstractDictChainMixin---
650 # TODO split this into several mix-ins....
651 # NOTE: this was not designed to be used directly...
652 class AbstractDictChainMixin(mapping
.Mapping
):
655 # mapping interface...
656 def __getitem__(self
, name
):
659 for m
in self
.__iterchainmembers
__():
662 raise KeyError, 'key "%s" is not present in any of the members.' % name
663 def __setitem__(self
, name
, value
):
668 raise TypeError, 'can\'t add values to an AbstractDictChainMixin object.'
669 def __delitem__(self
, name
):
672 raise TypeError, 'can\'t delete values from an AbstractDictChainMixin object.'
673 def __contains__(self
, name
):
676 for m
in self
.__iterchainmembers
__():
684 for m
in self
.__iterchainmembers
__():
689 # AbstractDictChainMixin specific extension interface...
690 ## def __iterchainmembers__(self):
692 ## this will yield dicts, elements of the chain.
694 ## raise NotImplementedError
695 # AbstractDictChainMixin specific methods...
698 this will return a dict copy of the DictUnion object.
700 return dict(self
.items())
703 #-----------------------------------------------------------DictUnion---
704 # XXX might be good to combine this and DictChain... (this will be
705 # quite easy using the itermembers instead of self._members)
706 class DictUnion(AbstractDictChainMixin
):
708 this is a dict like object, that acts as a union of its members but
709 without modifieng its members in any way.
711 this is similar to a sequential update of all members, but retains
712 the container information for each item, and does not have the
713 overhead of creating a new resulting dict.
715 NOTE: because of the nature of dicts, the later added members (unite)
716 have higher priority than the former.
717 NOTE: the members added in one call (be it __init__, unite or tailunite)
718 have descending priority -- first highest last lowest.
719 NOTE: due to ints nature this object is *live*, e.g. it emidiatly
720 reflects all modifications to its members as they are modified.
724 def __init__(self
, *members
):
727 members
= list(members
)
729 self
._members
= tuple(members
)
730 # AbstractDictChainMixin specific extension interface...
731 def __iterchainmembers__(self
):
734 for m
in self
._members
:
736 # the DictUnion specific interface...
737 # XXX should these depend on __iterchainmembers__ or directly on
739 def unite(self
, *others
):
741 add members to the union object.
743 NOTE: this method will add members to the top of the pririty
745 NOTE: the elements are added in sequence, thus, the later elements
746 have higher priority.
748 others
= list(others
)
750 self
._members
= tuple(others
) + self
._members
751 def tailunite(self
, *others
):
753 this is the same as unite but adds low priority members (to the
754 botom of the priority stack).
756 NOTE: the elements are added in sequence, thus, the later elements
759 others
= list(others
)
760 self
._members
= self
._members
+ tuple(others
)
761 def memberindex(self
, obj
):
764 return list(self
._members
).index(obj
)
765 def removemember(self
, obj
):
768 if obj
in self
._members
:
769 self
._members
= tuple(list(self
._members
).remove(obj
))
771 raise TypeError, '%s does not contain %s as a member.' % (self
, obj
)
772 def clearmembers(self
):
775 ## del self._members[:]
781 def popmember(self
, index
=0):
784 NOTE: this by default will remove the highest priority member.
786 m
= list(self
._members
)
788 self
._members
= tuple(m
)
790 itermembers
= __iterchainmembers__
791 def getcontainerof(self
, name
):
794 for m
in self
._members
:
797 raise KeyError, '%s does not contain "%s"' % (self
, name
)
798 def getallcontainersof(self
, name
):
802 for m
in self
._members
:
806 raise KeyError, '%s does not contain "%s"' % (self
, name
)
810 #---------------------------------------------------WritableDictUnion---
812 # get the last occurance...
814 # get the first occurance...
817 # if key is not contained in union, add it to the last member...
818 WRITE_NEW_TO_LAST
= 0
819 # if key is not contained in union, add it to the first member...
820 WRITE_NEW_TO_FIRST
= 2
821 # if the key is present in the union more than once, override the last
823 WRITE_TO_LAST_OWNER
= 0
824 # if the key is present in the union more than once, override the first
826 WRITE_TO_FIRST_OWNER
= 4
827 # write to local (temporary) dict...
828 # NOTE: if this is set, other write opts will be ignored...
833 # delete the last occurance of key...
835 # delete the first occurance of key...
837 # enable local key delete...
839 # disable deletion of anything but local keys...
840 DELETE_LOCAL_ONLY
= 128
842 DELETE_DISABLED
= 256
844 class WritableDictUnion(DictUnion
):
847 __modify_props__
= GET_LOCAL_FIRST \
848 | WRITE_NEW_TO_FIRST \
849 | WRITE_TO_FIRST_OWNER \
853 def __init__(self
, *members
):
856 super(WritableDictUnion
, self
).__init
__(*members
)
858 def __getitem__(self
, name
):
861 props
= getattr(self
, '__modify_props__', 0)
862 if props
& GET_LOCAL_FIRST
:
863 if name
in self
._locals
:
864 return self
._locals
[name
]
866 return super(WritableDictUnion
, self
).__getitem
__(name
)
868 return super(WritableDictUnion
, self
).__getitem
__(name
)
870 if name
in self
._locals
:
871 return self
._locals
[name
]
873 def __setitem__(self
, name
, value
):
876 props
= getattr(self
, '__modify_props__', 0)
877 if props
& WRITE_DISABLED
:
878 raise TypeError, 'can\'t add values to a dict union object (writing is disabled).'
879 elif props
& WRITE_LOCAL
:
880 self
._locals
[name
] = value
883 if props
& WRITE_TO_FIRST_OWNER
:
884 self
.getallcontainersof(name
)[0][name
] = value
886 self
.getallcontainersof(name
)[-1][name
] = value
888 ##!!! problem if there are no memebers... raise an apropriate error...
889 if props
& WRITE_NEW_TO_FIRST
:
890 self
.members()[0][name
] = value
892 self
.members()[-1][name
] = value
893 def __contains__(self
, name
):
896 if name
in self
._locals
or super(WritableDictUnion
, self
).__contains
__(name
):
899 def __delitem__(self
, name
):
902 props
= getattr(self
, '__modify_props__', 0)
903 if props
& DELETE_DISABLED
:
904 raise TypeError, 'can\'t delete items (deletion is disabled).'
905 if props
& DELETE_LOCAL
and name
in self
._locals
:
906 del self
._locals
[name
]
907 elif not props
& DELETE_LOCAL_ONLY
:
908 if props
& DELETE_FIRST
:
909 del self
.getallcontainersof(name
)[0][name
]
911 del self
.getallcontainersof(name
)[-1][name
]
913 raise TypeError, 'can\'t delete from contained dicts.'
918 props
= getattr(self
, '__modify_props__', 0)
919 if props
& GET_LOCAL_FIRST
:
920 for k
in self
._locals
:
923 for k
in super(WritableDictUnion
, self
).__iter
__():
927 if not props
& GET_LOCAL_FIRST
:
928 for k
in self
._locals
:
934 #-------------------------------------------------------DictTypeUnion---
935 # WARNING: this is not done!
936 class DictTypeUnion(DictUnion
, dict):
938 this is a diriviation from dict that can contain oun data.
944 #---------------------------------------------------BasicMappingChain---
945 class BasicMappingChain(AbstractDictChainMixin
, mapping
.Mapping
):
948 NOTE: this class was designed as a basic base class (atleast the
949 __iterchainmembers__ method should be overloaded).
950 NOTE: do not forget to call the original __iterchainmembers__.
951 NOTE: this, if used as-is will not differ from a dict.
955 def __init__(self
, *p
, **n
):
959 super(BasicMappingChain
, self
).__init
__(*p
, **n
)
960 proxyutils
.proxymethods((
965 def __iterchainmembers__(self
):
968 yield self
._dict
_data
972 return list of local to the current node keys.
974 return self
._dict
_data
.keys()
977 #--------------------------------------------------------MappingChain---
978 class MappingChain(BasicMappingChain
):
980 this is a basic mapping chain element.
982 when a key can not be found in the local data then the request is
983 forwarded to the .chain_next attribute.
985 NOTE: .chain_next can be None, then no other forwarding is done.
986 NOTE: editing is possible only to the local data.
990 def __iterchainmembers__(self
):
993 for v
in super(MappingChain
, self
).__iterchainmembers
__():
995 if self
.chain_next
!= None:
996 yield self
.chain_next
999 #-----------------------------------------------MappingChainLiveMixin---
1000 class MappingChainLiveMixin(object):
1003 _chain_attr_name
= None
1004 _chain_next_obj
= None
1006 chain_next
= property(
1007 fget
=lambda self
: getattr(self
.__chain
_next
_obj
__, self
.__chain
_attr
_name
__),
1008 fset
=lambda self
, val
: (setattr(self
, '__chain_next_obj__', val
[0]),
1009 setattr(self
, '__chain_attr_name__', val
[1])))
1012 #-----------------------------------------------------------DictChain---
1013 class DictChain(MappingChain
, mapping
.DictLike
):
1015 same as MappingChain but more dict like.
1018 pli.logictypes.MappingChain
1019 pli.pattern.mixin.mapping.DictLike
1024 #-------------------------------------------------------LiveDictChain---
1025 class LiveDictChain(MappingChainLiveMixin
, DictChain
):
1031 #---------------------------------------------------------dictchainto---
1032 def dictchainto(dct
):
1034 create a dictchain over a mapping.
1036 helper/factory function.
1043 #-----------------------------------------------------livedictchainto---
1044 def livedictchainto(obj
, attr
):
1046 create a live dictchain over a mapping.
1048 helper/factory function.
1051 d
.chain_next
= (obj
, attr
)
1056 #-----------------------------------------------------------------------
1057 #---------------------------------------------------------ObjectUnion---
1059 # TODO split to various mix-ins...
1060 ##class BasicObjectUnion(object):
1061 class ObjectUnion(object):
1063 this represents the union of the attr of several objects.
1065 def __init__(self
, *members
):
1068 members
= list(members
)
1070 self
._members
= tuple(members
)
1072 def __getattr__(self
, name
):
1075 for o
in self
._members
:
1076 if hasattr(o
, name
):
1077 return getattr(o
, name
)
1078 ## # Q: which is faster, this or the "if hasattr..."???
1080 ## return getattr(o, name)
1081 ## except AttributeError:
1083 raise AttributeError, name
1084 ## def __setattr__(self, name, value):
1087 ## raise TypeError, 'ca\'t write attributes of a ObjectUnion object.'
1088 ## def __delattr__(self, name, value):
1092 def __hasattr__(self
, name
):
1095 for o
in self
._members
:
1096 if hasattr(o
, name
):
1099 # interface methods...
1103 #=======================================================================
1104 if __name__
== '__main__':
1106 d1
= {'c':'!!!!!', 'b':'x'}
1108 D
= WritableDictUnion(d0
, d1
)
1119 print isodd(3), isodd(6)
1121 print isident('b0_c'), isident('aaa'), isident(''), isident('321_4')
1123 # check the dict chain...
1124 d
= DictChain(a
=1, b
=2, c
=3)
1126 d
.chain_next
= DictChain(c
=4, d
=5, e
=6)
1128 d
.chain_next
.chain_next
= dict(e
=7, f
=8, g
=9)
1133 xxx
= dict(a
=1, b
=2)
1137 ld
= livedictchainto(x
, 'xxx')
1157 print AND((1, ANY
), (ANY
, 2))
1158 print AND((1, ANY
), (ANY
, 2)) == (1, 2)
1159 print AND((1, ANY
), (ANY
, 2)) != (ANY
, 9)
1160 print OR((1, ANY
), (ANY
, 2)) == (1, 8)
1161 print OR((1, ANY
), (ANY
, 2)) != (7, 8)
1163 print AT(1, 10) == range(100)
1164 print AT(10, 10) == range(100)
1167 e
= C((1, 2, 3, 'a', 'b', 'c', CONTENT(C((1.1, 2.2, 3.3)))))
1176 ##!!! there should be a way to access content items...
1179 print e
== (1, 2, 3, 'a', 'c', 1.1, 2.2, 3.3, 'b')
1180 print ORDERED(e
) == (1, 2, 3, 'a', 'c', 1.1, 2.2, 3.3, 'b')
1181 print ORDERED(e
) == (1, 2, 3, 'a', 'b', 'c', 1.1, 2.2, 3.3)
1182 print ORDERED(CONTENT(e
)) == (1, 2, 3, 'a', 'b', 'c', 1.1, 2.2, 3.3)
1195 print i
.next
.next
.value
1196 print i
.next
.next
.next
.value
1197 print i
.next
.next
.next
.assign(2)
1198 print i
.next
.next
.next
.value
1199 # this will assign a value that does not match the pattern of
1200 # either the item or the view. thus, it will not appear in either
1202 # ...assigning to an item an that item still not having a value may
1203 # be counter intuitive.
1204 # another similar case would be assigning a value that we already
1205 # passed (this depends on the scheme of the positioning algorithm
1207 ##!!! this makes the item inconsistent...
1208 ##!!! ...asigning t a value incompatible to the pattern will make the
1209 ##!!! item object inconsistent -- heed to handle this in some obvious way
1210 ## print i.next.next.next.assign('aaa')
1211 ## print i.next.next.next
1217 print i
.next
.next
.value
1218 print i
.next
.next
.next
.value
1219 print i
.next
.next
.next
.prev
.value
1220 print i
.next
.next
.next
.prev
.prev
.value
1221 print i
.next
.next
.next
.prev
.prev
.prev
.value
1223 ##!!! this should be True both ways...
1224 print CONTENT((2, 3, 4)) == range(10)
1225 print range(10) == CONTENT((2, 3, 4))
1229 #=======================================================================
1230 # vim:set ts=4 sw=4 nowrap :