001:
002:
003:
004:
005:
006:
007:
008:
009: reloadables=[]
010:
011:
012:
013: import heapq
014:
015:
016:
017: class Entry(object):
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029: def canonical(x):
030: try:
031: return x.lower()
032: except AttributeError:
033: return x
034:
035: def canonical(x):
036: if hasattr(x,"lower"):
037: return x.lower()
038: else:
039: return x
040:
041: class ValueEntry(object):
042:
043:
044:
045:
046: def canonical_tuple(self):
047: return tuple([canonical(x) for x in self.entry_tuple()])
048:
049: def __str__(self):
050: return ":".join([str(x) for x in self.entry_tuple()])
051:
052: def __repr__(self):
053: return repr(self.entry_tuple())
054:
055: def __cmp__(self,other):
056: try:
057: return cmp(self.canonical_tuple(),other.canonical_tuple())
058: except AttributeError:
059: return -cmp(other,self.canonical_tuple())
060:
061: def __hash__(self):
062: return reduce(lambda x,y: x^hash(y),self.canonical_tuple(),0)
063:
064:
065:
066: def canonical_expansion(x):
067: try:
068: t=x.canonical_tuple()
069: except AttributeError:
070: return x
071: else:
072: return tuple([canonical_expansion(e) for e in t])
073:
074: def canonical_expansion(x):
075: if isinstance(x,tuple):
076: return tuple([canonical_expansion(t) for t in x])
077: else:
078: try:
079: t=x.canonical_tuple()
080: except AttributeError:
081: return x
082: else:
083: return canonical_expansion(t)
084:
085: class ValueListable(object):
086:
087:
088: def sort(container):
089: temp=[(canonical_expansion(x),x) for x in container]
090: temp.sort()
091: container[:]=[x for (t,x) in temp]
092:
093:
094:
095: class Enum(object):
096:
097:
098: def __init__(self,*sequence,**options):
099: self.sequence=sequence
100: self.casesensitive=options.pop("casesensitive",False)
101: self.refilter=options.pop("refilter",None)
102: self.strict=options.pop("strict",False)
103: assert not options
104: self.dictlowered=self.dictenum={}
105:
106: def create_dict(self):
107: for (i,e) in enumerate(self.sequence):
108: self.dictenum[e]=i
109: if not self.casesensitive:
110: for (i,e) in enumerate(self.sequence):
111: self.dictenum[e.lower()]=i
112:
113: class Enumeration(tuple):
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128: def __new__(Self,s,strict=False):
129: assert isinstance(Self.enum,Enum)
130: i=None
131: if isinstance(s,str) and Self.enum.refilter:
132: for (i,f) in Self.enum.refilter:
133: if f.match(s):
134: break
135: else:
136: i=None
137: elif isinstance(s,str) and Self.enum.dictlowered:
138: l=s.lower()
139: if l in Self.enum.dictlowered:
140: i=Self.enum.dictlowered[l]
141: elif Self.enum.dictenum:
142: if s in Self.enum.dictenum:
143: i=Self.enum.dictenum[s]
144: else:
145: try:
146: i=Self.enum.sequence.index(s)
147: except ValueError:
148: pass
149: if i<>None:
150: try:
151: Self.enumcache
152: except AttributeError:
153: Self.enumcache=[None]*len(Self.enum.sequence)
154: if not Self.enumcache[i]:
155: Self.enumcache[i]=tuple.__new__(Self,(Self.enum,0,i))
156: return Self.enumcache[i]
157: else:
158: if strict or Self.enum.strict:
159: raise ValueError
160: return tuple.__new__(Self,(Self.enum,1,s))
161:
162: def __str__(self):
163:
164: if self[1]:
165: return str(self[2])
166: else:
167: return str(self[0].sequence[self[2]])
168:
169: def __repr__(self):
170:
171: if self[1]:
172: return repr(self[2])
173: else:
174: return repr(self[0].sequence[self[2]])
175:
176: def __getattr__(self,attr):
177:
178: if self[1]:
179: return getattr(self[2],attr)
180: else:
181: return getattr(self[0].sequence[self[2]],attr)
182:
183: def canonical_tuple(self):
184: return self[1:]
185:
186:
187:
188:
189:
190: class JointAfterEntry(tuple):
191: def __getattr__(self,attr): return getattr(self[0],attr)
192: def __setattr__(self,attr,val): setattr(self[0],attr,val)
193:
194:
195:
196:
197: class JointBeforeEntry(tuple):
198: def __getattr__(self,attr): return getattr(self[-1],attr)
199: def __setattr__(self,attr,val): setattr(self[-1],attr,val)
200:
201:
202:
203: def stable_filter(data):
204:
205: for entry in enumerate(data):
206: yield JointBeforeEntry(entry)
207:
208: def semistable_filter(data):
209:
210: for (i,d) in enumerate(data):
211: yield JointAfterEntry((d,i))
212:
213: def process_column(c):
214:
215:
216:
217:
218:
219:
220:
221:
222:
223: def alt(attr): raise AttributeError
224: def filt(entry,attr): return attr
225: if isinstance(c,str):
226: name=c
227: else:
228: assert isinstance(c,tuple) and 1<=len(c)<=3
229: name=c[0]
230: assert isinstance(name,str)
231: if len(c)>1:
232: if c[1] is None:
233: pass
234: elif callable(c[1]):
235: filt=c[1]
236: else:
237: t=c[1]
238: def filt(entry,attr):
239: if attr==t: return attr
240: else: raise AttributeError
241: if len(c)>2:
242: if c[2] is None:
243: pass
244: elif callable(c[2]):
245: alt=c[2]
246: else:
247: t=c[2]
248: def alt(entry): return t
249: return (name,filt,alt)
250:
251: def adjoin_after_filter(data,columns):
252:
253: assert isinstance(columns,list)
254: columns=[process_column(c) for c in columns]
255: for entry in data:
256: jointentry=[entry]
257: for c in columns:
258: try:
259: try:
260: attr=getattr(entry,c[0])
261: except AttributeError:
262: jointentry.append(c[2](entry))
263: else:
264: jointentry.append(c[1](entry,attr))
265: except AttributeError:
266: break
267: else:
268: yield JointAfterEntry(jointentry)
269:
270: def adjoin_before_filter(data,columns):
271:
272: assert isinstance(columns,list)
273: columns=[process_column(c) for c in columns]
274: for entry in data:
275: jointentry=[]
276: for c in columns:
277: try:
278: try:
279: attr=getattr(entry,c[0])
280: except AttributeError:
281: jointentry.append(c[2](entry))
282: else:
283: jointentry.append(c[1](entry,attr))
284: except AttributeError:
285: break
286: else:
287: jointentry.append(entry)
288: yield JointBeforeEntry(jointentry)
289: adjoin_filter=adjoin_before_filter
290:
291: def obverse_filter(data,columns):
292:
293: assert isinstance(columns,list)
294: columns=[process_column(c) for c in columns]
295: for entry in data:
296: for c in columns:
297: try:
298: try:
299: attr=getattr(entry,c[0])
300: except AttributeError:
301: c[2](entry)
302: else:
303: c[1](entry,attr)
304: except AttributeError:
305: break
306: else:
307: yield entry
308:
309: def converse_filter(data,columns):
310:
311: assert isinstance(columns,list)
312: columns=[process_column(c) for c in columns]
313: for entry in data:
314: for c in columns:
315: try:
316: try:
317: attr=getattr(entry,c[0])
318: except AttributeError:
319: c[2](entry)
320: else:
321: c[1](entry,attr)
322: except AttributeError:
323: break
324: else:
325: continue
326: yield entry
327:
328:
329:
330: def stable_list(data):
331: return JointList([je for je in stable_filter(data)])
332:
333: def semistable_list(data):
334: return JointList([je for je in semistable_filter(data)])
335:
336: def adjoin_after_list(data,columns):
337: return JointList([je for je in adjoin_after_filter(data,columns)])
338:
339: def adjoin_before_list(data,columns):
340: return JointList([je for je in adjoin_before_filter(data,columns)])
341:
342: adjoin_list=adjoin_before_list
343:
344: def obverse_list(data,columns):
345: return JointList([je for je in obverse_filter(data,columns)])
346:
347: def converse_list(data,columns):
348: return JointList([je for je in converse_filter(data,columns)])
349:
350:
351:
352: def adjoin_after_heap(data,columns):
353: joint=[
354: (canonical_expansion(x),x,i)
355: for (i,x) in enumerate(adjoin_before_filter(data,columns))
356: ]
357: heapq.heapify(joint)
358: while joint:
359: je=heapq.heappop(joint)[1]
360: yield je[-1:]+je[:-1]
361:
362: def adjoin_before_heap(data,columns):
363: joint=[
364: (canonical_expansion(x),x,i)
365: for (i,x) in enumerate(adjoin_before_filter(data,columns))
366: ]
367: heapq.heapify(joint)
368: while joint:
369: yield heapq.heappop(joint)[1]
370:
371: adjoin_heap=adjoin_before_heap
372:
373: def obverse_heap(data,columns):
374: joint=[
375: (canonical_expansion(x),x,i)
376: for (i,x) in enumerate(adjoin_before_filter(data,columns))
377: ]
378: heapq.heapify(joint)
379: while joint:
380: je=heapq.heappop(joint)[1]
381: yield je[-1]
382:
383: def converse_heap(data,columns):
384: joint=[
385: (canonical_expansion(x),x,i)
386: for (i,x) in enumerate(converse_filter(data,columns))
387: ]
388: heapq.heapify(joint)
389: while joint:
390: yield heapq.heappop(joint)[1]
391:
392:
393:
394: def unstable_sort(data):
395: joint=[(canonical_expansion(je),je) for je in data]
396: joint.sort()
397: return JointList([je for (ce,je) in joint])
398:
399: def semistable_sort(data):
400: joint=[
401: (canonical_expansion(je),je)
402: for je in semistable_filter(data)
403: ]
404: joint.sort()
405: return JointList([je for (ce,je) in joint])
406:
407: def adjoin_after_sort(data,columns):
408: joint=[
409: (canonical_expansion(je),je)
410: for je in adjoin_before_filter(data,columns)
411: ]
412: joint.sort()
413: return JointList([je[-1:]+je[:-1] for (ce,je) in joint])
414:
415: def adjoin_before_sort(data,columns):
416: joint=[
417: (canonical_expansion(je),je)
418: for je in adjoin_before_filter(data,columns)
419: ]
420: joint.sort()
421: return JointList([je for (ce,je) in joint])
422:
423: adjoin_sort=adjoin_before_sort
424:
425: def obverse_sort(data,columns):
426: joint=[
427: (canonical_expansion(je),je)
428: for je in adjoin_before_filter(data,columns)
429: ]
430: joint.sort()
431: return JointList([je[-1] for (ce,je) in joint])
432:
433: def converse_sort(data,columns):
434: joint=[
435: (canonical_expansion(je),je)
436: for je in converse_filter(data,columns)
437: ]
438: joint.sort()
439: return JointList([je for (ce,je) in joint])
440:
441:
442:
443: def adjoin_before_hierarchy(data,columns):
444: joint=[
445: (canonical_expansion(je),je)
446: for je in adjoin_before_filter(data,columns)
447: ]
448: joint.sort()
449: return hierarchy_filter(columns,[je for (ce,je) in joint])
450:
451:
452:
453:
454: adjoin_hierarchy=adjoin_before_hierarchy
455:
456:
457:
458: def adjoin_before_dictionary(data,columns):
459: def lexicographer(c,hieriter):
460: if c>0:
461: return dict([
462: (x,lexicographer(c-1,subhierarchy))
463: for (x,subhierarchy) in hieriter
464: ])
465: else:
466: return [e for e in hieriter]
467: return lexicographer(len(columns),adjoin_before_hierarchy(data,columns))
468:
469: adjoin_dictionary=adjoin_before_dictionary
470:
471:
472:
473: def adjoin_before_polyhierarchy(*columns_and_data):
474: (data,columns)=(columns_and_data[:-1],columns_and_data[-1])
475: polyjoint=[]
476: for d in data:
477: joint=[
478: (canonical_expansion(je),je)
479: for je in adjoin_before_filter(d,columns)
480: ]
481: joint.sort()
482: polyjoint+=[[je for (ce,je) in joint]]
483: return polyhierarchy_filter(columns,*polyjoint)
484:
485:
486:
487:
488:
489:
490:
491: adjoin_polyhierarchy=adjoin_before_polyhierarchy
492:
493:
494:
495: def adjoin_before_polydictionary(*columns_and_data):
496: (data,columns)=(columns_and_data[:-1],columns_and_data[-1])
497: def lexicographer(c,hieriter):
498: if c>0:
499: return dict([
500: (x,lexicographer(c-1,subhierarchy))
501: for (x,subhierarchy) in hieriter
502: ])
503: else:
504: return [
505: [e for e in componentiter] for componentiter in hieriter
506: ]
507: return lexicographer(
508: len(columns),adjoin_before_polyhierarchy(*columns_and_data)
509: )
510:
511: adjoin_polydictionary=adjoin_before_polydictionary
512:
513:
514:
515: def hierarchy_filter(columns,jointiter):
516:
517:
518:
519:
520:
521:
522:
523: jointiter=iter(jointiter)
524: class Cursor(object): pass
525: j=Cursor()
526: try: j.n=jointiter.next()
527: except StopIteration: pass
528: def jnext():
529: t=j.n
530: try: j.n=jointiter.next()
531: except StopIteration: del j.n
532: return t
533: def recursive_iterator(constraint):
534: try:
535: c=len(constraint)
536: if c<len(columns):
537: while j.n[:c]==constraint:
538: car=j.n[c]
539: newconstraint=constraint+(car,)
540: yield (car,recursive_iterator(newconstraint))
541:
542: while j.n[:c+1]==newconstraint:
543: jnext()
544: else:
545: while j.n[:c]==constraint:
546: yield jnext()[c]
547: except AttributeError: pass
548: return recursive_iterator(())
549:
550:
551:
552: def polyhierarchy_filter(columns,*jointiters):
553:
554:
555:
556:
557:
558:
559:
560: nc=len(columns)
561: niters=len(jointiters)
562: assert niters>0
563: jointiters=[iter(i) for i in jointiters]
564: class Cursor(object): pass
565: j=Cursor()
566: j.n={}
567: for (i,iteri) in enumerate(jointiters):
568: try: j.n[i]=iteri.next()
569: except StopIteration: pass
570: def jnext(i):
571: t=j.n[i]
572: try: j.n[i]=jointiters[i].next()
573: except StopIteration: del j.n[i]
574: return t
575: def jmin():
576: return min(j.n.values())
577: def recursive_iterator(constraint):
578: c=len(constraint)
579: if c<len(columns):
580: def recursive_polyiterator():
581: try:
582: n=jmin()
583: while n[:c]==constraint:
584: car=n[c]
585: newconstraint=constraint+(car,)
586: yield (car,recursive_iterator(newconstraint))
587:
588: for i in j.n.keys():
589: try:
590: while j.n[i][:c+1]==newconstraint:
591: jnext(i)
592: except KeyError: pass
593: n=jmin()
594: except ValueError: pass
595: return recursive_polyiterator()
596: else:
597: def component_iterator(i):
598: try:
599: while j.n[i][:c]==constraint:
600: yield jnext(i)[c]
601: except KeyError: pass
602:
603:
604: return [component_iterator(i) for i in range(niters)]
605: return recursive_iterator(())
606:
607:
608:
609: def outer_product(componentiters):
610: components=[list(i) for i in componentiters[:-1]]
611: for c in components:
612: if len(c)==0:
613: return
614: elif len(c)>1:
615: break
616: else:
617: leading=tuple([x for [x] in components])
618: for x in componentiters[-1]:
619: yield JointBeforeEntry(leading+(x,))
620: return
621:
622: components.append(list(componentiters[-1]))
623: def recursive_product(product,components):
624: if components:
625: car=components[0]
626: cdr=components[1:]
627: for x in car:
628: for y in recursive_product(product+(x,),cdr):
629: yield y
630: else:
631: yield JointBeforeEntry(product)
632: for y in recursive_product((),components):
633: yield y
634:
635:
636:
637: def cohierarchy_filter(columns,*jointiters):
638:
639:
640:
641:
642:
643:
644:
645:
646:
647:
648:
649: nc=len(columns)
650: niters=len(jointiters)
651: assert niters>0
652: jointiters=[iter(i) for i in jointiters]
653: class Cursor(object):
654: pass
655: j=Cursor()
656: j.nheap=[]
657: for (i,iteri) in enumerate(jointiters):
658: try:
659: nn=iteri.next()
660: j.nheap+=[(nn[:nc],i,nn[nc])]
661: except StopIteration:
662: pass
663: if not j.nheap:
664: return iter(())
665: heapq.heapify(j.nheap)
666: def jnext():
667:
668: (n,i,e)=heapq.heappop(j.nheap)
669: try:
670: nn=jointiters[i].next()
671: heapq.heappush(j.nheap,(nn[:nc],i,nn[nc]),)
672: except StopIteration:
673: pass
674: return (n,i,e)
675:
676:
677: def recursive_iterator(constraint):
678: c=len(constraint)
679: if c<len(columns):
680: def recursive_polyiterator():
681: try:
682: (n,i,e)=j.nheap[0]
683: while n[:c]==constraint:
684: car=n[c]
685: newconstraint=constraint+(car,)
686: yield (car,recursive_iterator(newconstraint))
687: (n,i,e)=j.nheap[0]
688:
689: while n[:c+1]==newconstraint:
690: jnext()
691: (n,i,e)=j.nheap[0]
692: except IndexError:
693: pass
694: return recursive_polyiterator()
695: else:
696: def co_iterator():
697: try:
698: (n,i,e)=j.nheap[0]
699: while n==constraint:
700: yield (i,e)
701: jnext()
702: (n,i,e)=j.nheap[0]
703: except IndexError:
704: pass
705: return co_iterator()
706: return recursive_iterator(())
707:
708:
709:
710: class Joint(object):
711:
712:
713: stable_filter=stable_filter
714: semistable_filter=semistable_filter
715:
716: adjoin_after_filter=adjoin_after_filter
717: adjoin_filter=adjoin_filter
718: obverse_filter=obverse_filter
719: converse_filter=converse_filter
720:
721: stable_list=stable_list
722: semistable_list=stable_list
723: adjoin_after_list=adjoin_after_list
724: adjoin_list=adjoin_list
725: obverse_list=obverse_list
726: converse_list=converse_list
727:
728: adjoin_after_heap=adjoin_after_heap
729: adjoin_heap=adjoin_heap
730: obverse_heap=obverse_heap
731: converse_heap=converse_heap
732:
733: unstable_sort=unstable_sort
734: semistable_sort=semistable_sort
735: adjoin_after_sort=adjoin_after_sort
736: adjoin_sort=adjoin_sort
737: obverse_sort=obverse_sort
738: converse_sort=converse_sort
739:
740: adjoin_hierarchy=adjoin_hierarchy
741: adjoin_dictionary=adjoin_dictionary
742: adjoin_polyhierarchy=adjoin_polyhierarchy
743: adjoin_polydictionary=adjoin_polydictionary
744:
745: class JointList(ValueListable,list,Joint):
746:
747:
748: class JointDict(dict):
749:
750:
751: def values(self):
752: return JointList(super(JointDict,self).values())
753:
754: def items(self):
755: return JointList(super(JointDict,self).items())
756:
757: