[Zope] dtml-in sort by generic function
Steve Spicklemire
steve@spvi.com
Tue, 27 Mar 2001 19:03:30 -0500 (EST)
>>>>> "DM" == Dieter Maurer <dieter@handshake.de> writes:
DM> To separate the direction is a good idea. I like it. I am not
DM> so sure about the '/' separators. I expect, we will soon get
DM> "/" separated object access paths. Then, the use of "/" for a
DM> completely different purpose may be confusing. Not sure, that
DM> my "[...]" is better in this respect...
Zieve does this with ':' sorta like name="foo:int"
Another trick from Zieve is the use of comparison classes:
__doc__='''
Comparison class for sorting object based on runtime attributes...
Steve Spicklemire
Silicon Prairie Ventures Inc.
steve@spvi.com
'''
__version__='$Revision: 1.1.1.1 $'[11:-2]
import string
import traceback
import sys
class compClass:
#
# The idea here is to provide generic sorting...
#
def __init__(self, sortAttrs = None, raiseExceptions = 0, theClass = None, emptyLast = 1 ):
""" set up sort attributes and type conversions...."""
self.sortAttrs = []
self.raiseExceptions = raiseExceptions
self.emptyLast = emptyLast
if sortAttrs:
for theAttr in sortAttrs:
unbound = 1
if string.find(theAttr,':') != -1:
theAttr, theType = string.split(theAttr,':')
if self.typeFuncs.has_key(theType):
theTypeFunc = self.typeFuncs[theType]
elif hasattr(self, theType) and callable(getattr(self, theType)):
theTypeFunc = getattr(self, theType)
elif theClass and hasattr(theClass, theType) and callable(getattr(theClass, theType)):
unbound = 0
theTypeFunc = getattr(theClass, theType)
else:
theTypeFunc = None
else:
theTypeFunc = None
self.sortAttrs.append((theAttr, theTypeFunc, unbound))
def toInt(self, thing):
result = 0
if type(thing) == type(''):
try:
result = string.atoi(thing)
except:
if self.raiseExceptions:
raise
else:
result = thing
return result
def toChar(self, thing):
result = ''
if type(thing) != type(''):
result = str(thing)
else:
result = thing
return result
def doComp(self, a, b):
if self.emptyLast: # force empty strings last...
if type(a) == type('') and type(b) == type(''):
if len(a) == 0 and len(b) != 0:
return 1
elif len(b) == 0 and len(a) != 0:
return -1
if a<b:
return -1
if a==b:
return 0
return 1
def __call__(self, thingA, thingB):
if not self.sortAttrs:
return self.doComp(thingA, thingB)
result = 0
for theAttr, theFunc, unbound in self.sortAttrs:
if hasattr(thingA, theAttr) and hasattr(thingB, theAttr):
a = getattr(thingA, theAttr)
b = getattr(thingB, theAttr)
if theFunc is not None:
if unbound:
[a,b] = map(lambda o,s=self,t=theFunc:apply(t,(s,o)),[a,b]) # map type conversion onto elements
else:
[a,b] = map(lambda o,s=self,t=theFunc:apply(t,(o,)),[a,b]) # map type conversion onto elements
result = self.doComp(a,b)
if result != 0:
break
return result
typeFuncs = { 'int': toInt, 'char': toChar } # type conversion map....
def test():
#
# test this sort thingy on some random class....
#
class foo:
a = 0
b = 0
first = ''
def __repr__(self):
return '( a->%s, b->%s, first->%s, )[%s]' % ( `self.a`, `self.b`, self.first, id(self))
x = foo()
y = foo()
z = foo()
x.a = '30'
x.b = 10
x.first = 'c'
y.a = '30'
y.b = 100
y.first = 'D'
z.a = '200'
z.b = 10
z.first = 'E'
ccab = compClass(['a:int','b:char'])
ccba = compClass(['b:int','a:char'])
ccup = compClass(['first:toUpper'])
ccabr = compClass(['a:int','b:char'], 1)
cc = compClass()
list1 = [x,y,z]
list2 = ['200','30','300']
list1.sort(ccab)
print list1
list1.sort(ccba)
print list1
list2.sort(cc)
print list2
list1.sort(ccup)
print list1
z.a = 'foo'
try:
list1.sort(ccabr)
except ValueError:
print "we got the expected exception"
gotit = 0
try:
list1.sort(ccab)
except:
gotit = 1
if gotit:
print "dang we got the exception we wanted to miss.."
else:
print "OK.. no exception seen..."
if __name__ == '__main__':
test()