~ipython-dev/ipython/0.10.1

« back to all changes in this revision

Viewing changes to IPython/Extensions/ipipe.py

  • Committer: Fernando Perez
  • Date: 2008-06-02 01:26:30 UTC
  • mfrom: (0.1.130 ipython-local)
  • Revision ID: fernando.perez@berkeley.edu-20080602012630-m14vezrhydzvahf8
Merge in all development done in bzr since February 16 2008.

At that time, a clean bzr branch was started from the SVN tree, but
without SVN history.  That SVN history has now been used as the basis
of this branch, and the development done on the history-less BZR
branch has been added and is the content of this merge.  

This branch will be the new official main line of development in
Launchpad (equivalent to the old SVN trunk).

Show diffs side-by-side

added added

removed removed

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