##// END OF EJS Templates
Whitespace cleanup.
walter.doerwald -
Show More
@@ -1,2123 +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")
1085 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
1086 1086
1087 1087 def __xattrs__(self, mode):
1088 1088 if mode == "detail":
1089 1089 return (
1090 1090 "name",
1091 1091 "basename()",
1092 1092 "abspath()",
1093 1093 "realpath()",
1094 1094 "type",
1095 1095 "mode",
1096 1096 "modestr",
1097 1097 "stat()",
1098 1098 "lstat()",
1099 1099 "uid",
1100 1100 "gid",
1101 1101 "owner",
1102 1102 "group",
1103 1103 "dev",
1104 1104 "nlink",
1105 1105 "ctime",
1106 1106 "mtime",
1107 1107 "atime",
1108 1108 "cdate",
1109 1109 "mdate",
1110 1110 "adate",
1111 1111 "size",
1112 1112 "blocks",
1113 1113 "blksize",
1114 1114 "isdir()",
1115 1115 "islink()",
1116 1116 "mimetype()",
1117 1117 "encoding()",
1118 1118 "-listdir()",
1119 1119 "-dirs()",
1120 1120 "-files()",
1121 1121 "-walk()",
1122 1122 "-walkdirs()",
1123 1123 "-walkfiles()",
1124 1124 )
1125 1125 else:
1126 1126 return self.defaultattrs
1127 1127
1128 1128 def __xrepr__(self, mode):
1129 1129 try:
1130 1130 if self.isdir():
1131 1131 name = "idir"
1132 1132 style = astyle.style_dir
1133 1133 else:
1134 1134 name = "ifile"
1135 1135 style = astyle.style_file
1136 1136 except IOError:
1137 1137 name = "ifile"
1138 1138 style = astyle.style_default
1139 1139 if mode == "cell" or mode in "header" or mode == "footer":
1140 1140 abspath = repr(path._base(self.normpath()))
1141 1141 if abspath.startswith("u"):
1142 1142 abspath = abspath[2:-1]
1143 1143 else:
1144 1144 abspath = abspath[1:-1]
1145 1145 if mode == "cell":
1146 1146 yield (style, abspath)
1147 1147 else:
1148 1148 yield (style, "%s(%s)" % (name, abspath))
1149 1149 else:
1150 1150 yield (style, repr(self))
1151 1151
1152 1152 def __iter__(self):
1153 1153 if self.isdir():
1154 1154 yield iparentdir(self / os.pardir)
1155 1155 for child in sorted(self.listdir()):
1156 1156 yield child
1157 1157 else:
1158 1158 f = self.open("rb")
1159 1159 for line in f:
1160 1160 yield line
1161 1161 f.close()
1162 1162
1163 1163
1164 1164 class iparentdir(ifile):
1165 1165 def __xrepr__(self, mode):
1166 1166 if mode == "cell":
1167 1167 yield (astyle.style_dir, os.pardir)
1168 1168 else:
1169 1169 for part in ifile.__xrepr__(self, mode):
1170 1170 yield part
1171 1171
1172 1172
1173 1173 class ils(Table):
1174 1174 """
1175 1175 List the current (or a specific) directory.
1176 1176
1177 1177 Examples:
1178 1178
1179 1179 >>> ils
1180 1180 >>> ils("/usr/local/lib/python2.4")
1181 1181 >>> ils("~")
1182 1182 """
1183 1183 def __init__(self, base=os.curdir):
1184 1184 self.base = os.path.expanduser(base)
1185 1185
1186 1186 def __iter__(self):
1187 1187 return xiter(ifile(self.base))
1188 1188
1189 1189 def __xrepr__(self, mode):
1190 1190 return ifile(self.base).__xrepr__(mode)
1191 1191
1192 1192 def __repr__(self):
1193 1193 return "%s.%s(%r)" % \
1194 1194 (self.__class__.__module__, self.__class__.__name__, self.base)
1195 1195
1196 1196
1197 1197 class iglob(Table):
1198 1198 """
1199 1199 List all files and directories matching a specified pattern.
1200 1200 (See ``glob.glob()`` for more info.).
1201 1201
1202 1202 Examples:
1203 1203
1204 1204 >>> iglob("*.py")
1205 1205 """
1206 1206 def __init__(self, glob):
1207 1207 self.glob = glob
1208 1208
1209 1209 def __iter__(self):
1210 1210 for name in glob.glob(self.glob):
1211 1211 yield ifile(name)
1212 1212
1213 1213 def __xrepr__(self, mode):
1214 1214 if mode == "header" or mode == "footer" or mode == "cell":
1215 1215 yield (astyle.style_default,
1216 1216 "%s(%r)" % (self.__class__.__name__, self.glob))
1217 1217 else:
1218 1218 yield (astyle.style_default, repr(self))
1219 1219
1220 1220 def __repr__(self):
1221 1221 return "%s.%s(%r)" % \
1222 1222 (self.__class__.__module__, self.__class__.__name__, self.glob)
1223 1223
1224 1224
1225 1225 class iwalk(Table):
1226 1226 """
1227 1227 List all files and directories in a directory and it's subdirectory.
1228 1228
1229 1229 >>> iwalk
1230 1230 >>> iwalk("/usr/local/lib/python2.4")
1231 1231 >>> iwalk("~")
1232 1232 """
1233 1233 def __init__(self, base=os.curdir, dirs=True, files=True):
1234 1234 self.base = os.path.expanduser(base)
1235 1235 self.dirs = dirs
1236 1236 self.files = files
1237 1237
1238 1238 def __iter__(self):
1239 1239 for (dirpath, dirnames, filenames) in os.walk(self.base):
1240 1240 if self.dirs:
1241 1241 for name in sorted(dirnames):
1242 1242 yield ifile(os.path.join(dirpath, name))
1243 1243 if self.files:
1244 1244 for name in sorted(filenames):
1245 1245 yield ifile(os.path.join(dirpath, name))
1246 1246
1247 1247 def __xrepr__(self, mode):
1248 1248 if mode == "header" or mode == "footer" or mode == "cell":
1249 1249 yield (astyle.style_default,
1250 1250 "%s(%r)" % (self.__class__.__name__, self.base))
1251 1251 else:
1252 1252 yield (astyle.style_default, repr(self))
1253 1253
1254 1254 def __repr__(self):
1255 1255 return "%s.%s(%r)" % \
1256 1256 (self.__class__.__module__, self.__class__.__name__, self.base)
1257 1257
1258 1258
1259 1259 class ipwdentry(object):
1260 1260 """
1261 1261 ``ipwdentry`` objects encapsulate entries in the Unix user account and
1262 1262 password database.
1263 1263 """
1264 1264 def __init__(self, id):
1265 1265 self._id = id
1266 1266 self._entry = None
1267 1267
1268 1268 def _getentry(self):
1269 1269 if self._entry is None:
1270 1270 if isinstance(self._id, basestring):
1271 1271 self._entry = pwd.getpwnam(self._id)
1272 1272 else:
1273 1273 self._entry = pwd.getpwuid(self._id)
1274 1274 return self._entry
1275 1275
1276 1276 def getname(self):
1277 1277 if isinstance(self._id, basestring):
1278 1278 return self._id
1279 1279 else:
1280 1280 return self._getentry().pw_name
1281 1281 name = property(getname, None, None, "User name")
1282 1282
1283 1283 def getpasswd(self):
1284 1284 return self._getentry().pw_passwd
1285 1285 passwd = property(getpasswd, None, None, "Password")
1286 1286
1287 1287 def getuid(self):
1288 1288 if isinstance(self._id, basestring):
1289 1289 return self._getentry().pw_uid
1290 1290 else:
1291 1291 return self._id
1292 1292 uid = property(getuid, None, None, "User id")
1293 1293
1294 1294 def getgid(self):
1295 1295 return self._getentry().pw_gid
1296 1296 gid = property(getgid, None, None, "Primary group id")
1297 1297
1298 1298 def getgroup(self):
1299 1299 return igrpentry(self.gid)
1300 1300 group = property(getgroup, None, None, "Group")
1301 1301
1302 1302 def getgecos(self):
1303 1303 return self._getentry().pw_gecos
1304 1304 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1305 1305
1306 1306 def getdir(self):
1307 1307 return self._getentry().pw_dir
1308 1308 dir = property(getdir, None, None, "$HOME directory")
1309 1309
1310 1310 def getshell(self):
1311 1311 return self._getentry().pw_shell
1312 1312 shell = property(getshell, None, None, "Login shell")
1313 1313
1314 1314 def __xattrs__(self, mode):
1315 1315 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1316 1316
1317 1317 def __repr__(self):
1318 1318 return "%s.%s(%r)" % \
1319 1319 (self.__class__.__module__, self.__class__.__name__, self._id)
1320 1320
1321 1321
1322 1322 class ipwd(Table):
1323 1323 """
1324 1324 List all entries in the Unix user account and password database.
1325 1325
1326 1326 Example:
1327 1327
1328 1328 >>> ipwd | isort("uid")
1329 1329 """
1330 1330 def __iter__(self):
1331 1331 for entry in pwd.getpwall():
1332 1332 yield ipwdentry(entry.pw_name)
1333 1333
1334 1334 def __xrepr__(self, mode):
1335 1335 if mode == "header" or mode == "footer" or mode == "cell":
1336 1336 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1337 1337 else:
1338 1338 yield (astyle.style_default, repr(self))
1339 1339
1340 1340
1341 1341 class igrpentry(object):
1342 1342 """
1343 1343 ``igrpentry`` objects encapsulate entries in the Unix group database.
1344 1344 """
1345 1345 def __init__(self, id):
1346 1346 self._id = id
1347 1347 self._entry = None
1348 1348
1349 1349 def _getentry(self):
1350 1350 if self._entry is None:
1351 1351 if isinstance(self._id, basestring):
1352 1352 self._entry = grp.getgrnam(self._id)
1353 1353 else:
1354 1354 self._entry = grp.getgrgid(self._id)
1355 1355 return self._entry
1356 1356
1357 1357 def getname(self):
1358 1358 if isinstance(self._id, basestring):
1359 1359 return self._id
1360 1360 else:
1361 1361 return self._getentry().gr_name
1362 1362 name = property(getname, None, None, "Group name")
1363 1363
1364 1364 def getpasswd(self):
1365 1365 return self._getentry().gr_passwd
1366 1366 passwd = property(getpasswd, None, None, "Password")
1367 1367
1368 1368 def getgid(self):
1369 1369 if isinstance(self._id, basestring):
1370 1370 return self._getentry().gr_gid
1371 1371 else:
1372 1372 return self._id
1373 1373 gid = property(getgid, None, None, "Group id")
1374 1374
1375 1375 def getmem(self):
1376 1376 return self._getentry().gr_mem
1377 1377 mem = property(getmem, None, None, "Members")
1378 1378
1379 1379 def __xattrs__(self, mode):
1380 1380 return ("name", "passwd", "gid", "mem")
1381 1381
1382 1382 def __xrepr__(self, mode):
1383 1383 if mode == "header" or mode == "footer" or mode == "cell":
1384 1384 yield (astyle.style_default, "group ")
1385 1385 try:
1386 1386 yield (astyle.style_default, self.name)
1387 1387 except KeyError:
1388 1388 if isinstance(self._id, basestring):
1389 1389 yield (astyle.style_default, self.name_id)
1390 1390 else:
1391 1391 yield (astyle.style_type_number, str(self._id))
1392 1392 else:
1393 1393 yield (astyle.style_default, repr(self))
1394 1394
1395 1395 def __iter__(self):
1396 1396 for member in self.mem:
1397 1397 yield ipwdentry(member)
1398 1398
1399 1399 def __repr__(self):
1400 1400 return "%s.%s(%r)" % \
1401 1401 (self.__class__.__module__, self.__class__.__name__, self._id)
1402 1402
1403 1403
1404 1404 class igrp(Table):
1405 1405 """
1406 1406 This ``Table`` lists all entries in the Unix group database.
1407 1407 """
1408 1408 def __iter__(self):
1409 1409 for entry in grp.getgrall():
1410 1410 yield igrpentry(entry.gr_name)
1411 1411
1412 1412 def __xrepr__(self, mode):
1413 1413 if mode == "header" or mode == "footer":
1414 1414 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1415 1415 else:
1416 1416 yield (astyle.style_default, repr(self))
1417 1417
1418 1418
1419 1419 class Fields(object):
1420 1420 def __init__(self, fieldnames, **fields):
1421 1421 self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
1422 1422 for (key, value) in fields.iteritems():
1423 1423 setattr(self, key, value)
1424 1424
1425 1425 def __xattrs__(self, mode):
1426 1426 return self.__fieldnames
1427 1427
1428 1428 def __xrepr__(self, mode):
1429 1429 yield (-1, False)
1430 1430 if mode == "header" or mode == "cell":
1431 1431 yield (astyle.style_default, self.__class__.__name__)
1432 1432 yield (astyle.style_default, "(")
1433 1433 for (i, f) in enumerate(self.__fieldnames):
1434 1434 if i:
1435 1435 yield (astyle.style_default, ", ")
1436 1436 yield (astyle.style_default, f.name())
1437 1437 yield (astyle.style_default, "=")
1438 1438 for part in xrepr(getattr(self, f), "default"):
1439 1439 yield part
1440 1440 yield (astyle.style_default, ")")
1441 1441 elif mode == "footer":
1442 1442 yield (astyle.style_default, self.__class__.__name__)
1443 1443 yield (astyle.style_default, "(")
1444 1444 for (i, f) in enumerate(self.__fieldnames):
1445 1445 if i:
1446 1446 yield (astyle.style_default, ", ")
1447 1447 yield (astyle.style_default, f.name())
1448 1448 yield (astyle.style_default, ")")
1449 1449 else:
1450 1450 yield (astyle.style_default, repr(self))
1451 1451
1452 1452
1453 1453 class FieldTable(Table, list):
1454 1454 def __init__(self, *fields):
1455 1455 Table.__init__(self)
1456 1456 list.__init__(self)
1457 1457 self.fields = fields
1458 1458
1459 1459 def add(self, **fields):
1460 1460 self.append(Fields(self.fields, **fields))
1461 1461
1462 1462 def __xrepr__(self, mode):
1463 1463 yield (-1, False)
1464 1464 if mode == "header" or mode == "footer":
1465 1465 yield (astyle.style_default, self.__class__.__name__)
1466 1466 yield (astyle.style_default, "(")
1467 1467 for (i, f) in enumerate(self.__fieldnames):
1468 1468 if i:
1469 1469 yield (astyle.style_default, ", ")
1470 1470 yield (astyle.style_default, f)
1471 1471 yield (astyle.style_default, ")")
1472 1472 else:
1473 1473 yield (astyle.style_default, repr(self))
1474 1474
1475 1475 def __repr__(self):
1476 1476 return "<%s.%s object with fields=%r at 0x%x>" % \
1477 1477 (self.__class__.__module__, self.__class__.__name__,
1478 1478 ", ".join(map(repr, self.fields)), id(self))
1479 1479
1480 1480
1481 1481 class List(list):
1482 1482 def __xattrs__(self, mode):
1483 1483 return xrange(len(self))
1484 1484
1485 1485 def __xrepr__(self, mode):
1486 1486 yield (-1, False)
1487 1487 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1488 1488 yield (astyle.style_default, self.__class__.__name__)
1489 1489 yield (astyle.style_default, "(")
1490 1490 for (i, item) in enumerate(self):
1491 1491 if i:
1492 1492 yield (astyle.style_default, ", ")
1493 1493 for part in xrepr(item, "default"):
1494 1494 yield part
1495 1495 yield (astyle.style_default, ")")
1496 1496 else:
1497 1497 yield (astyle.style_default, repr(self))
1498 1498
1499 1499
1500 1500 class ienv(Table):
1501 1501 """
1502 1502 List environment variables.
1503 1503
1504 1504 Example:
1505 1505
1506 1506 >>> ienv
1507 1507 """
1508 1508
1509 1509 def __iter__(self):
1510 1510 fields = ("key", "value")
1511 1511 for (key, value) in os.environ.iteritems():
1512 1512 yield Fields(fields, key=key, value=value)
1513 1513
1514 1514 def __xrepr__(self, mode):
1515 1515 if mode == "header" or mode == "cell":
1516 1516 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1517 1517 else:
1518 1518 yield (astyle.style_default, repr(self))
1519 1519
1520 1520
1521 1521 class icsv(Pipe):
1522 1522 """
1523 1523 This ``Pipe`` lists turn the input (with must be a pipe outputting lines
1524 1524 or an ``ifile``) into lines of CVS columns.
1525 1525 """
1526 1526 def __init__(self, **csvargs):
1527 1527 """
1528 1528 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1529 1529 keyword arguments to ``cvs.reader()``.
1530 1530 """
1531 1531 self.csvargs = csvargs
1532 1532
1533 1533 def __iter__(self):
1534 1534 input = self.input
1535 1535 if isinstance(input, ifile):
1536 1536 input = input.open("rb")
1537 1537 reader = csv.reader(input, **self.csvargs)
1538 1538 for line in reader:
1539 1539 yield List(line)
1540 1540
1541 1541 def __xrepr__(self, mode):
1542 1542 yield (-1, False)
1543 1543 if mode == "header" or mode == "footer":
1544 1544 input = getattr(self, "input", None)
1545 1545 if input is not None:
1546 1546 for part in xrepr(input, mode):
1547 1547 yield part
1548 1548 yield (astyle.style_default, " | ")
1549 1549 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1550 1550 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1551 1551 if i:
1552 1552 yield (astyle.style_default, ", ")
1553 1553 yield (astyle.style_default, name)
1554 1554 yield (astyle.style_default, "=")
1555 1555 for part in xrepr(value, "default"):
1556 1556 yield part
1557 1557 yield (astyle.style_default, ")")
1558 1558 else:
1559 1559 yield (astyle.style_default, repr(self))
1560 1560
1561 1561 def __repr__(self):
1562 1562 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1563 1563 return "<%s.%s %s at 0x%x>" % \
1564 1564 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1565 1565
1566 1566
1567 1567 class ix(Table):
1568 1568 """
1569 1569 Execute a system command and list its output as lines
1570 1570 (similar to ``os.popen()``).
1571 1571
1572 1572 Examples:
1573 1573
1574 1574 >>> ix("ps x")
1575 1575 >>> ix("find .") | ifile
1576 1576 """
1577 1577 def __init__(self, cmd):
1578 1578 self.cmd = cmd
1579 1579 self._pipeout = None
1580 1580
1581 1581 def __iter__(self):
1582 1582 (_pipein, self._pipeout) = os.popen4(self.cmd)
1583 1583 _pipein.close()
1584 1584 for l in self._pipeout:
1585 1585 yield l.rstrip("\r\n")
1586 1586 self._pipeout.close()
1587 1587 self._pipeout = None
1588 1588
1589 1589 def __del__(self):
1590 1590 if self._pipeout is not None and not self._pipeout.closed:
1591 1591 self._pipeout.close()
1592 1592 self._pipeout = None
1593 1593
1594 1594 def __xrepr__(self, mode):
1595 1595 if mode == "header" or mode == "footer":
1596 1596 yield (astyle.style_default,
1597 1597 "%s(%r)" % (self.__class__.__name__, self.cmd))
1598 1598 else:
1599 1599 yield (astyle.style_default, repr(self))
1600 1600
1601 1601 def __repr__(self):
1602 1602 return "%s.%s(%r)" % \
1603 1603 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1604 1604
1605 1605
1606 1606 class ifilter(Pipe):
1607 1607 """
1608 1608 Filter an input pipe. Only objects where an expression evaluates to true
1609 1609 (and doesn't raise an exception) are listed.
1610 1610
1611 1611 Examples:
1612 1612
1613 1613 >>> ils | ifilter("_.isfile() and size>1000")
1614 1614 >>> igrp | ifilter("len(mem)")
1615 1615 >>> sys.modules | ifilter(lambda _:_.value is not None)
1616 1616 """
1617 1617
1618 1618 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1619 1619 """
1620 1620 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1621 1621 containing an expression. ``globals`` will be used as the global
1622 1622 namespace for calling string expressions (defaulting to IPython's
1623 1623 user namespace). ``errors`` specifies how exception during evaluation
1624 1624 of ``expr`` are handled:
1625 1625
1626 1626 * ``drop``: drop all items that have errors;
1627 1627
1628 1628 * ``keep``: keep all items that have errors;
1629 1629
1630 1630 * ``keeperror``: keep the exception of all items that have errors;
1631 1631
1632 1632 * ``raise``: raise the exception;
1633 1633
1634 1634 * ``raiseifallfail``: raise the first exception if all items have errors;
1635 1635 otherwise drop those with errors (this is the default).
1636 1636 """
1637 1637 self.expr = expr
1638 1638 self.globals = globals
1639 1639 self.errors = errors
1640 1640
1641 1641 def __iter__(self):
1642 1642 if callable(self.expr):
1643 1643 test = self.expr
1644 1644 else:
1645 1645 g = getglobals(self.globals)
1646 1646 expr = compile(self.expr, "ipipe-expression", "eval")
1647 1647 def test(item):
1648 1648 return eval(expr, g, AttrNamespace(item))
1649 1649
1650 1650 ok = 0
1651 1651 exc_info = None
1652 1652 for item in xiter(self.input):
1653 1653 try:
1654 1654 if test(item):
1655 1655 yield item
1656 1656 ok += 1
1657 1657 except (KeyboardInterrupt, SystemExit):
1658 1658 raise
1659 1659 except Exception, exc:
1660 1660 if self.errors == "drop":
1661 1661 pass # Ignore errors
1662 1662 elif self.errors == "keep":
1663 1663 yield item
1664 1664 elif self.errors == "keeperror":
1665 1665 yield exc
1666 1666 elif self.errors == "raise":
1667 1667 raise
1668 1668 elif self.errors == "raiseifallfail":
1669 1669 if exc_info is None:
1670 1670 exc_info = sys.exc_info()
1671 1671 if not ok and exc_info is not None:
1672 1672 raise exc_info[0], exc_info[1], exc_info[2]
1673 1673
1674 1674 def __xrepr__(self, mode):
1675 1675 if mode == "header" or mode == "footer":
1676 1676 input = getattr(self, "input", None)
1677 1677 if input is not None:
1678 1678 for part in xrepr(input, mode):
1679 1679 yield part
1680 1680 yield (astyle.style_default, " | ")
1681 1681 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1682 1682 for part in xrepr(self.expr, "default"):
1683 1683 yield part
1684 1684 yield (astyle.style_default, ")")
1685 1685 else:
1686 1686 yield (astyle.style_default, repr(self))
1687 1687
1688 1688 def __repr__(self):
1689 1689 return "<%s.%s expr=%r at 0x%x>" % \
1690 1690 (self.__class__.__module__, self.__class__.__name__,
1691 1691 self.expr, id(self))
1692 1692
1693 1693
1694 1694 class ieval(Pipe):
1695 1695 """
1696 1696 Evaluate an expression for each object in the input pipe.
1697 1697
1698 1698 Examples:
1699 1699
1700 1700 >>> ils | ieval("_.abspath()")
1701 1701 >>> sys.path | ieval(ifile)
1702 1702 """
1703 1703
1704 1704 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1705 1705 """
1706 1706 Create an ``ieval`` object. ``expr`` can be a callable or a string
1707 1707 containing an expression. For the meaning of ``globals`` and
1708 1708 ``errors`` see ``ifilter``.
1709 1709 """
1710 1710 self.expr = expr
1711 1711 self.globals = globals
1712 1712 self.errors = errors
1713 1713
1714 1714 def __iter__(self):
1715 1715 if callable(self.expr):
1716 1716 do = self.expr
1717 1717 else:
1718 1718 g = getglobals(self.globals)
1719 1719 expr = compile(self.expr, "ipipe-expression", "eval")
1720 1720 def do(item):
1721 1721 return eval(expr, g, AttrNamespace(item))
1722 1722
1723 1723 ok = 0
1724 1724 exc_info = None
1725 1725 for item in xiter(self.input):
1726 1726 try:
1727 1727 yield do(item)
1728 1728 except (KeyboardInterrupt, SystemExit):
1729 1729 raise
1730 1730 except Exception, exc:
1731 1731 if self.errors == "drop":
1732 1732 pass # Ignore errors
1733 1733 elif self.errors == "keep":
1734 1734 yield item
1735 1735 elif self.errors == "keeperror":
1736 1736 yield exc
1737 1737 elif self.errors == "raise":
1738 1738 raise
1739 1739 elif self.errors == "raiseifallfail":
1740 1740 if exc_info is None:
1741 1741 exc_info = sys.exc_info()
1742 1742 if not ok and exc_info is not None:
1743 1743 raise exc_info[0], exc_info[1], exc_info[2]
1744 1744
1745 1745 def __xrepr__(self, mode):
1746 1746 if mode == "header" or mode == "footer":
1747 1747 input = getattr(self, "input", None)
1748 1748 if input is not None:
1749 1749 for part in xrepr(input, mode):
1750 1750 yield part
1751 1751 yield (astyle.style_default, " | ")
1752 1752 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1753 1753 for part in xrepr(self.expr, "default"):
1754 1754 yield part
1755 1755 yield (astyle.style_default, ")")
1756 1756 else:
1757 1757 yield (astyle.style_default, repr(self))
1758 1758
1759 1759 def __repr__(self):
1760 1760 return "<%s.%s expr=%r at 0x%x>" % \
1761 1761 (self.__class__.__module__, self.__class__.__name__,
1762 1762 self.expr, id(self))
1763 1763
1764 1764
1765 1765 class ienum(Pipe):
1766 1766 """
1767 1767 Enumerate the input pipe (i.e. wrap each input object in an object
1768 1768 with ``index`` and ``object`` attributes).
1769 1769
1770 1770 Examples:
1771 1771
1772 1772 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1773 1773 """
1774 1774 def __iter__(self):
1775 1775 fields = ("index", "object")
1776 1776 for (index, object) in enumerate(xiter(self.input)):
1777 1777 yield Fields(fields, index=index, object=object)
1778 1778
1779 1779
1780 1780 class isort(Pipe):
1781 1781 """
1782 1782 Sorts the input pipe.
1783 1783
1784 1784 Examples:
1785 1785
1786 1786 >>> ils | isort("size")
1787 1787 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1788 1788 """
1789 1789
1790 1790 def __init__(self, key=None, globals=None, reverse=False):
1791 1791 """
1792 1792 Create an ``isort`` object. ``key`` can be a callable or a string
1793 1793 containing an expression (or ``None`` in which case the items
1794 1794 themselves will be sorted). If ``reverse`` is true the sort order
1795 1795 will be reversed. For the meaning of ``globals`` see ``ifilter``.
1796 1796 """
1797 1797 self.key = key
1798 1798 self.globals = globals
1799 1799 self.reverse = reverse
1800 1800
1801 1801 def __iter__(self):
1802 1802 if self.key is None:
1803 1803 items = sorted(xiter(self.input), reverse=self.reverse)
1804 1804 elif callable(self.key):
1805 1805 items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
1806 1806 else:
1807 1807 g = getglobals(self.globals)
1808 1808 key = compile(self.key, "ipipe-expression", "eval")
1809 1809 def realkey(item):
1810 1810 return eval(key, g, AttrNamespace(item))
1811 1811 items = sorted(
1812 1812 xiter(self.input, mode),
1813 1813 key=realkey,
1814 1814 reverse=self.reverse
1815 1815 )
1816 1816 for item in items:
1817 1817 yield item
1818 1818
1819 1819 def __xrepr__(self, mode):
1820 1820 if mode == "header" or mode == "footer":
1821 1821 input = getattr(self, "input", None)
1822 1822 if input is not None:
1823 1823 for part in xrepr(input, mode):
1824 1824 yield part
1825 1825 yield (astyle.style_default, " | ")
1826 1826 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1827 1827 for part in xrepr(self.key, "default"):
1828 1828 yield part
1829 1829 if self.reverse:
1830 1830 yield (astyle.style_default, ", ")
1831 1831 for part in xrepr(True, "default"):
1832 1832 yield part
1833 1833 yield (astyle.style_default, ")")
1834 1834 else:
1835 1835 yield (astyle.style_default, repr(self))
1836 1836
1837 1837 def __repr__(self):
1838 1838 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1839 1839 (self.__class__.__module__, self.__class__.__name__,
1840 1840 self.key, self.reverse, id(self))
1841 1841
1842 1842
1843 1843 tab = 3 # for expandtabs()
1844 1844
1845 1845 def _format(field):
1846 1846 if isinstance(field, str):
1847 1847 text = repr(field.expandtabs(tab))[1:-1]
1848 1848 elif isinstance(field, unicode):
1849 1849 text = repr(field.expandtabs(tab))[2:-1]
1850 1850 elif isinstance(field, datetime.datetime):
1851 1851 # Don't use strftime() here, as this requires year >= 1900
1852 1852 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1853 1853 (field.year, field.month, field.day,
1854 1854 field.hour, field.minute, field.second, field.microsecond)
1855 1855 elif isinstance(field, datetime.date):
1856 1856 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
1857 1857 else:
1858 1858 text = repr(field)
1859 1859 return text
1860 1860
1861 1861
1862 1862 class Display(object):
1863 1863 class __metaclass__(type):
1864 1864 def __ror__(self, input):
1865 1865 return input | self()
1866 1866
1867 1867 def __ror__(self, input):
1868 1868 self.input = input
1869 1869 return self
1870 1870
1871 1871 def display(self):
1872 1872 pass
1873 1873
1874 1874
1875 1875 class iless(Display):
1876 1876 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
1877 1877
1878 1878 def display(self):
1879 1879 try:
1880 1880 pager = os.popen(self.cmd, "w")
1881 1881 try:
1882 1882 for item in xiter(self.input, "default"):
1883 1883 attrs = tuple(_upgradexattrs(item, "default"))
1884 1884 attrs = ["%s=%s" % (a.name(item), a.value(item)) for a in attrs]
1885 1885 pager.write(" ".join(attrs))
1886 1886 pager.write("\n")
1887 1887 finally:
1888 1888 pager.close()
1889 1889 except Exception, exc:
1890 1890 print "%s: %s" % (exc.__class__.__name__, str(exc))
1891 1891
1892 1892
1893 1893 def xformat(value, mode, maxlength):
1894 1894 align = None
1895 1895 full = True
1896 1896 width = 0
1897 1897 text = astyle.Text()
1898 1898 for (style, part) in xrepr(value, mode):
1899 1899 # only consider the first result
1900 1900 if align is None:
1901 1901 if isinstance(style, int):
1902 1902 # (style, text) really is (alignment, stop)
1903 1903 align = style
1904 1904 full = part
1905 1905 continue
1906 1906 else:
1907 1907 align = -1
1908 1908 full = True
1909 1909 if not isinstance(style, int):
1910 1910 text.append((style, part))
1911 1911 width += len(part)
1912 1912 if width >= maxlength and not full:
1913 1913 text.append((astyle.style_ellisis, "..."))
1914 1914 width += 3
1915 1915 break
1916 1916 if align is None: # default to left alignment
1917 1917 align = -1
1918 1918 return (align, width, text)
1919 1919
1920 1920
1921 1921 class idump(Display):
1922 1922 # The approximate maximum length of a column entry
1923 1923 maxattrlength = 200
1924 1924
1925 1925 # Style for column names
1926 1926 style_header = astyle.Style.fromstr("white:black:bold")
1927 1927
1928 1928 def __init__(self, *attrs):
1929 1929 self.attrs = [upgradexattr(attr) for attr in attrs]
1930 1930 self.headerpadchar = " "
1931 1931 self.headersepchar = "|"
1932 1932 self.datapadchar = " "
1933 1933 self.datasepchar = "|"
1934 1934
1935 1935 def display(self):
1936 1936 stream = genutils.Term.cout
1937 1937 allattrs = []
1938 1938 attrset = set()
1939 1939 colwidths = {}
1940 1940 rows = []
1941 1941 for item in xiter(self.input, "default"):
1942 1942 row = {}
1943 1943 attrs = self.attrs
1944 1944 if not attrs:
1945 1945 attrs = xattrs(item, "default")
1946 1946 for attr in attrs:
1947 1947 if attr not in attrset:
1948 1948 allattrs.append(attr)
1949 1949 attrset.add(attr)
1950 1950 colwidths[attr] = len(attr.name())
1951 1951 try:
1952 1952 value = attr.value(item)
1953 1953 except (KeyboardInterrupt, SystemExit):
1954 1954 raise
1955 1955 except Exception, exc:
1956 1956 value = exc
1957 1957 (align, width, text) = xformat(value, "cell", self.maxattrlength)
1958 1958 colwidths[attr] = max(colwidths[attr], width)
1959 1959 # remember alignment, length and colored parts
1960 1960 row[attr] = (align, width, text)
1961 1961 rows.append(row)
1962 1962
1963 1963 stream.write("\n")
1964 1964 for (i, attr) in enumerate(allattrs):
1965 1965 attrname = attr.name()
1966 1966 self.style_header(attrname).write(stream)
1967 1967 spc = colwidths[attr] - len(attrname)
1968 1968 if i < len(colwidths)-1:
1969 1969 stream.write(self.headerpadchar*spc)
1970 1970 stream.write(self.headersepchar)
1971 1971 stream.write("\n")
1972 1972
1973 1973 for row in rows:
1974 1974 for (i, attr) in enumerate(allattrs):
1975 1975 (align, width, text) = row[attr]
1976 1976 spc = colwidths[attr] - width
1977 1977 if align == -1:
1978 1978 text.write(stream)
1979 1979 if i < len(colwidths)-1:
1980 1980 stream.write(self.datapadchar*spc)
1981 1981 elif align == 0:
1982 1982 spc = colwidths[attr] - width
1983 1983 spc1 = spc//2
1984 1984 spc2 = spc-spc1
1985 1985 stream.write(self.datapadchar*spc1)
1986 1986 text.write(stream)
1987 1987 if i < len(colwidths)-1:
1988 1988 stream.write(self.datapadchar*spc2)
1989 1989 else:
1990 1990 stream.write(self.datapadchar*spc)
1991 1991 text.write(stream)
1992 1992 if i < len(colwidths)-1:
1993 1993 stream.write(self.datasepchar)
1994 1994 stream.write("\n")
1995 1995
1996 1996
1997 1997 class XMode(object):
1998 1998 """
1999 1999 An ``XMode`` object describes one enter mode available for an object
2000 2000 """
2001 2001 def __init__(self, object, mode, title=None, description=None):
2002 2002 """
2003 2003 Create a new ``XMode`` object for the object ``object``. This object
2004 2004 must support the enter mode ``mode`` (i.e. ``object.__xiter__(mode)``
2005 2005 must return an iterable). ``title`` and ``description`` will be
2006 2006 displayed in the browser when selecting among the available modes.
2007 2007 """
2008 2008 self.object = object
2009 2009 self.mode = mode
2010 2010 self.title = title
2011 2011 self.description = description
2012 2012
2013 2013 def __repr__(self):
2014 2014 return "<%s.%s object mode=%r at 0x%x>" % \
2015 2015 (self.__class__.__module__, self.__class__.__name__,
2016 2016 self.mode, id(self))
2017 2017
2018 2018 def __xrepr__(self, mode):
2019 2019 if mode == "header" or mode == "footer":
2020 2020 yield (astyle.style_default, self.title)
2021 2021 else:
2022 2022 yield (astyle.style_default, repr(self))
2023 2023
2024 2024 def __xattrs__(self, mode):
2025 2025 if mode == "detail":
2026 2026 return ("object", "mode")
2027 2027 else:
2028 2028 return ("object", "mode", "title", "description")
2029 2029
2030 2030 def __xiter__(self, mode):
2031 2031 return xiter(self.object, self.mode)
2032 2032
2033 2033
2034 2034 class AttributeDetail(Table):
2035 2035 def __init__(self, object, descriptor):
2036 2036 self.object = object
2037 2037 self.descriptor = descriptor
2038 2038
2039 2039 def __iter__(self):
2040 2040 return self.descriptor.iter(self.object)
2041 2041
2042 2042 def name(self):
2043 2043 return self.descriptor.name()
2044 2044
2045 2045 def attrtype(self):
2046 2046 return self.descriptor.attrtype(self.object)
2047 2047
2048 2048 def valuetype(self):
2049 2049 return self.descriptor.valuetype(self.object)
2050 2050
2051 2051 def doc(self):
2052 2052 return self.descriptor.doc(self.object)
2053 2053
2054 2054 def shortdoc(self):
2055 2055 return self.descriptor.shortdoc(self.object)
2056 2056
2057 2057 def value(self):
2058 2058 return self.descriptor.value(self.object)
2059 2059
2060 2060 def __xattrs__(self, mode):
2061 2061 attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
2062 2062 if mode == "detail":
2063 2063 attrs += ("doc()",)
2064 2064 return attrs
2065 2065
2066 2066 def __xrepr__(self, mode):
2067 2067 yield (-1, True)
2068 2068 yield (astyle.style_default, self.attrtype())
2069 2069 yield (astyle.style_default, "(")
2070 2070 for part in xrepr(self.valuetype()):
2071 2071 yield part
2072 2072 yield (astyle.style_default, ") ")
2073 2073 yield (astyle.style_default, self.name())
2074 2074 yield (astyle.style_default, " of ")
2075 2075 for part in xrepr(self.object):
2076 2076 yield part
2077 2077
2078 2078
2079 2079 try:
2080 2080 from ibrowse import ibrowse
2081 2081 except ImportError:
2082 2082 # No curses (probably Windows) => use ``idump`` as the default display.
2083 2083 defaultdisplay = idump
2084 2084 else:
2085 2085 defaultdisplay = ibrowse
2086 2086 __all__.append("ibrowse")
2087 2087
2088 2088
2089 2089 # If we're running under IPython, install an IPython displayhook that
2090 2090 # returns the object from Display.display(), else install a displayhook
2091 2091 # directly as sys.displayhook
2092 2092 api = None
2093 2093 if ipapi is not None:
2094 2094 try:
2095 2095 api = ipapi.get()
2096 2096 except AttributeError:
2097 2097 pass
2098 2098
2099 2099 if api is not None:
2100 2100 def displayhook(self, obj):
2101 2101 if isinstance(obj, type) and issubclass(obj, Table):
2102 2102 obj = obj()
2103 2103 if isinstance(obj, Table):
2104 2104 obj = obj | defaultdisplay
2105 2105 if isinstance(obj, Display):
2106 2106 return obj.display()
2107 2107 else:
2108 2108 raise ipapi.TryNext
2109 2109 api.set_hook("result_display", displayhook)
2110 2110 else:
2111 2111 def installdisplayhook():
2112 2112 _originalhook = sys.displayhook
2113 2113 def displayhook(obj):
2114 2114 if isinstance(obj, type) and issubclass(obj, Table):
2115 2115 obj = obj()
2116 2116 if isinstance(obj, Table):
2117 2117 obj = obj | defaultdisplay
2118 2118 if isinstance(obj, Display):
2119 2119 return obj.display()
2120 2120 else:
2121 2121 _originalhook(obj)
2122 2122 sys.displayhook = displayhook
2123 2123 installdisplayhook()
General Comments 0
You need to be logged in to leave comments. Login now