blob: d81c46f2b1672cb927da7f62429cf2769e33ae55 [file] [log] [blame]
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001import W
2import Wkeys
3import struct
4import string
5import types
Jack Jansen9ad27522001-02-21 13:54:31 +00006import re
Just van Rossum4e6d13c2002-03-26 12:06:11 +00007from Carbon import Qd, Icn, Fm, QuickDraw
Just van Rossum4e6d13c2002-03-26 12:06:11 +00008from Carbon.QuickDraw import hilitetransfermode
9
Just van Rossum40f9b7b1999-01-30 22:39:17 +000010
11nullid = '\0\0'
12closedid = struct.pack('h', 468)
13openid = struct.pack('h', 469)
14closedsolidid = struct.pack('h', 470)
15opensolidid = struct.pack('h', 471)
16
17arrows = (nullid, closedid, openid, closedsolidid, opensolidid)
18
Just van Rossum3eec7622001-07-10 19:25:40 +000019has_ctlcharsRE = re.compile(r'[\000-\037\177-\377]')
Jack Jansen9ad27522001-02-21 13:54:31 +000020def ctlcharsREsearch(str):
Jack Jansendbd0c3a2001-03-01 23:15:54 +000021 if has_ctlcharsRE.search(str) is None:
Jack Jansen9ad27522001-02-21 13:54:31 +000022 return -1
23 return 1
24
Just van Rossum40f9b7b1999-01-30 22:39:17 +000025def double_repr(key, value, truncvalue = 0,
26 type = type, StringType = types.StringType,
Jack Jansen9ad27522001-02-21 13:54:31 +000027 has_ctlchars = ctlcharsREsearch, _repr = repr, str = str):
Just van Rossum40f9b7b1999-01-30 22:39:17 +000028 if type(key) == StringType and has_ctlchars(key) < 0:
29 key = str(key)
30 else:
31 key = _repr(key)
Just van Rossum460ff201999-10-30 11:43:25 +000032 if key == '__builtins__':
Just van Rossum40f9b7b1999-01-30 22:39:17 +000033 value = "<" + type(value).__name__ + " '__builtin__'>"
34 elif key == '__return__':
35 # bleh, when returning from a class codeblock we get infinite recursion in repr.
36 # Use safe repr instead.
37 import repr
38 value = repr.repr(value)
39 else:
40 try:
41 value = _repr(value)
42 '' + value # test to see if it is a string, in case a __repr__ method is buggy
43 except:
Just van Rossumdc3c6172001-06-19 21:37:33 +000044 value = '\xa5\xa5\xa5 exception in repr()'
Just van Rossum40f9b7b1999-01-30 22:39:17 +000045 if truncvalue:
46 return key + '\t' + value[:255]
47 return key + '\t' + value
48
49
Just van Rossum4e6d13c2002-03-26 12:06:11 +000050def truncString(s, maxwid):
51 if maxwid < 1:
52 return 1, ""
53 strlen = len(s)
54 strwid = Qd.TextWidth(s, 0, strlen);
55 if strwid <= maxwid:
56 return 0, s
Just van Rossum40f9b7b1999-01-30 22:39:17 +000057
Just van Rossum4e6d13c2002-03-26 12:06:11 +000058 Qd.TextFace(QuickDraw.condense)
59 strwid = Qd.TextWidth(s, 0, strlen)
60 ellipsis = Qd.StringWidth('\xc9')
61
62 if strwid <= maxwid:
63 Qd.TextFace(0)
64 return 1, s
65 if strwid < 1:
66 Qd.TextFace(0)
67 return 1, ""
68
69 mid = int(strlen * maxwid / strwid)
70 while 1:
71 if mid <= 0:
72 mid = 0
73 break
74 strwid = Qd.TextWidth(s, 0, mid) + ellipsis
75 strwid2 = Qd.TextWidth(s, 0, mid + 1) + ellipsis
76 if strwid <= maxwid and maxwid <= strwid2:
77 if maxwid == strwid2:
78 mid += 1
79 break
80 if strwid > maxwid:
81 mid -= 1
82 if mid <= 0:
83 mid = 0
84 break
85 elif strwid2 < maxwid:
86 mid += 1
87 Qd.TextFace(0)
88 return 1, s[:mid] + '\xc9'
89
90
91def drawTextCell(text, cellRect, ascent, theList):
92 l, t, r, b = cellRect
93 cellwidth = r - l
94 Qd.MoveTo(l + 2, t + ascent)
95 condense, text = truncString(text, cellwidth - 3)
96 if condense:
97 Qd.TextFace(QuickDraw.condense)
98 Qd.DrawText(text, 0, len(text))
99 Qd.TextFace(0)
100
101
102PICTWIDTH = 16
103
104
105class BrowserWidget(W.CustomList):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000106
107 def __init__(self, possize, object = None, col = 100, closechildren = 0):
108 W.List.__init__(self, possize, callback = self.listhit)
109 self.object = (None,)
110 self.indent = 16
111 self.lastmaxindent = 0
112 self.closechildren = closechildren
113 self.children = []
114 self.mincol = 64
115 self.setcolumn(col)
116 self.bind('return', self.openselection)
117 self.bind('enter', self.openselection)
118 if object is not None:
119 self.set(object)
120
121 def set(self, object):
122 if self.object[0] is not object:
123 self.object = object,
124 self[:] = self.unpack(object, 0)
125 elif self._parentwindow is not None and self._parentwindow.wid:
126 self.update()
127
128 def unpack(self, object, indent):
129 return unpack_object(object, indent)
130
131 def update(self):
132 # for now...
133 W.SetCursor('watch')
134 self.setdrawingmode(0)
135 sel = self.getselectedobjects()
136 fold = self.getunfoldedobjects()
137 topcell = self.gettopcell()
138 self[:] = self.unpack(self.object[0], 0)
139 self.unfoldobjects(fold)
140 self.setselectedobjects(sel)
141 self.settopcell(topcell)
142 self.setdrawingmode(1)
143
144 def setcolumn(self, col):
145 self.col = col
146 self.colstr = struct.pack('h', col)
147 if self._list:
148 sel = self.getselection()
149 self.setitems(self.items)
150 self.setselection(sel)
151
152 def key(self, char, event):
153 if char in (Wkeys.leftarrowkey, Wkeys.rightarrowkey):
154 sel = self.getselection()
155 sel.reverse()
156 self.setdrawingmode(0)
157 for index in sel:
158 self.fold(index, char == Wkeys.rightarrowkey)
159 self.setdrawingmode(1)
160 else:
161 W.List.key(self, char, event)
162
163 def rollover(self, (x, y), onoff):
164 if onoff:
165 if self.incolumn((x, y)):
166 W.SetCursor('hmover')
167 else:
168 W.SetCursor('arrow')
169
170 def inarrow(self, (x, y)):
171 cl, ct, cr, cb = self._list.LRect((0, 0))
172 l, t, r, b = self._bounds
173 if (x - cl) < 16:
174 cellheight = cb - ct
175 index = (y - ct) / cellheight
176 if index < len(self.items):
177 return 1, index
178 return None, None
179
180 def incolumn(self, (x, y)):
181 l, t, r, b = self._list.LRect((0, 0))
182 abscol = l + self.col
183 return abs(abscol - x) < 3
184
185 def trackcolumn(self, (x, y)):
Jack Jansen5a6fdcd2001-08-25 12:15:04 +0000186 from Carbon import Qd, QuickDraw, Evt
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000187 self.SetPort()
188 l, t, r, b = self._bounds
189 bounds = l, t, r, b = l + 1, t + 1, r - 16, b - 1
190 abscol = l + self.col
191 mincol = l + self.mincol
192 maxcol = r - 10
193 diff = abscol - x
194 Qd.PenPat('\000\377\000\377\000\377\000\377')
195 Qd.PenMode(QuickDraw.srcXor)
196 rect = abscol - 1, t, abscol, b
197 Qd.PaintRect(rect)
198 lastpoint = (x, y)
199 newcol = -1
200 #W.SetCursor('fist')
201 while Evt.Button():
Just van Rossumf376ef02001-11-18 14:12:43 +0000202 Evt.WaitNextEvent(0, 1, None) # needed for OSX
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000203 (x, y) = Evt.GetMouse()
204 if (x, y) <> lastpoint:
205 newcol = x + diff
206 newcol = max(newcol, mincol)
207 newcol = min(newcol, maxcol)
208 Qd.PaintRect(rect)
209 rect = newcol - 1, t, newcol, b
210 Qd.PaintRect(rect)
211 lastpoint = (x, y)
212 Qd.PaintRect(rect)
Jack Jansen362c7cd02002-11-30 00:01:29 +0000213 Qd.PenPat(Qd.GetQDGlobalsBlack())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000214 Qd.PenNormal()
215 if newcol > 0 and newcol <> abscol:
216 self.setcolumn(newcol - l)
217
218 def click(self, point, modifiers):
219 if point == (-1, -1): # gross.
220 W.List.click(self, point ,modifiers)
221 return
222 hit, index = self.inarrow(point)
223 if hit:
224 (key, value, arrow, indent) = self.items[index]
225 self.fold(index, arrow == 1)
226 elif self.incolumn(point):
227 self.trackcolumn(point)
228 else:
229 W.List.click(self, point, modifiers)
230
231 # for W.List.key
232 def findmatch(self, tag):
233 lower = string.lower
234 items = self.items
235 taglen = len(tag)
236 match = '\377' * 100
237 match_i = -1
238 for i in range(len(items)):
239 item = lower(str(items[i][0]))
240 if tag <= item < match:
241 match = item
242 match_i = i
243 if match_i >= 0:
244 return match_i
245 else:
246 return len(items) - 1
247
248 def close(self):
249 if self.closechildren:
250 for window in self.children:
251 window.close()
252 self.children = []
253 W.List.close(self)
254
255 def fold(self, index, onoff):
256 (key, value, arrow, indent) = self.items[index]
257 if arrow == 0 or (onoff and arrow == 2) or (not onoff and arrow == 1):
258 return
259 W.SetCursor('watch')
260 topcell = self.gettopcell()
261 if onoff:
262 self[index] = (key, value, 4, indent)
263 self.setdrawingmode(0)
264 self[index+1:index+1] = self.unpack(value, indent + 1)
265 self[index] = (key, value, 2, indent)
266 else:
267 self[index] = (key, value, 3, indent)
268 self.setdrawingmode(0)
269 count = 0
270 for i in range(index + 1, len(self.items)):
271 (dummy, dummy, dummy, subindent) = self.items[i]
272 if subindent <= indent:
273 break
274 count = count + 1
275 self[index+1:index+1+count] = []
276 self[index] = (key, value, 1, indent)
277 maxindent = self.getmaxindent()
278 if maxindent <> self.lastmaxindent:
279 newabsindent = self.col + (maxindent - self.lastmaxindent) * self.indent
280 if newabsindent >= self.mincol:
281 self.setcolumn(newabsindent)
282 self.lastmaxindent = maxindent
283 self.settopcell(topcell)
284 self.setdrawingmode(1)
285
286 def unfoldobjects(self, objects):
287 for obj in objects:
288 try:
289 index = self.items.index(obj)
290 except ValueError:
291 pass
292 else:
293 self.fold(index, 1)
294
295 def getunfoldedobjects(self):
296 curindent = 0
297 objects = []
298 for index in range(len(self.items)):
299 (key, value, arrow, indent) = self.items[index]
300 if indent > curindent:
301 (k, v, a, i) = self.items[index - 1]
302 objects.append((k, v, 1, i))
303 curindent = indent
304 elif indent < curindent:
305 curindent = indent
306 return objects
307
308 def listhit(self, isdbl):
309 if isdbl:
310 self.openselection()
311
312 def openselection(self):
313 import os
314 sel = self.getselection()
315 for index in sel:
316 (key, value, arrow, indent) = self[index]
317 if arrow:
318 self.children.append(Browser(value))
319 elif type(value) == types.StringType and '\0' not in value:
320 editor = self._parentwindow.parent.getscript(value)
321 if editor:
322 editor.select()
323 return
324 elif os.path.exists(value) and os.path.isfile(value):
325 import macfs
326 fss = macfs.FSSpec(value)
327 if fss.GetCreatorType()[1] == 'TEXT':
328 W.getapplication().openscript(value)
329
330 def itemrepr(self, (key, value, arrow, indent), str = str, double_repr = double_repr,
331 arrows = arrows, pack = struct.pack):
332 arrow = arrows[arrow]
333 return arrow + pack('h', self.indent * indent) + self.colstr + \
334 double_repr(key, value, 1)
335
336 def getmaxindent(self, max = max):
337 maxindent = 0
338 for item in self.items:
339 maxindent = max(maxindent, item[3])
340 return maxindent
341
342 def domenu_copy(self, *args):
343 sel = self.getselectedobjects()
344 selitems = []
345 for key, value, dummy, dummy in sel:
346 selitems.append(double_repr(key, value))
347 text = string.join(selitems, '\r')
348 if text:
Just van Rossum01c98052001-11-02 19:21:34 +0000349 from Carbon import Scrap
Jack Jansen65293682001-12-31 15:08:04 +0000350 if hasattr(Scrap, 'PutScrap'):
351 Scrap.ZeroScrap()
352 Scrap.PutScrap('TEXT', text)
353 else:
354 Scrap.ClearCurrentScrap()
355 sc = Scrap.GetCurrentScrap()
356 sc.PutScrapFlavor('TEXT', 0, text)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000357
Just van Rossum4e6d13c2002-03-26 12:06:11 +0000358 def listDefDraw(self, selected, cellRect, theCell,
359 dataOffset, dataLen, theList):
360 self.myDrawCell(0, selected, cellRect, theCell,
361 dataOffset, dataLen, theList)
362
363 def listDefHighlight(self, selected, cellRect, theCell,
364 dataOffset, dataLen, theList):
365 self.myDrawCell(1, selected, cellRect, theCell,
366 dataOffset, dataLen, theList)
367
368 def myDrawCell(self, onlyHilite, selected, cellRect, theCell,
369 dataOffset, dataLen, theList):
370 savedPort = Qd.GetPort()
Jack Jansen362c7cd02002-11-30 00:01:29 +0000371 Qd.SetPort(theList.GetListPort())
Just van Rossum4e6d13c2002-03-26 12:06:11 +0000372 savedClip = Qd.NewRgn()
373 Qd.GetClip(savedClip)
374 Qd.ClipRect(cellRect)
375 savedPenState = Qd.GetPenState()
376 Qd.PenNormal()
377
378 l, t, r, b = cellRect
379
380 if not onlyHilite:
381 Qd.EraseRect(cellRect)
382
383 ascent, descent, leading, size, hm = Fm.FontMetrics()
384 linefeed = ascent + descent + leading
385
386 if dataLen >= 6:
387 data = theList.LGetCell(dataLen, theCell)
388 iconId, indent, tab = struct.unpack("hhh", data[:6])
Just van Rossum3c4dee42002-09-16 21:18:49 +0000389 try:
390 key, value = data[6:].split("\t", 1)
391 except ValueError:
392 # bogus data, at least don't crash.
393 indent = 0
394 tab = 0
395 iconId = 0
396 key = ""
397 value = data[6:]
Just van Rossum4e6d13c2002-03-26 12:06:11 +0000398
399 if iconId:
Just van Rossum3c4dee42002-09-16 21:18:49 +0000400 try:
401 theIcon = Icn.GetCIcon(iconId)
402 except Icn.Error:
403 pass
404 else:
405 rect = (0, 0, 16, 16)
406 rect = Qd.OffsetRect(rect, l, t)
407 rect = Qd.OffsetRect(rect, 0, (theList.cellSize[1] - (rect[3] - rect[1])) / 2)
408 Icn.PlotCIcon(rect, theIcon)
Just van Rossum4e6d13c2002-03-26 12:06:11 +0000409
410 if len(key) >= 0:
411 cl, ct, cr, cb = cellRect
412 vl, vt, vr, vb = self._viewbounds
413 cl = vl + PICTWIDTH + indent
414 cr = vl + tab
415 if cr > vr:
416 cr = vr
417 if cl < cr:
418 drawTextCell(key, (cl, ct, cr, cb), ascent, theList)
419 cl = vl + tab
420 cr = vr
421 if cl < cr:
422 drawTextCell(value, (cl, ct, cr, cb), ascent, theList)
423 #elif dataLen != 0:
424 # drawTextCell("???", 3, cellRect, ascent, theList)
Just van Rossum3c4dee42002-09-16 21:18:49 +0000425 else:
426 return # we have bogus data
Just van Rossum4e6d13c2002-03-26 12:06:11 +0000427
428 # draw nice dotted line
429 l, t, r, b = cellRect
430 l = self._viewbounds[0] + tab
431 r = l + 1;
432 if not (theList.cellSize[1] & 0x01) or (t & 0x01):
433 myPat = "\xff\x00\xff\x00\xff\x00\xff\x00"
434 else:
435 myPat = "\x00\xff\x00\xff\x00\xff\x00\xff"
436 Qd.PenPat(myPat)
437 Qd.PenMode(QuickDraw.srcCopy)
438 Qd.PaintRect((l, t, r, b))
439 Qd.PenNormal()
440
441 if selected or onlyHilite:
442 l, t, r, b = cellRect
443 l = self._viewbounds[0] + PICTWIDTH
444 r = self._viewbounds[2]
445 Qd.PenMode(hilitetransfermode)
446 Qd.PaintRect((l, t, r, b))
447
448 # restore graphics environment
449 Qd.SetPort(savedPort)
450 Qd.SetClip(savedClip)
451 Qd.DisposeRgn(savedClip)
452 Qd.SetPenState(savedPenState)
453
454
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000455
456class Browser:
457
458 def __init__(self, object = None, title = None, closechildren = 0):
459 if hasattr(object, '__name__'):
460 name = object.__name__
461 else:
462 name = ''
463 if title is None:
464 title = 'Object browser'
465 if name:
466 title = title + ': ' + name
467 self.w = w = W.Window((300, 400), title, minsize = (100, 100))
468 w.info = W.TextBox((18, 8, -70, 15))
Just van Rossumf376ef02001-11-18 14:12:43 +0000469 w.updatebutton = W.BevelButton((-64, 4, 50, 16), 'Update', self.update)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000470 w.browser = BrowserWidget((-1, 24, 1, -14), None)
471 w.bind('cmdu', w.updatebutton.push)
472 w.open()
473 self.set(object, name)
474
475 def close(self):
476 if self.w.wid:
477 self.w.close()
478
479 def set(self, object, name = ''):
480 W.SetCursor('watch')
481 tp = type(object).__name__
482 try:
483 length = len(object)
484 except:
485 length = -1
486 if not name and hasattr(object, '__name__'):
487 name = object.__name__
488 if name:
489 info = name + ': ' + tp
490 else:
491 info = tp
492 if length >= 0:
493 if length == 1:
494 info = info + ' (%d element)' % length
495 else:
496 info = info + ' (%d elements)' % length
497 self.w.info.set(info)
498 self.w.browser.set(object)
499
500 def update(self):
501 self.w.browser.update()
502
503
504SIMPLE_TYPES = (
Just van Rossum927bc452002-12-01 22:10:36 +0000505 type(None),
506 int,
507 long,
508 float,
509 complex,
510 str,
511 unicode,
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000512)
513
Just van Rossum927bc452002-12-01 22:10:36 +0000514def get_ivars(obj):
515 """Return a list the names of all (potential) instance variables."""
516 # __mro__ recipe from Guido
517 slots = {}
518 # old-style C objects
519 if hasattr(obj, "__members__"):
520 for name in obj.__members__:
521 slots[name] = None
522 if hasattr(obj, "__methods__"):
523 for name in obj.__methods__:
524 slots[name] = None
525 # generic type
526 if hasattr(obj, "__dict__"):
527 slots.update(obj.__dict__)
528 cls = type(obj)
529 if hasattr(cls, "__mro__"):
530 # new-style class, use descriptors
531 for base in cls.__mro__:
532 for name, value in base.__dict__.items():
533 # XXX using callable() is a heuristic which isn't 100%
534 # foolproof.
535 if hasattr(value, "__get__") and not callable(value):
536 slots[name] = None
537 if "__dict__" in slots:
538 del slots["__dict__"]
539 slots = slots.keys()
540 slots.sort()
541 return slots
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000542
543def unpack_object(object, indent = 0):
544 tp = type(object)
Just van Rossum927bc452002-12-01 22:10:36 +0000545 if isinstance(object, SIMPLE_TYPES) and object is not None:
Just van Rossumdc3c6172001-06-19 21:37:33 +0000546 raise TypeError, "can't browse simple type: %s" % tp.__name__
Just van Rossum927bc452002-12-01 22:10:36 +0000547 elif isinstance(object, dict):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000548 return unpack_dict(object, indent)
Just van Rossum927bc452002-12-01 22:10:36 +0000549 elif isinstance(object, (tuple, list)):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000550 return unpack_sequence(object, indent)
Just van Rossum927bc452002-12-01 22:10:36 +0000551 elif isinstance(object, types.ModuleType):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000552 return unpack_dict(object.__dict__, indent)
553 else:
554 return unpack_other(object, indent)
555
556def unpack_sequence(seq, indent = 0):
Just van Rossum71fd01c2002-12-13 11:07:20 +0000557 return [(i, v, not isinstance(v, SIMPLE_TYPES), indent)
558 for i, v in enumerate(seq)]
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000559
560def unpack_dict(dict, indent = 0):
561 items = dict.items()
562 return pack_items(items, indent)
563
564def unpack_instance(inst, indent = 0):
565 if hasattr(inst, '__pybrowse_unpack__'):
566 return unpack_object(inst.__pybrowse_unpack__(), indent)
567 else:
568 items = [('__class__', inst.__class__)] + inst.__dict__.items()
569 return pack_items(items, indent)
570
571def unpack_class(clss, indent = 0):
572 items = [('__bases__', clss.__bases__), ('__name__', clss.__name__)] + clss.__dict__.items()
573 return pack_items(items, indent)
574
575def unpack_other(object, indent = 0):
Just van Rossum927bc452002-12-01 22:10:36 +0000576 attrs = get_ivars(object)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000577 items = []
578 for attr in attrs:
Just van Rossum927bc452002-12-01 22:10:36 +0000579 try:
580 value = getattr(object, attr)
581 except:
582 pass
583 else:
584 items.append((attr, value))
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000585 return pack_items(items, indent)
586
587def pack_items(items, indent = 0):
Just van Rossumfeddf772002-12-13 15:14:22 +0000588 items = [(k, v, not isinstance(v, SIMPLE_TYPES), indent)
589 for k, v in items]
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000590 return tuple_caselesssort(items)
591
592def caselesssort(alist):
593 """Return a sorted copy of a list. If there are only strings in the list,
594 it will not consider case"""
595
596 try:
597 # turn ['FOO', 'aaBc', 'ABcD'] into [('foo', 'FOO'), ('aabc', 'aaBc'), ('abcd', 'ABcD')], if possible
598 tupledlist = map(lambda item, lower = string.lower: (lower(item), item), alist)
599 except TypeError:
600 # at least one element in alist is not a string, proceed the normal way...
601 alist = alist[:]
602 alist.sort()
603 return alist
604 else:
605 tupledlist.sort()
606 # turn [('aabc', 'aaBc'), ('abcd', 'ABcD'), ('foo', 'FOO')] into ['aaBc', 'ABcD', 'FOO']
607 return map(lambda x: x[1], tupledlist)
608
609def tuple_caselesssort(items):
610 try:
611 tupledlist = map(lambda tuple, lower = string.lower: (lower(tuple[0]), tuple), items)
Just van Rossum6508c7c2000-10-20 06:34:57 +0000612 except (AttributeError, TypeError):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000613 items = items[:]
614 items.sort()
615 return items
616 else:
617 tupledlist.sort()
618 return map(lambda (low, tuple): tuple, tupledlist)
619