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