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 igrid import igrid | |||
|
2104 | except ImportError: | |||
|
2105 | # no wx | |||
|
2106 | try: | |||
2103 | from ibrowse import ibrowse |
|
2107 | from ibrowse import ibrowse | |
2104 | except ImportError: |
|
2108 | except ImportError: | |
2105 | # No curses (probably Windows) => use ``idump`` as the default display. |
|
2109 | # No curses (probably Windows) => use ``idump`` as the default display. | |
2106 | defaultdisplay = idump |
|
2110 | defaultdisplay = idump | |
2107 | else: |
|
2111 | else: | |
2108 | defaultdisplay = ibrowse |
|
2112 | defaultdisplay = ibrowse | |
2109 | __all__.append("ibrowse") |
|
2113 | __all__.append("ibrowse") | |
|
2114 | else: | |||
|
2115 | defaultdisplay = igrid | |||
|
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