##// END OF EJS Templates
* IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail...
walter.doerwald -
Show More
@@ -374,6 +374,7 b' style_type_none = Style.fromstr("magenta:black")'
374 374 style_type_bool = Style.fromstr("magenta:black")
375 375 style_type_number = Style.fromstr("yellow:black")
376 376 style_type_datetime = Style.fromstr("magenta:black")
377 style_type_type = Style.fromstr("cyan:black")
377 378
378 379 # Style for URLs and file/directory names
379 380 style_url = Style.fromstr("green:black")
@@ -97,7 +97,7 b' class _BrowserHelp(object):'
97 97 else:
98 98 yield (astyle.style_default, repr(self))
99 99
100 def __xiter__(self, mode):
100 def __iter__(self):
101 101 # Get reverse key mapping
102 102 allkeys = {}
103 103 for (key, cmd) in self.browser.keymap.iteritems():
@@ -125,7 +125,7 b' class _BrowserHelp(object):'
125 125 lines = textwrap.wrap(description, 60)
126 126 keys = allkeys.get(name, [])
127 127
128 yield ipipe.Fields(fields, description=astyle.Text((self.style_header, name)))
128 yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
129 129 for i in xrange(max(len(keys), len(lines))):
130 130 try:
131 131 key = self.browser.keylabel(keys[i])
@@ -183,13 +183,13 b' class _BrowserLevel(object):'
183 183 # Size of row number (changes when scrolling)
184 184 self.numbersizex = 0
185 185
186 # Attribute names to display (in this order)
186 # Attributes to display (in this order)
187 187 self.displayattrs = []
188 188
189 # index and name of attribute under the cursor
189 # index and attribute under the cursor
190 190 self.displayattr = (None, ipipe.noitem)
191 191
192 # Maps attribute names to column widths
192 # Maps attributes to column widths
193 193 self.colwidths = {}
194 194
195 195 # Set of hidden attributes
@@ -207,6 +207,13 b' class _BrowserLevel(object):'
207 207 except StopIteration:
208 208 self.exhausted = True
209 209 break
210 except (KeyboardInterrupt, SystemExit):
211 raise
212 except Exception, exc:
213 have += 1
214 self.items.append(_BrowserCachedItem(exc))
215 self.exhausted = True
216 break
210 217 else:
211 218 have += 1
212 219 self.items.append(_BrowserCachedItem(item))
@@ -215,22 +222,23 b' class _BrowserLevel(object):'
215 222 # Calculate which attributes are available from the objects that are
216 223 # currently visible on screen (and store it in ``self.displayattrs``)
217 224
218 attrnames = set()
225 attrs = set()
219 226 self.displayattrs = []
220 227 if self.attrs:
221 228 # If the browser object specifies a fixed list of attributes,
222 229 # simply use it (removing hidden attributes).
223 for attrname in self.attrs:
224 if attrname not in attrnames and attrname not in self.hiddenattrs:
225 self.displayattrs.append(attrname)
226 attrnames.add(attrname)
230 for attr in self.attrs:
231 attr = ipipe.upgradexattr(attr)
232 if attr not in attrs and attr not in self.hiddenattrs:
233 self.displayattrs.append(attr)
234 attrs.add(attr)
227 235 else:
228 236 endy = min(self.datastarty+self.mainsizey, len(self.items))
229 237 for i in xrange(self.datastarty, endy):
230 for attrname in ipipe.xattrs(self.items[i].item, "default"):
231 if attrname not in attrnames and attrname not in self.hiddenattrs:
232 self.displayattrs.append(attrname)
233 attrnames.add(attrname)
238 for attr in ipipe.xattrs(self.items[i].item, "default"):
239 if attr not in attrs and attr not in self.hiddenattrs:
240 self.displayattrs.append(attr)
241 attrs.add(attr)
234 242
235 243 def getrow(self, i):
236 244 # Return a dictinary with the attributes for the object
@@ -239,9 +247,9 b' class _BrowserLevel(object):'
239 247 # called before.
240 248 row = {}
241 249 item = self.items[i].item
242 for attrname in self.displayattrs:
250 for attr in self.displayattrs:
243 251 try:
244 value = ipipe._getattr(item, attrname, ipipe.noitem)
252 value = attr.value(item)
245 253 except (KeyboardInterrupt, SystemExit):
246 254 raise
247 255 except Exception, exc:
@@ -249,7 +257,7 b' class _BrowserLevel(object):'
249 257 # only store attribute if it exists (or we got an exception)
250 258 if value is not ipipe.noitem:
251 259 # remember alignment, length and colored text
252 row[attrname] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
260 row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
253 261 return row
254 262
255 263 def calcwidths(self):
@@ -260,16 +268,16 b' class _BrowserLevel(object):'
260 268 # column names to widths.
261 269 self.colwidths = {}
262 270 for row in self.displayrows:
263 for attrname in self.displayattrs:
271 for attr in self.displayattrs:
264 272 try:
265 length = row[attrname][1]
273 length = row[attr][1]
266 274 except KeyError:
267 275 length = 0
268 276 # always add attribute to colwidths, even if it doesn't exist
269 if attrname not in self.colwidths:
270 self.colwidths[attrname] = len(ipipe._attrname(attrname))
271 newwidth = max(self.colwidths[attrname], length)
272 self.colwidths[attrname] = newwidth
277 if attr not in self.colwidths:
278 self.colwidths[attr] = len(attr.name())
279 newwidth = max(self.colwidths[attr], length)
280 self.colwidths[attr] = newwidth
273 281
274 282 # How many characters do we need to paint the largest item number?
275 283 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
@@ -282,11 +290,11 b' class _BrowserLevel(object):'
282 290 # Find out which attribute the cursor is on and store this
283 291 # information in ``self.displayattr``.
284 292 pos = 0
285 for (i, attrname) in enumerate(self.displayattrs):
286 if pos+self.colwidths[attrname] >= self.curx:
287 self.displayattr = (i, attrname)
293 for (i, attr) in enumerate(self.displayattrs):
294 if pos+self.colwidths[attr] >= self.curx:
295 self.displayattr = (i, attr)
288 296 break
289 pos += self.colwidths[attrname]+1
297 pos += self.colwidths[attr]+1
290 298 else:
291 299 self.displayattr = (None, ipipe.noitem)
292 300
@@ -1030,7 +1038,7 b' class ibrowse(ipipe.Display):'
1030 1038 """
1031 1039 'Pick' the object under the cursor (i.e. the row the cursor is on).
1032 1040 This leaves the browser and returns the picked object to the caller.
1033 (In IPython this object will be available as the '_' variable.)
1041 (In IPython this object will be available as the ``_`` variable.)
1034 1042 """
1035 1043 level = self.levels[-1]
1036 1044 self.returnvalue = level.items[level.cury].item
@@ -1042,17 +1050,17 b' class ibrowse(ipipe.Display):'
1042 1050 cursor is on).
1043 1051 """
1044 1052 level = self.levels[-1]
1045 attrname = level.displayattr[1]
1046 if attrname is ipipe.noitem:
1053 attr = level.displayattr[1]
1054 if attr is ipipe.noitem:
1047 1055 curses.beep()
1048 self.report(AttributeError(ipipe._attrname(attrname)))
1056 self.report(CommandError("no column under cursor"))
1049 1057 return
1050 attr = ipipe._getattr(level.items[level.cury].item, attrname)
1051 if attr is ipipe.noitem:
1058 value = attr.value(level.items[level.cury].item)
1059 if value is ipipe.noitem:
1052 1060 curses.beep()
1053 self.report(AttributeError(ipipe._attrname(attrname)))
1061 self.report(AttributeError(attr.name()))
1054 1062 else:
1055 self.returnvalue = attr
1063 self.returnvalue = value
1056 1064 return True
1057 1065
1058 1066 def cmd_pickallattrs(self):
@@ -1062,16 +1070,16 b' class ibrowse(ipipe.Display):'
1062 1070 will be returned as a list.
1063 1071 """
1064 1072 level = self.levels[-1]
1065 attrname = level.displayattr[1]
1066 if attrname is ipipe.noitem:
1073 attr = level.displayattr[1]
1074 if attr is ipipe.noitem:
1067 1075 curses.beep()
1068 self.report(AttributeError(ipipe._attrname(attrname)))
1076 self.report(CommandError("no column under cursor"))
1069 1077 return
1070 1078 result = []
1071 1079 for cache in level.items:
1072 attr = ipipe._getattr(cache.item, attrname)
1073 if attr is not ipipe.noitem:
1074 result.append(attr)
1080 value = attr.value(cache.item)
1081 if value is not ipipe.noitem:
1082 result.append(value)
1075 1083 self.returnvalue = result
1076 1084 return True
1077 1085
@@ -1090,17 +1098,17 b' class ibrowse(ipipe.Display):'
1090 1098 """
1091 1099
1092 1100 level = self.levels[-1]
1093 attrname = level.displayattr[1]
1094 if attrname is ipipe.noitem:
1101 attr = level.displayattr[1]
1102 if attr is ipipe.noitem:
1095 1103 curses.beep()
1096 self.report(AttributeError(ipipe._attrname(attrname)))
1104 self.report(CommandError("no column under cursor"))
1097 1105 return
1098 1106 result = []
1099 1107 for cache in level.items:
1100 1108 if cache.marked:
1101 attr = ipipe._getattr(cache.item, attrname)
1102 if attr is not ipipe.noitem:
1103 result.append(attr)
1109 value = attr.value(cache.item)
1110 if value is not ipipe.noitem:
1111 result.append(value)
1104 1112 self.returnvalue = result
1105 1113 return True
1106 1114
@@ -1130,7 +1138,7 b' class ibrowse(ipipe.Display):'
1130 1138 def cmd_enterdefault(self):
1131 1139 """
1132 1140 Enter the object under the cursor. (what this mean depends on the object
1133 itself (i.e. how it implements the '__xiter__' method). This opens a new
1141 itself (i.e. how it implements the ``__xiter__`` method). This opens a new
1134 1142 browser 'level'.
1135 1143 """
1136 1144 level = self.levels[-1]
@@ -1176,10 +1184,10 b' class ibrowse(ipipe.Display):'
1176 1184 Enter the attribute under the cursor.
1177 1185 """
1178 1186 level = self.levels[-1]
1179 attrname = level.displayattr[1]
1180 if attrname is ipipe.noitem:
1187 attr = level.displayattr[1]
1188 if attr is ipipe.noitem:
1181 1189 curses.beep()
1182 self.report(AttributeError(ipipe._attrname(attrname)))
1190 self.report(CommandError("no column under cursor"))
1183 1191 return
1184 1192 try:
1185 1193 item = level.items[level.cury].item
@@ -1187,12 +1195,13 b' class ibrowse(ipipe.Display):'
1187 1195 self.report(CommandError("No object"))
1188 1196 curses.beep()
1189 1197 else:
1190 attr = ipipe._getattr(item, attrname)
1191 if attr is ipipe.noitem:
1192 self.report(AttributeError(ipipe._attrname(attrname)))
1198 value = attr.value(item)
1199 name = attr.name()
1200 if value is ipipe.noitem:
1201 self.report(AttributeError(name))
1193 1202 else:
1194 self.report("entering object attribute %s..." % ipipe._attrname(attrname))
1195 self.enter(attr, None)
1203 self.report("entering object attribute %s..." % name)
1204 self.enter(value, None)
1196 1205
1197 1206 def cmd_detail(self):
1198 1207 """
@@ -1209,17 +1218,18 b' class ibrowse(ipipe.Display):'
1209 1218 curses.beep()
1210 1219 else:
1211 1220 self.report("entering detail view for object...")
1212 self.enter(item, "detail")
1221 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1222 self.enter(attrs, "detail")
1213 1223
1214 1224 def cmd_detailattr(self):
1215 1225 """
1216 1226 Show a detail view of the attribute under the cursor.
1217 1227 """
1218 1228 level = self.levels[-1]
1219 attrname = level.displayattr[1]
1220 if attrname is ipipe.noitem:
1229 attr = level.displayattr[1]
1230 if attr is ipipe.noitem:
1221 1231 curses.beep()
1222 self.report(AttributeError(ipipe._attrname(attrname)))
1232 self.report(CommandError("no attribute"))
1223 1233 return
1224 1234 try:
1225 1235 item = level.items[level.cury].item
@@ -1227,12 +1237,16 b' class ibrowse(ipipe.Display):'
1227 1237 self.report(CommandError("No object"))
1228 1238 curses.beep()
1229 1239 else:
1230 attr = ipipe._getattr(item, attrname)
1231 if attr is ipipe.noitem:
1232 self.report(AttributeError(ipipe._attrname(attrname)))
1240 try:
1241 item = attr.value(item)
1242 except (KeyboardInterrupt, SystemExit):
1243 raise
1244 except Exception, exc:
1245 self.report(exc)
1233 1246 else:
1234 self.report("entering detail view for attribute...")
1235 self.enter(attr, "detail")
1247 self.report("entering detail view for attribute %s..." % attr.name())
1248 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1249 self.enter(attrs, "detail")
1236 1250
1237 1251 def cmd_tooglemark(self):
1238 1252 """
@@ -1259,15 +1273,15 b' class ibrowse(ipipe.Display):'
1259 1273 the cursor as the sort key.
1260 1274 """
1261 1275 level = self.levels[-1]
1262 attrname = level.displayattr[1]
1263 if attrname is ipipe.noitem:
1276 attr = level.displayattr[1]
1277 if attr is ipipe.noitem:
1264 1278 curses.beep()
1265 self.report(AttributeError(ipipe._attrname(attrname)))
1279 self.report(CommandError("no column under cursor"))
1266 1280 return
1267 self.report("sort by %s (ascending)" % ipipe._attrname(attrname))
1281 self.report("sort by %s (ascending)" % attr.name())
1268 1282 def key(item):
1269 1283 try:
1270 return ipipe._getattr(item, attrname, None)
1284 return attr.value(item)
1271 1285 except (KeyboardInterrupt, SystemExit):
1272 1286 raise
1273 1287 except Exception:
@@ -1280,15 +1294,15 b' class ibrowse(ipipe.Display):'
1280 1294 the cursor as the sort key.
1281 1295 """
1282 1296 level = self.levels[-1]
1283 attrname = level.displayattr[1]
1284 if attrname is ipipe.noitem:
1297 attr = level.displayattr[1]
1298 if attr is ipipe.noitem:
1285 1299 curses.beep()
1286 self.report(AttributeError(ipipe._attrname(attrname)))
1300 self.report(CommandError("no column under cursor"))
1287 1301 return
1288 self.report("sort by %s (descending)" % ipipe._attrname(attrname))
1302 self.report("sort by %s (descending)" % attr.name())
1289 1303 def key(item):
1290 1304 try:
1291 return ipipe._getattr(item, attrname, None)
1305 return attr.value(item)
1292 1306 except (KeyboardInterrupt, SystemExit):
1293 1307 raise
1294 1308 except Exception:
@@ -1427,11 +1441,11 b' class ibrowse(ipipe.Display):'
1427 1441 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1428 1442 begx = level.numbersizex+3
1429 1443 posx = begx-level.datastartx
1430 for attrname in level.displayattrs:
1431 strattrname = ipipe._attrname(attrname)
1432 cwidth = level.colwidths[attrname]
1433 header = strattrname.ljust(cwidth)
1434 if attrname == level.displayattr[1]:
1444 for attr in level.displayattrs:
1445 attrname = attr.name()
1446 cwidth = level.colwidths[attr]
1447 header = attrname.ljust(cwidth)
1448 if attr is level.displayattr[1]:
1435 1449 style = self.style_colheaderhere
1436 1450 else:
1437 1451 style = self.style_colheader
@@ -1527,19 +1541,19 b' class ibrowse(ipipe.Display):'
1527 1541 break
1528 1542
1529 1543 attrstyle = [(astyle.style_default, "no attribute")]
1530 attrname = level.displayattr[1]
1531 if attrname is not ipipe.noitem and attrname is not None:
1544 attr = level.displayattr[1]
1545 if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
1532 1546 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
1533 posx += self.addstr(posy, posx, 0, endx, ipipe._attrname(attrname), self.style_footer)
1547 posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
1534 1548 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1535 1549 try:
1536 attr = ipipe._getattr(item, attrname)
1550 value = attr.value(item)
1537 1551 except (SystemExit, KeyboardInterrupt):
1538 1552 raise
1539 1553 except Exception, exc:
1540 1554 attr = exc
1541 if attr is not ipipe.noitem:
1542 attrstyle = ipipe.xrepr(attr, "footer")
1555 if value is not ipipe.noitem:
1556 attrstyle = ipipe.xrepr(value, "footer")
1543 1557 for (nostyle, text) in attrstyle:
1544 1558 if not isinstance(nostyle, int):
1545 1559 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
This diff has been collapsed as it changes many lines, (596 lines changed) Show them Hide them
@@ -269,6 +269,251 b' def getglobals(g):'
269 269 return g
270 270
271 271
272 class Descriptor(object):
273 def __hash__(self):
274 return hash(self.__class__) ^ hash(self.key())
275
276 def __eq__(self, other):
277 return self.__class__ is other.__class__ and self.key() == other.key()
278
279 def __ne__(self, other):
280 return self.__class__ is not other.__class__ or self.key() != other.key()
281
282 def key(self):
283 pass
284
285 def name(self):
286 key = self.key()
287 if key is None:
288 return "_"
289 return str(key)
290
291 def attrtype(self, obj):
292 pass
293
294 def valuetype(self, obj):
295 pass
296
297 def value(self, obj):
298 pass
299
300 def doc(self, obj):
301 pass
302
303 def shortdoc(self, obj):
304 doc = self.doc(obj)
305 if doc is not None:
306 doc = doc.strip().splitlines()[0].strip()
307 return doc
308
309 def iter(self, obj):
310 return xiter(self.value(obj))
311
312
313 class SelfDescriptor(Descriptor):
314 def key(self):
315 return None
316
317 def attrtype(self, obj):
318 return "self"
319
320 def valuetype(self, obj):
321 return type(obj)
322
323 def value(self, obj):
324 return obj
325
326 def __repr__(self):
327 return "Self"
328
329 selfdescriptor = SelfDescriptor() # there's no need for more than one
330
331
332 class AttributeDescriptor(Descriptor):
333 __slots__ = ("_name", "_doc")
334
335 def __init__(self, name, doc=None):
336 self._name = name
337 self._doc = doc
338
339 def key(self):
340 return self._name
341
342 def doc(self, obj):
343 return self._doc
344
345 def attrtype(self, obj):
346 return "attr"
347
348 def valuetype(self, obj):
349 return type(getattr(obj, self._name))
350
351 def value(self, obj):
352 return getattr(obj, self._name)
353
354 def __repr__(self):
355 if self._doc is None:
356 return "Attribute(%r)" % self._name
357 else:
358 return "Attribute(%r, %r)" % (self._name, self._doc)
359
360
361 class IndexDescriptor(Descriptor):
362 __slots__ = ("_index",)
363
364 def __init__(self, index):
365 self._index = index
366
367 def key(self):
368 return self._index
369
370 def attrtype(self, obj):
371 return "item"
372
373 def valuetype(self, obj):
374 return type(obj[self._index])
375
376 def value(self, obj):
377 return obj[self._index]
378
379 def __repr__(self):
380 return "Index(%r)" % self._index
381
382
383 class MethodDescriptor(Descriptor):
384 __slots__ = ("_name", "_doc")
385
386 def __init__(self, name, doc=None):
387 self._name = name
388 self._doc = doc
389
390 def key(self):
391 return self._name
392
393 def doc(self, obj):
394 if self._doc is None:
395 return getattr(obj, self._name).__doc__
396 return self._doc
397
398 def attrtype(self, obj):
399 return "method"
400
401 def valuetype(self, obj):
402 return type(self.value(obj))
403
404 def value(self, obj):
405 return getattr(obj, self._name)()
406
407 def __repr__(self):
408 if self._doc is None:
409 return "Method(%r)" % self._name
410 else:
411 return "Method(%r, %r)" % (self._name, self._doc)
412
413
414 class IterAttributeDescriptor(Descriptor):
415 __slots__ = ("_name", "_doc")
416
417 def __init__(self, name, doc=None):
418 self._name = name
419 self._doc = doc
420
421 def key(self):
422 return self._name
423
424 def doc(self, obj):
425 return self._doc
426
427 def attrtype(self, obj):
428 return "iter"
429
430 def valuetype(self, obj):
431 return noitem
432
433 def value(self, obj):
434 return noitem
435
436 def iter(self, obj):
437 return xiter(getattr(obj, self._name))
438
439 def __repr__(self):
440 if self._doc is None:
441 return "IterAttribute(%r)" % self._name
442 else:
443 return "IterAttribute(%r, %r)" % (self._name, self._doc)
444
445
446 class IterMethodDescriptor(Descriptor):
447 __slots__ = ("_name", "_doc")
448
449 def __init__(self, name, doc=None):
450 self._name = name
451 self._doc = doc
452
453 def key(self):
454 return self._name
455
456 def doc(self, obj):
457 if self._doc is None:
458 return getattr(obj, self._name).__doc__
459 return self._doc
460
461 def attrtype(self, obj):
462 return "itermethod"
463
464 def valuetype(self, obj):
465 return noitem
466
467 def value(self, obj):
468 return noitem
469
470 def iter(self, obj):
471 return xiter(getattr(obj, self._name)())
472
473 def __repr__(self):
474 if self._doc is None:
475 return "IterMethod(%r)" % self._name
476 else:
477 return "IterMethod(%r, %r)" % (self._name, self._doc)
478
479
480 class FunctionDescriptor(Descriptor):
481 __slots__ = ("_function", "_name", "_doc")
482
483 def __init__(self, function, name=None, doc=None):
484 self._function = function
485 self._name = name
486 self._doc = doc
487
488 def key(self):
489 return self._function
490
491 def name(self):
492 if self._name is not None:
493 return self._name
494 return getattr(self._function, "__xname__", self._function.__name__)
495
496 def doc(self, obj):
497 if self._doc is None:
498 return self._function.__doc__
499 return self._doc
500
501 def attrtype(self, obj):
502 return "function"
503
504 def valuetype(self, obj):
505 return type(self._function(obj))
506
507 def value(self, obj):
508 return self._function(obj)
509
510 def __repr__(self):
511 if self._doc is None:
512 return "Function(%r)" % self._name
513 else:
514 return "Function(%r, %r)" % (self._name, self._doc)
515
516
272 517 class Table(object):
273 518 """
274 519 A ``Table`` is an object that produces items (just like a normal Python
@@ -350,47 +595,7 b' class Pipe(Table):'
350 595 return self
351 596
352 597
353 def _getattr(obj, name, default=noitem):
354 """
355 Internal helper for getting an attribute of an item. If ``name`` is ``None``
356 return the object itself. If ``name`` is an integer, use ``__getitem__``
357 instead. If the attribute or item does not exist, return ``default``.
358 """
359 if name is None:
360 return obj
361 elif isinstance(name, basestring):
362 if name.endswith("()"):
363 return getattr(obj, name[:-2], default)()
364 else:
365 return getattr(obj, name, default)
366 elif callable(name):
367 try:
368 return name(obj)
369 except AttributeError:
370 return default
371 else:
372 try:
373 return obj[name]
374 except IndexError:
375 return default
376
377
378 def _attrname(name):
379 """
380 Internal helper that gives a proper name for the attribute ``name``
381 (which might be ``None`` or an ``int``).
382 """
383 if name is None:
384 return "_"
385 elif isinstance(name, basestring):
386 return name
387 elif callable(name):
388 return getattr(name, "__xname__", name.__name__)
389 else:
390 return str(name)
391
392
393 def xrepr(item, mode):
598 def xrepr(item, mode="default"):
394 599 try:
395 600 func = item.__xrepr__
396 601 except AttributeError:
@@ -449,6 +654,11 b' def xrepr(item, mode):'
449 654 yield (astyle.style_type_datetime, repr(item))
450 655 elif isinstance(item, datetime.timedelta):
451 656 yield (astyle.style_type_datetime, repr(item))
657 elif isinstance(item, type):
658 if item.__module__ == "__builtin__":
659 yield (astyle.style_type_type, item.__name__)
660 else:
661 yield (astyle.style_type_type, "%s.%s" % (item.__module__, item.__name__))
452 662 elif isinstance(item, Exception):
453 663 if item.__class__.__module__ == "exceptions":
454 664 classname = item.__class__.__name__
@@ -514,33 +724,67 b' def xrepr(item, mode):'
514 724 yield (astyle.style_default, repr(item))
515 725
516 726
517 def xattrs(item, mode):
727 def upgradexattr(attr):
728 if attr is None:
729 return selfdescriptor
730 elif isinstance(attr, Descriptor):
731 return attr
732 elif isinstance(attr, str):
733 if attr.endswith("()"):
734 if attr.startswith("-"):
735 return IterMethodDescriptor(attr[1:-2])
736 else:
737 return MethodDescriptor(attr[:-2])
738 else:
739 if attr.startswith("-"):
740 return IterAttributeDescriptor(attr[1:])
741 else:
742 return AttributeDescriptor(attr)
743 elif isinstance(attr, (int, long)):
744 return IndexDescriptor(attr)
745 elif callable(attr):
746 return FunctionDescriptor(attr)
747 else:
748 raise TypeError("can't handle descriptor %r" % attr)
749
750
751 def xattrs(item, mode="default"):
518 752 try:
519 753 func = item.__xattrs__
520 754 except AttributeError:
521 755 if mode == "detail":
522 return dir(item)
756 for attrname in dir(item):
757 yield AttributeDescriptor(attrname)
523 758 else:
524 return (None,)
759 yield selfdescriptor
525 760 else:
526 try:
527 return func(mode)
528 except (KeyboardInterrupt, SystemExit):
529 raise
530 except Exception:
531 return (None,)
761 for attr in func(mode):
762 yield upgradexattr(attr)
532 763
533 764
534 def xiter(item, mode):
535 if mode == "detail":
536 def items():
537 for name in xattrs(item, mode):
538 yield XAttr(item, name)
539 return items()
765 def _isdict(item):
766 try:
767 itermeth = item.__class__.__iter__
768 except (AttributeError, TypeError):
769 return False
770 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
771
772
773 def _isstr(item):
774 if not isinstance(item, basestring):
775 return False
776 try:
777 itermeth = item.__class__.__iter__
778 except AttributeError:
779 return True
780 return False # ``__iter__`` has been redefined
781
782
783 def xiter(item, mode="default"):
540 784 try:
541 785 func = item.__xiter__
542 786 except AttributeError:
543 if isinstance(item, (dict, types.DictProxyType)):
787 if _isdict(item):
544 788 def items(item):
545 789 fields = ("key", "value")
546 790 for (key, value) in item.iteritems():
@@ -552,8 +796,8 b' def xiter(item, mode):'
552 796 for key in sorted(item.__dict__):
553 797 yield Fields(fields, key=key, value=getattr(item, key))
554 798 return items(item)
555 elif isinstance(item, basestring):
556 if not len(item):
799 elif _isstr(item):
800 if not item:
557 801 raise ValueError("can't enter empty string")
558 802 lines = item.splitlines()
559 803 if len(lines) <= 1:
@@ -572,7 +816,7 b' class ichain(Pipe):'
572 816 def __init__(self, *iters):
573 817 self.iters = iters
574 818
575 def __xiter__(self, mode):
819 def __iter__(self):
576 820 return itertools.chain(*self.iters)
577 821
578 822 def __xrepr__(self, mode):
@@ -823,30 +1067,61 b' class ifile(path.path):'
823 1067 return datetime.datetime.utcfromtimestamp(self.mtime)
824 1068 mdate = property(getmdate, None, None, "Modification date")
825 1069
826 def getmimetype(self):
1070 def mimetype(self):
1071 """
1072 Return MIME type guessed from the extension.
1073 """
827 1074 return mimetypes.guess_type(self.basename())[0]
828 mimetype = property(getmimetype, None, None, "MIME type")
829 1075
830 def getencoding(self):
1076 def encoding(self):
1077 """
1078 Return guessed compression (like "compress" or "gzip").
1079 """
831 1080 return mimetypes.guess_type(self.basename())[1]
832 encoding = property(getencoding, None, None, "Compression")
833 1081
834 1082 def __repr__(self):
835 1083 return "ifile(%s)" % path._base.__repr__(self)
836 1084
837 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
838
839 1085 def __xattrs__(self, mode):
840 1086 if mode == "detail":
841 1087 return (
842 "name", "basename()", "abspath()", "realpath()",
843 "type", "mode", "modestr", "stat()", "lstat()",
844 "uid", "gid", "owner", "group", "dev", "nlink",
845 "ctime", "mtime", "atime", "cdate", "mdate", "adate",
846 "size", "blocks", "blksize", "isdir()", "islink()",
847 "mimetype", "encoding"
1088 "name",
1089 "basename()",
1090 "abspath()",
1091 "realpath()",
1092 "type",
1093 "mode",
1094 "modestr",
1095 "stat()",
1096 "lstat()",
1097 "uid",
1098 "gid",
1099 "owner",
1100 "group",
1101 "dev",
1102 "nlink",
1103 "ctime",
1104 "mtime",
1105 "atime",
1106 "cdate",
1107 "mdate",
1108 "adate",
1109 "size",
1110 "blocks",
1111 "blksize",
1112 "isdir()",
1113 "islink()",
1114 "mimetype()",
1115 "encoding()",
1116 "-listdir()",
1117 "-dirs()",
1118 "-files()",
1119 "-walk()",
1120 "-walkdirs()",
1121 "-walkfiles()",
848 1122 )
849 return self.defaultattrs
1123 else:
1124 return (None, "type", "size", "modestr", "owner", "group", "mdate")
850 1125
851 1126 def __xrepr__(self, mode):
852 1127 try:
@@ -872,7 +1147,7 b' class ifile(path.path):'
872 1147 else:
873 1148 yield (style, repr(self))
874 1149
875 def __xiter__(self, mode):
1150 def __iter__(self):
876 1151 if self.isdir():
877 1152 yield iparentdir(self / os.pardir)
878 1153 for child in sorted(self.listdir()):
@@ -906,8 +1181,8 b' class ils(Table):'
906 1181 def __init__(self, base=os.curdir):
907 1182 self.base = os.path.expanduser(base)
908 1183
909 def __xiter__(self, mode):
910 return xiter(ifile(self.base), mode)
1184 def __iter__(self):
1185 return xiter(ifile(self.base))
911 1186
912 1187 def __xrepr__(self, mode):
913 1188 return ifile(self.base).__xrepr__(mode)
@@ -929,7 +1204,7 b' class iglob(Table):'
929 1204 def __init__(self, glob):
930 1205 self.glob = glob
931 1206
932 def __xiter__(self, mode):
1207 def __iter__(self):
933 1208 for name in glob.glob(self.glob):
934 1209 yield ifile(name)
935 1210
@@ -958,7 +1233,7 b' class iwalk(Table):'
958 1233 self.dirs = dirs
959 1234 self.files = files
960 1235
961 def __xiter__(self, mode):
1236 def __iter__(self):
962 1237 for (dirpath, dirnames, filenames) in os.walk(self.base):
963 1238 if self.dirs:
964 1239 for name in sorted(dirnames):
@@ -1035,7 +1310,7 b' class ipwdentry(object):'
1035 1310 shell = property(getshell, None, None, "Login shell")
1036 1311
1037 1312 def __xattrs__(self, mode):
1038 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1313 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1039 1314
1040 1315 def __repr__(self):
1041 1316 return "%s.%s(%r)" % \
@@ -1115,7 +1390,7 b' class igrpentry(object):'
1115 1390 else:
1116 1391 yield (astyle.style_default, repr(self))
1117 1392
1118 def __xiter__(self, mode):
1393 def __iter__(self):
1119 1394 for member in self.mem:
1120 1395 yield ipwdentry(member)
1121 1396
@@ -1128,7 +1403,7 b' class igrp(Table):'
1128 1403 """
1129 1404 This ``Table`` lists all entries in the Unix group database.
1130 1405 """
1131 def __xiter__(self, mode):
1406 def __iter__(self):
1132 1407 for entry in grp.getgrall():
1133 1408 yield igrpentry(entry.gr_name)
1134 1409
@@ -1141,7 +1416,7 b' class igrp(Table):'
1141 1416
1142 1417 class Fields(object):
1143 1418 def __init__(self, fieldnames, **fields):
1144 self.__fieldnames = fieldnames
1419 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1145 1420 for (key, value) in fields.iteritems():
1146 1421 setattr(self, key, value)
1147 1422
@@ -1156,7 +1431,7 b' class Fields(object):'
1156 1431 for (i, f) in enumerate(self.__fieldnames):
1157 1432 if i:
1158 1433 yield (astyle.style_default, ", ")
1159 yield (astyle.style_default, f)
1434 yield (astyle.style_default, f.name())
1160 1435 yield (astyle.style_default, "=")
1161 1436 for part in xrepr(getattr(self, f), "default"):
1162 1437 yield part
@@ -1167,7 +1442,7 b' class Fields(object):'
1167 1442 for (i, f) in enumerate(self.__fieldnames):
1168 1443 if i:
1169 1444 yield (astyle.style_default, ", ")
1170 yield (astyle.style_default, f)
1445 yield (astyle.style_default, f.name())
1171 1446 yield (astyle.style_default, ")")
1172 1447 else:
1173 1448 yield (astyle.style_default, repr(self))
@@ -1182,9 +1457,6 b' class FieldTable(Table, list):'
1182 1457 def add(self, **fields):
1183 1458 self.append(Fields(self.fields, **fields))
1184 1459
1185 def __xiter__(self, mode):
1186 return list.__iter__(self)
1187
1188 1460 def __xrepr__(self, mode):
1189 1461 yield (-1, False)
1190 1462 if mode == "header" or mode == "footer":
@@ -1232,7 +1504,7 b' class ienv(Table):'
1232 1504 >>> ienv
1233 1505 """
1234 1506
1235 def __xiter__(self, mode):
1507 def __iter__(self):
1236 1508 fields = ("key", "value")
1237 1509 for (key, value) in os.environ.iteritems():
1238 1510 yield Fields(fields, key=key, value=value)
@@ -1256,7 +1528,7 b' class icsv(Pipe):'
1256 1528 """
1257 1529 self.csvargs = csvargs
1258 1530
1259 def __xiter__(self, mode):
1531 def __iter__(self):
1260 1532 input = self.input
1261 1533 if isinstance(input, ifile):
1262 1534 input = input.open("rb")
@@ -1304,7 +1576,7 b' class ix(Table):'
1304 1576 self.cmd = cmd
1305 1577 self._pipeout = None
1306 1578
1307 def __xiter__(self, mode="default"):
1579 def __iter__(self):
1308 1580 (_pipein, self._pipeout) = os.popen4(self.cmd)
1309 1581 _pipein.close()
1310 1582 for l in self._pipeout:
@@ -1364,7 +1636,7 b' class ifilter(Pipe):'
1364 1636 self.globals = globals
1365 1637 self.errors = errors
1366 1638
1367 def __xiter__(self, mode):
1639 def __iter__(self):
1368 1640 if callable(self.expr):
1369 1641 test = self.expr
1370 1642 else:
@@ -1375,7 +1647,7 b' class ifilter(Pipe):'
1375 1647
1376 1648 ok = 0
1377 1649 exc_info = None
1378 for item in xiter(self.input, mode):
1650 for item in xiter(self.input):
1379 1651 try:
1380 1652 if test(item):
1381 1653 yield item
@@ -1437,7 +1709,7 b' class ieval(Pipe):'
1437 1709 self.globals = globals
1438 1710 self.errors = errors
1439 1711
1440 def __xiter__(self, mode):
1712 def __iter__(self):
1441 1713 if callable(self.expr):
1442 1714 do = self.expr
1443 1715 else:
@@ -1448,7 +1720,7 b' class ieval(Pipe):'
1448 1720
1449 1721 ok = 0
1450 1722 exc_info = None
1451 for item in xiter(self.input, mode):
1723 for item in xiter(self.input):
1452 1724 try:
1453 1725 yield do(item)
1454 1726 except (KeyboardInterrupt, SystemExit):
@@ -1497,9 +1769,9 b' class ienum(Pipe):'
1497 1769
1498 1770 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1499 1771 """
1500 def __xiter__(self, mode):
1772 def __iter__(self):
1501 1773 fields = ("index", "object")
1502 for (index, object) in enumerate(xiter(self.input, mode)):
1774 for (index, object) in enumerate(xiter(self.input)):
1503 1775 yield Fields(fields, index=index, object=object)
1504 1776
1505 1777
@@ -1524,18 +1796,11 b' class isort(Pipe):'
1524 1796 self.globals = globals
1525 1797 self.reverse = reverse
1526 1798
1527 def __xiter__(self, mode):
1799 def __iter__(self):
1528 1800 if self.key is None:
1529 items = sorted(
1530 xiter(self.input, mode),
1531 reverse=self.reverse
1532 )
1801 items = sorted(xiter(self.input), reverse=self.reverse)
1533 1802 elif callable(self.key):
1534 items = sorted(
1535 xiter(self.input, mode),
1536 key=self.key,
1537 reverse=self.reverse
1538 )
1803 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1539 1804 else:
1540 1805 g = getglobals(self.globals)
1541 1806 key = compile(self.key, "ipipe-expression", "eval")
@@ -1613,8 +1878,8 b' class iless(Display):'
1613 1878 pager = os.popen(self.cmd, "w")
1614 1879 try:
1615 1880 for item in xiter(self.input, "default"):
1616 attrs = xattrs(item, "default")
1617 attrs = ["%s=%s" % (a, _format(_getattr(item, a))) for a in attrs]
1881 attrs = tuple(_upgradexattrs(item, "default"))
1882 attrs = ["%s=%s" % (a.name(item), a.value(item)) for a in attrs]
1618 1883 pager.write(" ".join(attrs))
1619 1884 pager.write("\n")
1620 1885 finally:
@@ -1659,7 +1924,7 b' class idump(Display):'
1659 1924 style_header = astyle.Style.fromstr("white:black:bold")
1660 1925
1661 1926 def __init__(self, *attrs):
1662 self.attrs = attrs
1927 self.attrs = [upgradexattr(attr) for attr in attrs]
1663 1928 self.headerpadchar = " "
1664 1929 self.headersepchar = "|"
1665 1930 self.datapadchar = " "
@@ -1668,7 +1933,7 b' class idump(Display):'
1668 1933 def display(self):
1669 1934 stream = genutils.Term.cout
1670 1935 allattrs = []
1671 allattrset = set()
1936 attrset = set()
1672 1937 colwidths = {}
1673 1938 rows = []
1674 1939 for item in xiter(self.input, "default"):
@@ -1676,42 +1941,43 b' class idump(Display):'
1676 1941 attrs = self.attrs
1677 1942 if not attrs:
1678 1943 attrs = xattrs(item, "default")
1679 for attrname in attrs:
1680 if attrname not in allattrset:
1681 allattrs.append(attrname)
1682 allattrset.add(attrname)
1683 colwidths[attrname] = len(_attrname(attrname))
1944 for attr in attrs:
1945 if attr not in attrset:
1946 allattrs.append(attr)
1947 attrset.add(attr)
1948 colwidths[attr] = len(attr.name())
1684 1949 try:
1685 value = _getattr(item, attrname, None)
1950 value = attr.value(item)
1686 1951 except (KeyboardInterrupt, SystemExit):
1687 1952 raise
1688 1953 except Exception, exc:
1689 1954 value = exc
1690 1955 (align, width, text) = xformat(value, "cell", self.maxattrlength)
1691 colwidths[attrname] = max(colwidths[attrname], width)
1956 colwidths[attr] = max(colwidths[attr], width)
1692 1957 # remember alignment, length and colored parts
1693 row[attrname] = (align, width, text)
1958 row[attr] = (align, width, text)
1694 1959 rows.append(row)
1695 1960
1696 1961 stream.write("\n")
1697 for (i, attrname) in enumerate(allattrs):
1698 self.style_header(_attrname(attrname)).write(stream)
1699 spc = colwidths[attrname] - len(_attrname(attrname))
1962 for (i, attr) in enumerate(allattrs):
1963 attrname = attr.name()
1964 self.style_header(attrname).write(stream)
1965 spc = colwidths[attr] - len(attrname)
1700 1966 if i < len(colwidths)-1:
1701 1967 stream.write(self.headerpadchar*spc)
1702 1968 stream.write(self.headersepchar)
1703 1969 stream.write("\n")
1704 1970
1705 1971 for row in rows:
1706 for (i, attrname) in enumerate(allattrs):
1707 (align, width, text) = row[attrname]
1708 spc = colwidths[attrname] - width
1972 for (i, attr) in enumerate(allattrs):
1973 (align, width, text) = row[attr]
1974 spc = colwidths[attr] - width
1709 1975 if align == -1:
1710 1976 text.write(stream)
1711 1977 if i < len(colwidths)-1:
1712 1978 stream.write(self.datapadchar*spc)
1713 1979 elif align == 0:
1714 spc = colwidths[attrname] - width
1980 spc = colwidths[attr] - width
1715 1981 spc1 = spc//2
1716 1982 spc2 = spc-spc1
1717 1983 stream.write(self.datapadchar*spc1)
@@ -1755,55 +2021,57 b' class XMode(object):'
1755 2021
1756 2022 def __xattrs__(self, mode):
1757 2023 if mode == "detail":
2024 return ("object", "mode")
2025 else:
1758 2026 return ("object", "mode", "title", "description")
1759 return ("title", "description")
1760 2027
1761 2028 def __xiter__(self, mode):
1762 2029 return xiter(self.object, self.mode)
1763 2030
1764 2031
1765 class XAttr(object):
1766 def __init__(self, object, name):
1767 self.name = _attrname(name)
2032 class AttributeDetail(Table):
2033 def __init__(self, object, descriptor):
2034 self.object = object
2035 self.descriptor = descriptor
1768 2036
1769 try:
1770 self.value = _getattr(object, name)
1771 except (KeyboardInterrupt, SystemExit):
1772 raise
1773 except Exception, exc:
1774 if exc.__class__.__module__ == "exceptions":
1775 self.value = exc.__class__.__name__
1776 else:
1777 self.value = "%s.%s" % \
1778 (exc.__class__.__module__, exc.__class__.__name__)
1779 self.type = self.value
1780 else:
1781 t = type(self.value)
1782 if t.__module__ == "__builtin__":
1783 self.type = t.__name__
1784 else:
1785 self.type = "%s.%s" % (t.__module__, t.__name__)
2037 def __iter__(self):
2038 return self.descriptor.iter(self.object)
1786 2039
1787 doc = None
1788 if isinstance(name, basestring):
1789 if name.endswith("()"):
1790 doc = getattr(getattr(object, name[:-2]), "__doc__", None)
1791 else:
1792 try:
1793 meta = getattr(type(object), name)
1794 except AttributeError:
1795 pass
1796 else:
1797 if isinstance(meta, property):
1798 doc = getattr(meta, "__doc__", None)
1799 elif callable(name):
1800 doc = getattr(name, "__doc__", None)
1801 if isinstance(doc, basestring):
1802 doc = doc.strip()
1803 self.doc = doc
2040 def name(self):
2041 return self.descriptor.name()
2042
2043 def attrtype(self):
2044 return self.descriptor.attrtype(self.object)
2045
2046 def valuetype(self):
2047 return self.descriptor.valuetype(self.object)
2048
2049 def doc(self):
2050 return self.descriptor.doc(self.object)
2051
2052 def shortdoc(self):
2053 return self.descriptor.shortdoc(self.object)
2054
2055 def value(self):
2056 return self.descriptor.value(self.object)
1804 2057
1805 2058 def __xattrs__(self, mode):
1806 return ("name", "type", "doc", "value")
2059 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2060 if mode == "detail":
2061 attrs += ("doc()",)
2062 return attrs
2063
2064 def __xrepr__(self, mode):
2065 yield (-1, True)
2066 yield (astyle.style_default, self.attrtype())
2067 yield (astyle.style_default, "(")
2068 for part in xrepr(self.valuetype()):
2069 yield part
2070 yield (astyle.style_default, ") ")
2071 yield (astyle.style_default, self.name())
2072 yield (astyle.style_default, " of ")
2073 for part in xrepr(self.object):
2074 yield part
1807 2075
1808 2076
1809 2077 try:
@@ -3,6 +3,27 b''
3 3 * IPython/Extensions/ipipe.py: Fix getglobals() if we're
4 4 not running under IPython.
5 5
6 * IPython/Extensions/ipipe.py: Rename XAttr to AttributeDetail
7 and make it iterable (iterating over the attribute itself). Add two new
8 magic strings for __xattrs__(): If the string starts with "-", the attribute
9 will not be displayed in ibrowse's detail view (but it can still be
10 iterated over). This makes it possible to add attributes that are large
11 lists or generator methods to the detail view. Replace magic attribute names
12 and _attrname() and _getattr() with "descriptors": For each type of magic
13 attribute name there's a subclass of Descriptor: None -> SelfDescriptor();
14 "foo" -> AttributeDescriptor("foo"); "foo()" -> MethodDescriptor("foo");
15 "-foo" -> IterAttributeDescriptor("foo"); "-foo()" -> IterMethodDescriptor("foo");
16 foo() -> FunctionDescriptor(foo). Magic strings returned from __xattrs__()
17 are still supported.
18
19 * IPython/Extensions/ibrowse.py: If fetching the next row from the input
20 fails in ibrowse.fetch(), the exception object is added as the last item
21 and item fetching is canceled. This prevents ibrowse from aborting if e.g.
22 a generator throws an exception midway through execution.
23
24 * IPython/Extensions/ipipe.py: Turn ifile's properties mimetype and
25 encoding into methods.
26
6 27 2006-07-26 Ville Vainio <vivainio@gmail.com>
7 28
8 29 * iplib.py: history now stores multiline input as single
General Comments 0
You need to be logged in to leave comments. Login now