##// END OF EJS Templates
Use IPython's user namespace for the global namespace...
walter.doerwald -
Show More
@@ -1,1844 +1,1864 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 textwrap, 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 from IPython import genutils
157 from IPython import genutils, ipapi
158 158 except ImportError:
159 pass
159 genutils = None
160 ipapi = None
160 161
161 162 import astyle
162 163
163 164
164 165 __all__ = [
165 166 "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
166 167 "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum", "ienv",
167 168 "idump", "iless"
168 169 ]
169 170
170 171
171 172 os.stat_float_times(True) # enable microseconds
172 173
173 174
174 175 class AttrNamespace(object):
175 176 """
176 177 Helper class that is used for providing a namespace for evaluating
177 178 expressions containing attribute names of an object.
178 179 """
179 180 def __init__(self, wrapped):
180 181 self.wrapped = wrapped
181 182
182 183 def __getitem__(self, name):
183 184 if name == "_":
184 185 return self.wrapped
185 186 try:
186 187 return getattr(self.wrapped, name)
187 188 except AttributeError:
188 189 raise KeyError(name)
189 190
190 191 # Python 2.3 compatibility
191 192 # use eval workaround to find out which names are used in the
192 193 # eval string and put them into the locals. This works for most
193 194 # normal uses case, bizarre ones like accessing the locals()
194 195 # will fail
195 196 try:
196 197 eval("_", None, AttrNamespace(None))
197 198 except TypeError:
198 199 real_eval = eval
199 200 def eval(codestring, _globals, _locals):
200 201 """
201 202 eval(source[, globals[, locals]]) -> value
202 203
203 204 Evaluate the source in the context of globals and locals.
204 205 The source may be a string representing a Python expression
205 206 or a code object as returned by compile().
206 207 The globals must be a dictionary and locals can be any mappping.
207 208
208 209 This function is a workaround for the shortcomings of
209 210 Python 2.3's eval.
210 211 """
211 212
212 213 code = compile(codestring, "_eval", "eval")
213 214 newlocals = {}
214 215 for name in code.co_names:
215 216 try:
216 217 newlocals[name] = _locals[name]
217 218 except KeyError:
218 219 pass
219 220 return real_eval(code, _globals, newlocals)
220 221
221 222
222 223 noitem = object()
223 224
224 225 def item(iterator, index, default=noitem):
225 226 """
226 227 Return the ``index``th item from the iterator ``iterator``.
227 228 ``index`` must be an integer (negative integers are relative to the
228 229 end (i.e. the last item produced by the iterator)).
229 230
230 231 If ``default`` is given, this will be the default value when
231 232 the iterator doesn't contain an item at this position. Otherwise an
232 233 ``IndexError`` will be raised.
233 234
234 235 Note that using this function will partially or totally exhaust the
235 236 iterator.
236 237 """
237 238 i = index
238 239 if i>=0:
239 240 for item in iterator:
240 241 if not i:
241 242 return item
242 243 i -= 1
243 244 else:
244 245 i = -index
245 246 cache = deque()
246 247 for item in iterator:
247 248 cache.append(item)
248 249 if len(cache)>i:
249 250 cache.popleft()
250 251 if len(cache)==i:
251 252 return cache.popleft()
252 253 if default is noitem:
253 254 raise IndexError(index)
254 255 else:
255 256 return default
256 257
257 258
259 def getglobals(g):
260 if g is None:
261 if ipapi is not None:
262 return ipapi.get().user_ns()
263 else:
264 return globals()
265 return g
266
267
258 268 class Table(object):
259 269 """
260 270 A ``Table`` is an object that produces items (just like a normal Python
261 271 iterator/generator does) and can be used as the first object in a pipeline
262 272 expression. The displayhook will open the default browser for such an object
263 273 (instead of simply printing the ``repr()`` result).
264 274 """
265 275
266 276 # We want to support ``foo`` and ``foo()`` in pipeline expression:
267 277 # So we implement the required operators (``|`` and ``+``) in the metaclass,
268 278 # instantiate the class and forward the operator to the instance
269 279 class __metaclass__(type):
270 280 def __iter__(self):
271 281 return iter(self())
272 282
273 283 def __or__(self, other):
274 284 return self() | other
275 285
276 286 def __add__(self, other):
277 287 return self() + other
278 288
279 289 def __radd__(self, other):
280 290 return other + self()
281 291
282 292 def __getitem__(self, index):
283 293 return self()[index]
284 294
285 295 def __getitem__(self, index):
286 296 return item(self, index)
287 297
288 298 def __contains__(self, item):
289 299 for haveitem in self:
290 300 if item == haveitem:
291 301 return True
292 302 return False
293 303
294 304 def __or__(self, other):
295 305 # autoinstantiate right hand side
296 306 if isinstance(other, type) and issubclass(other, (Table, Display)):
297 307 other = other()
298 308 # treat simple strings and functions as ``ieval`` instances
299 309 elif not isinstance(other, Display) and not isinstance(other, Table):
300 310 other = ieval(other)
301 311 # forward operations to the right hand side
302 312 return other.__ror__(self)
303 313
304 314 def __add__(self, other):
305 315 # autoinstantiate right hand side
306 316 if isinstance(other, type) and issubclass(other, Table):
307 317 other = other()
308 318 return ichain(self, other)
309 319
310 320 def __radd__(self, other):
311 321 # autoinstantiate left hand side
312 322 if isinstance(other, type) and issubclass(other, Table):
313 323 other = other()
314 324 return ichain(other, self)
315 325
316 326 def __iter__(self):
317 327 return xiter(self, "default")
318 328
319 329
320 330 class Pipe(Table):
321 331 """
322 332 A ``Pipe`` is an object that can be used in a pipeline expression. It
323 333 processes the objects it gets from its input ``Table``/``Pipe``. Note that
324 334 a ``Pipe`` object can't be used as the first object in a pipeline
325 335 expression, as it doesn't produces items itself.
326 336 """
327 337 class __metaclass__(Table.__metaclass__):
328 338 def __ror__(self, input):
329 339 return input | self()
330 340
331 341 def __ror__(self, input):
332 342 # autoinstantiate left hand side
333 343 if isinstance(input, type) and issubclass(input, Table):
334 344 input = input()
335 345 self.input = input
336 346 return self
337 347
338 348
339 349 def _getattr(obj, name, default=noitem):
340 350 """
341 351 Internal helper for getting an attribute of an item. If ``name`` is ``None``
342 352 return the object itself. If ``name`` is an integer, use ``__getitem__``
343 353 instead. If the attribute or item does not exist, return ``default``.
344 354 """
345 355 if name is None:
346 356 return obj
347 357 elif isinstance(name, basestring):
348 358 if name.endswith("()"):
349 359 return getattr(obj, name[:-2], default)()
350 360 else:
351 361 return getattr(obj, name, default)
352 362 elif callable(name):
353 363 try:
354 364 return name(obj)
355 365 except AttributeError:
356 366 return default
357 367 else:
358 368 try:
359 369 return obj[name]
360 370 except IndexError:
361 371 return default
362 372
363 373
364 374 def _attrname(name):
365 375 """
366 376 Internal helper that gives a proper name for the attribute ``name``
367 377 (which might be ``None`` or an ``int``).
368 378 """
369 379 if name is None:
370 380 return "_"
371 381 elif isinstance(name, basestring):
372 382 return name
373 383 elif callable(name):
374 384 return getattr(name, "__xname__", name.__name__)
375 385 else:
376 386 return str(name)
377 387
378 388
379 389 def xrepr(item, mode):
380 390 try:
381 391 func = item.__xrepr__
382 392 except AttributeError:
383 393 pass
384 394 else:
385 395 try:
386 396 for x in func(mode):
387 397 yield x
388 398 except (KeyboardInterrupt, SystemExit):
389 399 raise
390 400 except Exception:
391 401 yield (-1, True)
392 402 yield (astyle.style_default, repr(item))
393 403 return
394 404 if item is None:
395 405 yield (-1, True)
396 406 yield (astyle.style_type_none, repr(item))
397 407 elif isinstance(item, bool):
398 408 yield (-1, True)
399 409 yield (astyle.style_type_bool, repr(item))
400 410 elif isinstance(item, str):
401 411 yield (-1, True)
402 412 if mode == "cell":
403 413 yield (astyle.style_default, repr(item.expandtabs(tab))[1:-1])
404 414 else:
405 415 yield (astyle.style_default, repr(item))
406 416 elif isinstance(item, unicode):
407 417 yield (-1, True)
408 418 if mode == "cell":
409 419 yield (astyle.style_default, repr(item.expandtabs(tab))[2:-1])
410 420 else:
411 421 yield (astyle.style_default, repr(item))
412 422 elif isinstance(item, (int, long, float)):
413 423 yield (1, True)
414 424 yield (astyle.style_type_number, repr(item))
415 425 elif isinstance(item, complex):
416 426 yield (-1, True)
417 427 yield (astyle.style_type_number, repr(item))
418 428 elif isinstance(item, datetime.datetime):
419 429 yield (-1, True)
420 430 if mode == "cell":
421 431 # Don't use strftime() here, as this requires year >= 1900
422 432 yield (astyle.style_type_datetime,
423 433 "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
424 434 (item.year, item.month, item.day,
425 435 item.hour, item.minute, item.second,
426 436 item.microsecond),
427 437 )
428 438 else:
429 439 yield (astyle.style_type_datetime, repr(item))
430 440 elif isinstance(item, datetime.date):
431 441 yield (-1, True)
432 442 if mode == "cell":
433 443 yield (astyle.style_type_datetime,
434 444 "%04d-%02d-%02d" % (item.year, item.month, item.day))
435 445 else:
436 446 yield (astyle.style_type_datetime, repr(item))
437 447 elif isinstance(item, datetime.time):
438 448 yield (-1, True)
439 449 if mode == "cell":
440 450 yield (astyle.style_type_datetime,
441 451 "%02d:%02d:%02d.%06d" % \
442 452 (item.hour, item.minute, item.second, item.microsecond))
443 453 else:
444 454 yield (astyle.style_type_datetime, repr(item))
445 455 elif isinstance(item, datetime.timedelta):
446 456 yield (-1, True)
447 457 yield (astyle.style_type_datetime, repr(item))
448 458 elif isinstance(item, Exception):
449 459 yield (-1, True)
450 460 if item.__class__.__module__ == "exceptions":
451 461 classname = item.__class__.__name__
452 462 else:
453 463 classname = "%s.%s" % \
454 464 (item.__class__.__module__, item.__class__.__name__)
455 465 if mode == "header" or mode == "footer":
456 466 yield (astyle.style_error, "%s: %s" % (classname, item))
457 467 else:
458 468 yield (astyle.style_error, classname)
459 469 elif isinstance(item, (list, tuple)):
460 470 yield (-1, False)
461 471 if mode == "header" or mode == "footer":
462 472 if item.__class__.__module__ == "__builtin__":
463 473 classname = item.__class__.__name__
464 474 else:
465 475 classname = "%s.%s" % \
466 476 (item.__class__.__module__,item.__class__.__name__)
467 477 yield (astyle.style_default,
468 478 "<%s object with %d items at 0x%x>" % \
469 479 (classname, len(item), id(item)))
470 480 else:
471 481 if isinstance(item, list):
472 482 yield (astyle.style_default, "[")
473 483 end = "]"
474 484 else:
475 485 yield (astyle.style_default, "(")
476 486 end = ")"
477 487 for (i, subitem) in enumerate(item):
478 488 if i:
479 489 yield (astyle.style_default, ", ")
480 490 for part in xrepr(subitem, "default"):
481 491 yield part
482 492 yield (astyle.style_default, end)
483 493 elif isinstance(item, (dict, types.DictProxyType)):
484 494 yield (-1, False)
485 495 if mode == "header" or mode == "footer":
486 496 if item.__class__.__module__ == "__builtin__":
487 497 classname = item.__class__.__name__
488 498 else:
489 499 classname = "%s.%s" % \
490 500 (item.__class__.__module__,item.__class__.__name__)
491 501 yield (astyle.style_default,
492 502 "<%s object with %d items at 0x%x>" % \
493 503 (classname, len(item), id(item)))
494 504 else:
495 505 if isinstance(item, dict):
496 506 yield (astyle.style_default, "{")
497 507 end = "}"
498 508 else:
499 509 yield (astyle.style_default, "dictproxy((")
500 510 end = "})"
501 511 for (i, (key, value)) in enumerate(item.iteritems()):
502 512 if i:
503 513 yield (astyle.style_default, ", ")
504 514 for part in xrepr(key, "default"):
505 515 yield part
506 516 yield (astyle.style_default, ": ")
507 517 for part in xrepr(value, "default"):
508 518 yield part
509 519 yield (astyle.style_default, end)
510 520 else:
511 521 yield (-1, True)
512 522 yield (astyle.style_default, repr(item))
513 523
514 524
515 525 def xattrs(item, mode):
516 526 try:
517 527 func = item.__xattrs__
518 528 except AttributeError:
519 529 if mode == "detail":
520 530 return dir(item)
521 531 else:
522 532 return (None,)
523 533 else:
524 534 try:
525 535 return func(mode)
526 536 except (KeyboardInterrupt, SystemExit):
527 537 raise
528 538 except Exception:
529 539 return (None,)
530 540
531 541
532 542 def xiter(item, mode):
533 543 if mode == "detail":
534 544 def items():
535 545 for name in xattrs(item, mode):
536 546 yield XAttr(item, name)
537 547 return items()
538 548 try:
539 549 func = item.__xiter__
540 550 except AttributeError:
541 551 if isinstance(item, (dict, types.DictProxyType)):
542 552 def items(item):
543 553 fields = ("key", "value")
544 554 for (key, value) in item.iteritems():
545 555 yield Fields(fields, key=key, value=value)
546 556 return items(item)
547 557 elif isinstance(item, new.module):
548 558 def items(item):
549 559 fields = ("key", "value")
550 560 for key in sorted(item.__dict__):
551 561 yield Fields(fields, key=key, value=getattr(item, key))
552 562 return items(item)
553 563 elif isinstance(item, basestring):
554 564 if not len(item):
555 565 raise ValueError("can't enter empty string")
556 566 lines = item.splitlines()
557 567 if len(lines) <= 1:
558 568 raise ValueError("can't enter one line string")
559 569 return iter(lines)
560 570 return iter(item)
561 571 else:
562 572 return iter(func(mode)) # iter() just to be safe
563 573
564 574
565 575 class ichain(Pipe):
566 576 """
567 577 Chains multiple ``Table``s into one.
568 578 """
569 579
570 580 def __init__(self, *iters):
571 581 self.iters = iters
572 582
573 583 def __xiter__(self, mode):
574 584 return itertools.chain(*self.iters)
575 585
576 586 def __xrepr__(self, mode):
577 587 yield (-1, True)
578 588 if mode == "header" or mode == "footer":
579 589 for (i, item) in enumerate(self.iters):
580 590 if i:
581 591 yield (astyle.style_default, "+")
582 592 if isinstance(item, Pipe):
583 593 yield (astyle.style_default, "(")
584 594 for part in xrepr(item, mode):
585 595 yield part
586 596 if isinstance(item, Pipe):
587 597 yield (astyle.style_default, ")")
588 598 else:
589 599 yield (astyle.style_default, repr(self))
590 600
591 601 def __repr__(self):
592 602 args = ", ".join([repr(it) for it in self.iters])
593 603 return "%s.%s(%s)" % \
594 604 (self.__class__.__module__, self.__class__.__name__, args)
595 605
596 606
597 607 class ifile(path.path):
598 608 """
599 609 file (or directory) object.
600 610 """
601 611
602 612 def __add_(self, other):
603 613 return ifile(path._base(self) + other)
604 614
605 615 def __radd_(self, other):
606 616 return ifile(other + path._base(self))
607 617
608 618 def __div_(self, other):
609 619 return ifile(path.__div__(self, other))
610 620
611 621 def getcwd():
612 622 return ifile(path.path.getcwd())
613 623 getcwd.__doc__ = path.path.getcwd.__doc__
614 624 getcwd = staticmethod(getcwd)
615 625
616 626 def abspath(self):
617 627 return ifile(path.path.abspath(self))
618 628 abspath.__doc__ = path.path.abspath.__doc__
619 629
620 630 def normcase(self):
621 631 return ifile(path.path.normcase(self))
622 632 normcase.__doc__ = path.path.normcase.__doc__
623 633
624 634 def normpath(self):
625 635 return ifile(path.path.normpath(self))
626 636 normpath.__doc__ = path.path.normpath.__doc__
627 637
628 638 def realpath(self):
629 639 return ifile(path.path.realpath(self))
630 640 realpath.__doc__ = path.path.realpath.__doc__
631 641
632 642 def expanduser(self):
633 643 return ifile(path.path.expanduser(self))
634 644 expanduser.__doc__ = path.path.expanduser.__doc__
635 645
636 646 def expandvars(self):
637 647 return ifile(path.path.expandvars(self))
638 648 expandvars.__doc__ = path.path.expandvars.__doc__
639 649
640 650 def dirname(self):
641 651 return ifile(path.path.dirname(self))
642 652 dirname.__doc__ = path.path.dirname.__doc__
643 653
644 654 parent = property(dirname, None, None, path.path.parent.__doc__)
645 655
646 656 def splitpath(self):
647 657 (parent, child) = path.path.splitpath(self)
648 658 return (ifile(parent), child)
649 659 splitpath.__doc__ = path.path.splitpath.__doc__
650 660
651 661 def splitdrive(self):
652 662 (drive, rel) = path.path.splitdrive(self)
653 663 return (ifile(drive), rel)
654 664 splitdrive.__doc__ = path.path.splitdrive.__doc__
655 665
656 666 def splitext(self):
657 667 (filename, ext) = path.path.splitext(self)
658 668 return (ifile(filename), ext)
659 669 splitext.__doc__ = path.path.splitext.__doc__
660 670
661 671 if hasattr(path.path, "splitunc"):
662 672 def splitunc(self):
663 673 (unc, rest) = path.path.splitunc(self)
664 674 return (ifile(unc), rest)
665 675 splitunc.__doc__ = path.path.splitunc.__doc__
666 676
667 677 def _get_uncshare(self):
668 678 unc, r = os.path.splitunc(self)
669 679 return ifile(unc)
670 680
671 681 uncshare = property(
672 682 _get_uncshare, None, None,
673 683 """ The UNC mount point for this path.
674 684 This is empty for paths on local drives. """)
675 685
676 686 def joinpath(self, *args):
677 687 return ifile(path.path.joinpath(self, *args))
678 688 joinpath.__doc__ = path.path.joinpath.__doc__
679 689
680 690 def splitall(self):
681 691 return map(ifile, path.path.splitall(self))
682 692 splitall.__doc__ = path.path.splitall.__doc__
683 693
684 694 def relpath(self):
685 695 return ifile(path.path.relpath(self))
686 696 relpath.__doc__ = path.path.relpath.__doc__
687 697
688 698 def relpathto(self, dest):
689 699 return ifile(path.path.relpathto(self, dest))
690 700 relpathto.__doc__ = path.path.relpathto.__doc__
691 701
692 702 def listdir(self, pattern=None):
693 703 return [ifile(child) for child in path.path.listdir(self, pattern)]
694 704 listdir.__doc__ = path.path.listdir.__doc__
695 705
696 706 def dirs(self, pattern=None):
697 707 return [ifile(child) for child in path.path.dirs(self, pattern)]
698 708 dirs.__doc__ = path.path.dirs.__doc__
699 709
700 710 def files(self, pattern=None):
701 711 return [ifile(child) for child in path.path.files(self, pattern)]
702 712 files.__doc__ = path.path.files.__doc__
703 713
704 714 def walk(self, pattern=None):
705 715 for child in path.path.walk(self, pattern):
706 716 yield ifile(child)
707 717 walk.__doc__ = path.path.walk.__doc__
708 718
709 719 def walkdirs(self, pattern=None):
710 720 for child in path.path.walkdirs(self, pattern):
711 721 yield ifile(child)
712 722 walkdirs.__doc__ = path.path.walkdirs.__doc__
713 723
714 724 def walkfiles(self, pattern=None):
715 725 for child in path.path.walkfiles(self, pattern):
716 726 yield ifile(child)
717 727 walkfiles.__doc__ = path.path.walkfiles.__doc__
718 728
719 729 def glob(self, pattern):
720 730 return map(ifile, path.path.glob(self, pattern))
721 731 glob.__doc__ = path.path.glob.__doc__
722 732
723 733 if hasattr(os, 'readlink'):
724 734 def readlink(self):
725 735 return ifile(path.path.readlink(self))
726 736 readlink.__doc__ = path.path.readlink.__doc__
727 737
728 738 def readlinkabs(self):
729 739 return ifile(path.path.readlinkabs(self))
730 740 readlinkabs.__doc__ = path.path.readlinkabs.__doc__
731 741
732 742 def getmode(self):
733 743 return self.stat().st_mode
734 744 mode = property(getmode, None, None, "Access mode")
735 745
736 746 def gettype(self):
737 747 data = [
738 748 (stat.S_ISREG, "file"),
739 749 (stat.S_ISDIR, "dir"),
740 750 (stat.S_ISCHR, "chardev"),
741 751 (stat.S_ISBLK, "blockdev"),
742 752 (stat.S_ISFIFO, "fifo"),
743 753 (stat.S_ISLNK, "symlink"),
744 754 (stat.S_ISSOCK,"socket"),
745 755 ]
746 756 lstat = self.lstat()
747 757 if lstat is not None:
748 758 types = set([text for (func, text) in data if func(lstat.st_mode)])
749 759 else:
750 760 types = set()
751 761 m = self.mode
752 762 types.update([text for (func, text) in data if func(m)])
753 763 return ", ".join(types)
754 764 type = property(gettype, None, None, "file type (file, directory, link, etc.)")
755 765
756 766 def getmodestr(self):
757 767 m = self.mode
758 768 data = [
759 769 (stat.S_IRUSR, "-r"),
760 770 (stat.S_IWUSR, "-w"),
761 771 (stat.S_IXUSR, "-x"),
762 772 (stat.S_IRGRP, "-r"),
763 773 (stat.S_IWGRP, "-w"),
764 774 (stat.S_IXGRP, "-x"),
765 775 (stat.S_IROTH, "-r"),
766 776 (stat.S_IWOTH, "-w"),
767 777 (stat.S_IXOTH, "-x"),
768 778 ]
769 779 return "".join([text[bool(m&bit)] for (bit, text) in data])
770 780
771 781 modestr = property(getmodestr, None, None, "Access mode as string")
772 782
773 783 def getblocks(self):
774 784 return self.stat().st_blocks
775 785 blocks = property(getblocks, None, None, "File size in blocks")
776 786
777 787 def getblksize(self):
778 788 return self.stat().st_blksize
779 789 blksize = property(getblksize, None, None, "Filesystem block size")
780 790
781 791 def getdev(self):
782 792 return self.stat().st_dev
783 793 dev = property(getdev)
784 794
785 795 def getnlink(self):
786 796 return self.stat().st_nlink
787 797 nlink = property(getnlink, None, None, "Number of links")
788 798
789 799 def getuid(self):
790 800 return self.stat().st_uid
791 801 uid = property(getuid, None, None, "User id of file owner")
792 802
793 803 def getgid(self):
794 804 return self.stat().st_gid
795 805 gid = property(getgid, None, None, "Group id of file owner")
796 806
797 807 def getowner(self):
798 808 stat = self.stat()
799 809 try:
800 810 return pwd.getpwuid(stat.st_uid).pw_name
801 811 except KeyError:
802 812 return stat.st_uid
803 813 owner = property(getowner, None, None, "Owner name (or id)")
804 814
805 815 def getgroup(self):
806 816 stat = self.stat()
807 817 try:
808 818 return grp.getgrgid(stat.st_gid).gr_name
809 819 except KeyError:
810 820 return stat.st_gid
811 821 group = property(getgroup, None, None, "Group name (or id)")
812 822
813 823 def getadate(self):
814 824 return datetime.datetime.utcfromtimestamp(self.atime)
815 825 adate = property(getadate, None, None, "Access date")
816 826
817 827 def getcdate(self):
818 828 return datetime.datetime.utcfromtimestamp(self.ctime)
819 829 cdate = property(getcdate, None, None, "Creation date")
820 830
821 831 def getmdate(self):
822 832 return datetime.datetime.utcfromtimestamp(self.mtime)
823 833 mdate = property(getmdate, None, None, "Modification date")
824 834
825 835 def getmimetype(self):
826 836 return mimetypes.guess_type(self.basename())[0]
827 837 mimetype = property(getmimetype, None, None, "MIME type")
828 838
829 839 def getencoding(self):
830 840 return mimetypes.guess_type(self.basename())[1]
831 841 encoding = property(getencoding, None, None, "Compression")
832 842
833 843 def __repr__(self):
834 844 return "ifile(%s)" % path._base.__repr__(self)
835 845
836 846 defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
837 847
838 848 def __xattrs__(self, mode):
839 849 if mode == "detail":
840 850 return (
841 851 "name", "basename()", "abspath()", "realpath()",
842 852 "type", "mode", "modestr", "stat()", "lstat()",
843 853 "uid", "gid", "owner", "group", "dev", "nlink",
844 854 "ctime", "mtime", "atime", "cdate", "mdate", "adate",
845 855 "size", "blocks", "blksize", "isdir()", "islink()",
846 856 "mimetype", "encoding"
847 857 )
848 858 return self.defaultattrs
849 859
850 860 def __xrepr__(self, mode):
851 861 yield (-1, True)
852 862 try:
853 863 if self.isdir():
854 864 name = "idir"
855 865 style = astyle.style_dir
856 866 else:
857 867 name = "ifile"
858 868 style = astyle.style_file
859 869 except IOError:
860 870 name = "ifile"
861 871 style = astyle.style_default
862 872 if mode == "cell" or mode in "header" or mode == "footer":
863 873 abspath = repr(path._base(self.normpath()))
864 874 if abspath.startswith("u"):
865 875 abspath = abspath[2:-1]
866 876 else:
867 877 abspath = abspath[1:-1]
868 878 if mode == "cell":
869 879 yield (style, abspath)
870 880 else:
871 881 yield (style, "%s(%s)" % (name, abspath))
872 882 else:
873 883 yield (style, repr(self))
874 884
875 885 def __xiter__(self, mode):
876 886 if self.isdir():
877 887 yield iparentdir(self / os.pardir)
878 888 for child in sorted(self.listdir()):
879 889 yield child
880 890 else:
881 891 f = self.open("rb")
882 892 for line in f:
883 893 yield line
884 894 f.close()
885 895
886 896
887 897 class iparentdir(ifile):
888 898 def __xrepr__(self, mode):
889 899 yield (-1, True)
890 900 if mode == "cell":
891 901 yield (astyle.style_dir, os.pardir)
892 902 else:
893 903 for part in ifile.__xrepr__(self, mode):
894 904 yield part
895 905
896 906
897 907 class ils(Table):
898 908 """
899 909 List the current (or a specific) directory.
900 910
901 911 Examples:
902 912
903 913 >>> ils
904 914 >>> ils("/usr/local/lib/python2.4")
905 915 >>> ils("~")
906 916 """
907 917 def __init__(self, base=os.curdir):
908 918 self.base = os.path.expanduser(base)
909 919
910 920 def __xiter__(self, mode):
911 921 return xiter(ifile(self.base), mode)
912 922
913 923 def __xrepr__(self, mode):
914 924 return ifile(self.base).__xrepr__(mode)
915 925
916 926 def __repr__(self):
917 927 return "%s.%s(%r)" % \
918 928 (self.__class__.__module__, self.__class__.__name__, self.base)
919 929
920 930
921 931 class iglob(Table):
922 932 """
923 933 List all files and directories matching a specified pattern.
924 934 (See ``glob.glob()`` for more info.).
925 935
926 936 Examples:
927 937
928 938 >>> iglob("*.py")
929 939 """
930 940 def __init__(self, glob):
931 941 self.glob = glob
932 942
933 943 def __xiter__(self, mode):
934 944 for name in glob.glob(self.glob):
935 945 yield ifile(name)
936 946
937 947 def __xrepr__(self, mode):
938 948 yield (-1, True)
939 949 if mode == "header" or mode == "footer" or mode == "cell":
940 950 yield (astyle.style_default,
941 951 "%s(%r)" % (self.__class__.__name__, self.glob))
942 952 else:
943 953 yield (astyle.style_default, repr(self))
944 954
945 955 def __repr__(self):
946 956 return "%s.%s(%r)" % \
947 957 (self.__class__.__module__, self.__class__.__name__, self.glob)
948 958
949 959
950 960 class iwalk(Table):
951 961 """
952 962 List all files and directories in a directory and it's subdirectory.
953 963
954 964 >>> iwalk
955 965 >>> iwalk("/usr/local/lib/python2.4")
956 966 >>> iwalk("~")
957 967 """
958 968 def __init__(self, base=os.curdir, dirs=True, files=True):
959 969 self.base = os.path.expanduser(base)
960 970 self.dirs = dirs
961 971 self.files = files
962 972
963 973 def __xiter__(self, mode):
964 974 for (dirpath, dirnames, filenames) in os.walk(self.base):
965 975 if self.dirs:
966 976 for name in sorted(dirnames):
967 977 yield ifile(os.path.join(dirpath, name))
968 978 if self.files:
969 979 for name in sorted(filenames):
970 980 yield ifile(os.path.join(dirpath, name))
971 981
972 982 def __xrepr__(self, mode):
973 983 yield (-1, True)
974 984 if mode == "header" or mode == "footer" or mode == "cell":
975 985 yield (astyle.style_default,
976 986 "%s(%r)" % (self.__class__.__name__, self.base))
977 987 else:
978 988 yield (astyle.style_default, repr(self))
979 989
980 990 def __repr__(self):
981 991 return "%s.%s(%r)" % \
982 992 (self.__class__.__module__, self.__class__.__name__, self.base)
983 993
984 994
985 995 class ipwdentry(object):
986 996 """
987 997 ``ipwdentry`` objects encapsulate entries in the Unix user account and
988 998 password database.
989 999 """
990 1000 def __init__(self, id):
991 1001 self._id = id
992 1002 self._entry = None
993 1003
994 1004 def _getentry(self):
995 1005 if self._entry is None:
996 1006 if isinstance(self._id, basestring):
997 1007 self._entry = pwd.getpwnam(self._id)
998 1008 else:
999 1009 self._entry = pwd.getpwuid(self._id)
1000 1010 return self._entry
1001 1011
1002 1012 def getname(self):
1003 1013 if isinstance(self._id, basestring):
1004 1014 return self._id
1005 1015 else:
1006 1016 return self._getentry().pw_name
1007 1017 name = property(getname, None, None, "User name")
1008 1018
1009 1019 def getpasswd(self):
1010 1020 return self._getentry().pw_passwd
1011 1021 passwd = property(getpasswd, None, None, "Password")
1012 1022
1013 1023 def getuid(self):
1014 1024 if isinstance(self._id, basestring):
1015 1025 return self._getentry().pw_uid
1016 1026 else:
1017 1027 return self._id
1018 1028 uid = property(getuid, None, None, "User id")
1019 1029
1020 1030 def getgid(self):
1021 1031 return self._getentry().pw_gid
1022 1032 gid = property(getgid, None, None, "Primary group id")
1023 1033
1024 1034 def getgroup(self):
1025 1035 return igrpentry(self.gid)
1026 1036 group = property(getgroup, None, None, "Group")
1027 1037
1028 1038 def getgecos(self):
1029 1039 return self._getentry().pw_gecos
1030 1040 gecos = property(getgecos, None, None, "Information (e.g. full user name)")
1031 1041
1032 1042 def getdir(self):
1033 1043 return self._getentry().pw_dir
1034 1044 dir = property(getdir, None, None, "$HOME directory")
1035 1045
1036 1046 def getshell(self):
1037 1047 return self._getentry().pw_shell
1038 1048 shell = property(getshell, None, None, "Login shell")
1039 1049
1040 1050 def __xattrs__(self, mode):
1041 1051 return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
1042 1052
1043 1053 def __repr__(self):
1044 1054 return "%s.%s(%r)" % \
1045 1055 (self.__class__.__module__, self.__class__.__name__, self._id)
1046 1056
1047 1057
1048 1058 class ipwd(Table):
1049 1059 """
1050 1060 List all entries in the Unix user account and password database.
1051 1061
1052 1062 Example:
1053 1063
1054 1064 >>> ipwd | isort("uid")
1055 1065 """
1056 1066 def __iter__(self):
1057 1067 for entry in pwd.getpwall():
1058 1068 yield ipwdentry(entry.pw_name)
1059 1069
1060 1070 def __xrepr__(self, mode):
1061 1071 yield (-1, True)
1062 1072 if mode == "header" or mode == "footer" or mode == "cell":
1063 1073 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1064 1074 else:
1065 1075 yield (astyle.style_default, repr(self))
1066 1076
1067 1077
1068 1078 class igrpentry(object):
1069 1079 """
1070 1080 ``igrpentry`` objects encapsulate entries in the Unix group database.
1071 1081 """
1072 1082 def __init__(self, id):
1073 1083 self._id = id
1074 1084 self._entry = None
1075 1085
1076 1086 def _getentry(self):
1077 1087 if self._entry is None:
1078 1088 if isinstance(self._id, basestring):
1079 1089 self._entry = grp.getgrnam(self._id)
1080 1090 else:
1081 1091 self._entry = grp.getgrgid(self._id)
1082 1092 return self._entry
1083 1093
1084 1094 def getname(self):
1085 1095 if isinstance(self._id, basestring):
1086 1096 return self._id
1087 1097 else:
1088 1098 return self._getentry().gr_name
1089 1099 name = property(getname, None, None, "Group name")
1090 1100
1091 1101 def getpasswd(self):
1092 1102 return self._getentry().gr_passwd
1093 1103 passwd = property(getpasswd, None, None, "Password")
1094 1104
1095 1105 def getgid(self):
1096 1106 if isinstance(self._id, basestring):
1097 1107 return self._getentry().gr_gid
1098 1108 else:
1099 1109 return self._id
1100 1110 gid = property(getgid, None, None, "Group id")
1101 1111
1102 1112 def getmem(self):
1103 1113 return self._getentry().gr_mem
1104 1114 mem = property(getmem, None, None, "Members")
1105 1115
1106 1116 def __xattrs__(self, mode):
1107 1117 return ("name", "passwd", "gid", "mem")
1108 1118
1109 1119 def __xrepr__(self, mode):
1110 1120 yield (-1, True)
1111 1121 if mode == "header" or mode == "footer" or mode == "cell":
1112 1122 yield (astyle.style_default, "group ")
1113 1123 try:
1114 1124 yield (astyle.style_default, self.name)
1115 1125 except KeyError:
1116 1126 if isinstance(self._id, basestring):
1117 1127 yield (astyle.style_default, self.name_id)
1118 1128 else:
1119 1129 yield (astyle.style_type_number, str(self._id))
1120 1130 else:
1121 1131 yield (astyle.style_default, repr(self))
1122 1132
1123 1133 def __xiter__(self, mode):
1124 1134 for member in self.mem:
1125 1135 yield ipwdentry(member)
1126 1136
1127 1137 def __repr__(self):
1128 1138 return "%s.%s(%r)" % \
1129 1139 (self.__class__.__module__, self.__class__.__name__, self._id)
1130 1140
1131 1141
1132 1142 class igrp(Table):
1133 1143 """
1134 1144 This ``Table`` lists all entries in the Unix group database.
1135 1145 """
1136 1146 def __xiter__(self, mode):
1137 1147 for entry in grp.getgrall():
1138 1148 yield igrpentry(entry.gr_name)
1139 1149
1140 1150 def __xrepr__(self, mode):
1141 1151 yield (-1, False)
1142 1152 if mode == "header" or mode == "footer":
1143 1153 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1144 1154 else:
1145 1155 yield (astyle.style_default, repr(self))
1146 1156
1147 1157
1148 1158 class Fields(object):
1149 1159 def __init__(self, fieldnames, **fields):
1150 1160 self.__fieldnames = fieldnames
1151 1161 for (key, value) in fields.iteritems():
1152 1162 setattr(self, key, value)
1153 1163
1154 1164 def __xattrs__(self, mode):
1155 1165 return self.__fieldnames
1156 1166
1157 1167 def __xrepr__(self, mode):
1158 1168 yield (-1, False)
1159 1169 if mode == "header" or mode == "cell":
1160 1170 yield (astyle.style_default, self.__class__.__name__)
1161 1171 yield (astyle.style_default, "(")
1162 1172 for (i, f) in enumerate(self.__fieldnames):
1163 1173 if i:
1164 1174 yield (astyle.style_default, ", ")
1165 1175 yield (astyle.style_default, f)
1166 1176 yield (astyle.style_default, "=")
1167 1177 for part in xrepr(getattr(self, f), "default"):
1168 1178 yield part
1169 1179 yield (astyle.style_default, ")")
1170 1180 elif mode == "footer":
1171 1181 yield (astyle.style_default, self.__class__.__name__)
1172 1182 yield (astyle.style_default, "(")
1173 1183 for (i, f) in enumerate(self.__fieldnames):
1174 1184 if i:
1175 1185 yield (astyle.style_default, ", ")
1176 1186 yield (astyle.style_default, f)
1177 1187 yield (astyle.style_default, ")")
1178 1188 else:
1179 1189 yield (astyle.style_default, repr(self))
1180 1190
1181 1191
1182 1192 class FieldTable(Table, list):
1183 1193 def __init__(self, *fields):
1184 1194 Table.__init__(self)
1185 1195 list.__init__(self)
1186 1196 self.fields = fields
1187 1197
1188 1198 def add(self, **fields):
1189 1199 self.append(Fields(self.fields, **fields))
1190 1200
1191 1201 def __xiter__(self, mode):
1192 1202 return list.__iter__(self)
1193 1203
1194 1204 def __xrepr__(self, mode):
1195 1205 yield (-1, False)
1196 1206 if mode == "header" or mode == "footer":
1197 1207 yield (astyle.style_default, self.__class__.__name__)
1198 1208 yield (astyle.style_default, "(")
1199 1209 for (i, f) in enumerate(self.__fieldnames):
1200 1210 if i:
1201 1211 yield (astyle.style_default, ", ")
1202 1212 yield (astyle.style_default, f)
1203 1213 yield (astyle.style_default, ")")
1204 1214 else:
1205 1215 yield (astyle.style_default, repr(self))
1206 1216
1207 1217 def __repr__(self):
1208 1218 return "<%s.%s object with fields=%r at 0x%x>" % \
1209 1219 (self.__class__.__module__, self.__class__.__name__,
1210 1220 ", ".join(map(repr, self.fields)), id(self))
1211 1221
1212 1222
1213 1223 class List(list):
1214 1224 def __xattrs__(self, mode):
1215 1225 return xrange(len(self))
1216 1226
1217 1227 def __xrepr__(self, mode):
1218 1228 yield (-1, False)
1219 1229 if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
1220 1230 yield (astyle.style_default, self.__class__.__name__)
1221 1231 yield (astyle.style_default, "(")
1222 1232 for (i, item) in enumerate(self):
1223 1233 if i:
1224 1234 yield (astyle.style_default, ", ")
1225 1235 for part in xrepr(item, "default"):
1226 1236 yield part
1227 1237 yield (astyle.style_default, ")")
1228 1238 else:
1229 1239 yield (astyle.style_default, repr(self))
1230 1240
1231 1241
1232 1242 class ienv(Table):
1233 1243 """
1234 1244 List environment variables.
1235 1245
1236 1246 Example:
1237 1247
1238 1248 >>> ienv
1239 1249 """
1240 1250
1241 1251 def __xiter__(self, mode):
1242 1252 fields = ("key", "value")
1243 1253 for (key, value) in os.environ.iteritems():
1244 1254 yield Fields(fields, key=key, value=value)
1245 1255
1246 1256 def __xrepr__(self, mode):
1247 1257 yield (-1, True)
1248 1258 if mode == "header" or mode == "cell":
1249 1259 yield (astyle.style_default, "%s()" % self.__class__.__name__)
1250 1260 else:
1251 1261 yield (astyle.style_default, repr(self))
1252 1262
1253 1263
1254 1264 class icsv(Pipe):
1255 1265 """
1256 1266 This ``Pipe`` lists turn the input (with must be a pipe outputting lines
1257 1267 or an ``ifile``) into lines of CVS columns.
1258 1268 """
1259 1269 def __init__(self, **csvargs):
1260 1270 """
1261 1271 Create an ``icsv`` object. ``cvsargs`` will be passed through as
1262 1272 keyword arguments to ``cvs.reader()``.
1263 1273 """
1264 1274 self.csvargs = csvargs
1265 1275
1266 1276 def __xiter__(self, mode):
1267 1277 input = self.input
1268 1278 if isinstance(input, ifile):
1269 1279 input = input.open("rb")
1270 1280 reader = csv.reader(input, **self.csvargs)
1271 1281 for line in reader:
1272 1282 yield List(line)
1273 1283
1274 1284 def __xrepr__(self, mode):
1275 1285 yield (-1, False)
1276 1286 if mode == "header" or mode == "footer":
1277 1287 input = getattr(self, "input", None)
1278 1288 if input is not None:
1279 1289 for part in xrepr(input, mode):
1280 1290 yield part
1281 1291 yield (astyle.style_default, " | ")
1282 1292 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1283 1293 for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
1284 1294 if i:
1285 1295 yield (astyle.style_default, ", ")
1286 1296 yield (astyle.style_default, name)
1287 1297 yield (astyle.style_default, "=")
1288 1298 for part in xrepr(value, "default"):
1289 1299 yield part
1290 1300 yield (astyle.style_default, ")")
1291 1301 else:
1292 1302 yield (astyle.style_default, repr(self))
1293 1303
1294 1304 def __repr__(self):
1295 1305 args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
1296 1306 return "<%s.%s %s at 0x%x>" % \
1297 1307 (self.__class__.__module__, self.__class__.__name__, args, id(self))
1298 1308
1299 1309
1300 1310 class ix(Table):
1301 1311 """
1302 1312 Execute a system command and list its output as lines
1303 1313 (similar to ``os.popen()``).
1304 1314
1305 1315 Examples:
1306 1316
1307 1317 >>> ix("ps x")
1308 1318 >>> ix("find .") | ifile
1309 1319 """
1310 1320 def __init__(self, cmd):
1311 1321 self.cmd = cmd
1312 1322 self._pipe = None
1313 1323
1314 1324 def __xiter__(self, mode):
1315 1325 self._pipe = os.popen(self.cmd)
1316 1326 for l in self._pipe:
1317 1327 yield l.rstrip("\r\n")
1318 1328 self._pipe.close()
1319 1329 self._pipe = None
1320 1330
1321 1331 def __del__(self):
1322 1332 if self._pipe is not None and not self._pipe.closed:
1323 1333 self._pipe.close()
1324 1334 self._pipe = None
1325 1335
1326 1336 def __xrepr__(self, mode):
1327 1337 yield (-1, True)
1328 1338 if mode == "header" or mode == "footer":
1329 1339 yield (astyle.style_default,
1330 1340 "%s(%r)" % (self.__class__.__name__, self.cmd))
1331 1341 else:
1332 1342 yield (astyle.style_default, repr(self))
1333 1343
1334 1344 def __repr__(self):
1335 1345 return "%s.%s(%r)" % \
1336 1346 (self.__class__.__module__, self.__class__.__name__, self.cmd)
1337 1347
1338 1348
1339 1349 class ifilter(Pipe):
1340 1350 """
1341 1351 Filter an input pipe. Only objects where an expression evaluates to true
1342 1352 (and doesn't raise an exception) are listed.
1343 1353
1344 1354 Examples:
1345 1355
1346 1356 >>> ils | ifilter("_.isfile() and size>1000")
1347 1357 >>> igrp | ifilter("len(mem)")
1348 1358 >>> sys.modules | ifilter(lambda _:_.value is not None)
1349 1359 """
1350 1360
1351 def __init__(self, expr, errors="raiseifallfail"):
1361 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1352 1362 """
1353 1363 Create an ``ifilter`` object. ``expr`` can be a callable or a string
1354 containing an expression. ``errors`` specifies how exception during
1355 evaluation of ``expr`` are handled:
1364 containing an expression. ``globals`` will be used as the global
1365 namespace for calling string expressions (defaulting to IPython's
1366 user namespace). ``errors`` specifies how exception during evaluation
1367 of ``expr`` are handled:
1356 1368
1357 1369 * ``drop``: drop all items that have errors;
1358 1370
1359 1371 * ``keep``: keep all items that have errors;
1360 1372
1361 1373 * ``keeperror``: keep the exception of all items that have errors;
1362 1374
1363 1375 * ``raise``: raise the exception;
1364 1376
1365 1377 * ``raiseifallfail``: raise the first exception if all items have errors;
1366 1378 otherwise drop those with errors (this is the default).
1367 1379 """
1368 1380 self.expr = expr
1381 self.globals = globals
1369 1382 self.errors = errors
1370 1383
1371 1384 def __xiter__(self, mode):
1372 1385 if callable(self.expr):
1373 1386 def test(item):
1374 1387 return self.expr(item)
1375 1388 else:
1389 g = getglobals(self.globals)
1376 1390 def test(item):
1377 return eval(self.expr, globals(), AttrNamespace(item))
1391 return eval(self.expr, g, AttrNamespace(item))
1378 1392
1379 1393 ok = 0
1380 1394 exc_info = None
1381 1395 for item in xiter(self.input, mode):
1382 1396 try:
1383 1397 if test(item):
1384 1398 yield item
1385 1399 ok += 1
1386 1400 except (KeyboardInterrupt, SystemExit):
1387 1401 raise
1388 1402 except Exception, exc:
1389 1403 if self.errors == "drop":
1390 1404 pass # Ignore errors
1391 1405 elif self.errors == "keep":
1392 1406 yield item
1393 1407 elif self.errors == "keeperror":
1394 1408 yield exc
1395 1409 elif self.errors == "raise":
1396 1410 raise
1397 1411 elif self.errors == "raiseifallfail":
1398 1412 if exc_info is None:
1399 1413 exc_info = sys.exc_info()
1400 1414 if not ok and exc_info is not None:
1401 1415 raise exc_info[0], exc_info[1], exc_info[2]
1402 1416
1403 1417 def __xrepr__(self, mode):
1404 1418 yield (-1, True)
1405 1419 if mode == "header" or mode == "footer":
1406 1420 input = getattr(self, "input", None)
1407 1421 if input is not None:
1408 1422 for part in xrepr(input, mode):
1409 1423 yield part
1410 1424 yield (astyle.style_default, " | ")
1411 1425 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1412 1426 for part in xrepr(self.expr, "default"):
1413 1427 yield part
1414 1428 yield (astyle.style_default, ")")
1415 1429 else:
1416 1430 yield (astyle.style_default, repr(self))
1417 1431
1418 1432 def __repr__(self):
1419 1433 return "<%s.%s expr=%r at 0x%x>" % \
1420 1434 (self.__class__.__module__, self.__class__.__name__,
1421 1435 self.expr, id(self))
1422 1436
1423 1437
1424 1438 class ieval(Pipe):
1425 1439 """
1426 1440 Evaluate an expression for each object in the input pipe.
1427 1441
1428 1442 Examples:
1429 1443
1430 1444 >>> ils | ieval("_.abspath()")
1431 1445 >>> sys.path | ieval(ifile)
1432 1446 """
1433 1447
1434 def __init__(self, expr, errors="raiseifallfail"):
1448 def __init__(self, expr, globals=None, errors="raiseifallfail"):
1435 1449 """
1436 1450 Create an ``ieval`` object. ``expr`` can be a callable or a string
1437 containing an expression. For the meaning of ``errors`` see ``ifilter``.
1451 containing an expression. For the meaning of ``globals`` and
1452 ``errors`` see ``ifilter``.
1438 1453 """
1439 1454 self.expr = expr
1455 self.globals = globals
1440 1456 self.errors = errors
1441 1457
1442 1458 def __xiter__(self, mode):
1443 1459 if callable(self.expr):
1444 1460 def do(item):
1445 1461 return self.expr(item)
1446 1462 else:
1463 g = getglobals(self.globals)
1447 1464 def do(item):
1448 return eval(self.expr, globals(), AttrNamespace(item))
1465 return eval(self.expr, g, AttrNamespace(item))
1449 1466
1450 1467 ok = 0
1451 1468 exc_info = None
1452 1469 for item in xiter(self.input, mode):
1453 1470 try:
1454 1471 yield do(item)
1455 1472 except (KeyboardInterrupt, SystemExit):
1456 1473 raise
1457 1474 except Exception, exc:
1458 1475 if self.errors == "drop":
1459 1476 pass # Ignore errors
1460 1477 elif self.errors == "keep":
1461 1478 yield item
1462 1479 elif self.errors == "keeperror":
1463 1480 yield exc
1464 1481 elif self.errors == "raise":
1465 1482 raise
1466 1483 elif self.errors == "raiseifallfail":
1467 1484 if exc_info is None:
1468 1485 exc_info = sys.exc_info()
1469 1486 if not ok and exc_info is not None:
1470 1487 raise exc_info[0], exc_info[1], exc_info[2]
1471 1488
1472 1489 def __xrepr__(self, mode):
1473 1490 yield (-1, True)
1474 1491 if mode == "header" or mode == "footer":
1475 1492 input = getattr(self, "input", None)
1476 1493 if input is not None:
1477 1494 for part in xrepr(input, mode):
1478 1495 yield part
1479 1496 yield (astyle.style_default, " | ")
1480 1497 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1481 1498 for part in xrepr(self.expr, "default"):
1482 1499 yield part
1483 1500 yield (astyle.style_default, ")")
1484 1501 else:
1485 1502 yield (astyle.style_default, repr(self))
1486 1503
1487 1504 def __repr__(self):
1488 1505 return "<%s.%s expr=%r at 0x%x>" % \
1489 1506 (self.__class__.__module__, self.__class__.__name__,
1490 1507 self.expr, id(self))
1491 1508
1492 1509
1493 1510 class ienum(Pipe):
1494 1511 """
1495 1512 Enumerate the input pipe (i.e. wrap each input object in an object
1496 1513 with ``index`` and ``object`` attributes).
1497 1514
1498 1515 Examples:
1499 1516
1500 1517 >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
1501 1518 """
1502 1519 def __xiter__(self, mode):
1503 1520 fields = ("index", "object")
1504 1521 for (index, object) in enumerate(xiter(self.input, mode)):
1505 1522 yield Fields(fields, index=index, object=object)
1506 1523
1507 1524
1508 1525 class isort(Pipe):
1509 1526 """
1510 1527 Sorts the input pipe.
1511 1528
1512 1529 Examples:
1513 1530
1514 1531 >>> ils | isort("size")
1515 1532 >>> ils | isort("_.isdir(), _.lower()", reverse=True)
1516 1533 """
1517 1534
1518 def __init__(self, key, reverse=False):
1535 def __init__(self, key, globals=None, reverse=False):
1519 1536 """
1520 1537 Create an ``isort`` object. ``key`` can be a callable or a string
1521 1538 containing an expression. If ``reverse`` is true the sort order will
1522 be reversed.
1539 be reversed. For the meaning of ``globals`` see ``ifilter``.
1523 1540 """
1524 1541 self.key = key
1542 self.globals = globals
1525 1543 self.reverse = reverse
1526 1544
1527 1545 def __xiter__(self, mode):
1528 1546 if callable(self.key):
1529 1547 items = sorted(
1530 1548 xiter(self.input, mode),
1531 1549 key=self.key,
1532 1550 reverse=self.reverse
1533 1551 )
1534 1552 else:
1553 g = getglobals(self.globals)
1535 1554 def key(item):
1536 return eval(self.key, globals(), AttrNamespace(item))
1555 return eval(self.key, g, AttrNamespace(item))
1537 1556 items = sorted(
1538 1557 xiter(self.input, mode),
1539 1558 key=key,
1540 1559 reverse=self.reverse
1541 1560 )
1542 1561 for item in items:
1543 1562 yield item
1544 1563
1545 1564 def __xrepr__(self, mode):
1546 1565 yield (-1, True)
1547 1566 if mode == "header" or mode == "footer":
1548 1567 input = getattr(self, "input", None)
1549 1568 if input is not None:
1550 1569 for part in xrepr(input, mode):
1551 1570 yield part
1552 1571 yield (astyle.style_default, " | ")
1553 1572 yield (astyle.style_default, "%s(" % self.__class__.__name__)
1554 1573 for part in xrepr(self.key, "default"):
1555 1574 yield part
1556 1575 if self.reverse:
1557 1576 yield (astyle.style_default, ", ")
1558 1577 for part in xrepr(True, "default"):
1559 1578 yield part
1560 1579 yield (astyle.style_default, ")")
1561 1580 else:
1562 1581 yield (astyle.style_default, repr(self))
1563 1582
1564 1583 def __repr__(self):
1565 1584 return "<%s.%s key=%r reverse=%r at 0x%x>" % \
1566 1585 (self.__class__.__module__, self.__class__.__name__,
1567 1586 self.key, self.reverse, id(self))
1568 1587
1569 1588
1570 1589 tab = 3 # for expandtabs()
1571 1590
1572 1591 def _format(field):
1573 1592 if isinstance(field, str):
1574 1593 text = repr(field.expandtabs(tab))[1:-1]
1575 1594 elif isinstance(field, unicode):
1576 1595 text = repr(field.expandtabs(tab))[2:-1]
1577 1596 elif isinstance(field, datetime.datetime):
1578 1597 # Don't use strftime() here, as this requires year >= 1900
1579 1598 text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
1580 1599 (field.year, field.month, field.day,
1581 1600 field.hour, field.minute, field.second, field.microsecond)
1582 1601 elif isinstance(field, datetime.date):
1583 1602 text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
1584 1603 else:
1585 1604 text = repr(field)
1586 1605 return text
1587 1606
1588 1607
1589 1608 class Display(object):
1590 1609 class __metaclass__(type):
1591 1610 def __ror__(self, input):
1592 1611 return input | self()
1593 1612
1594 1613 def __ror__(self, input):
1595 1614 self.input = input
1596 1615 return self
1597 1616
1598 1617 def display(self):
1599 1618 pass
1600 1619
1601 1620
1602 1621 class iless(Display):
1603 1622 cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
1604 1623
1605 1624 def display(self):
1606 1625 try:
1607 1626 pager = os.popen(self.cmd, "w")
1608 1627 try:
1609 1628 for item in xiter(self.input, "default"):
1610 1629 attrs = xattrs(item, "default")
1611 1630 attrs = ["%s=%s" % (a, _format(_getattr(item, a))) for a in attrs]
1612 1631 pager.write(" ".join(attrs))
1613 1632 pager.write("\n")
1614 1633 finally:
1615 1634 pager.close()
1616 1635 except Exception, exc:
1617 1636 print "%s: %s" % (exc.__class__.__name__, str(exc))
1618 1637
1619 1638
1620 1639 def xformat(value, mode, maxlength):
1621 1640 align = None
1622 1641 full = False
1623 1642 width = 0
1624 1643 text = astyle.Text()
1625 1644 for part in xrepr(value, mode):
1626 1645 # part is (alignment, stop)
1627 1646 if isinstance(part[0], int):
1628 1647 # only consider the first occurence
1629 1648 if align is None:
1630 1649 align = part[0]
1631 1650 full = part[1]
1632 1651 # part is (style, text)
1633 1652 else:
1634 1653 text.append(part)
1635 1654 width += len(part[1])
1636 1655 if width >= maxlength and not full:
1637 1656 text.append((astyle.style_ellisis, "..."))
1638 1657 width += 3
1639 1658 break
1640 1659 if align is None: # default to left alignment
1641 1660 align = -1
1642 1661 return (align, width, text)
1643 1662
1644 1663
1645 1664 class idump(Display):
1646 1665 # The approximate maximum length of a column entry
1647 1666 maxattrlength = 200
1648 1667
1649 1668 # Style for column names
1650 1669 style_header = astyle.Style.fromstr("white:black:bold")
1651 1670
1652 1671 def __init__(self, *attrs):
1653 1672 self.attrs = attrs
1654 1673 self.headerpadchar = " "
1655 1674 self.headersepchar = "|"
1656 1675 self.datapadchar = " "
1657 1676 self.datasepchar = "|"
1658 1677
1659 1678 def display(self):
1660 1679 stream = genutils.Term.cout
1661 1680 allattrs = []
1662 1681 allattrset = set()
1663 1682 colwidths = {}
1664 1683 rows = []
1665 1684 for item in xiter(self.input, "default"):
1666 1685 row = {}
1667 1686 attrs = self.attrs
1668 1687 if not attrs:
1669 1688 attrs = xattrs(item, "default")
1670 1689 for attrname in attrs:
1671 1690 if attrname not in allattrset:
1672 1691 allattrs.append(attrname)
1673 1692 allattrset.add(attrname)
1674 1693 colwidths[attrname] = len(_attrname(attrname))
1675 1694 try:
1676 1695 value = _getattr(item, attrname, None)
1677 1696 except (KeyboardInterrupt, SystemExit):
1678 1697 raise
1679 1698 except Exception, exc:
1680 1699 value = exc
1681 1700 (align, width, text) = xformat(value, "cell", self.maxattrlength)
1682 1701 colwidths[attrname] = max(colwidths[attrname], width)
1683 1702 # remember alignment, length and colored parts
1684 1703 row[attrname] = (align, width, text)
1685 1704 rows.append(row)
1686 1705
1687 1706 stream.write("\n")
1688 1707 for (i, attrname) in enumerate(allattrs):
1689 1708 self.style_header(_attrname(attrname)).write(stream)
1690 1709 spc = colwidths[attrname] - len(_attrname(attrname))
1691 1710 if i < len(colwidths)-1:
1692 1711 stream.write(self.headerpadchar*spc)
1693 1712 stream.write(self.headersepchar)
1694 1713 stream.write("\n")
1695 1714
1696 1715 for row in rows:
1697 1716 for (i, attrname) in enumerate(allattrs):
1698 1717 (align, width, text) = row[attrname]
1699 1718 spc = colwidths[attrname] - width
1700 1719 if align == -1:
1701 1720 text.write(stream)
1702 1721 if i < len(colwidths)-1:
1703 1722 stream.write(self.datapadchar*spc)
1704 1723 elif align == 0:
1705 1724 spc = colwidths[attrname] - width
1706 1725 spc1 = spc//2
1707 1726 spc2 = spc-spc1
1708 1727 stream.write(self.datapadchar*spc1)
1709 1728 text.write(stream)
1710 1729 if i < len(colwidths)-1:
1711 1730 stream.write(self.datapadchar*spc2)
1712 1731 else:
1713 1732 stream.write(self.datapadchar*spc)
1714 1733 text.write(stream)
1715 1734 if i < len(colwidths)-1:
1716 1735 stream.write(self.datasepchar)
1717 1736 stream.write("\n")
1718 1737
1719 1738
1720 1739 class XMode(object):
1721 1740 """
1722 1741 An ``XMode`` object describes one enter mode available for an object
1723 1742 """
1724 1743 def __init__(self, object, mode, title=None, description=None):
1725 1744 """
1726 1745 Create a new ``XMode`` object for the object ``object``. This object
1727 1746 must support the enter mode ``mode`` (i.e. ``object.__xiter__(mode)``
1728 1747 must return an iterable). ``title`` and ``description`` will be
1729 1748 displayed in the browser when selecting among the available modes.
1730 1749 """
1731 1750 self.object = object
1732 1751 self.mode = mode
1733 1752 self.title = title
1734 1753 self.description = description
1735 1754
1736 1755 def __repr__(self):
1737 1756 return "<%s.%s object mode=%r at 0x%x>" % \
1738 1757 (self.__class__.__module__, self.__class__.__name__,
1739 1758 self.mode, id(self))
1740 1759
1741 1760 def __xrepr__(self, mode):
1742 1761 yield (-1, True)
1743 1762 if mode == "header" or mode == "footer":
1744 1763 yield (astyle.style_default, self.title)
1745 1764 else:
1746 1765 yield (astyle.style_default, repr(self))
1747 1766
1748 1767 def __xattrs__(self, mode):
1749 1768 if mode == "detail":
1750 1769 return ("object", "mode", "title", "description")
1751 1770 return ("title", "description")
1752 1771
1753 1772 def __xiter__(self, mode):
1754 1773 return xiter(self.object, self.mode)
1755 1774
1756 1775
1757 1776 class XAttr(object):
1758 1777 def __init__(self, object, name):
1759 1778 self.name = _attrname(name)
1760 1779
1761 1780 try:
1762 1781 self.value = _getattr(object, name)
1763 1782 except (KeyboardInterrupt, SystemExit):
1764 1783 raise
1765 1784 except Exception, exc:
1766 1785 if exc.__class__.__module__ == "exceptions":
1767 1786 self.value = exc.__class__.__name__
1768 1787 else:
1769 1788 self.value = "%s.%s" % \
1770 1789 (exc.__class__.__module__, exc.__class__.__name__)
1771 1790 self.type = self.value
1772 1791 else:
1773 1792 t = type(self.value)
1774 1793 if t.__module__ == "__builtin__":
1775 1794 self.type = t.__name__
1776 1795 else:
1777 1796 self.type = "%s.%s" % (t.__module__, t.__name__)
1778 1797
1779 1798 doc = None
1780 1799 if isinstance(name, basestring):
1781 1800 if name.endswith("()"):
1782 1801 doc = getattr(getattr(object, name[:-2]), "__doc__", None)
1783 1802 else:
1784 1803 try:
1785 1804 meta = getattr(type(object), name)
1786 1805 except AttributeError:
1787 1806 pass
1788 1807 else:
1789 1808 if isinstance(meta, property):
1790 1809 doc = getattr(meta, "__doc__", None)
1791 1810 elif callable(name):
1792 1811 doc = getattr(name, "__doc__", None)
1793 1812 if isinstance(doc, basestring):
1794 1813 doc = doc.strip()
1795 1814 self.doc = doc
1796 1815
1797 1816 def __xattrs__(self, mode):
1798 1817 return ("name", "type", "doc", "value")
1799 1818
1800 1819
1801 1820 try:
1802 1821 from ibrowse import ibrowse
1803 1822 except ImportError:
1804 1823 # No curses (probably Windows) => use ``idump`` as the default display.
1805 1824 defaultdisplay = idump
1806 1825 else:
1807 1826 defaultdisplay = ibrowse
1808 1827 __all__.append("ibrowse")
1809 1828
1810 1829
1811 1830 # If we're running under IPython, install an IPython displayhook that
1812 1831 # returns the object from Display.display(), else install a displayhook
1813 1832 # directly as sys.displayhook
1814 try:
1815 from IPython import ipapi
1816 api = ipapi.get()
1817 except (ImportError, AttributeError):
1818 api = None
1833 api = None
1834 if ipapi is not None:
1835 try:
1836 api = ipapi.get()
1837 except AttributeError:
1838 pass
1819 1839
1820 1840 if api is not None:
1821 1841 def displayhook(self, obj):
1822 1842 if isinstance(obj, type) and issubclass(obj, Table):
1823 1843 obj = obj()
1824 1844 if isinstance(obj, Table):
1825 1845 obj = obj | defaultdisplay
1826 1846 if isinstance(obj, Display):
1827 1847 return obj.display()
1828 1848 else:
1829 1849 raise ipapi.TryNext
1830 1850 api.set_hook("result_display", displayhook)
1831 1851 else:
1832 1852 def installdisplayhook():
1833 1853 _originalhook = sys.displayhook
1834 1854 def displayhook(obj):
1835 1855 if isinstance(obj, type) and issubclass(obj, Table):
1836 1856 obj = obj()
1837 1857 if isinstance(obj, Table):
1838 1858 obj = obj | defaultdisplay
1839 1859 if isinstance(obj, Display):
1840 1860 return obj.display()
1841 1861 else:
1842 1862 _originalhook(obj)
1843 1863 sys.displayhook = displayhook
1844 1864 installdisplayhook()
General Comments 0
You need to be logged in to leave comments. Login now