##// END OF EJS Templates
Add Nik Tautenhahns igrid extension. (igrid is a wxPython-based...
walter.doerwald -
Show More

The requested changes are too big and content was truncated. Show full diff

This diff has been collapsed as it changes many lines, (764 lines changed) Show them Hide them
@@ -0,0 +1,764 b''
1 # -*- coding: iso-8859-1 -*-
2
3 import ipipe, os, webbrowser, urllib
4 import wx
5 import wx.grid, wx.html
6
7 try:
8 sorted
9 except NameError:
10 from ipipe import sorted
11
12
13 __all__ = ["igrid"]
14
15
16 class IGridRenderer(wx.grid.PyGridCellRenderer):
17 """
18 This is a custom renderer for our IGridGrid
19 """
20 def __init__(self, table):
21 self.maxchars = 200
22 self.table = table
23 self.colormap = (
24 ( 0, 0, 0),
25 (174, 0, 0),
26 ( 0, 174, 0),
27 (174, 174, 0),
28 ( 0, 0, 174),
29 (174, 0, 174),
30 ( 0, 174, 174),
31 ( 64, 64, 64)
32 )
33
34 wx.grid.PyGridCellRenderer.__init__(self)
35
36 def _getvalue(self, row, col):
37 try:
38 value = self.table.displayattrs[col].value(self.table.items[row])
39 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
40 except Exception, exc:
41 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
42 return (align, text)
43
44 def GetBestSize(self, grid, attr, dc, row, col):
45 text = grid.GetCellValue(row, col)
46 (align, text) = self._getvalue(row, col)
47 dc.SetFont(attr.GetFont())
48 (w, h) = dc.GetTextExtent(str(text))
49 return wx.Size(min(w+2, 600), h+2) # add border
50
51 def Draw(self, grid, attr, dc, rect, row, col, isSelected):
52 """
53 Takes care of drawing everything in the cell; aligns the text
54 """
55 text = grid.GetCellValue(row, col)
56 (align, text) = self._getvalue(row, col)
57 if isSelected:
58 bg = grid.GetSelectionBackground()
59 else:
60 bg = ["white", (240, 240, 240)][row%2]
61 dc.SetTextBackground(bg)
62 dc.SetBrush(wx.Brush(bg, wx.SOLID))
63 dc.SetPen(wx.TRANSPARENT_PEN)
64 dc.SetFont(attr.GetFont())
65 dc.DrawRectangleRect(rect)
66 dc.SetClippingRect(rect)
67 # Format the text
68 if align == -1: # left alignment
69 (width, height) = dc.GetTextExtent(str(text))
70 x = rect[0]+1
71 y = rect[1]+0.5*(rect[3]-height)
72
73 for (style, part) in text:
74 if isSelected:
75 fg = grid.GetSelectionForeground()
76 else:
77 fg = self.colormap[style.fg]
78 dc.SetTextForeground(fg)
79 (w, h) = dc.GetTextExtent(part)
80 dc.DrawText(part, x, y)
81 x += w
82 elif align == 0: # center alignment
83 (width, height) = dc.GetTextExtent(str(text))
84 x = rect[0]+0.5*(rect[2]-width)
85 y = rect[1]+0.5*(rect[3]-height)
86 for (style, part) in text:
87 if isSelected:
88 fg = grid.GetSelectionForeground()
89 else:
90 fg = self.colormap[style.fg]
91 dc.SetTextForeground(fg)
92 (w, h) = dc.GetTextExtent(part)
93 dc.DrawText(part, x, y)
94 x += w
95 else: # right alignment
96 (width, height) = dc.GetTextExtent(str(text))
97 x = rect[0]+rect[2]-1
98 y = rect[1]+0.5*(rect[3]-height)
99 for (style, part) in reversed(text):
100 (w, h) = dc.GetTextExtent(part)
101 x -= w
102 if isSelected:
103 fg = grid.GetSelectionForeground()
104 else:
105 fg = self.colormap[style.fg]
106 dc.SetTextForeground(fg)
107 dc.DrawText(part, x, y)
108 dc.DestroyClippingRegion()
109
110 def Clone(self):
111 return IGridRenderer(self.table)
112
113
114 class IGridTable(wx.grid.PyGridTableBase):
115 # The data table for the ``IGridGrid``. Some dirty tricks were used here:
116 # ``GetValue()`` does not get any values (or at least it does not return
117 # anything, accessing the values is done by the renderer)
118 # but rather tries to fetch the objects which were requested into the table.
119 # General behaviour is: Fetch the first X objects. If the user scrolls down
120 # to the last object another bunch of X objects is fetched (if possible)
121 def __init__(self, input, fontsize, *attrs):
122 wx.grid.PyGridTableBase.__init__(self)
123 self.input = input
124 self.iterator = ipipe.xiter(input)
125 self.items = []
126 self.hiddenattrs = []
127 self.attrs = attrs
128 self.displayattrs = []
129 self.fetch(1)
130 self.sizing = False
131 self.fontsize = fontsize
132
133 def GetAttr(self, *args):
134 attr = wx.grid.GridCellAttr()
135 attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
136 return attr
137
138 def GetNumberRows(self):
139 return len(self.items)
140
141 def GetNumberCols(self):
142 return len(self.displayattrs)
143
144 def GetColLabelValue(self, col):
145 if col < len(self.displayattrs):
146 return self.displayattrs[col].name()
147 else:
148 return ""
149
150 def GetRowLabelValue(self, row):
151 return str(row)
152
153 def IsEmptyCell(self, row, col):
154 return False
155
156 def fetch(self, count):
157 # Try to fill ``self.items`` with at least ``count`` objects.
158 have = len(self.items)
159 work = False
160 while self.iterator is not None and have < count:
161 try:
162 item = self.iterator.next()
163 except StopIteration:
164 self.iterator = None
165 break
166 except (KeyboardInterrupt, SystemExit):
167 raise
168 except Exception, exc:
169 have += 1
170 self.items.append(exc)
171 work = True
172 self.iterator = None
173 break
174 else:
175 have += 1
176 self.items.append(item)
177 work = True
178 if work:
179 self.calcdisplayattrs()
180
181 def calcdisplayattrs(self):
182 # Calculate which attributes are available from the objects that are
183 # currently visible on screen (and store it in ``self.displayattrs``)
184 attrs = set()
185 self.displayattrs = []
186 if self.attrs:
187 # If the browser object specifies a fixed list of attributes,
188 # simply use it (removing hidden attributes).
189 for attr in self.attrs:
190 attr = ipipe.upgradexattr(attr)
191 if attr not in attrs and attr not in self.hiddenattrs:
192 self.displayattrs.append(attr)
193 attrs.add(attr)
194 else:
195 endy = len(self.items)
196 for i in xrange(endy):
197 for attr in ipipe.xattrs(self.items[i]):
198 attr = ipipe.upgradexattr(attr)
199 if attr not in attrs and attr not in self.hiddenattrs:
200 self.displayattrs.append(attr)
201 attrs.add(attr)
202
203 def GetValue(self, row, col):
204 # some kind of dummy-function: does not return anything but "";
205 # (The value isn't use anyway)
206 # its main task is to trigger the fetch of new objects
207 had_cols = self.displayattrs[:]
208 had_rows = len(self.items)
209 if row == had_rows - 1 and self.iterator is not None and not self.sizing:
210 self.fetch(row + 20)
211 have_rows = len(self.items)
212 have_cols = len(self.displayattrs)
213 if have_rows > had_rows:
214 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
215 self.GetView().ProcessTableMessage(msg)
216 self.sizing = True
217 self.GetView().AutoSizeColumns(False)
218 self.sizing = False
219 if row >= have_rows:
220 return ""
221 if self.displayattrs != had_cols:
222 msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - len(had_cols))
223 self.GetView().ProcessTableMessage(msg)
224 return ""
225
226 def SetValue(self, row, col, value):
227 pass
228
229
230 class IGridGrid(wx.grid.Grid):
231 # The actual grid
232 # all methods for selecting/sorting/picking/... data are implemented here
233 def __init__(self, panel, input, *attrs):
234 wx.grid.Grid.__init__(self, panel)
235 fontsize = 9
236 self.input = input
237 self.table = IGridTable(self.input, fontsize, *attrs)
238 self.SetTable(self.table, True)
239 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
240 self.SetDefaultRenderer(IGridRenderer(self.table))
241 self.EnableEditing(False)
242 self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
243 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
244 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
245 self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
246 self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
247 self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
248 self.current_selection = set()
249 self.maxchars = 200
250
251 def on_label_leftclick(self, event):
252 event.Skip()
253
254 def error_output(self, text):
255 wx.Bell()
256 frame = self.GetParent().GetParent().GetParent()
257 frame.SetStatusText(text)
258
259 def _on_selected_range(self, event):
260 # Internal update to the selection tracking lists
261 if event.Selecting():
262 # adding to the list...
263 self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow()+1))
264 else:
265 # removal from list
266 for index in xrange( event.GetTopRow(), event.GetBottomRow()+1):
267 self.current_selection.discard(index)
268 event.Skip()
269
270 def _on_selected_cell(self, event):
271 # Internal update to the selection tracking list
272 self.current_selection = set([event.GetRow()])
273 event.Skip()
274
275 def sort(self, key, reverse=False):
276 """
277 Sort the current list of items using the key function ``key``. If
278 ``reverse`` is true the sort order is reversed.
279 """
280 row = self.GetGridCursorRow()
281 col = self.GetGridCursorCol()
282 curitem = self.table.items[row] # Remember where the cursor is now
283 # Sort items
284 def realkey(item):
285 return key(item)
286 try:
287 self.table.items = ipipe.deque(sorted(self.table.items, key=realkey, reverse=reverse))
288 except TypeError, exc:
289 self.error_output("Exception encountered: %s" % exc)
290 return
291 # Find out where the object under the cursor went
292 for (i, item) in enumerate(self.table.items):
293 if item is curitem:
294 self.SetGridCursor(i,col)
295 self.MakeCellVisible(i,col)
296 self.Refresh()
297
298 def sortattrasc(self):
299 """
300 Sort in ascending order; sorting criteria is the current attribute
301 """
302 col = self.GetGridCursorCol()
303 attr = self.table.displayattrs[col]
304 frame = self.GetParent().GetParent().GetParent()
305 if attr is ipipe.noitem:
306 self.error_output("no column under cursor")
307 return
308 frame.SetStatusText("sort by %s (ascending)" % attr.name())
309 def key(item):
310 try:
311 return attr.value(item)
312 except (KeyboardInterrupt, SystemExit):
313 raise
314 except Exception:
315 return None
316 self.sort(key)
317
318 def sortattrdesc(self):
319 """
320 Sort in descending order; sorting criteria is the current attribute
321 """
322 col = self.GetGridCursorCol()
323 attr = self.table.displayattrs[col]
324 frame = self.GetParent().GetParent().GetParent()
325 if attr is ipipe.noitem:
326 self.error_output("no column under cursor")
327 return
328 frame.SetStatusText("sort by %s (descending)" % attr.name())
329 def key(item):
330 try:
331 return attr.value(item)
332 except (KeyboardInterrupt, SystemExit):
333 raise
334 except Exception:
335 return None
336 self.sort(key, reverse=True)
337
338 def label_doubleclicked(self, event):
339 row = event.GetRow()
340 col = event.GetCol()
341 if col == -1:
342 self.enter(row)
343
344 def _getvalue(self, row, col):
345 """
346 Gets the text which is displayed at ``(row, col)``
347 """
348 try:
349 value = self.table.displayattrs[col].value(self.table.items[row])
350 (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
351 except IndexError:
352 raise IndexError
353 except Exception, exc:
354 (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
355 return text
356
357 def search(self, searchtext, startrow=0, startcol=0, search_forward=True):
358 """
359 search for ``searchtext``, starting in ``(startrow, startcol)``;
360 if ``search_forward`` is true the direction is "forward"
361 """
362 row = startrow
363 searchtext = searchtext.lower()
364 if search_forward:
365 while True:
366 for col in xrange(startcol, self.table.GetNumberCols()):
367 try:
368 foo = self.table.GetValue(row, col)
369 text = self._getvalue(row, col)
370 if searchtext in text.string().lower():
371 self.SetGridCursor(row, col)
372 self.MakeCellVisible(row, col)
373 return
374 except IndexError:
375 return
376 startcol = 0
377 row += 1
378 else:
379 while True:
380 for col in xrange(startcol, -1, -1):
381 try:
382 foo = self.table.GetValue(row, col)
383 text = self._getvalue(row, col)
384 if searchtext in text.string().lower():
385 self.SetGridCursor(row, col)
386 self.MakeCellVisible(row, col)
387 return
388 except IndexError:
389 return
390 startcol = self.table.GetNumberCols()-1
391 row -= 1
392
393 def key_pressed(self, event):
394 """
395 Maps pressed keys to functions
396 """
397 frame = self.GetParent().GetParent().GetParent()
398 frame.SetStatusText("")
399 sh = event.ShiftDown()
400 ctrl = event.ControlDown()
401
402 keycode = event.GetKeyCode()
403 if keycode == ord("P"):
404 row = self.GetGridCursorRow()
405 if event.ShiftDown():
406 col = self.GetGridCursorCol()
407 self.pickattr(row, col)
408 else:
409 self.pick(row)
410 elif keycode == ord("M"):
411 if ctrl:
412 col = self.GetGridCursorCol()
413 self.pickrowsattr(sorted(self.current_selection), col)
414 else:
415 self.pickrows(sorted(self.current_selection))
416 elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord("X")) and not (ctrl or sh):
417 self.delete_current_notebook()
418 elif keycode == ord("E") and not (ctrl or sh):
419 row = self.GetGridCursorRow()
420 self.enter(row)
421 elif keycode == ord("E") and sh and not ctrl:
422 row = self.GetGridCursorRow()
423 col = self.GetGridCursorCol()
424 self.enterattr(row, col)
425 elif keycode == ord("E") and ctrl:
426 row = self.GetGridCursorRow()
427 self.SetGridCursor(row, self.GetNumberCols()-1)
428 elif keycode == wx.WXK_HOME or (keycode == ord("A") and ctrl):
429 row = self.GetGridCursorRow()
430 self.SetGridCursor(row, 0)
431 elif keycode == ord("C") and sh:
432 col = self.GetGridCursorCol()
433 attr = self.table.displayattrs[col]
434 returnobj = []
435 for i in xrange(self.GetNumberRows()):
436 returnobj.append(self.table.displayattrs[col].value(self.table.items[i]))
437 self.quit(returnobj)
438 elif keycode in (wx.WXK_ESCAPE, ord("Q")) and not (ctrl or sh):
439 self.quit()
440 elif keycode == ord("<"):
441 row = self.GetGridCursorRow()
442 col = self.GetGridCursorCol()
443 if not event.ShiftDown():
444 newcol = col - 1
445 if newcol >= 0:
446 self.SetGridCursor(row, col - 1)
447 else:
448 newcol = col + 1
449 if newcol < self.GetNumberCols():
450 self.SetGridCursor(row, col + 1)
451 elif keycode == ord("D"):
452 col = self.GetGridCursorCol()
453 row = self.GetGridCursorRow()
454 if not sh:
455 self.detail(row, col)
456 else:
457 self.detail_attr(row, col)
458 elif keycode == ord("F") and ctrl:
459 frame.enter_searchtext(event)
460 elif keycode == wx.WXK_F3:
461 if sh:
462 frame.find_previous(event)
463 else:
464 frame.find_next(event)
465 elif keycode == ord("V"):
466 if sh:
467 self.sortattrdesc()
468 else:
469 self.sortattrasc()
470 else:
471 event.Skip()
472
473 def delete_current_notebook(self):
474 """
475 deletes the current notebook tab
476 """
477 panel = self.GetParent()
478 nb = panel.GetParent()
479 current = nb.GetSelection()
480 count = nb.GetPageCount()
481 if count > 1:
482 for i in xrange(count-1, current-1, -1):
483 nb.DeletePage(i)
484 nb.GetCurrentPage().grid.SetFocus()
485 else:
486 frame = nb.GetParent()
487 frame.SetStatusText("This is the last level!")
488
489 def _doenter(self, value, *attrs):
490 """
491 "enter" a special item resulting in a new notebook tab
492 """
493 panel = self.GetParent()
494 nb = panel.GetParent()
495 frame = nb.GetParent()
496 current = nb.GetSelection()
497 count = nb.GetPageCount()
498 try: # if we want to enter something non-iterable, e.g. a function
499 if current + 1 == count and value is not self.input: # we have an event in the last tab
500 frame._add_notebook(value, *attrs)
501 elif value != self.input: # we have to delete all tabs newer than [panel] first
502 for i in xrange(count-1, current, -1): # some tabs don't close if we don't close in *reverse* order
503 nb.DeletePage(i)
504 frame._add_notebook(value)
505 except TypeError, exc:
506 if exc.__class__.__module__ == "exceptions":
507 msg = "%s: %s" % (exc.__class__.__name__, exc)
508 else:
509 msg = "%s.%s: %s" % (exc.__class__.__module__, exc.__class__.__name__, exc)
510 frame.SetStatusText(msg)
511
512 def enterattr(self, row, col):
513 try:
514 attr = self.table.displayattrs[col]
515 value = attr.value(self.table.items[row])
516 except Exception, exc:
517 self.error_output(str(exc))
518 else:
519 self._doenter(value)
520
521 def enter(self, row):
522 try:
523 value = self.table.items[row]
524 except Exception, exc:
525 self.error_output(str(exc))
526 else:
527 self._doenter(value)
528
529 def detail(self, row, col):
530 """
531 shows a detail-view of the current cell
532 """
533 try:
534 attr = self.table.displayattrs[col]
535 item = self.table.items[row]
536 except Exception, exc:
537 self.error_output(str(exc))
538 else:
539 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
540 self._doenter(attrs)
541
542 def detail_attr(self, row, col):
543 try:
544 attr = self.table.displayattrs[col]
545 item = attr.value(self.table.items[row])
546 except Exception, exc:
547 self.error_output(str(exc))
548 else:
549 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
550 self._doenter(attrs)
551
552 def quit(self, returnobj=None):
553 """
554 quit
555 """
556 frame = self.GetParent().GetParent().GetParent()
557 frame.parent.returnobj = returnobj
558 frame.Close()
559 frame.Destroy()
560
561 def cell_doubleclicked(self, event):
562 self.enterattr(event.GetRow(), event.GetCol())
563
564 def pick(self, row):
565 """
566 pick a single row and return to the IPython prompt
567 """
568 try:
569 value = self.table.items[row]
570 except Exception, exc:
571 self.error_output(str(exc))
572 else:
573 self.quit(value)
574
575 def pickrows(self, rows):
576 """
577 pick multiple rows and return to the IPython prompt
578 """
579 try:
580 value = [self.table.items[row] for row in rows]
581 except Exception, exc:
582 self.error_output(str(exc))
583 else:
584 self.quit(value)
585
586 def pickrowsattr(self, rows, col):
587 """"
588 pick one column from multiple rows
589 """
590 values = []
591 try:
592 attr = self.table.displayattrs[col]
593 for row in rows:
594 try:
595 values.append(attr.value(self.table.items[row]))
596 except (SystemExit, KeyboardInterrupt):
597 raise
598 except Exception:
599 raise #pass
600 except Exception, exc:
601 self.error_output(str(exc))
602 else:
603 self.quit(values)
604
605 def pickattr(self, row, col):
606 try:
607 attr = self.table.displayattrs[col]
608 value = attr.value(self.table.items[row])
609 except Exception, exc:
610 self.error_output(str(exc))
611 else:
612 self.quit(value)
613
614
615 class IGridPanel(wx.Panel):
616 # Each IGridPanel contains an IGridGrid
617 def __init__(self, parent, input, *attrs):
618 wx.Panel.__init__(self, parent, -1)
619 self.grid = IGridGrid(self, input, *attrs)
620 sizer = wx.BoxSizer(wx.VERTICAL)
621 sizer.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
622 self.SetSizer(sizer)
623 sizer.Fit(self)
624 sizer.SetSizeHints(self)
625
626
627 class IGridHTMLHelp(wx.Frame):
628 def __init__(self, parent, title, filename, size):
629 wx.Frame.__init__(self, parent, -1, title, size=size)
630 html = wx.html.HtmlWindow(self)
631 if "gtk2" in wx.PlatformInfo:
632 html.SetStandardFonts()
633 html.LoadFile(filename)
634
635
636 class IGridFrame(wx.Frame):
637 maxtitlelen = 30
638
639 def __init__(self, parent, input):
640 wx.Frame.__init__(self, None, title="IGrid", size=(640, 480))
641 self.menubar = wx.MenuBar()
642 self.menucounter = 100
643 self.m_help = wx.Menu()
644 self.m_search = wx.Menu()
645 self.m_sort = wx.Menu()
646 self.notebook = wx.Notebook(self, -1, style=0)
647 self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
648 self.parent = parent
649 self._add_notebook(input)
650 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
651 self.makemenu(self.m_sort, "&Sort (asc)", "Sort ascending", self.sortasc)
652 self.makemenu(self.m_sort, "Sort (&desc)", "Sort descending", self.sortdesc)
653 self.makemenu(self.m_help, "&Help", "Help", self.display_help)
654 self.makemenu(self.m_help, "&Show help in browser", "Show help in browser", self.display_help_in_browser)
655 self.makemenu(self.m_search, "&Find text", "Find text", self.enter_searchtext)
656 self.makemenu(self.m_search, "Find by &expression", "Find by expression", self.enter_searchexpression)
657 self.makemenu(self.m_search, "Find &next", "Find next", self.find_next)
658 self.makemenu(self.m_search, "Find &previous", "Find previous", self.find_previous)
659 self.menubar.Append(self.m_search, "&Find")
660 self.menubar.Append(self.m_sort, "&Sort")
661 self.menubar.Append(self.m_help, "&Help")
662 self.SetMenuBar(self.menubar)
663 self.searchtext = ""
664
665 def sortasc(self, event):
666 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
667 grid.sortattrasc()
668
669 def sortdesc(self, event):
670 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
671 grid.sortattrdesc()
672
673 def find_previous(self, event):
674 """
675 find previous occurrences
676 """
677 if self.searchtext:
678 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
679 row = grid.GetGridCursorRow()
680 col = grid.GetGridCursorCol()
681 if col-1 >= 0:
682 grid.search(self.searchtext, row, col-1, False)
683 else:
684 grid.search(self.searchtext, row-1, grid.table.GetNumberCols()-1, False)
685 else:
686 self.enter_searchtext(event)
687
688 def find_next(self, event):
689 """
690 find the next occurrence
691 """
692 if self.searchtext:
693 grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
694 row = grid.GetGridCursorRow()
695 col = grid.GetGridCursorCol()
696 if col+1 < grid.table.GetNumberCols():
697 grid.search(self.searchtext, row, col+1)
698 else:
699 grid.search(self.searchtext, row+1, 0)
700 else:
701 self.enter_searchtext(event)
702
703 def display_help(self, event):
704 """
705 Display a help dialog
706 """
707 filename = os.path.join(os.path.dirname(__file__), "help.html")
708 frm = IGridHTMLHelp(None, title="Help", filename=filename, size=wx.Size(600,400))
709 frm.Show()
710
711 def display_help_in_browser(self, event):
712 """
713 Show the help-HTML in a browser (as a ``HtmlWindow`` does not understand
714 CSS this looks better)
715 """
716 filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), "help.html")))
717 if not filename.startswith("file"):
718 filename = "file:" + filename
719 webbrowser.open(filename, new=1, autoraise=True)
720
721 def enter_searchexpression(self, event):
722 pass
723
724 def makemenu(self, menu, label, help, cmd):
725 menu.Append(self.menucounter, label, help)
726 self.Bind(wx.EVT_MENU, cmd, id=self.menucounter)
727 self.menucounter += 1
728
729 def _add_notebook(self, input, *attrs):
730 # Adds another notebook which has the starting object ``input``
731 panel = IGridPanel(self.notebook, input, *attrs)
732 text = str(ipipe.xformat(input, "header", self.maxtitlelen)[2])
733 if len(text) >= self.maxtitlelen:
734 text = text[:self.maxtitlelen].rstrip(".") + "..."
735 self.notebook.AddPage(panel, text, True)
736 panel.grid.SetFocus()
737 self.Layout()
738
739 def OnCloseWindow(self, event):
740 self.Destroy()
741
742 def enter_searchtext(self, event):
743 # Displays a dialog asking for the searchtext
744 dlg = wx.TextEntryDialog(self, "Find:", "Find in list")
745 if dlg.ShowModal() == wx.ID_OK:
746 self.searchtext = dlg.GetValue()
747 self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext, 0, 0)
748 dlg.Destroy()
749
750
751 class igrid(ipipe.Display):
752 """
753 This is a wx-based display object that can be used instead of ``ibrowse``
754 (which is curses-based) or ``idump`` (which simply does a print).
755 """
756 def display(self):
757 self.returnobj = None
758 app = wx.App()
759 self.frame = IGridFrame(self, self.input)
760 self.frame.Show()
761 app.SetTopWindow(self.frame)
762 self.frame.Raise()
763 app.MainLoop()
764 return self.returnobj
@@ -1,2146 +1,2153 b''
1 # -*- coding: iso-8859-1 -*-
1 # -*- coding: iso-8859-1 -*-
2
2
3 """
3 """
4 ``ipipe`` provides classes to be used in an interactive Python session. Doing a
4 ``ipipe`` provides classes to be used in an interactive Python session. Doing a
5 ``from ipipe import *`` is the preferred way to do this. The name of all
5 ``from ipipe import *`` is the preferred way to do this. The name of all
6 objects imported this way starts with ``i`` to minimize collisions.
6 objects imported this way starts with ``i`` to minimize collisions.
7
7
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
8 ``ipipe`` supports "pipeline expressions", which is something resembling Unix
9 pipes. An example is:
9 pipes. An example is:
10
10
11 >>> ienv | isort("key.lower()")
11 >>> ienv | isort("key.lower()")
12
12
13 This gives a listing of all environment variables sorted by name.
13 This gives a listing of all environment variables sorted by name.
14
14
15
15
16 There are three types of objects in a pipeline expression:
16 There are three types of objects in a pipeline expression:
17
17
18 * ``Table``s: These objects produce items. Examples are ``ils`` (listing the
18 * ``Table``s: These objects produce items. Examples are ``ils`` (listing the
19 current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
19 current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
20 user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
20 user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
21 first object in a pipe expression.
21 first object in a pipe expression.
22
22
23 * ``Pipe``s: These objects sit in the middle of a pipe expression. They
23 * ``Pipe``s: These objects sit in the middle of a pipe expression. They
24 transform the input in some way (e.g. filtering or sorting it). Examples are:
24 transform the input in some way (e.g. filtering or sorting it). Examples are:
25 ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
25 ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
26 pipe) and ``ieval`` (which evaluates a function or expression for each object
26 pipe) and ``ieval`` (which evaluates a function or expression for each object
27 in the input pipe).
27 in the input pipe).
28
28
29 * ``Display``s: These objects can be put as the last object in a pipeline
29 * ``Display``s: These objects can be put as the last object in a pipeline
30 expression. There are responsible for displaying the result of the pipeline
30 expression. There are responsible for displaying the result of the pipeline
31 expression. If a pipeline expression doesn't end in a display object a default
31 expression. If a pipeline expression doesn't end in a display object a default
32 display objects will be used. One example is ``ibrowse`` which is a ``curses``
32 display objects will be used. One example is ``ibrowse`` which is a ``curses``
33 based browser.
33 based browser.
34
34
35
35
36 Adding support for pipeline expressions to your own objects can be done through
36 Adding support for pipeline expressions to your own objects can be done through
37 three extensions points (all of them optional):
37 three extensions points (all of them optional):
38
38
39 * An object that will be displayed as a row by a ``Display`` object should
39 * An object that will be displayed as a row by a ``Display`` object should
40 implement the method ``__xattrs__(self, mode)`` method or register an
40 implement the method ``__xattrs__(self, mode)`` method or register an
41 implementation of the generic function ``xattrs``. For more info see ``xattrs``.
41 implementation of the generic function ``xattrs``. For more info see ``xattrs``.
42
42
43 * When an object ``foo`` is displayed by a ``Display`` object, the generic
43 * When an object ``foo`` is displayed by a ``Display`` object, the generic
44 function ``xrepr`` is used.
44 function ``xrepr`` is used.
45
45
46 * Objects that can be iterated by ``Pipe``s must iterable. For special cases,
46 * Objects that can be iterated by ``Pipe``s must iterable. For special cases,
47 where iteration for display is different than the normal iteration a special
47 where iteration for display is different than the normal iteration a special
48 implementation can be registered with the generic function ``xiter``. This makes
48 implementation can be registered with the generic function ``xiter``. This makes
49 it possible to use dictionaries and modules in pipeline expressions, for example:
49 it possible to use dictionaries and modules in pipeline expressions, for example:
50
50
51 >>> import sys
51 >>> import sys
52 >>> sys | ifilter("isinstance(value, int)") | idump
52 >>> sys | ifilter("isinstance(value, int)") | idump
53 key |value
53 key |value
54 api_version| 1012
54 api_version| 1012
55 dllhandle | 503316480
55 dllhandle | 503316480
56 hexversion | 33817328
56 hexversion | 33817328
57 maxint |2147483647
57 maxint |2147483647
58 maxunicode | 65535
58 maxunicode | 65535
59 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
59 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
60 ...
60 ...
61
61
62 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
62 Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
63 refer to the object to be filtered or sorted via the variable ``_`` and to any
63 refer to the object to be filtered or sorted via the variable ``_`` and to any
64 of the attributes of the object, i.e.:
64 of the attributes of the object, i.e.:
65
65
66 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
66 >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
67
67
68 does the same as
68 does the same as
69
69
70 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
70 >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
71
71
72 In addition to expression strings, it's possible to pass callables (taking
72 In addition to expression strings, it's possible to pass callables (taking
73 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``:
73 the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``:
74
74
75 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
75 >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
76 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
76 ... | ieval(lambda _: (_.key, hex(_.value))) | idump
77 0 |1
77 0 |1
78 api_version|0x3f4
78 api_version|0x3f4
79 dllhandle |0x1e000000
79 dllhandle |0x1e000000
80 hexversion |0x20402f0
80 hexversion |0x20402f0
81 maxint |0x7fffffff
81 maxint |0x7fffffff
82 maxunicode |0xffff
82 maxunicode |0xffff
83 """
83 """
84
84
85 import sys, os, os.path, stat, glob, new, csv, datetime, types
85 import sys, os, os.path, stat, glob, new, csv, datetime, types
86 import itertools, mimetypes
86 import itertools, mimetypes
87
87
88 try: # Python 2.3 compatibility
88 try: # Python 2.3 compatibility
89 import collections
89 import collections
90 except ImportError:
90 except ImportError:
91 deque = list
91 deque = list
92 else:
92 else:
93 deque = collections.deque
93 deque = collections.deque
94
94
95 try: # Python 2.3 compatibility
95 try: # Python 2.3 compatibility
96 set
96 set
97 except NameError:
97 except NameError:
98 import sets
98 import sets
99 set = sets.Set
99 set = sets.Set
100
100
101 try: # Python 2.3 compatibility
101 try: # Python 2.3 compatibility
102 sorted
102 sorted
103 except NameError:
103 except NameError:
104 def sorted(iterator, key=None, reverse=False):
104 def sorted(iterator, key=None, reverse=False):
105 items = list(iterator)
105 items = list(iterator)
106 if key is not None:
106 if key is not None:
107 items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
107 items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
108 else:
108 else:
109 items.sort()
109 items.sort()
110 if reverse:
110 if reverse:
111 items.reverse()
111 items.reverse()
112 return items
112 return items
113
113
114 try:
114 try:
115 import pwd
115 import pwd
116 except ImportError:
116 except ImportError:
117 pwd = None
117 pwd = None
118
118
119 try:
119 try:
120 import grp
120 import grp
121 except ImportError:
121 except ImportError:
122 grp = None
122 grp = None
123
123
124 from IPython.external import simplegeneric
124 from IPython.external import simplegeneric
125
125
126 import path
126 import path
127 try:
127 try:
128 from IPython import genutils, ipapi
128 from IPython import genutils, ipapi
129 except ImportError:
129 except ImportError:
130 genutils = None
130 genutils = None
131 ipapi = None
131 ipapi = None
132
132
133 import astyle
133 import astyle
134
134
135
135
136 __all__ = [
136 __all__ = [
137 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
137 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
138 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum", "ienv",
138 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum", "ienv",
139 "idump", "iless"
139 "idump", "iless"
140 ]
140 ]
141
141
142
142
143 os.stat_float_times(True) # enable microseconds
143 os.stat_float_times(True) # enable microseconds
144
144
145
145
146 class AttrNamespace(object):
146 class AttrNamespace(object):
147 """
147 """
148 Helper class that is used for providing a namespace for evaluating
148 Helper class that is used for providing a namespace for evaluating
149 expressions containing attribute names of an object.
149 expressions containing attribute names of an object.
150 """
150 """
151 def __init__(self, wrapped):
151 def __init__(self, wrapped):
152 self.wrapped = wrapped
152 self.wrapped = wrapped
153
153
154 def __getitem__(self, name):
154 def __getitem__(self, name):
155 if name == "_":
155 if name == "_":
156 return self.wrapped
156 return self.wrapped
157 try:
157 try:
158 return getattr(self.wrapped, name)
158 return getattr(self.wrapped, name)
159 except AttributeError:
159 except AttributeError:
160 raise KeyError(name)
160 raise KeyError(name)
161
161
162 # Python 2.3 compatibility
162 # Python 2.3 compatibility
163 # use eval workaround to find out which names are used in the
163 # use eval workaround to find out which names are used in the
164 # eval string and put them into the locals. This works for most
164 # eval string and put them into the locals. This works for most
165 # normal uses case, bizarre ones like accessing the locals()
165 # normal uses case, bizarre ones like accessing the locals()
166 # will fail
166 # will fail
167 try:
167 try:
168 eval("_", None, AttrNamespace(None))
168 eval("_", None, AttrNamespace(None))
169 except TypeError:
169 except TypeError:
170 real_eval = eval
170 real_eval = eval
171 def eval(codestring, _globals, _locals):
171 def eval(codestring, _globals, _locals):
172 """
172 """
173 eval(source[, globals[, locals]]) -> value
173 eval(source[, globals[, locals]]) -> value
174
174
175 Evaluate the source in the context of globals and locals.
175 Evaluate the source in the context of globals and locals.
176 The source may be a string representing a Python expression
176 The source may be a string representing a Python expression
177 or a code object as returned by compile().
177 or a code object as returned by compile().
178 The globals must be a dictionary and locals can be any mappping.
178 The globals must be a dictionary and locals can be any mappping.
179
179
180 This function is a workaround for the shortcomings of
180 This function is a workaround for the shortcomings of
181 Python 2.3's eval.
181 Python 2.3's eval.
182 """
182 """
183
183
184 if isinstance(codestring, basestring):
184 if isinstance(codestring, basestring):
185 code = compile(codestring, "_eval", "eval")
185 code = compile(codestring, "_eval", "eval")
186 else:
186 else:
187 code = codestring
187 code = codestring
188 newlocals = {}
188 newlocals = {}
189 for name in code.co_names:
189 for name in code.co_names:
190 try:
190 try:
191 newlocals[name] = _locals[name]
191 newlocals[name] = _locals[name]
192 except KeyError:
192 except KeyError:
193 pass
193 pass
194 return real_eval(code, _globals, newlocals)
194 return real_eval(code, _globals, newlocals)
195
195
196
196
197 noitem = object()
197 noitem = object()
198
198
199
199
200 def item(iterator, index, default=noitem):
200 def item(iterator, index, default=noitem):
201 """
201 """
202 Return the ``index``th item from the iterator ``iterator``.
202 Return the ``index``th item from the iterator ``iterator``.
203 ``index`` must be an integer (negative integers are relative to the
203 ``index`` must be an integer (negative integers are relative to the
204 end (i.e. the last items produced by the iterator)).
204 end (i.e. the last items produced by the iterator)).
205
205
206 If ``default`` is given, this will be the default value when
206 If ``default`` is given, this will be the default value when
207 the iterator doesn't contain an item at this position. Otherwise an
207 the iterator doesn't contain an item at this position. Otherwise an
208 ``IndexError`` will be raised.
208 ``IndexError`` will be raised.
209
209
210 Note that using this function will partially or totally exhaust the
210 Note that using this function will partially or totally exhaust the
211 iterator.
211 iterator.
212 """
212 """
213 i = index
213 i = index
214 if i>=0:
214 if i>=0:
215 for item in iterator:
215 for item in iterator:
216 if not i:
216 if not i:
217 return item
217 return item
218 i -= 1
218 i -= 1
219 else:
219 else:
220 i = -index
220 i = -index
221 cache = deque()
221 cache = deque()
222 for item in iterator:
222 for item in iterator:
223 cache.append(item)
223 cache.append(item)
224 if len(cache)>i:
224 if len(cache)>i:
225 cache.popleft()
225 cache.popleft()
226 if len(cache)==i:
226 if len(cache)==i:
227 return cache.popleft()
227 return cache.popleft()
228 if default is noitem:
228 if default is noitem:
229 raise IndexError(index)
229 raise IndexError(index)
230 else:
230 else:
231 return default
231 return default
232
232
233
233
234 def getglobals(g):
234 def getglobals(g):
235 """
235 """
236 Return the global namespace that is used for expression strings in
236 Return the global namespace that is used for expression strings in
237 ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
237 ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
238 user namespace.
238 user namespace.
239 """
239 """
240 if g is None:
240 if g is None:
241 if ipapi is not None:
241 if ipapi is not None:
242 api = ipapi.get()
242 api = ipapi.get()
243 if api is not None:
243 if api is not None:
244 return api.user_ns
244 return api.user_ns
245 return globals()
245 return globals()
246 return g
246 return g
247
247
248
248
249 class Descriptor(object):
249 class Descriptor(object):
250 """
250 """
251 A ``Descriptor`` object is used for describing the attributes of objects.
251 A ``Descriptor`` object is used for describing the attributes of objects.
252 """
252 """
253 def __hash__(self):
253 def __hash__(self):
254 return hash(self.__class__) ^ hash(self.key())
254 return hash(self.__class__) ^ hash(self.key())
255
255
256 def __eq__(self, other):
256 def __eq__(self, other):
257 return self.__class__ is other.__class__ and self.key() == other.key()
257 return self.__class__ is other.__class__ and self.key() == other.key()
258
258
259 def __ne__(self, other):
259 def __ne__(self, other):
260 return self.__class__ is not other.__class__ or self.key() != other.key()
260 return self.__class__ is not other.__class__ or self.key() != other.key()
261
261
262 def key(self):
262 def key(self):
263 pass
263 pass
264
264
265 def name(self):
265 def name(self):
266 """
266 """
267 Return the name of this attribute for display by a ``Display`` object
267 Return the name of this attribute for display by a ``Display`` object
268 (e.g. as a column title).
268 (e.g. as a column title).
269 """
269 """
270 key = self.key()
270 key = self.key()
271 if key is None:
271 if key is None:
272 return "_"
272 return "_"
273 return str(key)
273 return str(key)
274
274
275 def attrtype(self, obj):
275 def attrtype(self, obj):
276 """
276 """
277 Return the type of this attribute (i.e. something like "attribute" or
277 Return the type of this attribute (i.e. something like "attribute" or
278 "method").
278 "method").
279 """
279 """
280
280
281 def valuetype(self, obj):
281 def valuetype(self, obj):
282 """
282 """
283 Return the type of this attribute value of the object ``obj``.
283 Return the type of this attribute value of the object ``obj``.
284 """
284 """
285
285
286 def value(self, obj):
286 def value(self, obj):
287 """
287 """
288 Return the value of this attribute of the object ``obj``.
288 Return the value of this attribute of the object ``obj``.
289 """
289 """
290
290
291 def doc(self, obj):
291 def doc(self, obj):
292 """
292 """
293 Return the documentation for this attribute.
293 Return the documentation for this attribute.
294 """
294 """
295
295
296 def shortdoc(self, obj):
296 def shortdoc(self, obj):
297 """
297 """
298 Return a short documentation for this attribute (defaulting to the
298 Return a short documentation for this attribute (defaulting to the
299 first line).
299 first line).
300 """
300 """
301 doc = self.doc(obj)
301 doc = self.doc(obj)
302 if doc is not None:
302 if doc is not None:
303 doc = doc.strip().splitlines()[0].strip()
303 doc = doc.strip().splitlines()[0].strip()
304 return doc
304 return doc
305
305
306 def iter(self, obj):
306 def iter(self, obj):
307 """
307 """
308 Return an iterator for this attribute of the object ``obj``.
308 Return an iterator for this attribute of the object ``obj``.
309 """
309 """
310 return xiter(self.value(obj))
310 return xiter(self.value(obj))
311
311
312
312
313 class SelfDescriptor(Descriptor):
313 class SelfDescriptor(Descriptor):
314 """
314 """
315 A ``SelfDescriptor`` describes the object itself.
315 A ``SelfDescriptor`` describes the object itself.
316 """
316 """
317 def key(self):
317 def key(self):
318 return None
318 return None
319
319
320 def attrtype(self, obj):
320 def attrtype(self, obj):
321 return "self"
321 return "self"
322
322
323 def valuetype(self, obj):
323 def valuetype(self, obj):
324 return type(obj)
324 return type(obj)
325
325
326 def value(self, obj):
326 def value(self, obj):
327 return obj
327 return obj
328
328
329 def __repr__(self):
329 def __repr__(self):
330 return "Self"
330 return "Self"
331
331
332 selfdescriptor = SelfDescriptor() # there's no need for more than one
332 selfdescriptor = SelfDescriptor() # there's no need for more than one
333
333
334
334
335 class AttributeDescriptor(Descriptor):
335 class AttributeDescriptor(Descriptor):
336 """
336 """
337 An ``AttributeDescriptor`` describes a simple attribute of an object.
337 An ``AttributeDescriptor`` describes a simple attribute of an object.
338 """
338 """
339 __slots__ = ("_name", "_doc")
339 __slots__ = ("_name", "_doc")
340
340
341 def __init__(self, name, doc=None):
341 def __init__(self, name, doc=None):
342 self._name = name
342 self._name = name
343 self._doc = doc
343 self._doc = doc
344
344
345 def key(self):
345 def key(self):
346 return self._name
346 return self._name
347
347
348 def doc(self, obj):
348 def doc(self, obj):
349 return self._doc
349 return self._doc
350
350
351 def attrtype(self, obj):
351 def attrtype(self, obj):
352 return "attr"
352 return "attr"
353
353
354 def valuetype(self, obj):
354 def valuetype(self, obj):
355 return type(getattr(obj, self._name))
355 return type(getattr(obj, self._name))
356
356
357 def value(self, obj):
357 def value(self, obj):
358 return getattr(obj, self._name)
358 return getattr(obj, self._name)
359
359
360 def __repr__(self):
360 def __repr__(self):
361 if self._doc is None:
361 if self._doc is None:
362 return "Attribute(%r)" % self._name
362 return "Attribute(%r)" % self._name
363 else:
363 else:
364 return "Attribute(%r, %r)" % (self._name, self._doc)
364 return "Attribute(%r, %r)" % (self._name, self._doc)
365
365
366
366
367 class IndexDescriptor(Descriptor):
367 class IndexDescriptor(Descriptor):
368 """
368 """
369 An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
369 An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
370 via ``__getitem__``.
370 via ``__getitem__``.
371 """
371 """
372 __slots__ = ("_index",)
372 __slots__ = ("_index",)
373
373
374 def __init__(self, index):
374 def __init__(self, index):
375 self._index = index
375 self._index = index
376
376
377 def key(self):
377 def key(self):
378 return self._index
378 return self._index
379
379
380 def attrtype(self, obj):
380 def attrtype(self, obj):
381 return "item"
381 return "item"
382
382
383 def valuetype(self, obj):
383 def valuetype(self, obj):
384 return type(obj[self._index])
384 return type(obj[self._index])
385
385
386 def value(self, obj):
386 def value(self, obj):
387 return obj[self._index]
387 return obj[self._index]
388
388
389 def __repr__(self):
389 def __repr__(self):
390 return "Index(%r)" % self._index
390 return "Index(%r)" % self._index
391
391
392
392
393 class MethodDescriptor(Descriptor):
393 class MethodDescriptor(Descriptor):
394 """
394 """
395 A ``MethodDescriptor`` describes a method of an object that can be called
395 A ``MethodDescriptor`` describes a method of an object that can be called
396 without argument. Note that this method shouldn't change the object.
396 without argument. Note that this method shouldn't change the object.
397 """
397 """
398 __slots__ = ("_name", "_doc")
398 __slots__ = ("_name", "_doc")
399
399
400 def __init__(self, name, doc=None):
400 def __init__(self, name, doc=None):
401 self._name = name
401 self._name = name
402 self._doc = doc
402 self._doc = doc
403
403
404 def key(self):
404 def key(self):
405 return self._name
405 return self._name
406
406
407 def doc(self, obj):
407 def doc(self, obj):
408 if self._doc is None:
408 if self._doc is None:
409 return getattr(obj, self._name).__doc__
409 return getattr(obj, self._name).__doc__
410 return self._doc
410 return self._doc
411
411
412 def attrtype(self, obj):
412 def attrtype(self, obj):
413 return "method"
413 return "method"
414
414
415 def valuetype(self, obj):
415 def valuetype(self, obj):
416 return type(self.value(obj))
416 return type(self.value(obj))
417
417
418 def value(self, obj):
418 def value(self, obj):
419 return getattr(obj, self._name)()
419 return getattr(obj, self._name)()
420
420
421 def __repr__(self):
421 def __repr__(self):
422 if self._doc is None:
422 if self._doc is None:
423 return "Method(%r)" % self._name
423 return "Method(%r)" % self._name
424 else:
424 else:
425 return "Method(%r, %r)" % (self._name, self._doc)
425 return "Method(%r, %r)" % (self._name, self._doc)
426
426
427
427
428 class IterAttributeDescriptor(Descriptor):
428 class IterAttributeDescriptor(Descriptor):
429 """
429 """
430 An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
430 An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
431 doesn't return an attribute values (because this value might be e.g. a large
431 doesn't return an attribute values (because this value might be e.g. a large
432 list).
432 list).
433 """
433 """
434 __slots__ = ("_name", "_doc")
434 __slots__ = ("_name", "_doc")
435
435
436 def __init__(self, name, doc=None):
436 def __init__(self, name, doc=None):
437 self._name = name
437 self._name = name
438 self._doc = doc
438 self._doc = doc
439
439
440 def key(self):
440 def key(self):
441 return self._name
441 return self._name
442
442
443 def doc(self, obj):
443 def doc(self, obj):
444 return self._doc
444 return self._doc
445
445
446 def attrtype(self, obj):
446 def attrtype(self, obj):
447 return "iter"
447 return "iter"
448
448
449 def valuetype(self, obj):
449 def valuetype(self, obj):
450 return noitem
450 return noitem
451
451
452 def value(self, obj):
452 def value(self, obj):
453 return noitem
453 return noitem
454
454
455 def iter(self, obj):
455 def iter(self, obj):
456 return xiter(getattr(obj, self._name))
456 return xiter(getattr(obj, self._name))
457
457
458 def __repr__(self):
458 def __repr__(self):
459 if self._doc is None:
459 if self._doc is None:
460 return "IterAttribute(%r)" % self._name
460 return "IterAttribute(%r)" % self._name
461 else:
461 else:
462 return "IterAttribute(%r, %r)" % (self._name, self._doc)
462 return "IterAttribute(%r, %r)" % (self._name, self._doc)
463
463
464
464
465 class IterMethodDescriptor(Descriptor):
465 class IterMethodDescriptor(Descriptor):
466 """
466 """
467 An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
467 An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
468 return an attribute values (because this value might be e.g. a large list).
468 return an attribute values (because this value might be e.g. a large list).
469 """
469 """
470 __slots__ = ("_name", "_doc")
470 __slots__ = ("_name", "_doc")
471
471
472 def __init__(self, name, doc=None):
472 def __init__(self, name, doc=None):
473 self._name = name
473 self._name = name
474 self._doc = doc
474 self._doc = doc
475
475
476 def key(self):
476 def key(self):
477 return self._name
477 return self._name
478
478
479 def doc(self, obj):
479 def doc(self, obj):
480 if self._doc is None:
480 if self._doc is None:
481 return getattr(obj, self._name).__doc__
481 return getattr(obj, self._name).__doc__
482 return self._doc
482 return self._doc
483
483
484 def attrtype(self, obj):
484 def attrtype(self, obj):
485 return "itermethod"
485 return "itermethod"
486
486
487 def valuetype(self, obj):
487 def valuetype(self, obj):
488 return noitem
488 return noitem
489
489
490 def value(self, obj):
490 def value(self, obj):
491 return noitem
491 return noitem
492
492
493 def iter(self, obj):
493 def iter(self, obj):
494 return xiter(getattr(obj, self._name)())
494 return xiter(getattr(obj, self._name)())
495
495
496 def __repr__(self):
496 def __repr__(self):
497 if self._doc is None:
497 if self._doc is None:
498 return "IterMethod(%r)" % self._name
498 return "IterMethod(%r)" % self._name
499 else:
499 else:
500 return "IterMethod(%r, %r)" % (self._name, self._doc)
500 return "IterMethod(%r, %r)" % (self._name, self._doc)
501
501
502
502
503 class FunctionDescriptor(Descriptor):
503 class FunctionDescriptor(Descriptor):
504 """
504 """
505 A ``FunctionDescriptor`` turns a function into a descriptor. The function
505 A ``FunctionDescriptor`` turns a function into a descriptor. The function
506 will be called with the object to get the type and value of the attribute.
506 will be called with the object to get the type and value of the attribute.
507 """
507 """
508 __slots__ = ("_function", "_name", "_doc")
508 __slots__ = ("_function", "_name", "_doc")
509
509
510 def __init__(self, function, name=None, doc=None):
510 def __init__(self, function, name=None, doc=None):
511 self._function = function
511 self._function = function
512 self._name = name
512 self._name = name
513 self._doc = doc
513 self._doc = doc
514
514
515 def key(self):
515 def key(self):
516 return self._function
516 return self._function
517
517
518 def name(self):
518 def name(self):
519 if self._name is not None:
519 if self._name is not None:
520 return self._name
520 return self._name
521 return getattr(self._function, "__xname__", self._function.__name__)
521 return getattr(self._function, "__xname__", self._function.__name__)
522
522
523 def doc(self, obj):
523 def doc(self, obj):
524 if self._doc is None:
524 if self._doc is None:
525 return self._function.__doc__
525 return self._function.__doc__
526 return self._doc
526 return self._doc
527
527
528 def attrtype(self, obj):
528 def attrtype(self, obj):
529 return "function"
529 return "function"
530
530
531 def valuetype(self, obj):
531 def valuetype(self, obj):
532 return type(self._function(obj))
532 return type(self._function(obj))
533
533
534 def value(self, obj):
534 def value(self, obj):
535 return self._function(obj)
535 return self._function(obj)
536
536
537 def __repr__(self):
537 def __repr__(self):
538 if self._doc is None:
538 if self._doc is None:
539 return "Function(%r)" % self._name
539 return "Function(%r)" % self._name
540 else:
540 else:
541 return "Function(%r, %r)" % (self._name, self._doc)
541 return "Function(%r, %r)" % (self._name, self._doc)
542
542
543
543
544 class Table(object):
544 class Table(object):
545 """
545 """
546 A ``Table`` is an object that produces items (just like a normal Python
546 A ``Table`` is an object that produces items (just like a normal Python
547 iterator/generator does) and can be used as the first object in a pipeline
547 iterator/generator does) and can be used as the first object in a pipeline
548 expression. The displayhook will open the default browser for such an object
548 expression. The displayhook will open the default browser for such an object
549 (instead of simply printing the ``repr()`` result).
549 (instead of simply printing the ``repr()`` result).
550 """
550 """
551
551
552 # We want to support ``foo`` and ``foo()`` in pipeline expression:
552 # We want to support ``foo`` and ``foo()`` in pipeline expression:
553 # So we implement the required operators (``|`` and ``+``) in the metaclass,
553 # So we implement the required operators (``|`` and ``+``) in the metaclass,
554 # instantiate the class and forward the operator to the instance
554 # instantiate the class and forward the operator to the instance
555 class __metaclass__(type):
555 class __metaclass__(type):
556 def __iter__(self):
556 def __iter__(self):
557 return iter(self())
557 return iter(self())
558
558
559 def __or__(self, other):
559 def __or__(self, other):
560 return self() | other
560 return self() | other
561
561
562 def __add__(self, other):
562 def __add__(self, other):
563 return self() + other
563 return self() + other
564
564
565 def __radd__(self, other):
565 def __radd__(self, other):
566 return other + self()
566 return other + self()
567
567
568 def __getitem__(self, index):
568 def __getitem__(self, index):
569 return self()[index]
569 return self()[index]
570
570
571 def __getitem__(self, index):
571 def __getitem__(self, index):
572 return item(self, index)
572 return item(self, index)
573
573
574 def __contains__(self, item):
574 def __contains__(self, item):
575 for haveitem in self:
575 for haveitem in self:
576 if item == haveitem:
576 if item == haveitem:
577 return True
577 return True
578 return False
578 return False
579
579
580 def __or__(self, other):
580 def __or__(self, other):
581 # autoinstantiate right hand side
581 # autoinstantiate right hand side
582 if isinstance(other, type) and issubclass(other, (Table, Display)):
582 if isinstance(other, type) and issubclass(other, (Table, Display)):
583 other = other()
583 other = other()
584 # treat simple strings and functions as ``ieval`` instances
584 # treat simple strings and functions as ``ieval`` instances
585 elif not isinstance(other, Display) and not isinstance(other, Table):
585 elif not isinstance(other, Display) and not isinstance(other, Table):
586 other = ieval(other)
586 other = ieval(other)
587 # forward operations to the right hand side
587 # forward operations to the right hand side
588 return other.__ror__(self)
588 return other.__ror__(self)
589
589
590 def __add__(self, other):
590 def __add__(self, other):
591 # autoinstantiate right hand side
591 # autoinstantiate right hand side
592 if isinstance(other, type) and issubclass(other, Table):
592 if isinstance(other, type) and issubclass(other, Table):
593 other = other()
593 other = other()
594 return ichain(self, other)
594 return ichain(self, other)
595
595
596 def __radd__(self, other):
596 def __radd__(self, other):
597 # autoinstantiate left hand side
597 # autoinstantiate left hand side
598 if isinstance(other, type) and issubclass(other, Table):
598 if isinstance(other, type) and issubclass(other, Table):
599 other = other()
599 other = other()
600 return ichain(other, self)
600 return ichain(other, self)
601
601
602
602
603 class Pipe(Table):
603 class Pipe(Table):
604 """
604 """
605 A ``Pipe`` is an object that can be used in a pipeline expression. It
605 A ``Pipe`` is an object that can be used in a pipeline expression. It
606 processes the objects it gets from its input ``Table``/``Pipe``. Note that
606 processes the objects it gets from its input ``Table``/``Pipe``. Note that
607 a ``Pipe`` object can't be used as the first object in a pipeline
607 a ``Pipe`` object can't be used as the first object in a pipeline
608 expression, as it doesn't produces items itself.
608 expression, as it doesn't produces items itself.
609 """
609 """
610 class __metaclass__(Table.__metaclass__):
610 class __metaclass__(Table.__metaclass__):
611 def __ror__(self, input):
611 def __ror__(self, input):
612 return input | self()
612 return input | self()
613
613
614 def __ror__(self, input):
614 def __ror__(self, input):
615 # autoinstantiate left hand side
615 # autoinstantiate left hand side
616 if isinstance(input, type) and issubclass(input, Table):
616 if isinstance(input, type) and issubclass(input, Table):
617 input = input()
617 input = input()
618 self.input = input
618 self.input = input
619 return self
619 return self
620
620
621
621
622 def xrepr(item, mode="default"):
622 def xrepr(item, mode="default"):
623 """
623 """
624 Generic function that adds color output and different display modes to ``repr``.
624 Generic function that adds color output and different display modes to ``repr``.
625
625
626 The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
626 The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
627 tuples. The ``style`` in this tuple must be a ``Style`` object from the
627 tuples. The ``style`` in this tuple must be a ``Style`` object from the
628 ``astring`` module. To reconfigure the output the first yielded tuple can be
628 ``astring`` module. To reconfigure the output the first yielded tuple can be
629 a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
629 a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
630 ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
630 ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
631 aligned (the default is left alignment). ``full`` is a boolean that specifies
631 aligned (the default is left alignment). ``full`` is a boolean that specifies
632 whether the complete output must be displayed or the ``Display`` object is
632 whether the complete output must be displayed or the ``Display`` object is
633 allowed to stop output after enough text has been produced (e.g. a syntax
633 allowed to stop output after enough text has been produced (e.g. a syntax
634 highlighted text line would use ``True``, but for a large data structure
634 highlighted text line would use ``True``, but for a large data structure
635 (i.e. a nested list, tuple or dictionary) ``False`` would be used).
635 (i.e. a nested list, tuple or dictionary) ``False`` would be used).
636 The default is full output.
636 The default is full output.
637
637
638 There are four different possible values for ``mode`` depending on where
638 There are four different possible values for ``mode`` depending on where
639 the ``Display`` object will display ``item``:
639 the ``Display`` object will display ``item``:
640
640
641 * ``"header"``: ``item`` will be displayed in a header line (this is used by
641 * ``"header"``: ``item`` will be displayed in a header line (this is used by
642 ``ibrowse``).
642 ``ibrowse``).
643 * ``"footer"``: ``item`` will be displayed in a footer line (this is used by
643 * ``"footer"``: ``item`` will be displayed in a footer line (this is used by
644 ``ibrowse``).
644 ``ibrowse``).
645 * ``"cell"``: ``item`` will be displayed in a table cell/list.
645 * ``"cell"``: ``item`` will be displayed in a table cell/list.
646 * ``"default"``: default mode. If an ``xrepr`` implementation recursively
646 * ``"default"``: default mode. If an ``xrepr`` implementation recursively
647 outputs objects, ``"default"`` must be passed in the recursive calls to
647 outputs objects, ``"default"`` must be passed in the recursive calls to
648 ``xrepr``.
648 ``xrepr``.
649
649
650 If no implementation is registered for ``item``, ``xrepr`` will try the
650 If no implementation is registered for ``item``, ``xrepr`` will try the
651 ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
651 ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
652 method it falls back to ``repr``/``__repr__`` for all modes.
652 method it falls back to ``repr``/``__repr__`` for all modes.
653 """
653 """
654 try:
654 try:
655 func = item.__xrepr__
655 func = item.__xrepr__
656 except AttributeError:
656 except AttributeError:
657 yield (astyle.style_default, repr(item))
657 yield (astyle.style_default, repr(item))
658 else:
658 else:
659 try:
659 try:
660 for x in func(mode):
660 for x in func(mode):
661 yield x
661 yield x
662 except (KeyboardInterrupt, SystemExit):
662 except (KeyboardInterrupt, SystemExit):
663 raise
663 raise
664 except Exception:
664 except Exception:
665 yield (astyle.style_default, repr(item))
665 yield (astyle.style_default, repr(item))
666 xrepr = simplegeneric.generic(xrepr)
666 xrepr = simplegeneric.generic(xrepr)
667
667
668
668
669 def xrepr_none(self, mode="default"):
669 def xrepr_none(self, mode="default"):
670 yield (astyle.style_type_none, repr(self))
670 yield (astyle.style_type_none, repr(self))
671 xrepr.when_object(None)(xrepr_none)
671 xrepr.when_object(None)(xrepr_none)
672
672
673
673
674 def xrepr_noitem(self, mode="default"):
674 def xrepr_noitem(self, mode="default"):
675 yield (2, True)
675 yield (2, True)
676 yield (astyle.style_nodata, "<?>")
676 yield (astyle.style_nodata, "<?>")
677 xrepr.when_object(noitem)(xrepr_noitem)
677 xrepr.when_object(noitem)(xrepr_noitem)
678
678
679
679
680 def xrepr_bool(self, mode="default"):
680 def xrepr_bool(self, mode="default"):
681 yield (astyle.style_type_bool, repr(self))
681 yield (astyle.style_type_bool, repr(self))
682 xrepr.when_type(bool)(xrepr_bool)
682 xrepr.when_type(bool)(xrepr_bool)
683
683
684
684
685 def xrepr_str(self, mode="default"):
685 def xrepr_str(self, mode="default"):
686 if mode == "cell":
686 if mode == "cell":
687 yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
687 yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
688 else:
688 else:
689 yield (astyle.style_default, repr(self))
689 yield (astyle.style_default, repr(self))
690 xrepr.when_type(str)(xrepr_str)
690 xrepr.when_type(str)(xrepr_str)
691
691
692
692
693 def xrepr_unicode(self, mode="default"):
693 def xrepr_unicode(self, mode="default"):
694 if mode == "cell":
694 if mode == "cell":
695 yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
695 yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
696 else:
696 else:
697 yield (astyle.style_default, repr(self))
697 yield (astyle.style_default, repr(self))
698 xrepr.when_type(unicode)(xrepr_unicode)
698 xrepr.when_type(unicode)(xrepr_unicode)
699
699
700
700
701 def xrepr_number(self, mode="default"):
701 def xrepr_number(self, mode="default"):
702 yield (1, True)
702 yield (1, True)
703 yield (astyle.style_type_number, repr(self))
703 yield (astyle.style_type_number, repr(self))
704 xrepr.when_type(int)(xrepr_number)
704 xrepr.when_type(int)(xrepr_number)
705 xrepr.when_type(long)(xrepr_number)
705 xrepr.when_type(long)(xrepr_number)
706 xrepr.when_type(float)(xrepr_number)
706 xrepr.when_type(float)(xrepr_number)
707
707
708
708
709 def xrepr_complex(self, mode="default"):
709 def xrepr_complex(self, mode="default"):
710 yield (astyle.style_type_number, repr(self))
710 yield (astyle.style_type_number, repr(self))
711 xrepr.when_type(complex)(xrepr_number)
711 xrepr.when_type(complex)(xrepr_number)
712
712
713
713
714 def xrepr_datetime(self, mode="default"):
714 def xrepr_datetime(self, mode="default"):
715 if mode == "cell":
715 if mode == "cell":
716 # Don't use strftime() here, as this requires year >= 1900
716 # Don't use strftime() here, as this requires year >= 1900
717 yield (astyle.style_type_datetime,
717 yield (astyle.style_type_datetime,
718 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
718 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
719 (self.year, self.month, self.day,
719 (self.year, self.month, self.day,
720 self.hour, self.minute, self.second,
720 self.hour, self.minute, self.second,
721 self.microsecond),
721 self.microsecond),
722 )
722 )
723 else:
723 else:
724 yield (astyle.style_type_datetime, repr(self))
724 yield (astyle.style_type_datetime, repr(self))
725 xrepr.when_type(datetime.datetime)(xrepr_datetime)
725 xrepr.when_type(datetime.datetime)(xrepr_datetime)
726
726
727
727
728 def xrepr_date(self, mode="default"):
728 def xrepr_date(self, mode="default"):
729 if mode == "cell":
729 if mode == "cell":
730 yield (astyle.style_type_datetime,
730 yield (astyle.style_type_datetime,
731 "%04d-%02d-%02d" % (self.year, self.month, self.day))
731 "%04d-%02d-%02d" % (self.year, self.month, self.day))
732 else:
732 else:
733 yield (astyle.style_type_datetime, repr(self))
733 yield (astyle.style_type_datetime, repr(self))
734 xrepr.when_type(datetime.date)(xrepr_date)
734 xrepr.when_type(datetime.date)(xrepr_date)
735
735
736
736
737 def xrepr_time(self, mode="default"):
737 def xrepr_time(self, mode="default"):
738 if mode == "cell":
738 if mode == "cell":
739 yield (astyle.style_type_datetime,
739 yield (astyle.style_type_datetime,
740 "%02d:%02d:%02d.%06d" % \
740 "%02d:%02d:%02d.%06d" % \
741 (self.hour, self.minute, self.second, self.microsecond))
741 (self.hour, self.minute, self.second, self.microsecond))
742 else:
742 else:
743 yield (astyle.style_type_datetime, repr(self))
743 yield (astyle.style_type_datetime, repr(self))
744 xrepr.when_type(datetime.time)(xrepr_time)
744 xrepr.when_type(datetime.time)(xrepr_time)
745
745
746
746
747 def xrepr_timedelta(self, mode="default"):
747 def xrepr_timedelta(self, mode="default"):
748 yield (astyle.style_type_datetime, repr(self))
748 yield (astyle.style_type_datetime, repr(self))
749 xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
749 xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
750
750
751
751
752 def xrepr_type(self, mode="default"):
752 def xrepr_type(self, mode="default"):
753 if self.__module__ == "__builtin__":
753 if self.__module__ == "__builtin__":
754 yield (astyle.style_type_type, self.__name__)
754 yield (astyle.style_type_type, self.__name__)
755 else:
755 else:
756 yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
756 yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
757 xrepr.when_type(type)(xrepr_type)
757 xrepr.when_type(type)(xrepr_type)
758
758
759
759
760 def xrepr_exception(self, mode="default"):
760 def xrepr_exception(self, mode="default"):
761 if self.__class__.__module__ == "exceptions":
761 if self.__class__.__module__ == "exceptions":
762 classname = self.__class__.__name__
762 classname = self.__class__.__name__
763 else:
763 else:
764 classname = "%s.%s" % \
764 classname = "%s.%s" % \
765 (self.__class__.__module__, self.__class__.__name__)
765 (self.__class__.__module__, self.__class__.__name__)
766 if mode == "header" or mode == "footer":
766 if mode == "header" or mode == "footer":
767 yield (astyle.style_error, "%s: %s" % (classname, self))
767 yield (astyle.style_error, "%s: %s" % (classname, self))
768 else:
768 else:
769 yield (astyle.style_error, classname)
769 yield (astyle.style_error, classname)
770 xrepr.when_type(Exception)(xrepr_exception)
770 xrepr.when_type(Exception)(xrepr_exception)
771
771
772
772
773 def xrepr_listtuple(self, mode="default"):
773 def xrepr_listtuple(self, mode="default"):
774 if mode == "header" or mode == "footer":
774 if mode == "header" or mode == "footer":
775 if self.__class__.__module__ == "__builtin__":
775 if self.__class__.__module__ == "__builtin__":
776 classname = self.__class__.__name__
776 classname = self.__class__.__name__
777 else:
777 else:
778 classname = "%s.%s" % \
778 classname = "%s.%s" % \
779 (self.__class__.__module__,self.__class__.__name__)
779 (self.__class__.__module__,self.__class__.__name__)
780 yield (astyle.style_default,
780 yield (astyle.style_default,
781 "<%s object with %d items at 0x%x>" % \
781 "<%s object with %d items at 0x%x>" % \
782 (classname, len(self), id(self)))
782 (classname, len(self), id(self)))
783 else:
783 else:
784 yield (-1, False)
784 yield (-1, False)
785 if isinstance(self, list):
785 if isinstance(self, list):
786 yield (astyle.style_default, "[")
786 yield (astyle.style_default, "[")
787 end = "]"
787 end = "]"
788 else:
788 else:
789 yield (astyle.style_default, "(")
789 yield (astyle.style_default, "(")
790 end = ")"
790 end = ")"
791 for (i, subself) in enumerate(self):
791 for (i, subself) in enumerate(self):
792 if i:
792 if i:
793 yield (astyle.style_default, ", ")
793 yield (astyle.style_default, ", ")
794 for part in xrepr(subself, "default"):
794 for part in xrepr(subself, "default"):
795 yield part
795 yield part
796 yield (astyle.style_default, end)
796 yield (astyle.style_default, end)
797 xrepr.when_type(list)(xrepr_listtuple)
797 xrepr.when_type(list)(xrepr_listtuple)
798 xrepr.when_type(tuple)(xrepr_listtuple)
798 xrepr.when_type(tuple)(xrepr_listtuple)
799
799
800
800
801 def xrepr_dict(self, mode="default"):
801 def xrepr_dict(self, mode="default"):
802 if mode == "header" or mode == "footer":
802 if mode == "header" or mode == "footer":
803 if self.__class__.__module__ == "__builtin__":
803 if self.__class__.__module__ == "__builtin__":
804 classname = self.__class__.__name__
804 classname = self.__class__.__name__
805 else:
805 else:
806 classname = "%s.%s" % \
806 classname = "%s.%s" % \
807 (self.__class__.__module__,self.__class__.__name__)
807 (self.__class__.__module__,self.__class__.__name__)
808 yield (astyle.style_default,
808 yield (astyle.style_default,
809 "<%s object with %d items at 0x%x>" % \
809 "<%s object with %d items at 0x%x>" % \
810 (classname, len(self), id(self)))
810 (classname, len(self), id(self)))
811 else:
811 else:
812 yield (-1, False)
812 yield (-1, False)
813 if isinstance(self, dict):
813 if isinstance(self, dict):
814 yield (astyle.style_default, "{")
814 yield (astyle.style_default, "{")
815 end = "}"
815 end = "}"
816 else:
816 else:
817 yield (astyle.style_default, "dictproxy((")
817 yield (astyle.style_default, "dictproxy((")
818 end = "})"
818 end = "})"
819 for (i, (key, value)) in enumerate(self.iteritems()):
819 for (i, (key, value)) in enumerate(self.iteritems()):
820 if i:
820 if i:
821 yield (astyle.style_default, ", ")
821 yield (astyle.style_default, ", ")
822 for part in xrepr(key, "default"):
822 for part in xrepr(key, "default"):
823 yield part
823 yield part
824 yield (astyle.style_default, ": ")
824 yield (astyle.style_default, ": ")
825 for part in xrepr(value, "default"):
825 for part in xrepr(value, "default"):
826 yield part
826 yield part
827 yield (astyle.style_default, end)
827 yield (astyle.style_default, end)
828 xrepr.when_type(dict)(xrepr_dict)
828 xrepr.when_type(dict)(xrepr_dict)
829 xrepr.when_type(types.DictProxyType)(xrepr_dict)
829 xrepr.when_type(types.DictProxyType)(xrepr_dict)
830
830
831
831
832 def upgradexattr(attr):
832 def upgradexattr(attr):
833 """
833 """
834 Convert an attribute descriptor string to a real descriptor object.
834 Convert an attribute descriptor string to a real descriptor object.
835
835
836 If attr already is a descriptor object return if unmodified. A
836 If attr already is a descriptor object return if unmodified. A
837 ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
837 ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
838 returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
838 returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
839 ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
839 ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
840 ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
840 ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
841 named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
841 named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
842 for the method named ``"foo"``. Furthermore integer will return the appropriate
842 for the method named ``"foo"``. Furthermore integer will return the appropriate
843 ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
843 ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
844 """
844 """
845 if attr is None:
845 if attr is None:
846 return selfdescriptor
846 return selfdescriptor
847 elif isinstance(attr, Descriptor):
847 elif isinstance(attr, Descriptor):
848 return attr
848 return attr
849 elif isinstance(attr, str):
849 elif isinstance(attr, str):
850 if attr.endswith("()"):
850 if attr.endswith("()"):
851 if attr.startswith("-"):
851 if attr.startswith("-"):
852 return IterMethodDescriptor(attr[1:-2])
852 return IterMethodDescriptor(attr[1:-2])
853 else:
853 else:
854 return MethodDescriptor(attr[:-2])
854 return MethodDescriptor(attr[:-2])
855 else:
855 else:
856 if attr.startswith("-"):
856 if attr.startswith("-"):
857 return IterAttributeDescriptor(attr[1:])
857 return IterAttributeDescriptor(attr[1:])
858 else:
858 else:
859 return AttributeDescriptor(attr)
859 return AttributeDescriptor(attr)
860 elif isinstance(attr, (int, long)):
860 elif isinstance(attr, (int, long)):
861 return IndexDescriptor(attr)
861 return IndexDescriptor(attr)
862 elif callable(attr):
862 elif callable(attr):
863 return FunctionDescriptor(attr)
863 return FunctionDescriptor(attr)
864 else:
864 else:
865 raise TypeError("can't handle descriptor %r" % attr)
865 raise TypeError("can't handle descriptor %r" % attr)
866
866
867
867
868 def xattrs(item, mode="default"):
868 def xattrs(item, mode="default"):
869 """
869 """
870 Generic function that returns an iterable of attribute descriptors
870 Generic function that returns an iterable of attribute descriptors
871 to be used for displaying the attributes ob the object ``item`` in display
871 to be used for displaying the attributes ob the object ``item`` in display
872 mode ``mode``.
872 mode ``mode``.
873
873
874 There are two possible modes:
874 There are two possible modes:
875
875
876 * ``"detail"``: The ``Display`` object wants to display a detailed list
876 * ``"detail"``: The ``Display`` object wants to display a detailed list
877 of the object attributes.
877 of the object attributes.
878 * ``"default"``: The ``Display`` object wants to display the object in a
878 * ``"default"``: The ``Display`` object wants to display the object in a
879 list view.
879 list view.
880
880
881 If no implementation is registered for the object ``item`` ``xattrs`` falls
881 If no implementation is registered for the object ``item`` ``xattrs`` falls
882 back to trying the ``__xattrs__`` method of the object. If this doesn't
882 back to trying the ``__xattrs__`` method of the object. If this doesn't
883 exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
883 exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
884 for ``"default"`` mode.
884 for ``"default"`` mode.
885
885
886 The implementation must yield attribute descriptor (see the class
886 The implementation must yield attribute descriptor (see the class
887 ``Descriptor`` for more info). The ``__xattrs__`` method may also return
887 ``Descriptor`` for more info). The ``__xattrs__`` method may also return
888 attribute descriptor string (and ``None``) which will be converted to real
888 attribute descriptor string (and ``None``) which will be converted to real
889 descriptors by ``upgradexattr()``.
889 descriptors by ``upgradexattr()``.
890 """
890 """
891 try:
891 try:
892 func = item.__xattrs__
892 func = item.__xattrs__
893 except AttributeError:
893 except AttributeError:
894 if mode == "detail":
894 if mode == "detail":
895 for attrname in dir(item):
895 for attrname in dir(item):
896 yield AttributeDescriptor(attrname)
896 yield AttributeDescriptor(attrname)
897 else:
897 else:
898 yield selfdescriptor
898 yield selfdescriptor
899 else:
899 else:
900 for attr in func(mode):
900 for attr in func(mode):
901 yield upgradexattr(attr)
901 yield upgradexattr(attr)
902 xattrs = simplegeneric.generic(xattrs)
902 xattrs = simplegeneric.generic(xattrs)
903
903
904
904
905 def xattrs_complex(self, mode="default"):
905 def xattrs_complex(self, mode="default"):
906 if mode == "detail":
906 if mode == "detail":
907 return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
907 return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
908 return (selfdescriptor,)
908 return (selfdescriptor,)
909 xattrs.when_type(complex)(xattrs_complex)
909 xattrs.when_type(complex)(xattrs_complex)
910
910
911
911
912 def _isdict(item):
912 def _isdict(item):
913 try:
913 try:
914 itermeth = item.__class__.__iter__
914 itermeth = item.__class__.__iter__
915 except (AttributeError, TypeError):
915 except (AttributeError, TypeError):
916 return False
916 return False
917 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
917 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
918
918
919
919
920 def _isstr(item):
920 def _isstr(item):
921 if not isinstance(item, basestring):
921 if not isinstance(item, basestring):
922 return False
922 return False
923 try:
923 try:
924 itermeth = item.__class__.__iter__
924 itermeth = item.__class__.__iter__
925 except AttributeError:
925 except AttributeError:
926 return True
926 return True
927 return False # ``__iter__`` has been redefined
927 return False # ``__iter__`` has been redefined
928
928
929
929
930 def xiter(item):
930 def xiter(item):
931 """
931 """
932 Generic function that implements iteration for pipeline expression. If no
932 Generic function that implements iteration for pipeline expression. If no
933 implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
933 implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
934 """
934 """
935 try:
935 try:
936 func = item.__xiter__
936 func = item.__xiter__
937 except AttributeError:
937 except AttributeError:
938 if _isdict(item):
938 if _isdict(item):
939 def items(item):
939 def items(item):
940 fields = ("key", "value")
940 fields = ("key", "value")
941 for (key, value) in item.iteritems():
941 for (key, value) in item.iteritems():
942 yield Fields(fields, key=key, value=value)
942 yield Fields(fields, key=key, value=value)
943 return items(item)
943 return items(item)
944 elif isinstance(item, new.module):
944 elif isinstance(item, new.module):
945 def items(item):
945 def items(item):
946 fields = ("key", "value")
946 fields = ("key", "value")
947 for key in sorted(item.__dict__):
947 for key in sorted(item.__dict__):
948 yield Fields(fields, key=key, value=getattr(item, key))
948 yield Fields(fields, key=key, value=getattr(item, key))
949 return items(item)
949 return items(item)
950 elif _isstr(item):
950 elif _isstr(item):
951 if not item:
951 if not item:
952 raise ValueError("can't enter empty string")
952 raise ValueError("can't enter empty string")
953 lines = item.splitlines()
953 lines = item.splitlines()
954 if len(lines) == 1:
954 if len(lines) == 1:
955 def iterone(item):
955 def iterone(item):
956 yield item
956 yield item
957 return iterone(item)
957 return iterone(item)
958 else:
958 else:
959 return iter(lines)
959 return iter(lines)
960 return iter(item)
960 return iter(item)
961 else:
961 else:
962 return iter(func()) # iter() just to be safe
962 return iter(func()) # iter() just to be safe
963 xiter = simplegeneric.generic(xiter)
963 xiter = simplegeneric.generic(xiter)
964
964
965
965
966 class ichain(Pipe):
966 class ichain(Pipe):
967 """
967 """
968 Chains multiple ``Table``s into one.
968 Chains multiple ``Table``s into one.
969 """
969 """
970
970
971 def __init__(self, *iters):
971 def __init__(self, *iters):
972 self.iters = iters
972 self.iters = iters
973
973
974 def __iter__(self):
974 def __iter__(self):
975 return itertools.chain(*self.iters)
975 return itertools.chain(*self.iters)
976
976
977 def __xrepr__(self, mode="default"):
977 def __xrepr__(self, mode="default"):
978 if mode == "header" or mode == "footer":
978 if mode == "header" or mode == "footer":
979 for (i, item) in enumerate(self.iters):
979 for (i, item) in enumerate(self.iters):
980 if i:
980 if i:
981 yield (astyle.style_default, "+")
981 yield (astyle.style_default, "+")
982 if isinstance(item, Pipe):
982 if isinstance(item, Pipe):
983 yield (astyle.style_default, "(")
983 yield (astyle.style_default, "(")
984 for part in xrepr(item, mode):
984 for part in xrepr(item, mode):
985 yield part
985 yield part
986 if isinstance(item, Pipe):
986 if isinstance(item, Pipe):
987 yield (astyle.style_default, ")")
987 yield (astyle.style_default, ")")
988 else:
988 else:
989 yield (astyle.style_default, repr(self))
989 yield (astyle.style_default, repr(self))
990
990
991 def __repr__(self):
991 def __repr__(self):
992 args = ", ".join([repr(it) for it in self.iters])
992 args = ", ".join([repr(it) for it in self.iters])
993 return "%s.%s(%s)" % \
993 return "%s.%s(%s)" % \
994 (self.__class__.__module__, self.__class__.__name__, args)
994 (self.__class__.__module__, self.__class__.__name__, args)
995
995
996
996
997 class ifile(path.path):
997 class ifile(path.path):
998 """
998 """
999 file (or directory) object.
999 file (or directory) object.
1000 """
1000 """
1001
1001
1002 def getmode(self):
1002 def getmode(self):
1003 return self.stat().st_mode
1003 return self.stat().st_mode
1004 mode = property(getmode, None, None, "Access mode")
1004 mode = property(getmode, None, None, "Access mode")
1005
1005
1006 def gettype(self):
1006 def gettype(self):
1007 data = [
1007 data = [
1008 (stat.S_ISREG, "file"),
1008 (stat.S_ISREG, "file"),
1009 (stat.S_ISDIR, "dir"),
1009 (stat.S_ISDIR, "dir"),
1010 (stat.S_ISCHR, "chardev"),
1010 (stat.S_ISCHR, "chardev"),
1011 (stat.S_ISBLK, "blockdev"),
1011 (stat.S_ISBLK, "blockdev"),
1012 (stat.S_ISFIFO, "fifo"),
1012 (stat.S_ISFIFO, "fifo"),
1013 (stat.S_ISLNK, "symlink"),
1013 (stat.S_ISLNK, "symlink"),
1014 (stat.S_ISSOCK,"socket"),
1014 (stat.S_ISSOCK,"socket"),
1015 ]
1015 ]
1016 lstat = self.lstat()
1016 lstat = self.lstat()
1017 if lstat is not None:
1017 if lstat is not None:
1018 types = set([text for (func, text) in data if func(lstat.st_mode)])
1018 types = set([text for (func, text) in data if func(lstat.st_mode)])
1019 else:
1019 else:
1020 types = set()
1020 types = set()
1021 m = self.mode
1021 m = self.mode
1022 types.update([text for (func, text) in data if func(m)])
1022 types.update([text for (func, text) in data if func(m)])
1023 return ", ".join(types)
1023 return ", ".join(types)
1024 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
1024 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
1025
1025
1026 def getmodestr(self):
1026 def getmodestr(self):
1027 m = self.mode
1027 m = self.mode
1028 data = [
1028 data = [
1029 (stat.S_IRUSR, "-r"),
1029 (stat.S_IRUSR, "-r"),
1030 (stat.S_IWUSR, "-w"),
1030 (stat.S_IWUSR, "-w"),
1031 (stat.S_IXUSR, "-x"),
1031 (stat.S_IXUSR, "-x"),
1032 (stat.S_IRGRP, "-r"),
1032 (stat.S_IRGRP, "-r"),
1033 (stat.S_IWGRP, "-w"),
1033 (stat.S_IWGRP, "-w"),
1034 (stat.S_IXGRP, "-x"),
1034 (stat.S_IXGRP, "-x"),
1035 (stat.S_IROTH, "-r"),
1035 (stat.S_IROTH, "-r"),
1036 (stat.S_IWOTH, "-w"),
1036 (stat.S_IWOTH, "-w"),
1037 (stat.S_IXOTH, "-x"),
1037 (stat.S_IXOTH, "-x"),
1038 ]
1038 ]
1039 return "".join([text[bool(m&bit)] for (bit, text) in data])
1039 return "".join([text[bool(m&bit)] for (bit, text) in data])
1040
1040
1041 modestr = property(getmodestr, None, None, "Access mode as string")
1041 modestr = property(getmodestr, None, None, "Access mode as string")
1042
1042
1043 def getblocks(self):
1043 def getblocks(self):
1044 return self.stat().st_blocks
1044 return self.stat().st_blocks
1045 blocks = property(getblocks, None, None, "File size in blocks")
1045 blocks = property(getblocks, None, None, "File size in blocks")
1046
1046
1047 def getblksize(self):
1047 def getblksize(self):
1048 return self.stat().st_blksize
1048 return self.stat().st_blksize
1049 blksize = property(getblksize, None, None, "Filesystem block size")
1049 blksize = property(getblksize, None, None, "Filesystem block size")
1050
1050
1051 def getdev(self):
1051 def getdev(self):
1052 return self.stat().st_dev
1052 return self.stat().st_dev
1053 dev = property(getdev)
1053 dev = property(getdev)
1054
1054
1055 def getnlink(self):
1055 def getnlink(self):
1056 return self.stat().st_nlink
1056 return self.stat().st_nlink
1057 nlink = property(getnlink, None, None, "Number of links")
1057 nlink = property(getnlink, None, None, "Number of links")
1058
1058
1059 def getuid(self):
1059 def getuid(self):
1060 return self.stat().st_uid
1060 return self.stat().st_uid
1061 uid = property(getuid, None, None, "User id of file owner")
1061 uid = property(getuid, None, None, "User id of file owner")
1062
1062
1063 def getgid(self):
1063 def getgid(self):
1064 return self.stat().st_gid
1064 return self.stat().st_gid
1065 gid = property(getgid, None, None, "Group id of file owner")
1065 gid = property(getgid, None, None, "Group id of file owner")
1066
1066
1067 def getowner(self):
1067 def getowner(self):
1068 stat = self.stat()
1068 stat = self.stat()
1069 try:
1069 try:
1070 return pwd.getpwuid(stat.st_uid).pw_name
1070 return pwd.getpwuid(stat.st_uid).pw_name
1071 except KeyError:
1071 except KeyError:
1072 return stat.st_uid
1072 return stat.st_uid
1073 owner = property(getowner, None, None, "Owner name (or id)")
1073 owner = property(getowner, None, None, "Owner name (or id)")
1074
1074
1075 def getgroup(self):
1075 def getgroup(self):
1076 stat = self.stat()
1076 stat = self.stat()
1077 try:
1077 try:
1078 return grp.getgrgid(stat.st_gid).gr_name
1078 return grp.getgrgid(stat.st_gid).gr_name
1079 except KeyError:
1079 except KeyError:
1080 return stat.st_gid
1080 return stat.st_gid
1081 group = property(getgroup, None, None, "Group name (or id)")
1081 group = property(getgroup, None, None, "Group name (or id)")
1082
1082
1083 def getadate(self):
1083 def getadate(self):
1084 return datetime.datetime.utcfromtimestamp(self.atime)
1084 return datetime.datetime.utcfromtimestamp(self.atime)
1085 adate = property(getadate, None, None, "Access date")
1085 adate = property(getadate, None, None, "Access date")
1086
1086
1087 def getcdate(self):
1087 def getcdate(self):
1088 return datetime.datetime.utcfromtimestamp(self.ctime)
1088 return datetime.datetime.utcfromtimestamp(self.ctime)
1089 cdate = property(getcdate, None, None, "Creation date")
1089 cdate = property(getcdate, None, None, "Creation date")
1090
1090
1091 def getmdate(self):
1091 def getmdate(self):
1092 return datetime.datetime.utcfromtimestamp(self.mtime)
1092 return datetime.datetime.utcfromtimestamp(self.mtime)
1093 mdate = property(getmdate, None, None, "Modification date")
1093 mdate = property(getmdate, None, None, "Modification date")
1094
1094
1095 def mimetype(self):
1095 def mimetype(self):
1096 """
1096 """
1097 Return MIME type guessed from the extension.
1097 Return MIME type guessed from the extension.
1098 """
1098 """
1099 return mimetypes.guess_type(self.basename())[0]
1099 return mimetypes.guess_type(self.basename())[0]
1100
1100
1101 def encoding(self):
1101 def encoding(self):
1102 """
1102 """
1103 Return guessed compression (like "compress" or "gzip").
1103 Return guessed compression (like "compress" or "gzip").
1104 """
1104 """
1105 return mimetypes.guess_type(self.basename())[1]
1105 return mimetypes.guess_type(self.basename())[1]
1106
1106
1107 def __repr__(self):
1107 def __repr__(self):
1108 return "ifile(%s)" % path._base.__repr__(self)
1108 return "ifile(%s)" % path._base.__repr__(self)
1109
1109
1110 if sys.platform == "win32":
1110 if sys.platform == "win32":
1111 defaultattrs = (None, "type", "size", "modestr", "mdate")
1111 defaultattrs = (None, "type", "size", "modestr", "mdate")
1112 else:
1112 else:
1113 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1113 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1114
1114
1115 def __xattrs__(self, mode="default"):
1115 def __xattrs__(self, mode="default"):
1116 if mode == "detail":
1116 if mode == "detail":
1117 return (
1117 return (
1118 "name",
1118 "name",
1119 "basename()",
1119 "basename()",
1120 "abspath()",
1120 "abspath()",
1121 "realpath()",
1121 "realpath()",
1122 "type",
1122 "type",
1123 "mode",
1123 "mode",
1124 "modestr",
1124 "modestr",
1125 "stat()",
1125 "stat()",
1126 "lstat()",
1126 "lstat()",
1127 "uid",
1127 "uid",
1128 "gid",
1128 "gid",
1129 "owner",
1129 "owner",
1130 "group",
1130 "group",
1131 "dev",
1131 "dev",
1132 "nlink",
1132 "nlink",
1133 "ctime",
1133 "ctime",
1134 "mtime",
1134 "mtime",
1135 "atime",
1135 "atime",
1136 "cdate",
1136 "cdate",
1137 "mdate",
1137 "mdate",
1138 "adate",
1138 "adate",
1139 "size",
1139 "size",
1140 "blocks",
1140 "blocks",
1141 "blksize",
1141 "blksize",
1142 "isdir()",
1142 "isdir()",
1143 "islink()",
1143 "islink()",
1144 "mimetype()",
1144 "mimetype()",
1145 "encoding()",
1145 "encoding()",
1146 "-listdir()",
1146 "-listdir()",
1147 "-dirs()",
1147 "-dirs()",
1148 "-files()",
1148 "-files()",
1149 "-walk()",
1149 "-walk()",
1150 "-walkdirs()",
1150 "-walkdirs()",
1151 "-walkfiles()",
1151 "-walkfiles()",
1152 )
1152 )
1153 else:
1153 else:
1154 return self.defaultattrs
1154 return self.defaultattrs
1155
1155
1156
1156
1157 def xiter_ifile(self):
1157 def xiter_ifile(self):
1158 if self.isdir():
1158 if self.isdir():
1159 yield (self / os.pardir).abspath()
1159 yield (self / os.pardir).abspath()
1160 for child in sorted(self.listdir()):
1160 for child in sorted(self.listdir()):
1161 yield child
1161 yield child
1162 else:
1162 else:
1163 f = self.open("rb")
1163 f = self.open("rb")
1164 for line in f:
1164 for line in f:
1165 yield line
1165 yield line
1166 f.close()
1166 f.close()
1167 xiter.when_type(ifile)(xiter_ifile)
1167 xiter.when_type(ifile)(xiter_ifile)
1168
1168
1169
1169
1170 # We need to implement ``xrepr`` for ``ifile`` as a generic function, because
1170 # We need to implement ``xrepr`` for ``ifile`` as a generic function, because
1171 # otherwise ``xrepr_str`` would kick in.
1171 # otherwise ``xrepr_str`` would kick in.
1172 def xrepr_ifile(self, mode="default"):
1172 def xrepr_ifile(self, mode="default"):
1173 try:
1173 try:
1174 if self.isdir():
1174 if self.isdir():
1175 name = "idir"
1175 name = "idir"
1176 style = astyle.style_dir
1176 style = astyle.style_dir
1177 else:
1177 else:
1178 name = "ifile"
1178 name = "ifile"
1179 style = astyle.style_file
1179 style = astyle.style_file
1180 except IOError:
1180 except IOError:
1181 name = "ifile"
1181 name = "ifile"
1182 style = astyle.style_default
1182 style = astyle.style_default
1183 if mode == "cell" or mode in "header" or mode == "footer":
1183 if mode == "cell" or mode in "header" or mode == "footer":
1184 abspath = repr(path._base(self.normpath()))
1184 abspath = repr(path._base(self.normpath()))
1185 if abspath.startswith("u"):
1185 if abspath.startswith("u"):
1186 abspath = abspath[2:-1]
1186 abspath = abspath[2:-1]
1187 else:
1187 else:
1188 abspath = abspath[1:-1]
1188 abspath = abspath[1:-1]
1189 if mode == "cell":
1189 if mode == "cell":
1190 yield (style, abspath)
1190 yield (style, abspath)
1191 else:
1191 else:
1192 yield (style, "%s(%s)" % (name, abspath))
1192 yield (style, "%s(%s)" % (name, abspath))
1193 else:
1193 else:
1194 yield (style, repr(self))
1194 yield (style, repr(self))
1195 xrepr.when_type(ifile)(xrepr_ifile)
1195 xrepr.when_type(ifile)(xrepr_ifile)
1196
1196
1197
1197
1198 class ils(Table):
1198 class ils(Table):
1199 """
1199 """
1200 List the current (or a specified) directory.
1200 List the current (or a specified) directory.
1201
1201
1202 Examples:
1202 Examples:
1203
1203
1204 >>> ils
1204 >>> ils
1205 >>> ils("/usr/local/lib/python2.4")
1205 >>> ils("/usr/local/lib/python2.4")
1206 >>> ils("~")
1206 >>> ils("~")
1207 """
1207 """
1208 def __init__(self, base=os.curdir, dirs=True, files=True):
1208 def __init__(self, base=os.curdir, dirs=True, files=True):
1209 self.base = os.path.expanduser(base)
1209 self.base = os.path.expanduser(base)
1210 self.dirs = dirs
1210 self.dirs = dirs
1211 self.files = files
1211 self.files = files
1212
1212
1213 def __iter__(self):
1213 def __iter__(self):
1214 base = ifile(self.base)
1214 base = ifile(self.base)
1215 yield (base / os.pardir).abspath()
1215 yield (base / os.pardir).abspath()
1216 for child in base.listdir():
1216 for child in base.listdir():
1217 if self.dirs:
1217 if self.dirs:
1218 if self.files:
1218 if self.files:
1219 yield child
1219 yield child
1220 else:
1220 else:
1221 if child.isdir():
1221 if child.isdir():
1222 yield child
1222 yield child
1223 elif self.files:
1223 elif self.files:
1224 if not child.isdir():
1224 if not child.isdir():
1225 yield child
1225 yield child
1226
1226
1227 def __xrepr__(self, mode="default"):
1227 def __xrepr__(self, mode="default"):
1228 return xrepr(ifile(self.base), mode)
1228 return xrepr(ifile(self.base), mode)
1229
1229
1230 def __repr__(self):
1230 def __repr__(self):
1231 return "%s.%s(%r)" % \
1231 return "%s.%s(%r)" % \
1232 (self.__class__.__module__, self.__class__.__name__, self.base)
1232 (self.__class__.__module__, self.__class__.__name__, self.base)
1233
1233
1234
1234
1235 class iglob(Table):
1235 class iglob(Table):
1236 """
1236 """
1237 List all files and directories matching a specified pattern.
1237 List all files and directories matching a specified pattern.
1238 (See ``glob.glob()`` for more info.).
1238 (See ``glob.glob()`` for more info.).
1239
1239
1240 Examples:
1240 Examples:
1241
1241
1242 >>> iglob("*.py")
1242 >>> iglob("*.py")
1243 """
1243 """
1244 def __init__(self, glob):
1244 def __init__(self, glob):
1245 self.glob = glob
1245 self.glob = glob
1246
1246
1247 def __iter__(self):
1247 def __iter__(self):
1248 for name in glob.glob(self.glob):
1248 for name in glob.glob(self.glob):
1249 yield ifile(name)
1249 yield ifile(name)
1250
1250
1251 def __xrepr__(self, mode="default"):
1251 def __xrepr__(self, mode="default"):
1252 if mode == "header" or mode == "footer" or mode == "cell":
1252 if mode == "header" or mode == "footer" or mode == "cell":
1253 yield (astyle.style_default,
1253 yield (astyle.style_default,
1254 "%s(%r)" % (self.__class__.__name__, self.glob))
1254 "%s(%r)" % (self.__class__.__name__, self.glob))
1255 else:
1255 else:
1256 yield (astyle.style_default, repr(self))
1256 yield (astyle.style_default, repr(self))
1257
1257
1258 def __repr__(self):
1258 def __repr__(self):
1259 return "%s.%s(%r)" % \
1259 return "%s.%s(%r)" % \
1260 (self.__class__.__module__, self.__class__.__name__, self.glob)
1260 (self.__class__.__module__, self.__class__.__name__, self.glob)
1261
1261
1262
1262
1263 class iwalk(Table):
1263 class iwalk(Table):
1264 """
1264 """
1265 List all files and directories in a directory and it's subdirectory.
1265 List all files and directories in a directory and it's subdirectory.
1266
1266
1267 >>> iwalk
1267 >>> iwalk
1268 >>> iwalk("/usr/local/lib/python2.4")
1268 >>> iwalk("/usr/local/lib/python2.4")
1269 >>> iwalk("~")
1269 >>> iwalk("~")
1270 """
1270 """
1271 def __init__(self, base=os.curdir, dirs=True, files=True):
1271 def __init__(self, base=os.curdir, dirs=True, files=True):
1272 self.base = os.path.expanduser(base)
1272 self.base = os.path.expanduser(base)
1273 self.dirs = dirs
1273 self.dirs = dirs
1274 self.files = files
1274 self.files = files
1275
1275
1276 def __iter__(self):
1276 def __iter__(self):
1277 for (dirpath, dirnames, filenames) in os.walk(self.base):
1277 for (dirpath, dirnames, filenames) in os.walk(self.base):
1278 if self.dirs:
1278 if self.dirs:
1279 for name in sorted(dirnames):
1279 for name in sorted(dirnames):
1280 yield ifile(os.path.join(dirpath, name))
1280 yield ifile(os.path.join(dirpath, name))
1281 if self.files:
1281 if self.files:
1282 for name in sorted(filenames):
1282 for name in sorted(filenames):
1283 yield ifile(os.path.join(dirpath, name))
1283 yield ifile(os.path.join(dirpath, name))
1284
1284
1285 def __xrepr__(self, mode="default"):
1285 def __xrepr__(self, mode="default"):
1286 if mode == "header" or mode == "footer" or mode == "cell":
1286 if mode == "header" or mode == "footer" or mode == "cell":
1287 yield (astyle.style_default,
1287 yield (astyle.style_default,
1288 "%s(%r)" % (self.__class__.__name__, self.base))
1288 "%s(%r)" % (self.__class__.__name__, self.base))
1289 else:
1289 else:
1290 yield (astyle.style_default, repr(self))
1290 yield (astyle.style_default, repr(self))
1291
1291
1292 def __repr__(self):
1292 def __repr__(self):
1293 return "%s.%s(%r)" % \
1293 return "%s.%s(%r)" % \
1294 (self.__class__.__module__, self.__class__.__name__, self.base)
1294 (self.__class__.__module__, self.__class__.__name__, self.base)
1295
1295
1296
1296
1297 class ipwdentry(object):
1297 class ipwdentry(object):
1298 """
1298 """
1299 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1299 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1300 password database.
1300 password database.
1301 """
1301 """
1302 def __init__(self, id):
1302 def __init__(self, id):
1303 self._id = id
1303 self._id = id
1304 self._entry = None
1304 self._entry = None
1305
1305
1306 def __eq__(self, other):
1306 def __eq__(self, other):
1307 return self.__class__ is other.__class__ and self._id == other._id
1307 return self.__class__ is other.__class__ and self._id == other._id
1308
1308
1309 def __ne__(self, other):
1309 def __ne__(self, other):
1310 return self.__class__ is not other.__class__ or self._id != other._id
1310 return self.__class__ is not other.__class__ or self._id != other._id
1311
1311
1312 def _getentry(self):
1312 def _getentry(self):
1313 if self._entry is None:
1313 if self._entry is None:
1314 if isinstance(self._id, basestring):
1314 if isinstance(self._id, basestring):
1315 self._entry = pwd.getpwnam(self._id)
1315 self._entry = pwd.getpwnam(self._id)
1316 else:
1316 else:
1317 self._entry = pwd.getpwuid(self._id)
1317 self._entry = pwd.getpwuid(self._id)
1318 return self._entry
1318 return self._entry
1319
1319
1320 def getname(self):
1320 def getname(self):
1321 if isinstance(self._id, basestring):
1321 if isinstance(self._id, basestring):
1322 return self._id
1322 return self._id
1323 else:
1323 else:
1324 return self._getentry().pw_name
1324 return self._getentry().pw_name
1325 name = property(getname, None, None, "User name")
1325 name = property(getname, None, None, "User name")
1326
1326
1327 def getpasswd(self):
1327 def getpasswd(self):
1328 return self._getentry().pw_passwd
1328 return self._getentry().pw_passwd
1329 passwd = property(getpasswd, None, None, "Password")
1329 passwd = property(getpasswd, None, None, "Password")
1330
1330
1331 def getuid(self):
1331 def getuid(self):
1332 if isinstance(self._id, basestring):
1332 if isinstance(self._id, basestring):
1333 return self._getentry().pw_uid
1333 return self._getentry().pw_uid
1334 else:
1334 else:
1335 return self._id
1335 return self._id
1336 uid = property(getuid, None, None, "User id")
1336 uid = property(getuid, None, None, "User id")
1337
1337
1338 def getgid(self):
1338 def getgid(self):
1339 return self._getentry().pw_gid
1339 return self._getentry().pw_gid
1340 gid = property(getgid, None, None, "Primary group id")
1340 gid = property(getgid, None, None, "Primary group id")
1341
1341
1342 def getgroup(self):
1342 def getgroup(self):
1343 return igrpentry(self.gid)
1343 return igrpentry(self.gid)
1344 group = property(getgroup, None, None, "Group")
1344 group = property(getgroup, None, None, "Group")
1345
1345
1346 def getgecos(self):
1346 def getgecos(self):
1347 return self._getentry().pw_gecos
1347 return self._getentry().pw_gecos
1348 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1348 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1349
1349
1350 def getdir(self):
1350 def getdir(self):
1351 return self._getentry().pw_dir
1351 return self._getentry().pw_dir
1352 dir = property(getdir, None, None, "$HOME directory")
1352 dir = property(getdir, None, None, "$HOME directory")
1353
1353
1354 def getshell(self):
1354 def getshell(self):
1355 return self._getentry().pw_shell
1355 return self._getentry().pw_shell
1356 shell = property(getshell, None, None, "Login shell")
1356 shell = property(getshell, None, None, "Login shell")
1357
1357
1358 def __xattrs__(self, mode="default"):
1358 def __xattrs__(self, mode="default"):
1359 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1359 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1360
1360
1361 def __repr__(self):
1361 def __repr__(self):
1362 return "%s.%s(%r)" % \
1362 return "%s.%s(%r)" % \
1363 (self.__class__.__module__, self.__class__.__name__, self._id)
1363 (self.__class__.__module__, self.__class__.__name__, self._id)
1364
1364
1365
1365
1366 class ipwd(Table):
1366 class ipwd(Table):
1367 """
1367 """
1368 List all entries in the Unix user account and password database.
1368 List all entries in the Unix user account and password database.
1369
1369
1370 Example:
1370 Example:
1371
1371
1372 >>> ipwd | isort("uid")
1372 >>> ipwd | isort("uid")
1373 """
1373 """
1374 def __iter__(self):
1374 def __iter__(self):
1375 for entry in pwd.getpwall():
1375 for entry in pwd.getpwall():
1376 yield ipwdentry(entry.pw_name)
1376 yield ipwdentry(entry.pw_name)
1377
1377
1378 def __xrepr__(self, mode="default"):
1378 def __xrepr__(self, mode="default"):
1379 if mode == "header" or mode == "footer" or mode == "cell":
1379 if mode == "header" or mode == "footer" or mode == "cell":
1380 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1380 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1381 else:
1381 else:
1382 yield (astyle.style_default, repr(self))
1382 yield (astyle.style_default, repr(self))
1383
1383
1384
1384
1385 class igrpentry(object):
1385 class igrpentry(object):
1386 """
1386 """
1387 ``igrpentry`` objects encapsulate entries in the Unix group database.
1387 ``igrpentry`` objects encapsulate entries in the Unix group database.
1388 """
1388 """
1389 def __init__(self, id):
1389 def __init__(self, id):
1390 self._id = id
1390 self._id = id
1391 self._entry = None
1391 self._entry = None
1392
1392
1393 def __eq__(self, other):
1393 def __eq__(self, other):
1394 return self.__class__ is other.__class__ and self._id == other._id
1394 return self.__class__ is other.__class__ and self._id == other._id
1395
1395
1396 def __ne__(self, other):
1396 def __ne__(self, other):
1397 return self.__class__ is not other.__class__ or self._id != other._id
1397 return self.__class__ is not other.__class__ or self._id != other._id
1398
1398
1399 def _getentry(self):
1399 def _getentry(self):
1400 if self._entry is None:
1400 if self._entry is None:
1401 if isinstance(self._id, basestring):
1401 if isinstance(self._id, basestring):
1402 self._entry = grp.getgrnam(self._id)
1402 self._entry = grp.getgrnam(self._id)
1403 else:
1403 else:
1404 self._entry = grp.getgrgid(self._id)
1404 self._entry = grp.getgrgid(self._id)
1405 return self._entry
1405 return self._entry
1406
1406
1407 def getname(self):
1407 def getname(self):
1408 if isinstance(self._id, basestring):
1408 if isinstance(self._id, basestring):
1409 return self._id
1409 return self._id
1410 else:
1410 else:
1411 return self._getentry().gr_name
1411 return self._getentry().gr_name
1412 name = property(getname, None, None, "Group name")
1412 name = property(getname, None, None, "Group name")
1413
1413
1414 def getpasswd(self):
1414 def getpasswd(self):
1415 return self._getentry().gr_passwd
1415 return self._getentry().gr_passwd
1416 passwd = property(getpasswd, None, None, "Password")
1416 passwd = property(getpasswd, None, None, "Password")
1417
1417
1418 def getgid(self):
1418 def getgid(self):
1419 if isinstance(self._id, basestring):
1419 if isinstance(self._id, basestring):
1420 return self._getentry().gr_gid
1420 return self._getentry().gr_gid
1421 else:
1421 else:
1422 return self._id
1422 return self._id
1423 gid = property(getgid, None, None, "Group id")
1423 gid = property(getgid, None, None, "Group id")
1424
1424
1425 def getmem(self):
1425 def getmem(self):
1426 return self._getentry().gr_mem
1426 return self._getentry().gr_mem
1427 mem = property(getmem, None, None, "Members")
1427 mem = property(getmem, None, None, "Members")
1428
1428
1429 def __xattrs__(self, mode="default"):
1429 def __xattrs__(self, mode="default"):
1430 return ("name", "passwd", "gid", "mem")
1430 return ("name", "passwd", "gid", "mem")
1431
1431
1432 def __xrepr__(self, mode="default"):
1432 def __xrepr__(self, mode="default"):
1433 if mode == "header" or mode == "footer" or mode == "cell":
1433 if mode == "header" or mode == "footer" or mode == "cell":
1434 yield (astyle.style_default, "group ")
1434 yield (astyle.style_default, "group ")
1435 try:
1435 try:
1436 yield (astyle.style_default, self.name)
1436 yield (astyle.style_default, self.name)
1437 except KeyError:
1437 except KeyError:
1438 if isinstance(self._id, basestring):
1438 if isinstance(self._id, basestring):
1439 yield (astyle.style_default, self.name_id)
1439 yield (astyle.style_default, self.name_id)
1440 else:
1440 else:
1441 yield (astyle.style_type_number, str(self._id))
1441 yield (astyle.style_type_number, str(self._id))
1442 else:
1442 else:
1443 yield (astyle.style_default, repr(self))
1443 yield (astyle.style_default, repr(self))
1444
1444
1445 def __iter__(self):
1445 def __iter__(self):
1446 for member in self.mem:
1446 for member in self.mem:
1447 yield ipwdentry(member)
1447 yield ipwdentry(member)
1448
1448
1449 def __repr__(self):
1449 def __repr__(self):
1450 return "%s.%s(%r)" % \
1450 return "%s.%s(%r)" % \
1451 (self.__class__.__module__, self.__class__.__name__, self._id)
1451 (self.__class__.__module__, self.__class__.__name__, self._id)
1452
1452
1453
1453
1454 class igrp(Table):
1454 class igrp(Table):
1455 """
1455 """
1456 This ``Table`` lists all entries in the Unix group database.
1456 This ``Table`` lists all entries in the Unix group database.
1457 """
1457 """
1458 def __iter__(self):
1458 def __iter__(self):
1459 for entry in grp.getgrall():
1459 for entry in grp.getgrall():
1460 yield igrpentry(entry.gr_name)
1460 yield igrpentry(entry.gr_name)
1461
1461
1462 def __xrepr__(self, mode="default"):
1462 def __xrepr__(self, mode="default"):
1463 if mode == "header" or mode == "footer":
1463 if mode == "header" or mode == "footer":
1464 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1464 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1465 else:
1465 else:
1466 yield (astyle.style_default, repr(self))
1466 yield (astyle.style_default, repr(self))
1467
1467
1468
1468
1469 class Fields(object):
1469 class Fields(object):
1470 def __init__(self, fieldnames, **fields):
1470 def __init__(self, fieldnames, **fields):
1471 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1471 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1472 for (key, value) in fields.iteritems():
1472 for (key, value) in fields.iteritems():
1473 setattr(self, key, value)
1473 setattr(self, key, value)
1474
1474
1475 def __xattrs__(self, mode="default"):
1475 def __xattrs__(self, mode="default"):
1476 return self.__fieldnames
1476 return self.__fieldnames
1477
1477
1478 def __xrepr__(self, mode="default"):
1478 def __xrepr__(self, mode="default"):
1479 yield (-1, False)
1479 yield (-1, False)
1480 if mode == "header" or mode == "cell":
1480 if mode == "header" or mode == "cell":
1481 yield (astyle.style_default, self.__class__.__name__)
1481 yield (astyle.style_default, self.__class__.__name__)
1482 yield (astyle.style_default, "(")
1482 yield (astyle.style_default, "(")
1483 for (i, f) in enumerate(self.__fieldnames):
1483 for (i, f) in enumerate(self.__fieldnames):
1484 if i:
1484 if i:
1485 yield (astyle.style_default, ", ")
1485 yield (astyle.style_default, ", ")
1486 yield (astyle.style_default, f.name())
1486 yield (astyle.style_default, f.name())
1487 yield (astyle.style_default, "=")
1487 yield (astyle.style_default, "=")
1488 for part in xrepr(getattr(self, f), "default"):
1488 for part in xrepr(getattr(self, f), "default"):
1489 yield part
1489 yield part
1490 yield (astyle.style_default, ")")
1490 yield (astyle.style_default, ")")
1491 elif mode == "footer":
1491 elif mode == "footer":
1492 yield (astyle.style_default, self.__class__.__name__)
1492 yield (astyle.style_default, self.__class__.__name__)
1493 yield (astyle.style_default, "(")
1493 yield (astyle.style_default, "(")
1494 for (i, f) in enumerate(self.__fieldnames):
1494 for (i, f) in enumerate(self.__fieldnames):
1495 if i:
1495 if i:
1496 yield (astyle.style_default, ", ")
1496 yield (astyle.style_default, ", ")
1497 yield (astyle.style_default, f.name())
1497 yield (astyle.style_default, f.name())
1498 yield (astyle.style_default, ")")
1498 yield (astyle.style_default, ")")
1499 else:
1499 else:
1500 yield (astyle.style_default, repr(self))
1500 yield (astyle.style_default, repr(self))
1501
1501
1502
1502
1503 class FieldTable(Table, list):
1503 class FieldTable(Table, list):
1504 def __init__(self, *fields):
1504 def __init__(self, *fields):
1505 Table.__init__(self)
1505 Table.__init__(self)
1506 list.__init__(self)
1506 list.__init__(self)
1507 self.fields = fields
1507 self.fields = fields
1508
1508
1509 def add(self, **fields):
1509 def add(self, **fields):
1510 self.append(Fields(self.fields, **fields))
1510 self.append(Fields(self.fields, **fields))
1511
1511
1512 def __xrepr__(self, mode="default"):
1512 def __xrepr__(self, mode="default"):
1513 yield (-1, False)
1513 yield (-1, False)
1514 if mode == "header" or mode == "footer":
1514 if mode == "header" or mode == "footer":
1515 yield (astyle.style_default, self.__class__.__name__)
1515 yield (astyle.style_default, self.__class__.__name__)
1516 yield (astyle.style_default, "(")
1516 yield (astyle.style_default, "(")
1517 for (i, f) in enumerate(self.__fieldnames):
1517 for (i, f) in enumerate(self.__fieldnames):
1518 if i:
1518 if i:
1519 yield (astyle.style_default, ", ")
1519 yield (astyle.style_default, ", ")
1520 yield (astyle.style_default, f)
1520 yield (astyle.style_default, f)
1521 yield (astyle.style_default, ")")
1521 yield (astyle.style_default, ")")
1522 else:
1522 else:
1523 yield (astyle.style_default, repr(self))
1523 yield (astyle.style_default, repr(self))
1524
1524
1525 def __repr__(self):
1525 def __repr__(self):
1526 return "<%s.%s object with fields=%r at 0x%x>" % \
1526 return "<%s.%s object with fields=%r at 0x%x>" % \
1527 (self.__class__.__module__, self.__class__.__name__,
1527 (self.__class__.__module__, self.__class__.__name__,
1528 ", ".join(map(repr, self.fields)), id(self))
1528 ", ".join(map(repr, self.fields)), id(self))
1529
1529
1530
1530
1531 class List(list):
1531 class List(list):
1532 def __xattrs__(self, mode="default"):
1532 def __xattrs__(self, mode="default"):
1533 return xrange(len(self))
1533 return xrange(len(self))
1534
1534
1535 def __xrepr__(self, mode="default"):
1535 def __xrepr__(self, mode="default"):
1536 yield (-1, False)
1536 yield (-1, False)
1537 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1537 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1538 yield (astyle.style_default, self.__class__.__name__)
1538 yield (astyle.style_default, self.__class__.__name__)
1539 yield (astyle.style_default, "(")
1539 yield (astyle.style_default, "(")
1540 for (i, item) in enumerate(self):
1540 for (i, item) in enumerate(self):
1541 if i:
1541 if i:
1542 yield (astyle.style_default, ", ")
1542 yield (astyle.style_default, ", ")
1543 for part in xrepr(item, "default"):
1543 for part in xrepr(item, "default"):
1544 yield part
1544 yield part
1545 yield (astyle.style_default, ")")
1545 yield (astyle.style_default, ")")
1546 else:
1546 else:
1547 yield (astyle.style_default, repr(self))
1547 yield (astyle.style_default, repr(self))
1548
1548
1549
1549
1550 class ienv(Table):
1550 class ienv(Table):
1551 """
1551 """
1552 List environment variables.
1552 List environment variables.
1553
1553
1554 Example:
1554 Example:
1555
1555
1556 >>> ienv
1556 >>> ienv
1557 """
1557 """
1558
1558
1559 def __iter__(self):
1559 def __iter__(self):
1560 fields = ("key", "value")
1560 fields = ("key", "value")
1561 for (key, value) in os.environ.iteritems():
1561 for (key, value) in os.environ.iteritems():
1562 yield Fields(fields, key=key, value=value)
1562 yield Fields(fields, key=key, value=value)
1563
1563
1564 def __xrepr__(self, mode="default"):
1564 def __xrepr__(self, mode="default"):
1565 if mode == "header" or mode == "cell":
1565 if mode == "header" or mode == "cell":
1566 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1566 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1567 else:
1567 else:
1568 yield (astyle.style_default, repr(self))
1568 yield (astyle.style_default, repr(self))
1569
1569
1570
1570
1571 class icsv(Pipe):
1571 class icsv(Pipe):
1572 """
1572 """
1573 This ``Pipe`` lists turn the input (with must be a pipe outputting lines
1573 This ``Pipe`` lists turn the input (with must be a pipe outputting lines
1574 or an ``ifile``) into lines of CVS columns.
1574 or an ``ifile``) into lines of CVS columns.
1575 """
1575 """
1576 def __init__(self, **csvargs):
1576 def __init__(self, **csvargs):
1577 """
1577 """
1578 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1578 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1579 keyword arguments to ``cvs.reader()``.
1579 keyword arguments to ``cvs.reader()``.
1580 """
1580 """
1581 self.csvargs = csvargs
1581 self.csvargs = csvargs
1582
1582
1583 def __iter__(self):
1583 def __iter__(self):
1584 input = self.input
1584 input = self.input
1585 if isinstance(input, ifile):
1585 if isinstance(input, ifile):
1586 input = input.open("rb")
1586 input = input.open("rb")
1587 reader = csv.reader(input, **self.csvargs)
1587 reader = csv.reader(input, **self.csvargs)
1588 for line in reader:
1588 for line in reader:
1589 yield List(line)
1589 yield List(line)
1590
1590
1591 def __xrepr__(self, mode="default"):
1591 def __xrepr__(self, mode="default"):
1592 yield (-1, False)
1592 yield (-1, False)
1593 if mode == "header" or mode == "footer":
1593 if mode == "header" or mode == "footer":
1594 input = getattr(self, "input", None)
1594 input = getattr(self, "input", None)
1595 if input is not None:
1595 if input is not None:
1596 for part in xrepr(input, mode):
1596 for part in xrepr(input, mode):
1597 yield part
1597 yield part
1598 yield (astyle.style_default, " | ")
1598 yield (astyle.style_default, " | ")
1599 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1599 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1600 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1600 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1601 if i:
1601 if i:
1602 yield (astyle.style_default, ", ")
1602 yield (astyle.style_default, ", ")
1603 yield (astyle.style_default, name)
1603 yield (astyle.style_default, name)
1604 yield (astyle.style_default, "=")
1604 yield (astyle.style_default, "=")
1605 for part in xrepr(value, "default"):
1605 for part in xrepr(value, "default"):
1606 yield part
1606 yield part
1607 yield (astyle.style_default, ")")
1607 yield (astyle.style_default, ")")
1608 else:
1608 else:
1609 yield (astyle.style_default, repr(self))
1609 yield (astyle.style_default, repr(self))
1610
1610
1611 def __repr__(self):
1611 def __repr__(self):
1612 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1612 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1613 return "<%s.%s %s at 0x%x>" % \
1613 return "<%s.%s %s at 0x%x>" % \
1614 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1614 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1615
1615
1616
1616
1617 class ix(Table):
1617 class ix(Table):
1618 """
1618 """
1619 Execute a system command and list its output as lines
1619 Execute a system command and list its output as lines
1620 (similar to ``os.popen()``).
1620 (similar to ``os.popen()``).
1621
1621
1622 Examples:
1622 Examples:
1623
1623
1624 >>> ix("ps x")
1624 >>> ix("ps x")
1625 >>> ix("find .") | ifile
1625 >>> ix("find .") | ifile
1626 """
1626 """
1627 def __init__(self, cmd):
1627 def __init__(self, cmd):
1628 self.cmd = cmd
1628 self.cmd = cmd
1629 self._pipeout = None
1629 self._pipeout = None
1630
1630
1631 def __iter__(self):
1631 def __iter__(self):
1632 (_pipein, self._pipeout) = os.popen4(self.cmd)
1632 (_pipein, self._pipeout) = os.popen4(self.cmd)
1633 _pipein.close()
1633 _pipein.close()
1634 for l in self._pipeout:
1634 for l in self._pipeout:
1635 yield l.rstrip("\r\n")
1635 yield l.rstrip("\r\n")
1636 self._pipeout.close()
1636 self._pipeout.close()
1637 self._pipeout = None
1637 self._pipeout = None
1638
1638
1639 def __del__(self):
1639 def __del__(self):
1640 if self._pipeout is not None and not self._pipeout.closed:
1640 if self._pipeout is not None and not self._pipeout.closed:
1641 self._pipeout.close()
1641 self._pipeout.close()
1642 self._pipeout = None
1642 self._pipeout = None
1643
1643
1644 def __xrepr__(self, mode="default"):
1644 def __xrepr__(self, mode="default"):
1645 if mode == "header" or mode == "footer":
1645 if mode == "header" or mode == "footer":
1646 yield (astyle.style_default,
1646 yield (astyle.style_default,
1647 "%s(%r)" % (self.__class__.__name__, self.cmd))
1647 "%s(%r)" % (self.__class__.__name__, self.cmd))
1648 else:
1648 else:
1649 yield (astyle.style_default, repr(self))
1649 yield (astyle.style_default, repr(self))
1650
1650
1651 def __repr__(self):
1651 def __repr__(self):
1652 return "%s.%s(%r)" % \
1652 return "%s.%s(%r)" % \
1653 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1653 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1654
1654
1655
1655
1656 class ifilter(Pipe):
1656 class ifilter(Pipe):
1657 """
1657 """
1658 Filter an input pipe. Only objects where an expression evaluates to true
1658 Filter an input pipe. Only objects where an expression evaluates to true
1659 (and doesn't raise an exception) are listed.
1659 (and doesn't raise an exception) are listed.
1660
1660
1661 Examples:
1661 Examples:
1662
1662
1663 >>> ils | ifilter("_.isfile() and size>1000")
1663 >>> ils | ifilter("_.isfile() and size>1000")
1664 >>> igrp | ifilter("len(mem)")
1664 >>> igrp | ifilter("len(mem)")
1665 >>> sys.modules | ifilter(lambda _:_.value is not None)
1665 >>> sys.modules | ifilter(lambda _:_.value is not None)
1666 """
1666 """
1667
1667
1668 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1668 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1669 """
1669 """
1670 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1670 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1671 containing an expression. ``globals`` will be used as the global
1671 containing an expression. ``globals`` will be used as the global
1672 namespace for calling string expressions (defaulting to IPython's
1672 namespace for calling string expressions (defaulting to IPython's
1673 user namespace). ``errors`` specifies how exception during evaluation
1673 user namespace). ``errors`` specifies how exception during evaluation
1674 of ``expr`` are handled:
1674 of ``expr`` are handled:
1675
1675
1676 * ``drop``: drop all items that have errors;
1676 * ``drop``: drop all items that have errors;
1677
1677
1678 * ``keep``: keep all items that have errors;
1678 * ``keep``: keep all items that have errors;
1679
1679
1680 * ``keeperror``: keep the exception of all items that have errors;
1680 * ``keeperror``: keep the exception of all items that have errors;
1681
1681
1682 * ``raise``: raise the exception;
1682 * ``raise``: raise the exception;
1683
1683
1684 * ``raiseifallfail``: raise the first exception if all items have errors;
1684 * ``raiseifallfail``: raise the first exception if all items have errors;
1685 otherwise drop those with errors (this is the default).
1685 otherwise drop those with errors (this is the default).
1686 """
1686 """
1687 self.expr = expr
1687 self.expr = expr
1688 self.globals = globals
1688 self.globals = globals
1689 self.errors = errors
1689 self.errors = errors
1690
1690
1691 def __iter__(self):
1691 def __iter__(self):
1692 if callable(self.expr):
1692 if callable(self.expr):
1693 test = self.expr
1693 test = self.expr
1694 else:
1694 else:
1695 g = getglobals(self.globals)
1695 g = getglobals(self.globals)
1696 expr = compile(self.expr, "ipipe-expression", "eval")
1696 expr = compile(self.expr, "ipipe-expression", "eval")
1697 def test(item):
1697 def test(item):
1698 return eval(expr, g, AttrNamespace(item))
1698 return eval(expr, g, AttrNamespace(item))
1699
1699
1700 ok = 0
1700 ok = 0
1701 exc_info = None
1701 exc_info = None
1702 for item in xiter(self.input):
1702 for item in xiter(self.input):
1703 try:
1703 try:
1704 if test(item):
1704 if test(item):
1705 yield item
1705 yield item
1706 ok += 1
1706 ok += 1
1707 except (KeyboardInterrupt, SystemExit):
1707 except (KeyboardInterrupt, SystemExit):
1708 raise
1708 raise
1709 except Exception, exc:
1709 except Exception, exc:
1710 if self.errors == "drop":
1710 if self.errors == "drop":
1711 pass # Ignore errors
1711 pass # Ignore errors
1712 elif self.errors == "keep":
1712 elif self.errors == "keep":
1713 yield item
1713 yield item
1714 elif self.errors == "keeperror":
1714 elif self.errors == "keeperror":
1715 yield exc
1715 yield exc
1716 elif self.errors == "raise":
1716 elif self.errors == "raise":
1717 raise
1717 raise
1718 elif self.errors == "raiseifallfail":
1718 elif self.errors == "raiseifallfail":
1719 if exc_info is None:
1719 if exc_info is None:
1720 exc_info = sys.exc_info()
1720 exc_info = sys.exc_info()
1721 if not ok and exc_info is not None:
1721 if not ok and exc_info is not None:
1722 raise exc_info[0], exc_info[1], exc_info[2]
1722 raise exc_info[0], exc_info[1], exc_info[2]
1723
1723
1724 def __xrepr__(self, mode="default"):
1724 def __xrepr__(self, mode="default"):
1725 if mode == "header" or mode == "footer":
1725 if mode == "header" or mode == "footer":
1726 input = getattr(self, "input", None)
1726 input = getattr(self, "input", None)
1727 if input is not None:
1727 if input is not None:
1728 for part in xrepr(input, mode):
1728 for part in xrepr(input, mode):
1729 yield part
1729 yield part
1730 yield (astyle.style_default, " | ")
1730 yield (astyle.style_default, " | ")
1731 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1731 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1732 for part in xrepr(self.expr, "default"):
1732 for part in xrepr(self.expr, "default"):
1733 yield part
1733 yield part
1734 yield (astyle.style_default, ")")
1734 yield (astyle.style_default, ")")
1735 else:
1735 else:
1736 yield (astyle.style_default, repr(self))
1736 yield (astyle.style_default, repr(self))
1737
1737
1738 def __repr__(self):
1738 def __repr__(self):
1739 return "<%s.%s expr=%r at 0x%x>" % \
1739 return "<%s.%s expr=%r at 0x%x>" % \
1740 (self.__class__.__module__, self.__class__.__name__,
1740 (self.__class__.__module__, self.__class__.__name__,
1741 self.expr, id(self))
1741 self.expr, id(self))
1742
1742
1743
1743
1744 class ieval(Pipe):
1744 class ieval(Pipe):
1745 """
1745 """
1746 Evaluate an expression for each object in the input pipe.
1746 Evaluate an expression for each object in the input pipe.
1747
1747
1748 Examples:
1748 Examples:
1749
1749
1750 >>> ils | ieval("_.abspath()")
1750 >>> ils | ieval("_.abspath()")
1751 >>> sys.path | ieval(ifile)
1751 >>> sys.path | ieval(ifile)
1752 """
1752 """
1753
1753
1754 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1754 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1755 """
1755 """
1756 Create an ``ieval`` object. ``expr`` can be a callable or a string
1756 Create an ``ieval`` object. ``expr`` can be a callable or a string
1757 containing an expression. For the meaning of ``globals`` and
1757 containing an expression. For the meaning of ``globals`` and
1758 ``errors`` see ``ifilter``.
1758 ``errors`` see ``ifilter``.
1759 """
1759 """
1760 self.expr = expr
1760 self.expr = expr
1761 self.globals = globals
1761 self.globals = globals
1762 self.errors = errors
1762 self.errors = errors
1763
1763
1764 def __iter__(self):
1764 def __iter__(self):
1765 if callable(self.expr):
1765 if callable(self.expr):
1766 do = self.expr
1766 do = self.expr
1767 else:
1767 else:
1768 g = getglobals(self.globals)
1768 g = getglobals(self.globals)
1769 expr = compile(self.expr, "ipipe-expression", "eval")
1769 expr = compile(self.expr, "ipipe-expression", "eval")
1770 def do(item):
1770 def do(item):
1771 return eval(expr, g, AttrNamespace(item))
1771 return eval(expr, g, AttrNamespace(item))
1772
1772
1773 ok = 0
1773 ok = 0
1774 exc_info = None
1774 exc_info = None
1775 for item in xiter(self.input):
1775 for item in xiter(self.input):
1776 try:
1776 try:
1777 yield do(item)
1777 yield do(item)
1778 except (KeyboardInterrupt, SystemExit):
1778 except (KeyboardInterrupt, SystemExit):
1779 raise
1779 raise
1780 except Exception, exc:
1780 except Exception, exc:
1781 if self.errors == "drop":
1781 if self.errors == "drop":
1782 pass # Ignore errors
1782 pass # Ignore errors
1783 elif self.errors == "keep":
1783 elif self.errors == "keep":
1784 yield item
1784 yield item
1785 elif self.errors == "keeperror":
1785 elif self.errors == "keeperror":
1786 yield exc
1786 yield exc
1787 elif self.errors == "raise":
1787 elif self.errors == "raise":
1788 raise
1788 raise
1789 elif self.errors == "raiseifallfail":
1789 elif self.errors == "raiseifallfail":
1790 if exc_info is None:
1790 if exc_info is None:
1791 exc_info = sys.exc_info()
1791 exc_info = sys.exc_info()
1792 if not ok and exc_info is not None:
1792 if not ok and exc_info is not None:
1793 raise exc_info[0], exc_info[1], exc_info[2]
1793 raise exc_info[0], exc_info[1], exc_info[2]
1794
1794
1795 def __xrepr__(self, mode="default"):
1795 def __xrepr__(self, mode="default"):
1796 if mode == "header" or mode == "footer":
1796 if mode == "header" or mode == "footer":
1797 input = getattr(self, "input", None)
1797 input = getattr(self, "input", None)
1798 if input is not None:
1798 if input is not None:
1799 for part in xrepr(input, mode):
1799 for part in xrepr(input, mode):
1800 yield part
1800 yield part
1801 yield (astyle.style_default, " | ")
1801 yield (astyle.style_default, " | ")
1802 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1802 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1803 for part in xrepr(self.expr, "default"):
1803 for part in xrepr(self.expr, "default"):
1804 yield part
1804 yield part
1805 yield (astyle.style_default, ")")
1805 yield (astyle.style_default, ")")
1806 else:
1806 else:
1807 yield (astyle.style_default, repr(self))
1807 yield (astyle.style_default, repr(self))
1808
1808
1809 def __repr__(self):
1809 def __repr__(self):
1810 return "<%s.%s expr=%r at 0x%x>" % \
1810 return "<%s.%s expr=%r at 0x%x>" % \
1811 (self.__class__.__module__, self.__class__.__name__,
1811 (self.__class__.__module__, self.__class__.__name__,
1812 self.expr, id(self))
1812 self.expr, id(self))
1813
1813
1814
1814
1815 class ienum(Pipe):
1815 class ienum(Pipe):
1816 """
1816 """
1817 Enumerate the input pipe (i.e. wrap each input object in an object
1817 Enumerate the input pipe (i.e. wrap each input object in an object
1818 with ``index`` and ``object`` attributes).
1818 with ``index`` and ``object`` attributes).
1819
1819
1820 Examples:
1820 Examples:
1821
1821
1822 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1822 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1823 """
1823 """
1824 def __iter__(self):
1824 def __iter__(self):
1825 fields = ("index", "object")
1825 fields = ("index", "object")
1826 for (index, object) in enumerate(xiter(self.input)):
1826 for (index, object) in enumerate(xiter(self.input)):
1827 yield Fields(fields, index=index, object=object)
1827 yield Fields(fields, index=index, object=object)
1828
1828
1829
1829
1830 class isort(Pipe):
1830 class isort(Pipe):
1831 """
1831 """
1832 Sorts the input pipe.
1832 Sorts the input pipe.
1833
1833
1834 Examples:
1834 Examples:
1835
1835
1836 >>> ils | isort("size")
1836 >>> ils | isort("size")
1837 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1837 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1838 """
1838 """
1839
1839
1840 def __init__(self, key=None, globals=None, reverse=False):
1840 def __init__(self, key=None, globals=None, reverse=False):
1841 """
1841 """
1842 Create an ``isort`` object. ``key`` can be a callable or a string
1842 Create an ``isort`` object. ``key`` can be a callable or a string
1843 containing an expression (or ``None`` in which case the items
1843 containing an expression (or ``None`` in which case the items
1844 themselves will be sorted). If ``reverse`` is true the sort order
1844 themselves will be sorted). If ``reverse`` is true the sort order
1845 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1845 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1846 """
1846 """
1847 self.key = key
1847 self.key = key
1848 self.globals = globals
1848 self.globals = globals
1849 self.reverse = reverse
1849 self.reverse = reverse
1850
1850
1851 def __iter__(self):
1851 def __iter__(self):
1852 if self.key is None:
1852 if self.key is None:
1853 items = sorted(xiter(self.input), reverse=self.reverse)
1853 items = sorted(xiter(self.input), reverse=self.reverse)
1854 elif callable(self.key):
1854 elif callable(self.key):
1855 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1855 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1856 else:
1856 else:
1857 g = getglobals(self.globals)
1857 g = getglobals(self.globals)
1858 key = compile(self.key, "ipipe-expression", "eval")
1858 key = compile(self.key, "ipipe-expression", "eval")
1859 def realkey(item):
1859 def realkey(item):
1860 return eval(key, g, AttrNamespace(item))
1860 return eval(key, g, AttrNamespace(item))
1861 items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
1861 items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
1862 for item in items:
1862 for item in items:
1863 yield item
1863 yield item
1864
1864
1865 def __xrepr__(self, mode="default"):
1865 def __xrepr__(self, mode="default"):
1866 if mode == "header" or mode == "footer":
1866 if mode == "header" or mode == "footer":
1867 input = getattr(self, "input", None)
1867 input = getattr(self, "input", None)
1868 if input is not None:
1868 if input is not None:
1869 for part in xrepr(input, mode):
1869 for part in xrepr(input, mode):
1870 yield part
1870 yield part
1871 yield (astyle.style_default, " | ")
1871 yield (astyle.style_default, " | ")
1872 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1872 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1873 for part in xrepr(self.key, "default"):
1873 for part in xrepr(self.key, "default"):
1874 yield part
1874 yield part
1875 if self.reverse:
1875 if self.reverse:
1876 yield (astyle.style_default, ", ")
1876 yield (astyle.style_default, ", ")
1877 for part in xrepr(True, "default"):
1877 for part in xrepr(True, "default"):
1878 yield part
1878 yield part
1879 yield (astyle.style_default, ")")
1879 yield (astyle.style_default, ")")
1880 else:
1880 else:
1881 yield (astyle.style_default, repr(self))
1881 yield (astyle.style_default, repr(self))
1882
1882
1883 def __repr__(self):
1883 def __repr__(self):
1884 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1884 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1885 (self.__class__.__module__, self.__class__.__name__,
1885 (self.__class__.__module__, self.__class__.__name__,
1886 self.key, self.reverse, id(self))
1886 self.key, self.reverse, id(self))
1887
1887
1888
1888
1889 tab = 3 # for expandtabs()
1889 tab = 3 # for expandtabs()
1890
1890
1891 def _format(field):
1891 def _format(field):
1892 if isinstance(field, str):
1892 if isinstance(field, str):
1893 text = repr(field.expandtabs(tab))[1:-1]
1893 text = repr(field.expandtabs(tab))[1:-1]
1894 elif isinstance(field, unicode):
1894 elif isinstance(field, unicode):
1895 text = repr(field.expandtabs(tab))[2:-1]
1895 text = repr(field.expandtabs(tab))[2:-1]
1896 elif isinstance(field, datetime.datetime):
1896 elif isinstance(field, datetime.datetime):
1897 # Don't use strftime() here, as this requires year >= 1900
1897 # Don't use strftime() here, as this requires year >= 1900
1898 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1898 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1899 (field.year, field.month, field.day,
1899 (field.year, field.month, field.day,
1900 field.hour, field.minute, field.second, field.microsecond)
1900 field.hour, field.minute, field.second, field.microsecond)
1901 elif isinstance(field, datetime.date):
1901 elif isinstance(field, datetime.date):
1902 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
1902 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
1903 else:
1903 else:
1904 text = repr(field)
1904 text = repr(field)
1905 return text
1905 return text
1906
1906
1907
1907
1908 class Display(object):
1908 class Display(object):
1909 class __metaclass__(type):
1909 class __metaclass__(type):
1910 def __ror__(self, input):
1910 def __ror__(self, input):
1911 return input | self()
1911 return input | self()
1912
1912
1913 def __ror__(self, input):
1913 def __ror__(self, input):
1914 self.input = input
1914 self.input = input
1915 return self
1915 return self
1916
1916
1917 def display(self):
1917 def display(self):
1918 pass
1918 pass
1919
1919
1920
1920
1921 class iless(Display):
1921 class iless(Display):
1922 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
1922 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
1923
1923
1924 def display(self):
1924 def display(self):
1925 try:
1925 try:
1926 pager = os.popen(self.cmd, "w")
1926 pager = os.popen(self.cmd, "w")
1927 try:
1927 try:
1928 for item in xiter(self.input):
1928 for item in xiter(self.input):
1929 first = False
1929 first = False
1930 for attr in xattrs(item, "default"):
1930 for attr in xattrs(item, "default"):
1931 if first:
1931 if first:
1932 first = False
1932 first = False
1933 else:
1933 else:
1934 pager.write(" ")
1934 pager.write(" ")
1935 attr = upgradexattr(attr)
1935 attr = upgradexattr(attr)
1936 if not isinstance(attr, SelfDescriptor):
1936 if not isinstance(attr, SelfDescriptor):
1937 pager.write(attr.name())
1937 pager.write(attr.name())
1938 pager.write("=")
1938 pager.write("=")
1939 pager.write(str(attr.value(item)))
1939 pager.write(str(attr.value(item)))
1940 pager.write("\n")
1940 pager.write("\n")
1941 finally:
1941 finally:
1942 pager.close()
1942 pager.close()
1943 except Exception, exc:
1943 except Exception, exc:
1944 print "%s: %s" % (exc.__class__.__name__, str(exc))
1944 print "%s: %s" % (exc.__class__.__name__, str(exc))
1945
1945
1946
1946
1947 def xformat(value, mode, maxlength):
1947 def xformat(value, mode, maxlength):
1948 align = None
1948 align = None
1949 full = True
1949 full = True
1950 width = 0
1950 width = 0
1951 text = astyle.Text()
1951 text = astyle.Text()
1952 for (style, part) in xrepr(value, mode):
1952 for (style, part) in xrepr(value, mode):
1953 # only consider the first result
1953 # only consider the first result
1954 if align is None:
1954 if align is None:
1955 if isinstance(style, int):
1955 if isinstance(style, int):
1956 # (style, text) really is (alignment, stop)
1956 # (style, text) really is (alignment, stop)
1957 align = style
1957 align = style
1958 full = part
1958 full = part
1959 continue
1959 continue
1960 else:
1960 else:
1961 align = -1
1961 align = -1
1962 full = True
1962 full = True
1963 if not isinstance(style, int):
1963 if not isinstance(style, int):
1964 text.append((style, part))
1964 text.append((style, part))
1965 width += len(part)
1965 width += len(part)
1966 if width >= maxlength and not full:
1966 if width >= maxlength and not full:
1967 text.append((astyle.style_ellisis, "..."))
1967 text.append((astyle.style_ellisis, "..."))
1968 width += 3
1968 width += 3
1969 break
1969 break
1970 if align is None: # default to left alignment
1970 if align is None: # default to left alignment
1971 align = -1
1971 align = -1
1972 return (align, width, text)
1972 return (align, width, text)
1973
1973
1974
1974
1975 class idump(Display):
1975 class idump(Display):
1976 # The approximate maximum length of a column entry
1976 # The approximate maximum length of a column entry
1977 maxattrlength = 200
1977 maxattrlength = 200
1978
1978
1979 # Style for column names
1979 # Style for column names
1980 style_header = astyle.Style.fromstr("white:black:bold")
1980 style_header = astyle.Style.fromstr("white:black:bold")
1981
1981
1982 def __init__(self, *attrs):
1982 def __init__(self, *attrs):
1983 self.attrs = [upgradexattr(attr) for attr in attrs]
1983 self.attrs = [upgradexattr(attr) for attr in attrs]
1984 self.headerpadchar = " "
1984 self.headerpadchar = " "
1985 self.headersepchar = "|"
1985 self.headersepchar = "|"
1986 self.datapadchar = " "
1986 self.datapadchar = " "
1987 self.datasepchar = "|"
1987 self.datasepchar = "|"
1988
1988
1989 def display(self):
1989 def display(self):
1990 stream = genutils.Term.cout
1990 stream = genutils.Term.cout
1991 allattrs = []
1991 allattrs = []
1992 attrset = set()
1992 attrset = set()
1993 colwidths = {}
1993 colwidths = {}
1994 rows = []
1994 rows = []
1995 for item in xiter(self.input):
1995 for item in xiter(self.input):
1996 row = {}
1996 row = {}
1997 attrs = self.attrs
1997 attrs = self.attrs
1998 if not attrs:
1998 if not attrs:
1999 attrs = xattrs(item, "default")
1999 attrs = xattrs(item, "default")
2000 for attr in attrs:
2000 for attr in attrs:
2001 if attr not in attrset:
2001 if attr not in attrset:
2002 allattrs.append(attr)
2002 allattrs.append(attr)
2003 attrset.add(attr)
2003 attrset.add(attr)
2004 colwidths[attr] = len(attr.name())
2004 colwidths[attr] = len(attr.name())
2005 try:
2005 try:
2006 value = attr.value(item)
2006 value = attr.value(item)
2007 except (KeyboardInterrupt, SystemExit):
2007 except (KeyboardInterrupt, SystemExit):
2008 raise
2008 raise
2009 except Exception, exc:
2009 except Exception, exc:
2010 value = exc
2010 value = exc
2011 (align, width, text) = xformat(value, "cell", self.maxattrlength)
2011 (align, width, text) = xformat(value, "cell", self.maxattrlength)
2012 colwidths[attr] = max(colwidths[attr], width)
2012 colwidths[attr] = max(colwidths[attr], width)
2013 # remember alignment, length and colored parts
2013 # remember alignment, length and colored parts
2014 row[attr] = (align, width, text)
2014 row[attr] = (align, width, text)
2015 rows.append(row)
2015 rows.append(row)
2016
2016
2017 stream.write("\n")
2017 stream.write("\n")
2018 for (i, attr) in enumerate(allattrs):
2018 for (i, attr) in enumerate(allattrs):
2019 attrname = attr.name()
2019 attrname = attr.name()
2020 self.style_header(attrname).write(stream)
2020 self.style_header(attrname).write(stream)
2021 spc = colwidths[attr] - len(attrname)
2021 spc = colwidths[attr] - len(attrname)
2022 if i < len(colwidths)-1:
2022 if i < len(colwidths)-1:
2023 stream.write(self.headerpadchar*spc)
2023 stream.write(self.headerpadchar*spc)
2024 stream.write(self.headersepchar)
2024 stream.write(self.headersepchar)
2025 stream.write("\n")
2025 stream.write("\n")
2026
2026
2027 for row in rows:
2027 for row in rows:
2028 for (i, attr) in enumerate(allattrs):
2028 for (i, attr) in enumerate(allattrs):
2029 (align, width, text) = row[attr]
2029 (align, width, text) = row[attr]
2030 spc = colwidths[attr] - width
2030 spc = colwidths[attr] - width
2031 if align == -1:
2031 if align == -1:
2032 text.write(stream)
2032 text.write(stream)
2033 if i < len(colwidths)-1:
2033 if i < len(colwidths)-1:
2034 stream.write(self.datapadchar*spc)
2034 stream.write(self.datapadchar*spc)
2035 elif align == 0:
2035 elif align == 0:
2036 spc = colwidths[attr] - width
2036 spc = colwidths[attr] - width
2037 spc1 = spc//2
2037 spc1 = spc//2
2038 spc2 = spc-spc1
2038 spc2 = spc-spc1
2039 stream.write(self.datapadchar*spc1)
2039 stream.write(self.datapadchar*spc1)
2040 text.write(stream)
2040 text.write(stream)
2041 if i < len(colwidths)-1:
2041 if i < len(colwidths)-1:
2042 stream.write(self.datapadchar*spc2)
2042 stream.write(self.datapadchar*spc2)
2043 else:
2043 else:
2044 stream.write(self.datapadchar*spc)
2044 stream.write(self.datapadchar*spc)
2045 text.write(stream)
2045 text.write(stream)
2046 if i < len(colwidths)-1:
2046 if i < len(colwidths)-1:
2047 stream.write(self.datasepchar)
2047 stream.write(self.datasepchar)
2048 stream.write("\n")
2048 stream.write("\n")
2049
2049
2050
2050
2051 class AttributeDetail(Table):
2051 class AttributeDetail(Table):
2052 """
2052 """
2053 ``AttributeDetail`` objects are use for displaying a detailed list of object
2053 ``AttributeDetail`` objects are use for displaying a detailed list of object
2054 attributes.
2054 attributes.
2055 """
2055 """
2056 def __init__(self, object, descriptor):
2056 def __init__(self, object, descriptor):
2057 self.object = object
2057 self.object = object
2058 self.descriptor = descriptor
2058 self.descriptor = descriptor
2059
2059
2060 def __iter__(self):
2060 def __iter__(self):
2061 return self.descriptor.iter(self.object)
2061 return self.descriptor.iter(self.object)
2062
2062
2063 def name(self):
2063 def name(self):
2064 return self.descriptor.name()
2064 return self.descriptor.name()
2065
2065
2066 def attrtype(self):
2066 def attrtype(self):
2067 return self.descriptor.attrtype(self.object)
2067 return self.descriptor.attrtype(self.object)
2068
2068
2069 def valuetype(self):
2069 def valuetype(self):
2070 return self.descriptor.valuetype(self.object)
2070 return self.descriptor.valuetype(self.object)
2071
2071
2072 def doc(self):
2072 def doc(self):
2073 return self.descriptor.doc(self.object)
2073 return self.descriptor.doc(self.object)
2074
2074
2075 def shortdoc(self):
2075 def shortdoc(self):
2076 return self.descriptor.shortdoc(self.object)
2076 return self.descriptor.shortdoc(self.object)
2077
2077
2078 def value(self):
2078 def value(self):
2079 return self.descriptor.value(self.object)
2079 return self.descriptor.value(self.object)
2080
2080
2081 def __xattrs__(self, mode="default"):
2081 def __xattrs__(self, mode="default"):
2082 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2082 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2083 if mode == "detail":
2083 if mode == "detail":
2084 attrs += ("doc()",)
2084 attrs += ("doc()",)
2085 return attrs
2085 return attrs
2086
2086
2087 def __xrepr__(self, mode="default"):
2087 def __xrepr__(self, mode="default"):
2088 yield (-1, True)
2088 yield (-1, True)
2089 valuetype = self.valuetype()
2089 valuetype = self.valuetype()
2090 if valuetype is not noitem:
2090 if valuetype is not noitem:
2091 for part in xrepr(valuetype):
2091 for part in xrepr(valuetype):
2092 yield part
2092 yield part
2093 yield (astyle.style_default, " ")
2093 yield (astyle.style_default, " ")
2094 yield (astyle.style_default, self.attrtype())
2094 yield (astyle.style_default, self.attrtype())
2095 yield (astyle.style_default, " ")
2095 yield (astyle.style_default, " ")
2096 yield (astyle.style_default, self.name())
2096 yield (astyle.style_default, self.name())
2097 yield (astyle.style_default, " of ")
2097 yield (astyle.style_default, " of ")
2098 for part in xrepr(self.object):
2098 for part in xrepr(self.object):
2099 yield part
2099 yield part
2100
2100
2101
2101
2102 try:
2102 try:
2103 from ibrowse import ibrowse
2103 from igrid import igrid
2104 except ImportError:
2104 except ImportError:
2105 # No curses (probably Windows) => use ``idump`` as the default display.
2105 # no wx
2106 defaultdisplay = idump
2106 try:
2107 from ibrowse import ibrowse
2108 except ImportError:
2109 # No curses (probably Windows) => use ``idump`` as the default display.
2110 defaultdisplay = idump
2111 else:
2112 defaultdisplay = ibrowse
2113 __all__.append("ibrowse")
2107 else:
2114 else:
2108 defaultdisplay = ibrowse
2115 defaultdisplay = igrid
2109 __all__.append("ibrowse")
2116 __all__.append("igrid")
2110
2117
2111
2118
2112 # If we're running under IPython, install an IPython displayhook that
2119 # If we're running under IPython, install an IPython displayhook that
2113 # returns the object from Display.display(), else install a displayhook
2120 # returns the object from Display.display(), else install a displayhook
2114 # directly as sys.displayhook
2121 # directly as sys.displayhook
2115 api = None
2122 api = None
2116 if ipapi is not None:
2123 if ipapi is not None:
2117 try:
2124 try:
2118 api = ipapi.get()
2125 api = ipapi.get()
2119 except AttributeError:
2126 except AttributeError:
2120 pass
2127 pass
2121
2128
2122 if api is not None:
2129 if api is not None:
2123 def displayhook(self, obj):
2130 def displayhook(self, obj):
2124 if isinstance(obj, type) and issubclass(obj, Table):
2131 if isinstance(obj, type) and issubclass(obj, Table):
2125 obj = obj()
2132 obj = obj()
2126 if isinstance(obj, Table):
2133 if isinstance(obj, Table):
2127 obj = obj | defaultdisplay
2134 obj = obj | defaultdisplay
2128 if isinstance(obj, Display):
2135 if isinstance(obj, Display):
2129 return obj.display()
2136 return obj.display()
2130 else:
2137 else:
2131 raise ipapi.TryNext
2138 raise ipapi.TryNext
2132 api.set_hook("result_display", displayhook)
2139 api.set_hook("result_display", displayhook)
2133 else:
2140 else:
2134 def installdisplayhook():
2141 def installdisplayhook():
2135 _originalhook = sys.displayhook
2142 _originalhook = sys.displayhook
2136 def displayhook(obj):
2143 def displayhook(obj):
2137 if isinstance(obj, type) and issubclass(obj, Table):
2144 if isinstance(obj, type) and issubclass(obj, Table):
2138 obj = obj()
2145 obj = obj()
2139 if isinstance(obj, Table):
2146 if isinstance(obj, Table):
2140 obj = obj | defaultdisplay
2147 obj = obj | defaultdisplay
2141 if isinstance(obj, Display):
2148 if isinstance(obj, Display):
2142 return obj.display()
2149 return obj.display()
2143 else:
2150 else:
2144 _originalhook(obj)
2151 _originalhook(obj)
2145 sys.displayhook = displayhook
2152 sys.displayhook = displayhook
2146 installdisplayhook()
2153 installdisplayhook()
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now