##// END OF EJS Templates
Make isort usable without a key argument....
walter.doerwald -
Show More

The requested changes are too big and content was truncated. Show full diff

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