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