##// 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 style_type_bool = Style.fromstr("magenta:black")
374 style_type_bool = Style.fromstr("magenta:black")
375 style_type_number = Style.fromstr("yellow:black")
375 style_type_number = Style.fromstr("yellow:black")
376 style_type_datetime = Style.fromstr("magenta:black")
376 style_type_datetime = Style.fromstr("magenta:black")
377 style_type_type = Style.fromstr("cyan:black")
377
378
378 # Style for URLs and file/directory names
379 # Style for URLs and file/directory names
379 style_url = Style.fromstr("green:black")
380 style_url = Style.fromstr("green:black")
@@ -97,7 +97,7 b' class _BrowserHelp(object):'
97 else:
97 else:
98 yield (astyle.style_default, repr(self))
98 yield (astyle.style_default, repr(self))
99
99
100 def __xiter__(self, mode):
100 def __iter__(self):
101 # Get reverse key mapping
101 # Get reverse key mapping
102 allkeys = {}
102 allkeys = {}
103 for (key, cmd) in self.browser.keymap.iteritems():
103 for (key, cmd) in self.browser.keymap.iteritems():
@@ -125,7 +125,7 b' class _BrowserHelp(object):'
125 lines = textwrap.wrap(description, 60)
125 lines = textwrap.wrap(description, 60)
126 keys = allkeys.get(name, [])
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 for i in xrange(max(len(keys), len(lines))):
129 for i in xrange(max(len(keys), len(lines))):
130 try:
130 try:
131 key = self.browser.keylabel(keys[i])
131 key = self.browser.keylabel(keys[i])
@@ -183,13 +183,13 b' class _BrowserLevel(object):'
183 # Size of row number (changes when scrolling)
183 # Size of row number (changes when scrolling)
184 self.numbersizex = 0
184 self.numbersizex = 0
185
185
186 # Attribute names to display (in this order)
186 # Attributes to display (in this order)
187 self.displayattrs = []
187 self.displayattrs = []
188
188
189 # index and name of attribute under the cursor
189 # index and attribute under the cursor
190 self.displayattr = (None, ipipe.noitem)
190 self.displayattr = (None, ipipe.noitem)
191
191
192 # Maps attribute names to column widths
192 # Maps attributes to column widths
193 self.colwidths = {}
193 self.colwidths = {}
194
194
195 # Set of hidden attributes
195 # Set of hidden attributes
@@ -207,6 +207,13 b' class _BrowserLevel(object):'
207 except StopIteration:
207 except StopIteration:
208 self.exhausted = True
208 self.exhausted = True
209 break
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 else:
217 else:
211 have += 1
218 have += 1
212 self.items.append(_BrowserCachedItem(item))
219 self.items.append(_BrowserCachedItem(item))
@@ -215,22 +222,23 b' class _BrowserLevel(object):'
215 # Calculate which attributes are available from the objects that are
222 # Calculate which attributes are available from the objects that are
216 # currently visible on screen (and store it in ``self.displayattrs``)
223 # currently visible on screen (and store it in ``self.displayattrs``)
217
224
218 attrnames = set()
225 attrs = set()
219 self.displayattrs = []
226 self.displayattrs = []
220 if self.attrs:
227 if self.attrs:
221 # If the browser object specifies a fixed list of attributes,
228 # If the browser object specifies a fixed list of attributes,
222 # simply use it (removing hidden attributes).
229 # simply use it (removing hidden attributes).
223 for attrname in self.attrs:
230 for attr in self.attrs:
224 if attrname not in attrnames and attrname not in self.hiddenattrs:
231 attr = ipipe.upgradexattr(attr)
225 self.displayattrs.append(attrname)
232 if attr not in attrs and attr not in self.hiddenattrs:
226 attrnames.add(attrname)
233 self.displayattrs.append(attr)
234 attrs.add(attr)
227 else:
235 else:
228 endy = min(self.datastarty+self.mainsizey, len(self.items))
236 endy = min(self.datastarty+self.mainsizey, len(self.items))
229 for i in xrange(self.datastarty, endy):
237 for i in xrange(self.datastarty, endy):
230 for attrname in ipipe.xattrs(self.items[i].item, "default"):
238 for attr in ipipe.xattrs(self.items[i].item, "default"):
231 if attrname not in attrnames and attrname not in self.hiddenattrs:
239 if attr not in attrs and attr not in self.hiddenattrs:
232 self.displayattrs.append(attrname)
240 self.displayattrs.append(attr)
233 attrnames.add(attrname)
241 attrs.add(attr)
234
242
235 def getrow(self, i):
243 def getrow(self, i):
236 # Return a dictinary with the attributes for the object
244 # Return a dictinary with the attributes for the object
@@ -239,9 +247,9 b' class _BrowserLevel(object):'
239 # called before.
247 # called before.
240 row = {}
248 row = {}
241 item = self.items[i].item
249 item = self.items[i].item
242 for attrname in self.displayattrs:
250 for attr in self.displayattrs:
243 try:
251 try:
244 value = ipipe._getattr(item, attrname, ipipe.noitem)
252 value = attr.value(item)
245 except (KeyboardInterrupt, SystemExit):
253 except (KeyboardInterrupt, SystemExit):
246 raise
254 raise
247 except Exception, exc:
255 except Exception, exc:
@@ -249,7 +257,7 b' class _BrowserLevel(object):'
249 # only store attribute if it exists (or we got an exception)
257 # only store attribute if it exists (or we got an exception)
250 if value is not ipipe.noitem:
258 if value is not ipipe.noitem:
251 # remember alignment, length and colored text
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 return row
261 return row
254
262
255 def calcwidths(self):
263 def calcwidths(self):
@@ -260,16 +268,16 b' class _BrowserLevel(object):'
260 # column names to widths.
268 # column names to widths.
261 self.colwidths = {}
269 self.colwidths = {}
262 for row in self.displayrows:
270 for row in self.displayrows:
263 for attrname in self.displayattrs:
271 for attr in self.displayattrs:
264 try:
272 try:
265 length = row[attrname][1]
273 length = row[attr][1]
266 except KeyError:
274 except KeyError:
267 length = 0
275 length = 0
268 # always add attribute to colwidths, even if it doesn't exist
276 # always add attribute to colwidths, even if it doesn't exist
269 if attrname not in self.colwidths:
277 if attr not in self.colwidths:
270 self.colwidths[attrname] = len(ipipe._attrname(attrname))
278 self.colwidths[attr] = len(attr.name())
271 newwidth = max(self.colwidths[attrname], length)
279 newwidth = max(self.colwidths[attr], length)
272 self.colwidths[attrname] = newwidth
280 self.colwidths[attr] = newwidth
273
281
274 # How many characters do we need to paint the largest item number?
282 # How many characters do we need to paint the largest item number?
275 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
283 self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
@@ -282,11 +290,11 b' class _BrowserLevel(object):'
282 # Find out which attribute the cursor is on and store this
290 # Find out which attribute the cursor is on and store this
283 # information in ``self.displayattr``.
291 # information in ``self.displayattr``.
284 pos = 0
292 pos = 0
285 for (i, attrname) in enumerate(self.displayattrs):
293 for (i, attr) in enumerate(self.displayattrs):
286 if pos+self.colwidths[attrname] >= self.curx:
294 if pos+self.colwidths[attr] >= self.curx:
287 self.displayattr = (i, attrname)
295 self.displayattr = (i, attr)
288 break
296 break
289 pos += self.colwidths[attrname]+1
297 pos += self.colwidths[attr]+1
290 else:
298 else:
291 self.displayattr = (None, ipipe.noitem)
299 self.displayattr = (None, ipipe.noitem)
292
300
@@ -1030,7 +1038,7 b' class ibrowse(ipipe.Display):'
1030 """
1038 """
1031 'Pick' the object under the cursor (i.e. the row the cursor is on).
1039 'Pick' the object under the cursor (i.e. the row the cursor is on).
1032 This leaves the browser and returns the picked object to the caller.
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 level = self.levels[-1]
1043 level = self.levels[-1]
1036 self.returnvalue = level.items[level.cury].item
1044 self.returnvalue = level.items[level.cury].item
@@ -1042,17 +1050,17 b' class ibrowse(ipipe.Display):'
1042 cursor is on).
1050 cursor is on).
1043 """
1051 """
1044 level = self.levels[-1]
1052 level = self.levels[-1]
1045 attrname = level.displayattr[1]
1053 attr = level.displayattr[1]
1046 if attrname is ipipe.noitem:
1054 if attr is ipipe.noitem:
1047 curses.beep()
1055 curses.beep()
1048 self.report(AttributeError(ipipe._attrname(attrname)))
1056 self.report(CommandError("no column under cursor"))
1049 return
1057 return
1050 attr = ipipe._getattr(level.items[level.cury].item, attrname)
1058 value = attr.value(level.items[level.cury].item)
1051 if attr is ipipe.noitem:
1059 if value is ipipe.noitem:
1052 curses.beep()
1060 curses.beep()
1053 self.report(AttributeError(ipipe._attrname(attrname)))
1061 self.report(AttributeError(attr.name()))
1054 else:
1062 else:
1055 self.returnvalue = attr
1063 self.returnvalue = value
1056 return True
1064 return True
1057
1065
1058 def cmd_pickallattrs(self):
1066 def cmd_pickallattrs(self):
@@ -1062,16 +1070,16 b' class ibrowse(ipipe.Display):'
1062 will be returned as a list.
1070 will be returned as a list.
1063 """
1071 """
1064 level = self.levels[-1]
1072 level = self.levels[-1]
1065 attrname = level.displayattr[1]
1073 attr = level.displayattr[1]
1066 if attrname is ipipe.noitem:
1074 if attr is ipipe.noitem:
1067 curses.beep()
1075 curses.beep()
1068 self.report(AttributeError(ipipe._attrname(attrname)))
1076 self.report(CommandError("no column under cursor"))
1069 return
1077 return
1070 result = []
1078 result = []
1071 for cache in level.items:
1079 for cache in level.items:
1072 attr = ipipe._getattr(cache.item, attrname)
1080 value = attr.value(cache.item)
1073 if attr is not ipipe.noitem:
1081 if value is not ipipe.noitem:
1074 result.append(attr)
1082 result.append(value)
1075 self.returnvalue = result
1083 self.returnvalue = result
1076 return True
1084 return True
1077
1085
@@ -1090,17 +1098,17 b' class ibrowse(ipipe.Display):'
1090 """
1098 """
1091
1099
1092 level = self.levels[-1]
1100 level = self.levels[-1]
1093 attrname = level.displayattr[1]
1101 attr = level.displayattr[1]
1094 if attrname is ipipe.noitem:
1102 if attr is ipipe.noitem:
1095 curses.beep()
1103 curses.beep()
1096 self.report(AttributeError(ipipe._attrname(attrname)))
1104 self.report(CommandError("no column under cursor"))
1097 return
1105 return
1098 result = []
1106 result = []
1099 for cache in level.items:
1107 for cache in level.items:
1100 if cache.marked:
1108 if cache.marked:
1101 attr = ipipe._getattr(cache.item, attrname)
1109 value = attr.value(cache.item)
1102 if attr is not ipipe.noitem:
1110 if value is not ipipe.noitem:
1103 result.append(attr)
1111 result.append(value)
1104 self.returnvalue = result
1112 self.returnvalue = result
1105 return True
1113 return True
1106
1114
@@ -1130,7 +1138,7 b' class ibrowse(ipipe.Display):'
1130 def cmd_enterdefault(self):
1138 def cmd_enterdefault(self):
1131 """
1139 """
1132 Enter the object under the cursor. (what this mean depends on the object
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 browser 'level'.
1142 browser 'level'.
1135 """
1143 """
1136 level = self.levels[-1]
1144 level = self.levels[-1]
@@ -1176,10 +1184,10 b' class ibrowse(ipipe.Display):'
1176 Enter the attribute under the cursor.
1184 Enter the attribute under the cursor.
1177 """
1185 """
1178 level = self.levels[-1]
1186 level = self.levels[-1]
1179 attrname = level.displayattr[1]
1187 attr = level.displayattr[1]
1180 if attrname is ipipe.noitem:
1188 if attr is ipipe.noitem:
1181 curses.beep()
1189 curses.beep()
1182 self.report(AttributeError(ipipe._attrname(attrname)))
1190 self.report(CommandError("no column under cursor"))
1183 return
1191 return
1184 try:
1192 try:
1185 item = level.items[level.cury].item
1193 item = level.items[level.cury].item
@@ -1187,12 +1195,13 b' class ibrowse(ipipe.Display):'
1187 self.report(CommandError("No object"))
1195 self.report(CommandError("No object"))
1188 curses.beep()
1196 curses.beep()
1189 else:
1197 else:
1190 attr = ipipe._getattr(item, attrname)
1198 value = attr.value(item)
1191 if attr is ipipe.noitem:
1199 name = attr.name()
1192 self.report(AttributeError(ipipe._attrname(attrname)))
1200 if value is ipipe.noitem:
1201 self.report(AttributeError(name))
1193 else:
1202 else:
1194 self.report("entering object attribute %s..." % ipipe._attrname(attrname))
1203 self.report("entering object attribute %s..." % name)
1195 self.enter(attr, None)
1204 self.enter(value, None)
1196
1205
1197 def cmd_detail(self):
1206 def cmd_detail(self):
1198 """
1207 """
@@ -1209,17 +1218,18 b' class ibrowse(ipipe.Display):'
1209 curses.beep()
1218 curses.beep()
1210 else:
1219 else:
1211 self.report("entering detail view for object...")
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 def cmd_detailattr(self):
1224 def cmd_detailattr(self):
1215 """
1225 """
1216 Show a detail view of the attribute under the cursor.
1226 Show a detail view of the attribute under the cursor.
1217 """
1227 """
1218 level = self.levels[-1]
1228 level = self.levels[-1]
1219 attrname = level.displayattr[1]
1229 attr = level.displayattr[1]
1220 if attrname is ipipe.noitem:
1230 if attr is ipipe.noitem:
1221 curses.beep()
1231 curses.beep()
1222 self.report(AttributeError(ipipe._attrname(attrname)))
1232 self.report(CommandError("no attribute"))
1223 return
1233 return
1224 try:
1234 try:
1225 item = level.items[level.cury].item
1235 item = level.items[level.cury].item
@@ -1227,12 +1237,16 b' class ibrowse(ipipe.Display):'
1227 self.report(CommandError("No object"))
1237 self.report(CommandError("No object"))
1228 curses.beep()
1238 curses.beep()
1229 else:
1239 else:
1230 attr = ipipe._getattr(item, attrname)
1240 try:
1231 if attr is ipipe.noitem:
1241 item = attr.value(item)
1232 self.report(AttributeError(ipipe._attrname(attrname)))
1242 except (KeyboardInterrupt, SystemExit):
1243 raise
1244 except Exception, exc:
1245 self.report(exc)
1233 else:
1246 else:
1234 self.report("entering detail view for attribute...")
1247 self.report("entering detail view for attribute %s..." % attr.name())
1235 self.enter(attr, "detail")
1248 attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
1249 self.enter(attrs, "detail")
1236
1250
1237 def cmd_tooglemark(self):
1251 def cmd_tooglemark(self):
1238 """
1252 """
@@ -1259,15 +1273,15 b' class ibrowse(ipipe.Display):'
1259 the cursor as the sort key.
1273 the cursor as the sort key.
1260 """
1274 """
1261 level = self.levels[-1]
1275 level = self.levels[-1]
1262 attrname = level.displayattr[1]
1276 attr = level.displayattr[1]
1263 if attrname is ipipe.noitem:
1277 if attr is ipipe.noitem:
1264 curses.beep()
1278 curses.beep()
1265 self.report(AttributeError(ipipe._attrname(attrname)))
1279 self.report(CommandError("no column under cursor"))
1266 return
1280 return
1267 self.report("sort by %s (ascending)" % ipipe._attrname(attrname))
1281 self.report("sort by %s (ascending)" % attr.name())
1268 def key(item):
1282 def key(item):
1269 try:
1283 try:
1270 return ipipe._getattr(item, attrname, None)
1284 return attr.value(item)
1271 except (KeyboardInterrupt, SystemExit):
1285 except (KeyboardInterrupt, SystemExit):
1272 raise
1286 raise
1273 except Exception:
1287 except Exception:
@@ -1280,15 +1294,15 b' class ibrowse(ipipe.Display):'
1280 the cursor as the sort key.
1294 the cursor as the sort key.
1281 """
1295 """
1282 level = self.levels[-1]
1296 level = self.levels[-1]
1283 attrname = level.displayattr[1]
1297 attr = level.displayattr[1]
1284 if attrname is ipipe.noitem:
1298 if attr is ipipe.noitem:
1285 curses.beep()
1299 curses.beep()
1286 self.report(AttributeError(ipipe._attrname(attrname)))
1300 self.report(CommandError("no column under cursor"))
1287 return
1301 return
1288 self.report("sort by %s (descending)" % ipipe._attrname(attrname))
1302 self.report("sort by %s (descending)" % attr.name())
1289 def key(item):
1303 def key(item):
1290 try:
1304 try:
1291 return ipipe._getattr(item, attrname, None)
1305 return attr.value(item)
1292 except (KeyboardInterrupt, SystemExit):
1306 except (KeyboardInterrupt, SystemExit):
1293 raise
1307 raise
1294 except Exception:
1308 except Exception:
@@ -1427,11 +1441,11 b' class ibrowse(ipipe.Display):'
1427 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1441 scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
1428 begx = level.numbersizex+3
1442 begx = level.numbersizex+3
1429 posx = begx-level.datastartx
1443 posx = begx-level.datastartx
1430 for attrname in level.displayattrs:
1444 for attr in level.displayattrs:
1431 strattrname = ipipe._attrname(attrname)
1445 attrname = attr.name()
1432 cwidth = level.colwidths[attrname]
1446 cwidth = level.colwidths[attr]
1433 header = strattrname.ljust(cwidth)
1447 header = attrname.ljust(cwidth)
1434 if attrname == level.displayattr[1]:
1448 if attr is level.displayattr[1]:
1435 style = self.style_colheaderhere
1449 style = self.style_colheaderhere
1436 else:
1450 else:
1437 style = self.style_colheader
1451 style = self.style_colheader
@@ -1527,19 +1541,19 b' class ibrowse(ipipe.Display):'
1527 break
1541 break
1528
1542
1529 attrstyle = [(astyle.style_default, "no attribute")]
1543 attrstyle = [(astyle.style_default, "no attribute")]
1530 attrname = level.displayattr[1]
1544 attr = level.displayattr[1]
1531 if attrname is not ipipe.noitem and attrname is not None:
1545 if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
1532 posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
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 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1548 posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
1535 try:
1549 try:
1536 attr = ipipe._getattr(item, attrname)
1550 value = attr.value(item)
1537 except (SystemExit, KeyboardInterrupt):
1551 except (SystemExit, KeyboardInterrupt):
1538 raise
1552 raise
1539 except Exception, exc:
1553 except Exception, exc:
1540 attr = exc
1554 attr = exc
1541 if attr is not ipipe.noitem:
1555 if value is not ipipe.noitem:
1542 attrstyle = ipipe.xrepr(attr, "footer")
1556 attrstyle = ipipe.xrepr(value, "footer")
1543 for (nostyle, text) in attrstyle:
1557 for (nostyle, text) in attrstyle:
1544 if not isinstance(nostyle, int):
1558 if not isinstance(nostyle, int):
1545 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
1559 posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
This diff has been collapsed as it changes many lines, (592 lines changed) Show them Hide them
@@ -269,6 +269,251 b' def getglobals(g):'
269 return g
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 class Table(object):
517 class Table(object):
273 """
518 """
274 A ``Table`` is an object that produces items (just like a normal Python
519 A ``Table`` is an object that produces items (just like a normal Python
@@ -350,47 +595,7 b' class Pipe(Table):'
350 return self
595 return self
351
596
352
597
353 def _getattr(obj, name, default=noitem):
598 def xrepr(item, mode="default"):
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):
394 try:
599 try:
395 func = item.__xrepr__
600 func = item.__xrepr__
396 except AttributeError:
601 except AttributeError:
@@ -449,6 +654,11 b' def xrepr(item, mode):'
449 yield (astyle.style_type_datetime, repr(item))
654 yield (astyle.style_type_datetime, repr(item))
450 elif isinstance(item, datetime.timedelta):
655 elif isinstance(item, datetime.timedelta):
451 yield (astyle.style_type_datetime, repr(item))
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 elif isinstance(item, Exception):
662 elif isinstance(item, Exception):
453 if item.__class__.__module__ == "exceptions":
663 if item.__class__.__module__ == "exceptions":
454 classname = item.__class__.__name__
664 classname = item.__class__.__name__
@@ -514,33 +724,67 b' def xrepr(item, mode):'
514 yield (astyle.style_default, repr(item))
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 try:
752 try:
519 func = item.__xattrs__
753 func = item.__xattrs__
520 except AttributeError:
754 except AttributeError:
521 if mode == "detail":
755 if mode == "detail":
522 return dir(item)
756 for attrname in dir(item):
757 yield AttributeDescriptor(attrname)
523 else:
758 else:
524 return (None,)
759 yield selfdescriptor
525 else:
760 else:
761 for attr in func(mode):
762 yield upgradexattr(attr)
763
764
765 def _isdict(item):
526 try:
766 try:
527 return func(mode)
767 itermeth = item.__class__.__iter__
528 except (KeyboardInterrupt, SystemExit):
768 except (AttributeError, TypeError):
529 raise
769 return False
530 except Exception:
770 return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
531 return (None,)
532
771
533
772
534 def xiter(item, mode):
773 def _isstr(item):
535 if mode == "detail":
774 if not isinstance(item, basestring):
536 def items():
775 return False
537 for name in xattrs(item, mode):
776 try:
538 yield XAttr(item, name)
777 itermeth = item.__class__.__iter__
539 return items()
778 except AttributeError:
779 return True
780 return False # ``__iter__`` has been redefined
781
782
783 def xiter(item, mode="default"):
540 try:
784 try:
541 func = item.__xiter__
785 func = item.__xiter__
542 except AttributeError:
786 except AttributeError:
543 if isinstance(item, (dict, types.DictProxyType)):
787 if _isdict(item):
544 def items(item):
788 def items(item):
545 fields = ("key", "value")
789 fields = ("key", "value")
546 for (key, value) in item.iteritems():
790 for (key, value) in item.iteritems():
@@ -552,8 +796,8 b' def xiter(item, mode):'
552 for key in sorted(item.__dict__):
796 for key in sorted(item.__dict__):
553 yield Fields(fields, key=key, value=getattr(item, key))
797 yield Fields(fields, key=key, value=getattr(item, key))
554 return items(item)
798 return items(item)
555 elif isinstance(item, basestring):
799 elif _isstr(item):
556 if not len(item):
800 if not item:
557 raise ValueError("can't enter empty string")
801 raise ValueError("can't enter empty string")
558 lines = item.splitlines()
802 lines = item.splitlines()
559 if len(lines) <= 1:
803 if len(lines) <= 1:
@@ -572,7 +816,7 b' class ichain(Pipe):'
572 def __init__(self, *iters):
816 def __init__(self, *iters):
573 self.iters = iters
817 self.iters = iters
574
818
575 def __xiter__(self, mode):
819 def __iter__(self):
576 return itertools.chain(*self.iters)
820 return itertools.chain(*self.iters)
577
821
578 def __xrepr__(self, mode):
822 def __xrepr__(self, mode):
@@ -823,30 +1067,61 b' class ifile(path.path):'
823 return datetime.datetime.utcfromtimestamp(self.mtime)
1067 return datetime.datetime.utcfromtimestamp(self.mtime)
824 mdate = property(getmdate, None, None, "Modification date")
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 return mimetypes.guess_type(self.basename())[0]
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 return mimetypes.guess_type(self.basename())[1]
1080 return mimetypes.guess_type(self.basename())[1]
832 encoding = property(getencoding, None, None, "Compression")
833
1081
834 def __repr__(self):
1082 def __repr__(self):
835 return "ifile(%s)" % path._base.__repr__(self)
1083 return "ifile(%s)" % path._base.__repr__(self)
836
1084
837 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
838
839 def __xattrs__(self, mode):
1085 def __xattrs__(self, mode):
840 if mode == "detail":
1086 if mode == "detail":
841 return (
1087 return (
842 "name", "basename()", "abspath()", "realpath()",
1088 "name",
843 "type", "mode", "modestr", "stat()", "lstat()",
1089 "basename()",
844 "uid", "gid", "owner", "group", "dev", "nlink",
1090 "abspath()",
845 "ctime", "mtime", "atime", "cdate", "mdate", "adate",
1091 "realpath()",
846 "size", "blocks", "blksize", "isdir()", "islink()",
1092 "type",
847 "mimetype", "encoding"
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 def __xrepr__(self, mode):
1126 def __xrepr__(self, mode):
852 try:
1127 try:
@@ -872,7 +1147,7 b' class ifile(path.path):'
872 else:
1147 else:
873 yield (style, repr(self))
1148 yield (style, repr(self))
874
1149
875 def __xiter__(self, mode):
1150 def __iter__(self):
876 if self.isdir():
1151 if self.isdir():
877 yield iparentdir(self / os.pardir)
1152 yield iparentdir(self / os.pardir)
878 for child in sorted(self.listdir()):
1153 for child in sorted(self.listdir()):
@@ -906,8 +1181,8 b' class ils(Table):'
906 def __init__(self, base=os.curdir):
1181 def __init__(self, base=os.curdir):
907 self.base = os.path.expanduser(base)
1182 self.base = os.path.expanduser(base)
908
1183
909 def __xiter__(self, mode):
1184 def __iter__(self):
910 return xiter(ifile(self.base), mode)
1185 return xiter(ifile(self.base))
911
1186
912 def __xrepr__(self, mode):
1187 def __xrepr__(self, mode):
913 return ifile(self.base).__xrepr__(mode)
1188 return ifile(self.base).__xrepr__(mode)
@@ -929,7 +1204,7 b' class iglob(Table):'
929 def __init__(self, glob):
1204 def __init__(self, glob):
930 self.glob = glob
1205 self.glob = glob
931
1206
932 def __xiter__(self, mode):
1207 def __iter__(self):
933 for name in glob.glob(self.glob):
1208 for name in glob.glob(self.glob):
934 yield ifile(name)
1209 yield ifile(name)
935
1210
@@ -958,7 +1233,7 b' class iwalk(Table):'
958 self.dirs = dirs
1233 self.dirs = dirs
959 self.files = files
1234 self.files = files
960
1235
961 def __xiter__(self, mode):
1236 def __iter__(self):
962 for (dirpath, dirnames, filenames) in os.walk(self.base):
1237 for (dirpath, dirnames, filenames) in os.walk(self.base):
963 if self.dirs:
1238 if self.dirs:
964 for name in sorted(dirnames):
1239 for name in sorted(dirnames):
@@ -1115,7 +1390,7 b' class igrpentry(object):'
1115 else:
1390 else:
1116 yield (astyle.style_default, repr(self))
1391 yield (astyle.style_default, repr(self))
1117
1392
1118 def __xiter__(self, mode):
1393 def __iter__(self):
1119 for member in self.mem:
1394 for member in self.mem:
1120 yield ipwdentry(member)
1395 yield ipwdentry(member)
1121
1396
@@ -1128,7 +1403,7 b' class igrp(Table):'
1128 """
1403 """
1129 This ``Table`` lists all entries in the Unix group database.
1404 This ``Table`` lists all entries in the Unix group database.
1130 """
1405 """
1131 def __xiter__(self, mode):
1406 def __iter__(self):
1132 for entry in grp.getgrall():
1407 for entry in grp.getgrall():
1133 yield igrpentry(entry.gr_name)
1408 yield igrpentry(entry.gr_name)
1134
1409
@@ -1141,7 +1416,7 b' class igrp(Table):'
1141
1416
1142 class Fields(object):
1417 class Fields(object):
1143 def __init__(self, fieldnames, **fields):
1418 def __init__(self, fieldnames, **fields):
1144 self.__fieldnames = fieldnames
1419 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1145 for (key, value) in fields.iteritems():
1420 for (key, value) in fields.iteritems():
1146 setattr(self, key, value)
1421 setattr(self, key, value)
1147
1422
@@ -1156,7 +1431,7 b' class Fields(object):'
1156 for (i, f) in enumerate(self.__fieldnames):
1431 for (i, f) in enumerate(self.__fieldnames):
1157 if i:
1432 if i:
1158 yield (astyle.style_default, ", ")
1433 yield (astyle.style_default, ", ")
1159 yield (astyle.style_default, f)
1434 yield (astyle.style_default, f.name())
1160 yield (astyle.style_default, "=")
1435 yield (astyle.style_default, "=")
1161 for part in xrepr(getattr(self, f), "default"):
1436 for part in xrepr(getattr(self, f), "default"):
1162 yield part
1437 yield part
@@ -1167,7 +1442,7 b' class Fields(object):'
1167 for (i, f) in enumerate(self.__fieldnames):
1442 for (i, f) in enumerate(self.__fieldnames):
1168 if i:
1443 if i:
1169 yield (astyle.style_default, ", ")
1444 yield (astyle.style_default, ", ")
1170 yield (astyle.style_default, f)
1445 yield (astyle.style_default, f.name())
1171 yield (astyle.style_default, ")")
1446 yield (astyle.style_default, ")")
1172 else:
1447 else:
1173 yield (astyle.style_default, repr(self))
1448 yield (astyle.style_default, repr(self))
@@ -1182,9 +1457,6 b' class FieldTable(Table, list):'
1182 def add(self, **fields):
1457 def add(self, **fields):
1183 self.append(Fields(self.fields, **fields))
1458 self.append(Fields(self.fields, **fields))
1184
1459
1185 def __xiter__(self, mode):
1186 return list.__iter__(self)
1187
1188 def __xrepr__(self, mode):
1460 def __xrepr__(self, mode):
1189 yield (-1, False)
1461 yield (-1, False)
1190 if mode == "header" or mode == "footer":
1462 if mode == "header" or mode == "footer":
@@ -1232,7 +1504,7 b' class ienv(Table):'
1232 >>> ienv
1504 >>> ienv
1233 """
1505 """
1234
1506
1235 def __xiter__(self, mode):
1507 def __iter__(self):
1236 fields = ("key", "value")
1508 fields = ("key", "value")
1237 for (key, value) in os.environ.iteritems():
1509 for (key, value) in os.environ.iteritems():
1238 yield Fields(fields, key=key, value=value)
1510 yield Fields(fields, key=key, value=value)
@@ -1256,7 +1528,7 b' class icsv(Pipe):'
1256 """
1528 """
1257 self.csvargs = csvargs
1529 self.csvargs = csvargs
1258
1530
1259 def __xiter__(self, mode):
1531 def __iter__(self):
1260 input = self.input
1532 input = self.input
1261 if isinstance(input, ifile):
1533 if isinstance(input, ifile):
1262 input = input.open("rb")
1534 input = input.open("rb")
@@ -1304,7 +1576,7 b' class ix(Table):'
1304 self.cmd = cmd
1576 self.cmd = cmd
1305 self._pipeout = None
1577 self._pipeout = None
1306
1578
1307 def __xiter__(self, mode="default"):
1579 def __iter__(self):
1308 (_pipein, self._pipeout) = os.popen4(self.cmd)
1580 (_pipein, self._pipeout) = os.popen4(self.cmd)
1309 _pipein.close()
1581 _pipein.close()
1310 for l in self._pipeout:
1582 for l in self._pipeout:
@@ -1364,7 +1636,7 b' class ifilter(Pipe):'
1364 self.globals = globals
1636 self.globals = globals
1365 self.errors = errors
1637 self.errors = errors
1366
1638
1367 def __xiter__(self, mode):
1639 def __iter__(self):
1368 if callable(self.expr):
1640 if callable(self.expr):
1369 test = self.expr
1641 test = self.expr
1370 else:
1642 else:
@@ -1375,7 +1647,7 b' class ifilter(Pipe):'
1375
1647
1376 ok = 0
1648 ok = 0
1377 exc_info = None
1649 exc_info = None
1378 for item in xiter(self.input, mode):
1650 for item in xiter(self.input):
1379 try:
1651 try:
1380 if test(item):
1652 if test(item):
1381 yield item
1653 yield item
@@ -1437,7 +1709,7 b' class ieval(Pipe):'
1437 self.globals = globals
1709 self.globals = globals
1438 self.errors = errors
1710 self.errors = errors
1439
1711
1440 def __xiter__(self, mode):
1712 def __iter__(self):
1441 if callable(self.expr):
1713 if callable(self.expr):
1442 do = self.expr
1714 do = self.expr
1443 else:
1715 else:
@@ -1448,7 +1720,7 b' class ieval(Pipe):'
1448
1720
1449 ok = 0
1721 ok = 0
1450 exc_info = None
1722 exc_info = None
1451 for item in xiter(self.input, mode):
1723 for item in xiter(self.input):
1452 try:
1724 try:
1453 yield do(item)
1725 yield do(item)
1454 except (KeyboardInterrupt, SystemExit):
1726 except (KeyboardInterrupt, SystemExit):
@@ -1497,9 +1769,9 b' class ienum(Pipe):'
1497
1769
1498 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1770 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1499 """
1771 """
1500 def __xiter__(self, mode):
1772 def __iter__(self):
1501 fields = ("index", "object")
1773 fields = ("index", "object")
1502 for (index, object) in enumerate(xiter(self.input, mode)):
1774 for (index, object) in enumerate(xiter(self.input)):
1503 yield Fields(fields, index=index, object=object)
1775 yield Fields(fields, index=index, object=object)
1504
1776
1505
1777
@@ -1524,18 +1796,11 b' class isort(Pipe):'
1524 self.globals = globals
1796 self.globals = globals
1525 self.reverse = reverse
1797 self.reverse = reverse
1526
1798
1527 def __xiter__(self, mode):
1799 def __iter__(self):
1528 if self.key is None:
1800 if self.key is None:
1529 items = sorted(
1801 items = sorted(xiter(self.input), reverse=self.reverse)
1530 xiter(self.input, mode),
1531 reverse=self.reverse
1532 )
1533 elif callable(self.key):
1802 elif callable(self.key):
1534 items = sorted(
1803 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1535 xiter(self.input, mode),
1536 key=self.key,
1537 reverse=self.reverse
1538 )
1539 else:
1804 else:
1540 g = getglobals(self.globals)
1805 g = getglobals(self.globals)
1541 key = compile(self.key, "ipipe-expression", "eval")
1806 key = compile(self.key, "ipipe-expression", "eval")
@@ -1613,8 +1878,8 b' class iless(Display):'
1613 pager = os.popen(self.cmd, "w")
1878 pager = os.popen(self.cmd, "w")
1614 try:
1879 try:
1615 for item in xiter(self.input, "default"):
1880 for item in xiter(self.input, "default"):
1616 attrs = xattrs(item, "default")
1881 attrs = tuple(_upgradexattrs(item, "default"))
1617 attrs = ["%s=%s" % (a, _format(_getattr(item, a))) for a in attrs]
1882 attrs = ["%s=%s" % (a.name(item), a.value(item)) for a in attrs]
1618 pager.write(" ".join(attrs))
1883 pager.write(" ".join(attrs))
1619 pager.write("\n")
1884 pager.write("\n")
1620 finally:
1885 finally:
@@ -1659,7 +1924,7 b' class idump(Display):'
1659 style_header = astyle.Style.fromstr("white:black:bold")
1924 style_header = astyle.Style.fromstr("white:black:bold")
1660
1925
1661 def __init__(self, *attrs):
1926 def __init__(self, *attrs):
1662 self.attrs = attrs
1927 self.attrs = [upgradexattr(attr) for attr in attrs]
1663 self.headerpadchar = " "
1928 self.headerpadchar = " "
1664 self.headersepchar = "|"
1929 self.headersepchar = "|"
1665 self.datapadchar = " "
1930 self.datapadchar = " "
@@ -1668,7 +1933,7 b' class idump(Display):'
1668 def display(self):
1933 def display(self):
1669 stream = genutils.Term.cout
1934 stream = genutils.Term.cout
1670 allattrs = []
1935 allattrs = []
1671 allattrset = set()
1936 attrset = set()
1672 colwidths = {}
1937 colwidths = {}
1673 rows = []
1938 rows = []
1674 for item in xiter(self.input, "default"):
1939 for item in xiter(self.input, "default"):
@@ -1676,42 +1941,43 b' class idump(Display):'
1676 attrs = self.attrs
1941 attrs = self.attrs
1677 if not attrs:
1942 if not attrs:
1678 attrs = xattrs(item, "default")
1943 attrs = xattrs(item, "default")
1679 for attrname in attrs:
1944 for attr in attrs:
1680 if attrname not in allattrset:
1945 if attr not in attrset:
1681 allattrs.append(attrname)
1946 allattrs.append(attr)
1682 allattrset.add(attrname)
1947 attrset.add(attr)
1683 colwidths[attrname] = len(_attrname(attrname))
1948 colwidths[attr] = len(attr.name())
1684 try:
1949 try:
1685 value = _getattr(item, attrname, None)
1950 value = attr.value(item)
1686 except (KeyboardInterrupt, SystemExit):
1951 except (KeyboardInterrupt, SystemExit):
1687 raise
1952 raise
1688 except Exception, exc:
1953 except Exception, exc:
1689 value = exc
1954 value = exc
1690 (align, width, text) = xformat(value, "cell", self.maxattrlength)
1955 (align, width, text) = xformat(value, "cell", self.maxattrlength)
1691 colwidths[attrname] = max(colwidths[attrname], width)
1956 colwidths[attr] = max(colwidths[attr], width)
1692 # remember alignment, length and colored parts
1957 # remember alignment, length and colored parts
1693 row[attrname] = (align, width, text)
1958 row[attr] = (align, width, text)
1694 rows.append(row)
1959 rows.append(row)
1695
1960
1696 stream.write("\n")
1961 stream.write("\n")
1697 for (i, attrname) in enumerate(allattrs):
1962 for (i, attr) in enumerate(allattrs):
1698 self.style_header(_attrname(attrname)).write(stream)
1963 attrname = attr.name()
1699 spc = colwidths[attrname] - len(_attrname(attrname))
1964 self.style_header(attrname).write(stream)
1965 spc = colwidths[attr] - len(attrname)
1700 if i < len(colwidths)-1:
1966 if i < len(colwidths)-1:
1701 stream.write(self.headerpadchar*spc)
1967 stream.write(self.headerpadchar*spc)
1702 stream.write(self.headersepchar)
1968 stream.write(self.headersepchar)
1703 stream.write("\n")
1969 stream.write("\n")
1704
1970
1705 for row in rows:
1971 for row in rows:
1706 for (i, attrname) in enumerate(allattrs):
1972 for (i, attr) in enumerate(allattrs):
1707 (align, width, text) = row[attrname]
1973 (align, width, text) = row[attr]
1708 spc = colwidths[attrname] - width
1974 spc = colwidths[attr] - width
1709 if align == -1:
1975 if align == -1:
1710 text.write(stream)
1976 text.write(stream)
1711 if i < len(colwidths)-1:
1977 if i < len(colwidths)-1:
1712 stream.write(self.datapadchar*spc)
1978 stream.write(self.datapadchar*spc)
1713 elif align == 0:
1979 elif align == 0:
1714 spc = colwidths[attrname] - width
1980 spc = colwidths[attr] - width
1715 spc1 = spc//2
1981 spc1 = spc//2
1716 spc2 = spc-spc1
1982 spc2 = spc-spc1
1717 stream.write(self.datapadchar*spc1)
1983 stream.write(self.datapadchar*spc1)
@@ -1755,55 +2021,57 b' class XMode(object):'
1755
2021
1756 def __xattrs__(self, mode):
2022 def __xattrs__(self, mode):
1757 if mode == "detail":
2023 if mode == "detail":
2024 return ("object", "mode")
2025 else:
1758 return ("object", "mode", "title", "description")
2026 return ("object", "mode", "title", "description")
1759 return ("title", "description")
1760
2027
1761 def __xiter__(self, mode):
2028 def __xiter__(self, mode):
1762 return xiter(self.object, self.mode)
2029 return xiter(self.object, self.mode)
1763
2030
1764
2031
1765 class XAttr(object):
2032 class AttributeDetail(Table):
1766 def __init__(self, object, name):
2033 def __init__(self, object, descriptor):
1767 self.name = _attrname(name)
2034 self.object = object
2035 self.descriptor = descriptor
1768
2036
1769 try:
2037 def __iter__(self):
1770 self.value = _getattr(object, name)
2038 return self.descriptor.iter(self.object)
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__)
1786
2039
1787 doc = None
2040 def name(self):
1788 if isinstance(name, basestring):
2041 return self.descriptor.name()
1789 if name.endswith("()"):
2042
1790 doc = getattr(getattr(object, name[:-2]), "__doc__", None)
2043 def attrtype(self):
1791 else:
2044 return self.descriptor.attrtype(self.object)
1792 try:
2045
1793 meta = getattr(type(object), name)
2046 def valuetype(self):
1794 except AttributeError:
2047 return self.descriptor.valuetype(self.object)
1795 pass
2048
1796 else:
2049 def doc(self):
1797 if isinstance(meta, property):
2050 return self.descriptor.doc(self.object)
1798 doc = getattr(meta, "__doc__", None)
2051
1799 elif callable(name):
2052 def shortdoc(self):
1800 doc = getattr(name, "__doc__", None)
2053 return self.descriptor.shortdoc(self.object)
1801 if isinstance(doc, basestring):
2054
1802 doc = doc.strip()
2055 def value(self):
1803 self.doc = doc
2056 return self.descriptor.value(self.object)
1804
2057
1805 def __xattrs__(self, mode):
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 try:
2077 try:
@@ -3,6 +3,27 b''
3 * IPython/Extensions/ipipe.py: Fix getglobals() if we're
3 * IPython/Extensions/ipipe.py: Fix getglobals() if we're
4 not running under IPython.
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 2006-07-26 Ville Vainio <vivainio@gmail.com>
27 2006-07-26 Ville Vainio <vivainio@gmail.com>
7
28
8 * iplib.py: history now stores multiline input as single
29 * iplib.py: history now stores multiline input as single
General Comments 0
You need to be logged in to leave comments. Login now