ipipe.py
2153 lines
| 65.6 KiB
| text/x-python
|
PythonLexer
vivainio
|
r208 | # -*- coding: iso-8859-1 -*- | ||
""" | ||||
``ipipe`` provides classes to be used in an interactive Python session. Doing a | ||||
``from ipipe import *`` is the preferred way to do this. The name of all | ||||
objects imported this way starts with ``i`` to minimize collisions. | ||||
``ipipe`` supports "pipeline expressions", which is something resembling Unix | ||||
pipes. An example is: | ||||
vivainio
|
r225 | >>> ienv | isort("key.lower()") | ||
vivainio
|
r214 | |||
This gives a listing of all environment variables sorted by name. | ||||
vivainio
|
r208 | |||
There are three types of objects in a pipeline expression: | ||||
walter.doerwald
|
r415 | * ``Table``s: These objects produce items. Examples are ``ils`` (listing the | ||
vivainio
|
r208 | current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing | ||
walter.doerwald
|
r415 | user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the | ||
vivainio
|
r209 | first object in a pipe expression. | ||
vivainio
|
r208 | |||
vivainio
|
r209 | * ``Pipe``s: These objects sit in the middle of a pipe expression. They | ||
transform the input in some way (e.g. filtering or sorting it). Examples are: | ||||
``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input | ||||
pipe) and ``ieval`` (which evaluates a function or expression for each object | ||||
in the input pipe). | ||||
vivainio
|
r208 | |||
* ``Display``s: These objects can be put as the last object in a pipeline | ||||
expression. There are responsible for displaying the result of the pipeline | ||||
expression. If a pipeline expression doesn't end in a display object a default | ||||
walter.doerwald
|
r415 | display objects will be used. One example is ``ibrowse`` which is a ``curses`` | ||
vivainio
|
r208 | based browser. | ||
vivainio
|
r214 | |||
Adding support for pipeline expressions to your own objects can be done through | ||||
three extensions points (all of them optional): | ||||
* An object that will be displayed as a row by a ``Display`` object should | ||||
walter.doerwald
|
r415 | implement the method ``__xattrs__(self, mode)`` method or register an | ||
implementation of the generic function ``xattrs``. For more info see ``xattrs``. | ||||
* When an object ``foo`` is displayed by a ``Display`` object, the generic | ||||
function ``xrepr`` is used. | ||||
* Objects that can be iterated by ``Pipe``s must iterable. For special cases, | ||||
where iteration for display is different than the normal iteration a special | ||||
implementation can be registered with the generic function ``xiter``. This makes | ||||
it possible to use dictionaries and modules in pipeline expressions, for example: | ||||
vivainio
|
r214 | |||
>>> import sys | ||||
vivainio
|
r225 | >>> sys | ifilter("isinstance(value, int)") | idump | ||
vivainio
|
r214 | key |value | ||
api_version| 1012 | ||||
dllhandle | 503316480 | ||||
hexversion | 33817328 | ||||
maxint |2147483647 | ||||
maxunicode | 65535 | ||||
>>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()") | ||||
... | ||||
Note: The expression strings passed to ``ifilter()`` and ``isort()`` can | ||||
vivainio
|
r225 | refer to the object to be filtered or sorted via the variable ``_`` and to any | ||
of the attributes of the object, i.e.: | ||||
vivainio
|
r214 | |||
>>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()") | ||||
vivainio
|
r225 | does the same as | ||
vivainio
|
r214 | |||
>>> sys.modules | ifilter("value is not None") | isort("key.lower()") | ||||
In addition to expression strings, it's possible to pass callables (taking | ||||
the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``: | ||||
>>> sys | ifilter(lambda _:isinstance(_.value, int)) \ | ||||
... | ieval(lambda _: (_.key, hex(_.value))) | idump | ||||
0 |1 | ||||
api_version|0x3f4 | ||||
dllhandle |0x1e000000 | ||||
hexversion |0x20402f0 | ||||
maxint |0x7fffffff | ||||
maxunicode |0xffff | ||||
vivainio
|
r208 | """ | ||
vivainio
|
r225 | import sys, os, os.path, stat, glob, new, csv, datetime, types | ||
walter.doerwald
|
r278 | import itertools, mimetypes | ||
vivainio
|
r208 | |||
try: # Python 2.3 compatibility | ||||
import collections | ||||
except ImportError: | ||||
deque = list | ||||
else: | ||||
deque = collections.deque | ||||
try: # Python 2.3 compatibility | ||||
set | ||||
except NameError: | ||||
import sets | ||||
set = sets.Set | ||||
try: # Python 2.3 compatibility | ||||
sorted | ||||
except NameError: | ||||
def sorted(iterator, key=None, reverse=False): | ||||
items = list(iterator) | ||||
if key is not None: | ||||
items.sort(lambda i1, i2: cmp(key(i1), key(i2))) | ||||
else: | ||||
items.sort() | ||||
if reverse: | ||||
items.reverse() | ||||
return items | ||||
try: | ||||
import pwd | ||||
except ImportError: | ||||
pwd = None | ||||
try: | ||||
import grp | ||||
except ImportError: | ||||
grp = None | ||||
walter.doerwald
|
r415 | from IPython.external import simplegeneric | ||
vivainio
|
r237 | import path | ||
vivainio
|
r247 | try: | ||
walter.doerwald
|
r276 | from IPython import genutils, ipapi | ||
vivainio
|
r247 | except ImportError: | ||
walter.doerwald
|
r276 | genutils = None | ||
ipapi = None | ||||
vivainio
|
r237 | |||
walter.doerwald
|
r269 | import astyle | ||
vivainio
|
r208 | |||
__all__ = [ | ||||
"ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp", | ||||
vivainio
|
r209 | "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum", "ienv", | ||
vivainio
|
r208 | "idump", "iless" | ||
] | ||||
os.stat_float_times(True) # enable microseconds | ||||
walter.doerwald
|
r272 | class AttrNamespace(object): | ||
vivainio
|
r214 | """ | ||
walter.doerwald
|
r272 | Helper class that is used for providing a namespace for evaluating | ||
expressions containing attribute names of an object. | ||||
vivainio
|
r214 | """ | ||
def __init__(self, wrapped): | ||||
self.wrapped = wrapped | ||||
def __getitem__(self, name): | ||||
if name == "_": | ||||
return self.wrapped | ||||
try: | ||||
return getattr(self.wrapped, name) | ||||
except AttributeError: | ||||
raise KeyError(name) | ||||
# Python 2.3 compatibility | ||||
vivainio
|
r225 | # use eval workaround to find out which names are used in the | ||
# eval string and put them into the locals. This works for most | ||||
# normal uses case, bizarre ones like accessing the locals() | ||||
# will fail | ||||
vivainio
|
r214 | try: | ||
walter.doerwald
|
r272 | eval("_", None, AttrNamespace(None)) | ||
vivainio
|
r214 | except TypeError: | ||
vivainio
|
r225 | real_eval = eval | ||
def eval(codestring, _globals, _locals): | ||||
""" | ||||
eval(source[, globals[, locals]]) -> value | ||||
Evaluate the source in the context of globals and locals. | ||||
The source may be a string representing a Python expression | ||||
or a code object as returned by compile(). | ||||
The globals must be a dictionary and locals can be any mappping. | ||||
This function is a workaround for the shortcomings of | ||||
Python 2.3's eval. | ||||
""" | ||||
walter.doerwald
|
r349 | if isinstance(codestring, basestring): | ||
code = compile(codestring, "_eval", "eval") | ||||
else: | ||||
code = codestring | ||||
vivainio
|
r225 | newlocals = {} | ||
for name in code.co_names: | ||||
try: | ||||
newlocals[name] = _locals[name] | ||||
except KeyError: | ||||
pass | ||||
return real_eval(code, _globals, newlocals) | ||||
vivainio
|
r214 | |||
walter.doerwald
|
r274 | noitem = object() | ||
vivainio
|
r208 | |||
walter.doerwald
|
r519 | |||
walter.doerwald
|
r274 | def item(iterator, index, default=noitem): | ||
vivainio
|
r208 | """ | ||
Return the ``index``th item from the iterator ``iterator``. | ||||
``index`` must be an integer (negative integers are relative to the | ||||
walter.doerwald
|
r415 | end (i.e. the last items produced by the iterator)). | ||
vivainio
|
r208 | |||
If ``default`` is given, this will be the default value when | ||||
the iterator doesn't contain an item at this position. Otherwise an | ||||
``IndexError`` will be raised. | ||||
Note that using this function will partially or totally exhaust the | ||||
iterator. | ||||
""" | ||||
i = index | ||||
if i>=0: | ||||
for item in iterator: | ||||
if not i: | ||||
return item | ||||
i -= 1 | ||||
else: | ||||
i = -index | ||||
cache = deque() | ||||
for item in iterator: | ||||
cache.append(item) | ||||
if len(cache)>i: | ||||
cache.popleft() | ||||
if len(cache)==i: | ||||
return cache.popleft() | ||||
walter.doerwald
|
r274 | if default is noitem: | ||
vivainio
|
r208 | raise IndexError(index) | ||
else: | ||||
return default | ||||
walter.doerwald
|
r276 | def getglobals(g): | ||
walter.doerwald
|
r415 | """ | ||
Return the global namespace that is used for expression strings in | ||||
``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's | ||||
user namespace. | ||||
""" | ||||
walter.doerwald
|
r276 | if g is None: | ||
if ipapi is not None: | ||||
walter.doerwald
|
r354 | api = ipapi.get() | ||
if api is not None: | ||||
return api.user_ns | ||||
return globals() | ||||
walter.doerwald
|
r276 | return g | ||
walter.doerwald
|
r355 | class Descriptor(object): | ||
walter.doerwald
|
r415 | """ | ||
A ``Descriptor`` object is used for describing the attributes of objects. | ||||
""" | ||||
walter.doerwald
|
r355 | def __hash__(self): | ||
return hash(self.__class__) ^ hash(self.key()) | ||||
def __eq__(self, other): | ||||
return self.__class__ is other.__class__ and self.key() == other.key() | ||||
def __ne__(self, other): | ||||
return self.__class__ is not other.__class__ or self.key() != other.key() | ||||
def key(self): | ||||
pass | ||||
def name(self): | ||||
walter.doerwald
|
r415 | """ | ||
Return the name of this attribute for display by a ``Display`` object | ||||
(e.g. as a column title). | ||||
""" | ||||
walter.doerwald
|
r355 | key = self.key() | ||
if key is None: | ||||
return "_" | ||||
return str(key) | ||||
def attrtype(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return the type of this attribute (i.e. something like "attribute" or | ||||
"method"). | ||||
""" | ||||
walter.doerwald
|
r355 | |||
def valuetype(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return the type of this attribute value of the object ``obj``. | ||||
""" | ||||
walter.doerwald
|
r355 | |||
def value(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return the value of this attribute of the object ``obj``. | ||||
""" | ||||
walter.doerwald
|
r355 | |||
def doc(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return the documentation for this attribute. | ||||
""" | ||||
walter.doerwald
|
r355 | |||
def shortdoc(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return a short documentation for this attribute (defaulting to the | ||||
first line). | ||||
""" | ||||
walter.doerwald
|
r355 | doc = self.doc(obj) | ||
if doc is not None: | ||||
doc = doc.strip().splitlines()[0].strip() | ||||
return doc | ||||
def iter(self, obj): | ||||
walter.doerwald
|
r415 | """ | ||
Return an iterator for this attribute of the object ``obj``. | ||||
""" | ||||
walter.doerwald
|
r355 | return xiter(self.value(obj)) | ||
class SelfDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
A ``SelfDescriptor`` describes the object itself. | ||||
""" | ||||
walter.doerwald
|
r355 | def key(self): | ||
return None | ||||
def attrtype(self, obj): | ||||
return "self" | ||||
def valuetype(self, obj): | ||||
return type(obj) | ||||
def value(self, obj): | ||||
return obj | ||||
def __repr__(self): | ||||
return "Self" | ||||
selfdescriptor = SelfDescriptor() # there's no need for more than one | ||||
class AttributeDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
An ``AttributeDescriptor`` describes a simple attribute of an object. | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_name", "_doc") | ||
def __init__(self, name, doc=None): | ||||
self._name = name | ||||
self._doc = doc | ||||
def key(self): | ||||
return self._name | ||||
def doc(self, obj): | ||||
return self._doc | ||||
def attrtype(self, obj): | ||||
return "attr" | ||||
def valuetype(self, obj): | ||||
return type(getattr(obj, self._name)) | ||||
def value(self, obj): | ||||
return getattr(obj, self._name) | ||||
def __repr__(self): | ||||
if self._doc is None: | ||||
return "Attribute(%r)" % self._name | ||||
else: | ||||
return "Attribute(%r, %r)" % (self._name, self._doc) | ||||
class IndexDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
An ``IndexDescriptor`` describes an "attribute" of an object that is fetched | ||||
via ``__getitem__``. | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_index",) | ||
def __init__(self, index): | ||||
self._index = index | ||||
def key(self): | ||||
return self._index | ||||
def attrtype(self, obj): | ||||
return "item" | ||||
def valuetype(self, obj): | ||||
return type(obj[self._index]) | ||||
def value(self, obj): | ||||
return obj[self._index] | ||||
def __repr__(self): | ||||
return "Index(%r)" % self._index | ||||
class MethodDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
A ``MethodDescriptor`` describes a method of an object that can be called | ||||
without argument. Note that this method shouldn't change the object. | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_name", "_doc") | ||
def __init__(self, name, doc=None): | ||||
self._name = name | ||||
self._doc = doc | ||||
def key(self): | ||||
return self._name | ||||
def doc(self, obj): | ||||
if self._doc is None: | ||||
return getattr(obj, self._name).__doc__ | ||||
return self._doc | ||||
def attrtype(self, obj): | ||||
return "method" | ||||
def valuetype(self, obj): | ||||
return type(self.value(obj)) | ||||
def value(self, obj): | ||||
return getattr(obj, self._name)() | ||||
def __repr__(self): | ||||
if self._doc is None: | ||||
return "Method(%r)" % self._name | ||||
else: | ||||
return "Method(%r, %r)" % (self._name, self._doc) | ||||
class IterAttributeDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but | ||||
doesn't return an attribute values (because this value might be e.g. a large | ||||
list). | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_name", "_doc") | ||
def __init__(self, name, doc=None): | ||||
self._name = name | ||||
self._doc = doc | ||||
def key(self): | ||||
return self._name | ||||
def doc(self, obj): | ||||
return self._doc | ||||
def attrtype(self, obj): | ||||
return "iter" | ||||
def valuetype(self, obj): | ||||
return noitem | ||||
def value(self, obj): | ||||
return noitem | ||||
def iter(self, obj): | ||||
return xiter(getattr(obj, self._name)) | ||||
def __repr__(self): | ||||
if self._doc is None: | ||||
return "IterAttribute(%r)" % self._name | ||||
else: | ||||
return "IterAttribute(%r, %r)" % (self._name, self._doc) | ||||
class IterMethodDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't | ||||
return an attribute values (because this value might be e.g. a large list). | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_name", "_doc") | ||
def __init__(self, name, doc=None): | ||||
self._name = name | ||||
self._doc = doc | ||||
def key(self): | ||||
return self._name | ||||
def doc(self, obj): | ||||
if self._doc is None: | ||||
return getattr(obj, self._name).__doc__ | ||||
return self._doc | ||||
def attrtype(self, obj): | ||||
return "itermethod" | ||||
def valuetype(self, obj): | ||||
return noitem | ||||
def value(self, obj): | ||||
return noitem | ||||
def iter(self, obj): | ||||
return xiter(getattr(obj, self._name)()) | ||||
def __repr__(self): | ||||
if self._doc is None: | ||||
return "IterMethod(%r)" % self._name | ||||
else: | ||||
return "IterMethod(%r, %r)" % (self._name, self._doc) | ||||
class FunctionDescriptor(Descriptor): | ||||
walter.doerwald
|
r415 | """ | ||
A ``FunctionDescriptor`` turns a function into a descriptor. The function | ||||
will be called with the object to get the type and value of the attribute. | ||||
""" | ||||
walter.doerwald
|
r355 | __slots__ = ("_function", "_name", "_doc") | ||
def __init__(self, function, name=None, doc=None): | ||||
self._function = function | ||||
self._name = name | ||||
self._doc = doc | ||||
def key(self): | ||||
return self._function | ||||
def name(self): | ||||
if self._name is not None: | ||||
return self._name | ||||
return getattr(self._function, "__xname__", self._function.__name__) | ||||
def doc(self, obj): | ||||
if self._doc is None: | ||||
return self._function.__doc__ | ||||
return self._doc | ||||
def attrtype(self, obj): | ||||
return "function" | ||||
def valuetype(self, obj): | ||||
return type(self._function(obj)) | ||||
def value(self, obj): | ||||
return self._function(obj) | ||||
def __repr__(self): | ||||
if self._doc is None: | ||||
return "Function(%r)" % self._name | ||||
else: | ||||
return "Function(%r, %r)" % (self._name, self._doc) | ||||
vivainio
|
r208 | class Table(object): | ||
""" | ||||
A ``Table`` is an object that produces items (just like a normal Python | ||||
iterator/generator does) and can be used as the first object in a pipeline | ||||
expression. The displayhook will open the default browser for such an object | ||||
(instead of simply printing the ``repr()`` result). | ||||
""" | ||||
vivainio
|
r214 | |||
# We want to support ``foo`` and ``foo()`` in pipeline expression: | ||||
# So we implement the required operators (``|`` and ``+``) in the metaclass, | ||||
# instantiate the class and forward the operator to the instance | ||||
vivainio
|
r208 | class __metaclass__(type): | ||
def __iter__(self): | ||||
return iter(self()) | ||||
def __or__(self, other): | ||||
return self() | other | ||||
def __add__(self, other): | ||||
return self() + other | ||||
def __radd__(self, other): | ||||
return other + self() | ||||
def __getitem__(self, index): | ||||
return self()[index] | ||||
def __getitem__(self, index): | ||||
return item(self, index) | ||||
def __contains__(self, item): | ||||
for haveitem in self: | ||||
if item == haveitem: | ||||
return True | ||||
return False | ||||
def __or__(self, other): | ||||
vivainio
|
r214 | # autoinstantiate right hand side | ||
vivainio
|
r209 | if isinstance(other, type) and issubclass(other, (Table, Display)): | ||
vivainio
|
r208 | other = other() | ||
vivainio
|
r214 | # treat simple strings and functions as ``ieval`` instances | ||
vivainio
|
r208 | elif not isinstance(other, Display) and not isinstance(other, Table): | ||
other = ieval(other) | ||||
vivainio
|
r214 | # forward operations to the right hand side | ||
vivainio
|
r208 | return other.__ror__(self) | ||
def __add__(self, other): | ||||
vivainio
|
r214 | # autoinstantiate right hand side | ||
vivainio
|
r208 | if isinstance(other, type) and issubclass(other, Table): | ||
other = other() | ||||
return ichain(self, other) | ||||
def __radd__(self, other): | ||||
vivainio
|
r214 | # autoinstantiate left hand side | ||
vivainio
|
r208 | if isinstance(other, type) and issubclass(other, Table): | ||
other = other() | ||||
return ichain(other, self) | ||||
class Pipe(Table): | ||||
""" | ||||
vivainio
|
r209 | A ``Pipe`` is an object that can be used in a pipeline expression. It | ||
processes the objects it gets from its input ``Table``/``Pipe``. Note that | ||||
a ``Pipe`` object can't be used as the first object in a pipeline | ||||
expression, as it doesn't produces items itself. | ||||
vivainio
|
r208 | """ | ||
class __metaclass__(Table.__metaclass__): | ||||
def __ror__(self, input): | ||||
return input | self() | ||||
def __ror__(self, input): | ||||
vivainio
|
r214 | # autoinstantiate left hand side | ||
vivainio
|
r208 | if isinstance(input, type) and issubclass(input, Table): | ||
input = input() | ||||
self.input = input | ||||
return self | ||||
walter.doerwald
|
r355 | def xrepr(item, mode="default"): | ||
walter.doerwald
|
r415 | """ | ||
Generic function that adds color output and different display modes to ``repr``. | ||||
The result of an ``xrepr`` call is iterable and consists of ``(style, string)`` | ||||
tuples. The ``style`` in this tuple must be a ``Style`` object from the | ||||
``astring`` module. To reconfigure the output the first yielded tuple can be | ||||
a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple. | ||||
``alignment`` can be -1 for left aligned, 0 for centered and 1 for right | ||||
aligned (the default is left alignment). ``full`` is a boolean that specifies | ||||
whether the complete output must be displayed or the ``Display`` object is | ||||
allowed to stop output after enough text has been produced (e.g. a syntax | ||||
highlighted text line would use ``True``, but for a large data structure | ||||
(i.e. a nested list, tuple or dictionary) ``False`` would be used). | ||||
The default is full output. | ||||
There are four different possible values for ``mode`` depending on where | ||||
the ``Display`` object will display ``item``: | ||||
* ``"header"``: ``item`` will be displayed in a header line (this is used by | ||||
``ibrowse``). | ||||
* ``"footer"``: ``item`` will be displayed in a footer line (this is used by | ||||
``ibrowse``). | ||||
* ``"cell"``: ``item`` will be displayed in a table cell/list. | ||||
* ``"default"``: default mode. If an ``xrepr`` implementation recursively | ||||
outputs objects, ``"default"`` must be passed in the recursive calls to | ||||
``xrepr``. | ||||
If no implementation is registered for ``item``, ``xrepr`` will try the | ||||
``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__`` | ||||
method it falls back to ``repr``/``__repr__`` for all modes. | ||||
""" | ||||
vivainio
|
r208 | try: | ||
func = item.__xrepr__ | ||||
vivainio
|
r214 | except AttributeError: | ||
walter.doerwald
|
r415 | yield (astyle.style_default, repr(item)) | ||
vivainio
|
r208 | else: | ||
vivainio
|
r231 | try: | ||
for x in func(mode): | ||||
yield x | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item)) | ||
walter.doerwald
|
r415 | xrepr = simplegeneric.generic(xrepr) | ||
def xrepr_none(self, mode="default"): | ||||
yield (astyle.style_type_none, repr(self)) | ||||
xrepr.when_object(None)(xrepr_none) | ||||
walter.doerwald
|
r519 | def xrepr_noitem(self, mode="default"): | ||
yield (2, True) | ||||
yield (astyle.style_nodata, "<?>") | ||||
xrepr.when_object(noitem)(xrepr_noitem) | ||||
walter.doerwald
|
r415 | def xrepr_bool(self, mode="default"): | ||
yield (astyle.style_type_bool, repr(self)) | ||||
xrepr.when_type(bool)(xrepr_bool) | ||||
def xrepr_str(self, mode="default"): | ||||
if mode == "cell": | ||||
yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1]) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
xrepr.when_type(str)(xrepr_str) | ||||
def xrepr_unicode(self, mode="default"): | ||||
if mode == "cell": | ||||
yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1]) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
xrepr.when_type(unicode)(xrepr_unicode) | ||||
def xrepr_number(self, mode="default"): | ||||
yield (1, True) | ||||
yield (astyle.style_type_number, repr(self)) | ||||
xrepr.when_type(int)(xrepr_number) | ||||
xrepr.when_type(long)(xrepr_number) | ||||
xrepr.when_type(float)(xrepr_number) | ||||
def xrepr_complex(self, mode="default"): | ||||
yield (astyle.style_type_number, repr(self)) | ||||
xrepr.when_type(complex)(xrepr_number) | ||||
def xrepr_datetime(self, mode="default"): | ||||
if mode == "cell": | ||||
# Don't use strftime() here, as this requires year >= 1900 | ||||
yield (astyle.style_type_datetime, | ||||
"%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | ||||
(self.year, self.month, self.day, | ||||
self.hour, self.minute, self.second, | ||||
self.microsecond), | ||||
) | ||||
else: | ||||
yield (astyle.style_type_datetime, repr(self)) | ||||
xrepr.when_type(datetime.datetime)(xrepr_datetime) | ||||
def xrepr_date(self, mode="default"): | ||||
if mode == "cell": | ||||
yield (astyle.style_type_datetime, | ||||
"%04d-%02d-%02d" % (self.year, self.month, self.day)) | ||||
else: | ||||
yield (astyle.style_type_datetime, repr(self)) | ||||
xrepr.when_type(datetime.date)(xrepr_date) | ||||
def xrepr_time(self, mode="default"): | ||||
if mode == "cell": | ||||
yield (astyle.style_type_datetime, | ||||
"%02d:%02d:%02d.%06d" % \ | ||||
(self.hour, self.minute, self.second, self.microsecond)) | ||||
else: | ||||
yield (astyle.style_type_datetime, repr(self)) | ||||
xrepr.when_type(datetime.time)(xrepr_time) | ||||
def xrepr_timedelta(self, mode="default"): | ||||
yield (astyle.style_type_datetime, repr(self)) | ||||
xrepr.when_type(datetime.timedelta)(xrepr_timedelta) | ||||
def xrepr_type(self, mode="default"): | ||||
if self.__module__ == "__builtin__": | ||||
yield (astyle.style_type_type, self.__name__) | ||||
else: | ||||
yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__)) | ||||
xrepr.when_type(type)(xrepr_type) | ||||
def xrepr_exception(self, mode="default"): | ||||
if self.__class__.__module__ == "exceptions": | ||||
classname = self.__class__.__name__ | ||||
else: | ||||
classname = "%s.%s" % \ | ||||
(self.__class__.__module__, self.__class__.__name__) | ||||
if mode == "header" or mode == "footer": | ||||
yield (astyle.style_error, "%s: %s" % (classname, self)) | ||||
else: | ||||
yield (astyle.style_error, classname) | ||||
xrepr.when_type(Exception)(xrepr_exception) | ||||
def xrepr_listtuple(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
if self.__class__.__module__ == "__builtin__": | ||||
classname = self.__class__.__name__ | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r262 | classname = "%s.%s" % \ | ||
walter.doerwald
|
r415 | (self.__class__.__module__,self.__class__.__name__) | ||
yield (astyle.style_default, | ||||
"<%s object with %d items at 0x%x>" % \ | ||||
(classname, len(self), id(self))) | ||||
else: | ||||
yield (-1, False) | ||||
if isinstance(self, list): | ||||
yield (astyle.style_default, "[") | ||||
end = "]" | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r415 | yield (astyle.style_default, "(") | ||
end = ")" | ||||
for (i, subself) in enumerate(self): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
for part in xrepr(subself, "default"): | ||||
yield part | ||||
yield (astyle.style_default, end) | ||||
xrepr.when_type(list)(xrepr_listtuple) | ||||
xrepr.when_type(tuple)(xrepr_listtuple) | ||||
def xrepr_dict(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
if self.__class__.__module__ == "__builtin__": | ||||
classname = self.__class__.__name__ | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r415 | classname = "%s.%s" % \ | ||
(self.__class__.__module__,self.__class__.__name__) | ||||
yield (astyle.style_default, | ||||
"<%s object with %d items at 0x%x>" % \ | ||||
(classname, len(self), id(self))) | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r415 | yield (-1, False) | ||
if isinstance(self, dict): | ||||
yield (astyle.style_default, "{") | ||||
end = "}" | ||||
else: | ||||
yield (astyle.style_default, "dictproxy((") | ||||
end = "})" | ||||
for (i, (key, value)) in enumerate(self.iteritems()): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
for part in xrepr(key, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ": ") | ||||
for part in xrepr(value, "default"): | ||||
yield part | ||||
yield (astyle.style_default, end) | ||||
xrepr.when_type(dict)(xrepr_dict) | ||||
xrepr.when_type(types.DictProxyType)(xrepr_dict) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def upgradexattr(attr): | ||
walter.doerwald
|
r415 | """ | ||
Convert an attribute descriptor string to a real descriptor object. | ||||
If attr already is a descriptor object return if unmodified. A | ||||
``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"`` | ||||
returns an ``AttributeDescriptor`` for the attribute named ``"foo"``. | ||||
``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``. | ||||
``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute | ||||
named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor`` | ||||
for the method named ``"foo"``. Furthermore integer will return the appropriate | ||||
``IndexDescriptor`` and callables will return a ``FunctionDescriptor``. | ||||
""" | ||||
walter.doerwald
|
r355 | if attr is None: | ||
return selfdescriptor | ||||
elif isinstance(attr, Descriptor): | ||||
return attr | ||||
elif isinstance(attr, str): | ||||
if attr.endswith("()"): | ||||
if attr.startswith("-"): | ||||
return IterMethodDescriptor(attr[1:-2]) | ||||
else: | ||||
return MethodDescriptor(attr[:-2]) | ||||
else: | ||||
if attr.startswith("-"): | ||||
return IterAttributeDescriptor(attr[1:]) | ||||
else: | ||||
return AttributeDescriptor(attr) | ||||
elif isinstance(attr, (int, long)): | ||||
return IndexDescriptor(attr) | ||||
elif callable(attr): | ||||
return FunctionDescriptor(attr) | ||||
else: | ||||
raise TypeError("can't handle descriptor %r" % attr) | ||||
def xattrs(item, mode="default"): | ||||
walter.doerwald
|
r415 | """ | ||
Generic function that returns an iterable of attribute descriptors | ||||
to be used for displaying the attributes ob the object ``item`` in display | ||||
mode ``mode``. | ||||
There are two possible modes: | ||||
* ``"detail"``: The ``Display`` object wants to display a detailed list | ||||
of the object attributes. | ||||
* ``"default"``: The ``Display`` object wants to display the object in a | ||||
list view. | ||||
If no implementation is registered for the object ``item`` ``xattrs`` falls | ||||
back to trying the ``__xattrs__`` method of the object. If this doesn't | ||||
exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)`` | ||||
for ``"default"`` mode. | ||||
The implementation must yield attribute descriptor (see the class | ||||
``Descriptor`` for more info). The ``__xattrs__`` method may also return | ||||
attribute descriptor string (and ``None``) which will be converted to real | ||||
descriptors by ``upgradexattr()``. | ||||
""" | ||||
vivainio
|
r208 | try: | ||
func = item.__xattrs__ | ||||
except AttributeError: | ||||
vivainio
|
r252 | if mode == "detail": | ||
walter.doerwald
|
r355 | for attrname in dir(item): | ||
yield AttributeDescriptor(attrname) | ||||
vivainio
|
r252 | else: | ||
walter.doerwald
|
r355 | yield selfdescriptor | ||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r355 | for attr in func(mode): | ||
yield upgradexattr(attr) | ||||
walter.doerwald
|
r415 | xattrs = simplegeneric.generic(xattrs) | ||
def xattrs_complex(self, mode="default"): | ||||
if mode == "detail": | ||||
return (AttributeDescriptor("real"), AttributeDescriptor("imag")) | ||||
return (selfdescriptor,) | ||||
xattrs.when_type(complex)(xattrs_complex) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def _isdict(item): | ||
try: | ||||
itermeth = item.__class__.__iter__ | ||||
except (AttributeError, TypeError): | ||||
return False | ||||
return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__ | ||||
def _isstr(item): | ||||
if not isinstance(item, basestring): | ||||
return False | ||||
try: | ||||
itermeth = item.__class__.__iter__ | ||||
except AttributeError: | ||||
return True | ||||
return False # ``__iter__`` has been redefined | ||||
walter.doerwald
|
r415 | def xiter(item): | ||
""" | ||||
Generic function that implements iteration for pipeline expression. If no | ||||
implementation is registered for ``item`` ``xiter`` falls back to ``iter``. | ||||
""" | ||||
vivainio
|
r208 | try: | ||
func = item.__xiter__ | ||||
except AttributeError: | ||||
walter.doerwald
|
r355 | if _isdict(item): | ||
vivainio
|
r210 | def items(item): | ||
fields = ("key", "value") | ||||
for (key, value) in item.iteritems(): | ||||
yield Fields(fields, key=key, value=value) | ||||
return items(item) | ||||
vivainio
|
r208 | elif isinstance(item, new.module): | ||
def items(item): | ||||
vivainio
|
r210 | fields = ("key", "value") | ||
vivainio
|
r208 | for key in sorted(item.__dict__): | ||
vivainio
|
r214 | yield Fields(fields, key=key, value=getattr(item, key)) | ||
vivainio
|
r208 | return items(item) | ||
walter.doerwald
|
r355 | elif _isstr(item): | ||
if not item: | ||||
vivainio
|
r208 | raise ValueError("can't enter empty string") | ||
walter.doerwald
|
r513 | lines = item.splitlines() | ||
if len(lines) == 1: | ||||
def iterone(item): | ||||
yield item | ||||
return iterone(item) | ||||
else: | ||||
return iter(lines) | ||||
vivainio
|
r208 | return iter(item) | ||
else: | ||||
walter.doerwald
|
r415 | return iter(func()) # iter() just to be safe | ||
xiter = simplegeneric.generic(xiter) | ||||
vivainio
|
r208 | |||
class ichain(Pipe): | ||||
""" | ||||
Chains multiple ``Table``s into one. | ||||
""" | ||||
def __init__(self, *iters): | ||||
self.iters = iters | ||||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | return itertools.chain(*self.iters) | ||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
vivainio
|
r230 | for (i, item) in enumerate(self.iters): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, "+") | ||
vivainio
|
r230 | if isinstance(item, Pipe): | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "(") | ||
vivainio
|
r230 | for part in xrepr(item, mode): | ||
yield part | ||||
vivainio
|
r208 | if isinstance(item, Pipe): | ||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r230 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | args = ", ".join([repr(it) for it in self.iters]) | ||
return "%s.%s(%s)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, args) | ||||
vivainio
|
r208 | |||
vivainio
|
r237 | class ifile(path.path): | ||
vivainio
|
r215 | """ | ||
file (or directory) object. | ||||
""" | ||||
vivainio
|
r208 | |||
def getmode(self): | ||||
vivainio
|
r237 | return self.stat().st_mode | ||
vivainio
|
r208 | mode = property(getmode, None, None, "Access mode") | ||
def gettype(self): | ||||
data = [ | ||||
(stat.S_ISREG, "file"), | ||||
(stat.S_ISDIR, "dir"), | ||||
(stat.S_ISCHR, "chardev"), | ||||
(stat.S_ISBLK, "blockdev"), | ||||
(stat.S_ISFIFO, "fifo"), | ||||
(stat.S_ISLNK, "symlink"), | ||||
(stat.S_ISSOCK,"socket"), | ||||
] | ||||
vivainio
|
r237 | lstat = self.lstat() | ||
vivainio
|
r208 | if lstat is not None: | ||
types = set([text for (func, text) in data if func(lstat.st_mode)]) | ||||
else: | ||||
types = set() | ||||
m = self.mode | ||||
types.update([text for (func, text) in data if func(m)]) | ||||
return ", ".join(types) | ||||
vivainio
|
r237 | type = property(gettype, None, None, "file type (file, directory, link, etc.)") | ||
vivainio
|
r208 | |||
vivainio
|
r237 | def getmodestr(self): | ||
vivainio
|
r208 | m = self.mode | ||
data = [ | ||||
(stat.S_IRUSR, "-r"), | ||||
(stat.S_IWUSR, "-w"), | ||||
(stat.S_IXUSR, "-x"), | ||||
(stat.S_IRGRP, "-r"), | ||||
(stat.S_IWGRP, "-w"), | ||||
(stat.S_IXGRP, "-x"), | ||||
(stat.S_IROTH, "-r"), | ||||
(stat.S_IWOTH, "-w"), | ||||
(stat.S_IXOTH, "-x"), | ||||
] | ||||
return "".join([text[bool(m&bit)] for (bit, text) in data]) | ||||
vivainio
|
r237 | modestr = property(getmodestr, None, None, "Access mode as string") | ||
vivainio
|
r208 | |||
def getblocks(self): | ||||
vivainio
|
r237 | return self.stat().st_blocks | ||
vivainio
|
r208 | blocks = property(getblocks, None, None, "File size in blocks") | ||
def getblksize(self): | ||||
vivainio
|
r237 | return self.stat().st_blksize | ||
vivainio
|
r208 | blksize = property(getblksize, None, None, "Filesystem block size") | ||
def getdev(self): | ||||
vivainio
|
r237 | return self.stat().st_dev | ||
vivainio
|
r208 | dev = property(getdev) | ||
def getnlink(self): | ||||
vivainio
|
r237 | return self.stat().st_nlink | ||
vivainio
|
r208 | nlink = property(getnlink, None, None, "Number of links") | ||
def getuid(self): | ||||
vivainio
|
r237 | return self.stat().st_uid | ||
vivainio
|
r208 | uid = property(getuid, None, None, "User id of file owner") | ||
def getgid(self): | ||||
vivainio
|
r237 | return self.stat().st_gid | ||
vivainio
|
r208 | gid = property(getgid, None, None, "Group id of file owner") | ||
def getowner(self): | ||||
vivainio
|
r237 | stat = self.stat() | ||
vivainio
|
r208 | try: | ||
vivainio
|
r237 | return pwd.getpwuid(stat.st_uid).pw_name | ||
vivainio
|
r208 | except KeyError: | ||
vivainio
|
r237 | return stat.st_uid | ||
vivainio
|
r208 | owner = property(getowner, None, None, "Owner name (or id)") | ||
def getgroup(self): | ||||
vivainio
|
r237 | stat = self.stat() | ||
vivainio
|
r208 | try: | ||
vivainio
|
r237 | return grp.getgrgid(stat.st_gid).gr_name | ||
vivainio
|
r208 | except KeyError: | ||
vivainio
|
r237 | return stat.st_gid | ||
vivainio
|
r208 | group = property(getgroup, None, None, "Group name (or id)") | ||
def getadate(self): | ||||
return datetime.datetime.utcfromtimestamp(self.atime) | ||||
adate = property(getadate, None, None, "Access date") | ||||
def getcdate(self): | ||||
return datetime.datetime.utcfromtimestamp(self.ctime) | ||||
cdate = property(getcdate, None, None, "Creation date") | ||||
def getmdate(self): | ||||
return datetime.datetime.utcfromtimestamp(self.mtime) | ||||
mdate = property(getmdate, None, None, "Modification date") | ||||
walter.doerwald
|
r355 | def mimetype(self): | ||
""" | ||||
Return MIME type guessed from the extension. | ||||
""" | ||||
vivainio
|
r237 | return mimetypes.guess_type(self.basename())[0] | ||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def encoding(self): | ||
""" | ||||
Return guessed compression (like "compress" or "gzip"). | ||||
""" | ||||
vivainio
|
r237 | return mimetypes.guess_type(self.basename())[1] | ||
vivainio
|
r208 | |||
vivainio
|
r237 | def __repr__(self): | ||
return "ifile(%s)" % path._base.__repr__(self) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r423 | if sys.platform == "win32": | ||
defaultattrs = (None, "type", "size", "modestr", "mdate") | ||||
else: | ||||
defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate") | ||||
walter.doerwald
|
r356 | |||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "detail": | ||
vivainio
|
r209 | return ( | ||
walter.doerwald
|
r355 | "name", | ||
"basename()", | ||||
"abspath()", | ||||
"realpath()", | ||||
"type", | ||||
"mode", | ||||
"modestr", | ||||
"stat()", | ||||
"lstat()", | ||||
"uid", | ||||
"gid", | ||||
"owner", | ||||
"group", | ||||
"dev", | ||||
"nlink", | ||||
"ctime", | ||||
"mtime", | ||||
"atime", | ||||
"cdate", | ||||
"mdate", | ||||
"adate", | ||||
"size", | ||||
"blocks", | ||||
"blksize", | ||||
"isdir()", | ||||
"islink()", | ||||
"mimetype()", | ||||
"encoding()", | ||||
"-listdir()", | ||||
"-dirs()", | ||||
"-files()", | ||||
"-walk()", | ||||
"-walkdirs()", | ||||
"-walkfiles()", | ||||
vivainio
|
r209 | ) | ||
walter.doerwald
|
r355 | else: | ||
walter.doerwald
|
r356 | return self.defaultattrs | ||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def xiter_ifile(self): | ||
if self.isdir(): | ||||
yield (self / os.pardir).abspath() | ||||
for child in sorted(self.listdir()): | ||||
yield child | ||||
else: | ||||
f = self.open("rb") | ||||
for line in f: | ||||
yield line | ||||
f.close() | ||||
xiter.when_type(ifile)(xiter_ifile) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | # We need to implement ``xrepr`` for ``ifile`` as a generic function, because | ||
# otherwise ``xrepr_str`` would kick in. | ||||
def xrepr_ifile(self, mode="default"): | ||||
try: | ||||
if self.isdir(): | ||||
name = "idir" | ||||
style = astyle.style_dir | ||||
else: | ||||
name = "ifile" | ||||
style = astyle.style_file | ||||
except IOError: | ||||
name = "ifile" | ||||
style = astyle.style_default | ||||
walter.doerwald
|
r661 | if mode in ("cell", "header", "footer"): | ||
walter.doerwald
|
r415 | abspath = repr(path._base(self.normpath())) | ||
if abspath.startswith("u"): | ||||
abspath = abspath[2:-1] | ||||
else: | ||||
abspath = abspath[1:-1] | ||||
vivainio
|
r237 | if mode == "cell": | ||
walter.doerwald
|
r415 | yield (style, abspath) | ||
vivainio
|
r237 | else: | ||
walter.doerwald
|
r415 | yield (style, "%s(%s)" % (name, abspath)) | ||
else: | ||||
yield (style, repr(self)) | ||||
xrepr.when_type(ifile)(xrepr_ifile) | ||||
vivainio
|
r208 | |||
class ils(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r415 | List the current (or a specified) directory. | ||
walter.doerwald
|
r261 | |||
Examples: | ||||
>>> ils | ||||
>>> ils("/usr/local/lib/python2.4") | ||||
>>> ils("~") | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r365 | def __init__(self, base=os.curdir, dirs=True, files=True): | ||
vivainio
|
r208 | self.base = os.path.expanduser(base) | ||
walter.doerwald
|
r365 | self.dirs = dirs | ||
self.files = files | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
walter.doerwald
|
r415 | base = ifile(self.base) | ||
yield (base / os.pardir).abspath() | ||||
walter.doerwald
|
r600 | for child in sorted(base.listdir()): | ||
walter.doerwald
|
r365 | if self.dirs: | ||
if self.files: | ||||
yield child | ||||
else: | ||||
if child.isdir(): | ||||
yield child | ||||
elif self.files: | ||||
if not child.isdir(): | ||||
yield child | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
walter.doerwald
|
r443 | return xrepr(ifile(self.base), mode) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self.base) | ||||
vivainio
|
r208 | |||
class iglob(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | List all files and directories matching a specified pattern. | ||
(See ``glob.glob()`` for more info.). | ||||
Examples: | ||||
>>> iglob("*.py") | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | def __init__(self, glob): | ||
self.glob = glob | ||||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | for name in glob.glob(self.glob): | ||
yield ifile(name) | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | if mode == "header" or mode == "footer" or mode == "cell": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, | ||
"%s(%r)" % (self.__class__.__name__, self.glob)) | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self.glob) | ||||
vivainio
|
r208 | |||
class iwalk(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | List all files and directories in a directory and it's subdirectory. | ||
>>> iwalk | ||||
>>> iwalk("/usr/local/lib/python2.4") | ||||
>>> iwalk("~") | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | def __init__(self, base=os.curdir, dirs=True, files=True): | ||
self.base = os.path.expanduser(base) | ||||
self.dirs = dirs | ||||
self.files = files | ||||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | for (dirpath, dirnames, filenames) in os.walk(self.base): | ||
if self.dirs: | ||||
for name in sorted(dirnames): | ||||
yield ifile(os.path.join(dirpath, name)) | ||||
if self.files: | ||||
for name in sorted(filenames): | ||||
yield ifile(os.path.join(dirpath, name)) | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | if mode == "header" or mode == "footer" or mode == "cell": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, | ||
"%s(%r)" % (self.__class__.__name__, self.base)) | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self.base) | ||||
vivainio
|
r208 | |||
class ipwdentry(object): | ||||
vivainio
|
r215 | """ | ||
``ipwdentry`` objects encapsulate entries in the Unix user account and | ||||
password database. | ||||
""" | ||||
vivainio
|
r208 | def __init__(self, id): | ||
self._id = id | ||||
self._entry = None | ||||
walter.doerwald
|
r472 | def __eq__(self, other): | ||
return self.__class__ is other.__class__ and self._id == other._id | ||||
def __ne__(self, other): | ||||
return self.__class__ is not other.__class__ or self._id != other._id | ||||
vivainio
|
r208 | def _getentry(self): | ||
if self._entry is None: | ||||
if isinstance(self._id, basestring): | ||||
self._entry = pwd.getpwnam(self._id) | ||||
else: | ||||
self._entry = pwd.getpwuid(self._id) | ||||
return self._entry | ||||
def getname(self): | ||||
if isinstance(self._id, basestring): | ||||
return self._id | ||||
else: | ||||
return self._getentry().pw_name | ||||
name = property(getname, None, None, "User name") | ||||
def getpasswd(self): | ||||
return self._getentry().pw_passwd | ||||
passwd = property(getpasswd, None, None, "Password") | ||||
def getuid(self): | ||||
if isinstance(self._id, basestring): | ||||
return self._getentry().pw_uid | ||||
else: | ||||
return self._id | ||||
uid = property(getuid, None, None, "User id") | ||||
def getgid(self): | ||||
return self._getentry().pw_gid | ||||
gid = property(getgid, None, None, "Primary group id") | ||||
def getgroup(self): | ||||
return igrpentry(self.gid) | ||||
group = property(getgroup, None, None, "Group") | ||||
def getgecos(self): | ||||
return self._getentry().pw_gecos | ||||
gecos = property(getgecos, None, None, "Information (e.g. full user name)") | ||||
def getdir(self): | ||||
return self._getentry().pw_dir | ||||
dir = property(getdir, None, None, "$HOME directory") | ||||
def getshell(self): | ||||
return self._getentry().pw_shell | ||||
shell = property(getshell, None, None, "Login shell") | ||||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
walter.doerwald
|
r355 | return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell") | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self._id) | ||||
vivainio
|
r208 | |||
class ipwd(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | List all entries in the Unix user account and password database. | ||
Example: | ||||
>>> ipwd | isort("uid") | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | def __iter__(self): | ||
for entry in pwd.getpwall(): | ||||
yield ipwdentry(entry.pw_name) | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | if mode == "header" or mode == "footer" or mode == "cell": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
class igrpentry(object): | ||||
vivainio
|
r215 | """ | ||
``igrpentry`` objects encapsulate entries in the Unix group database. | ||||
""" | ||||
vivainio
|
r208 | def __init__(self, id): | ||
self._id = id | ||||
self._entry = None | ||||
walter.doerwald
|
r472 | def __eq__(self, other): | ||
return self.__class__ is other.__class__ and self._id == other._id | ||||
def __ne__(self, other): | ||||
return self.__class__ is not other.__class__ or self._id != other._id | ||||
vivainio
|
r208 | def _getentry(self): | ||
if self._entry is None: | ||||
if isinstance(self._id, basestring): | ||||
self._entry = grp.getgrnam(self._id) | ||||
else: | ||||
self._entry = grp.getgrgid(self._id) | ||||
return self._entry | ||||
def getname(self): | ||||
if isinstance(self._id, basestring): | ||||
return self._id | ||||
else: | ||||
return self._getentry().gr_name | ||||
name = property(getname, None, None, "Group name") | ||||
def getpasswd(self): | ||||
return self._getentry().gr_passwd | ||||
passwd = property(getpasswd, None, None, "Password") | ||||
def getgid(self): | ||||
if isinstance(self._id, basestring): | ||||
return self._getentry().gr_gid | ||||
else: | ||||
return self._id | ||||
gid = property(getgid, None, None, "Group id") | ||||
def getmem(self): | ||||
return self._getentry().gr_mem | ||||
mem = property(getmem, None, None, "Members") | ||||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
vivainio
|
r208 | return ("name", "passwd", "gid", "mem") | ||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | if mode == "header" or mode == "footer" or mode == "cell": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "group ") | ||
vivainio
|
r230 | try: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, self.name) | ||
vivainio
|
r230 | except KeyError: | ||
if isinstance(self._id, basestring): | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, self.name_id) | ||
vivainio
|
r230 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_type_number, str(self._id)) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | for member in self.mem: | ||
yield ipwdentry(member) | ||||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self._id) | ||||
vivainio
|
r208 | |||
class igrp(Table): | ||||
vivainio
|
r215 | """ | ||
This ``Table`` lists all entries in the Unix group database. | ||||
""" | ||||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | for entry in grp.getgrall(): | ||
yield igrpentry(entry.gr_name) | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
vivainio
|
r209 | class Fields(object): | ||
def __init__(self, fieldnames, **fields): | ||||
walter.doerwald
|
r355 | self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames] | ||
vivainio
|
r209 | for (key, value) in fields.iteritems(): | ||
setattr(self, key, value) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
vivainio
|
r209 | return self.__fieldnames | ||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | yield (-1, False) | ||
if mode == "header" or mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, self.__class__.__name__) | ||
yield (astyle.style_default, "(") | ||||
vivainio
|
r225 | for (i, f) in enumerate(self.__fieldnames): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
walter.doerwald
|
r355 | yield (astyle.style_default, f.name()) | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "=") | ||
vivainio
|
r225 | for part in xrepr(getattr(self, f), "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | elif mode == "footer": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, self.__class__.__name__) | ||
yield (astyle.style_default, "(") | ||||
vivainio
|
r225 | for (i, f) in enumerate(self.__fieldnames): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
walter.doerwald
|
r355 | yield (astyle.style_default, f.name()) | ||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
vivainio
|
r209 | class FieldTable(Table, list): | ||
def __init__(self, *fields): | ||||
vivainio
|
r220 | Table.__init__(self) | ||
vivainio
|
r209 | list.__init__(self) | ||
self.fields = fields | ||||
vivainio
|
r208 | |||
vivainio
|
r209 | def add(self, **fields): | ||
vivainio
|
r221 | self.append(Fields(self.fields, **fields)) | ||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | yield (-1, False) | ||
vivainio
|
r209 | if mode == "header" or mode == "footer": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, self.__class__.__name__) | ||
yield (astyle.style_default, "(") | ||||
vivainio
|
r225 | for (i, f) in enumerate(self.__fieldnames): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
yield (astyle.style_default, f) | ||||
yield (astyle.style_default, ")") | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r209 | |||
def __repr__(self): | ||||
return "<%s.%s object with fields=%r at 0x%x>" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, | ||||
", ".join(map(repr, self.fields)), id(self)) | ||||
vivainio
|
r208 | |||
vivainio
|
r225 | class List(list): | ||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
vivainio
|
r225 | return xrange(len(self)) | ||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | yield (-1, False) | ||
if mode == "header" or mode == "cell" or mode == "footer" or mode == "default": | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, self.__class__.__name__) | ||
yield (astyle.style_default, "(") | ||||
vivainio
|
r225 | for (i, item) in enumerate(self): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
vivainio
|
r225 | for part in xrepr(item, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r225 | |||
vivainio
|
r208 | class ienv(Table): | ||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | List environment variables. | ||
Example: | ||||
>>> ienv | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r209 | fields = ("key", "value") | ||
for (key, value) in os.environ.iteritems(): | ||||
yield Fields(fields, key=key, value=value) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | if mode == "header" or mode == "cell": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
class icsv(Pipe): | ||||
vivainio
|
r215 | """ | ||
This ``Pipe`` lists turn the input (with must be a pipe outputting lines | ||||
or an ``ifile``) into lines of CVS columns. | ||||
""" | ||||
vivainio
|
r208 | def __init__(self, **csvargs): | ||
vivainio
|
r215 | """ | ||
Create an ``icsv`` object. ``cvsargs`` will be passed through as | ||||
keyword arguments to ``cvs.reader()``. | ||||
""" | ||||
vivainio
|
r208 | self.csvargs = csvargs | ||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | input = self.input | ||
if isinstance(input, ifile): | ||||
input = input.open("rb") | ||||
reader = csv.reader(input, **self.csvargs) | ||||
for line in reader: | ||||
vivainio
|
r225 | yield List(line) | ||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r225 | yield (-1, False) | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
vivainio
|
r225 | for part in xrepr(input, mode): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, " | ") | ||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
vivainio
|
r225 | for (i, (name, value)) in enumerate(self.csvargs.iteritems()): | ||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
yield (astyle.style_default, name) | ||||
yield (astyle.style_default, "=") | ||||
vivainio
|
r225 | for part in xrepr(value, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()]) | ||
return "<%s.%s %s at 0x%x>" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, args, id(self)) | ||||
vivainio
|
r208 | |||
class ix(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | Execute a system command and list its output as lines | ||
vivainio
|
r215 | (similar to ``os.popen()``). | ||
walter.doerwald
|
r261 | |||
Examples: | ||||
>>> ix("ps x") | ||||
>>> ix("find .") | ifile | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | def __init__(self, cmd): | ||
self.cmd = cmd | ||||
walter.doerwald
|
r351 | self._pipeout = None | ||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
walter.doerwald
|
r351 | (_pipein, self._pipeout) = os.popen4(self.cmd) | ||
_pipein.close() | ||||
for l in self._pipeout: | ||||
vivainio
|
r208 | yield l.rstrip("\r\n") | ||
walter.doerwald
|
r351 | self._pipeout.close() | ||
self._pipeout = None | ||||
vivainio
|
r208 | |||
def __del__(self): | ||||
walter.doerwald
|
r351 | if self._pipeout is not None and not self._pipeout.closed: | ||
self._pipeout.close() | ||||
self._pipeout = None | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
walter.doerwald
|
r269 | yield (astyle.style_default, | ||
"%s(%r)" % (self.__class__.__name__, self.cmd)) | ||||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "%s.%s(%r)" % \ | ||
(self.__class__.__module__, self.__class__.__name__, self.cmd) | ||||
vivainio
|
r208 | |||
class ifilter(Pipe): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | Filter an input pipe. Only objects where an expression evaluates to true | ||
(and doesn't raise an exception) are listed. | ||||
Examples: | ||||
>>> ils | ifilter("_.isfile() and size>1000") | ||||
>>> igrp | ifilter("len(mem)") | ||||
>>> sys.modules | ifilter(lambda _:_.value is not None) | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r276 | def __init__(self, expr, globals=None, errors="raiseifallfail"): | ||
vivainio
|
r215 | """ | ||
Create an ``ifilter`` object. ``expr`` can be a callable or a string | ||||
walter.doerwald
|
r276 | containing an expression. ``globals`` will be used as the global | ||
namespace for calling string expressions (defaulting to IPython's | ||||
user namespace). ``errors`` specifies how exception during evaluation | ||||
of ``expr`` are handled: | ||||
vivainio
|
r232 | |||
* ``drop``: drop all items that have errors; | ||||
* ``keep``: keep all items that have errors; | ||||
* ``keeperror``: keep the exception of all items that have errors; | ||||
* ``raise``: raise the exception; | ||||
* ``raiseifallfail``: raise the first exception if all items have errors; | ||||
otherwise drop those with errors (this is the default). | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | self.expr = expr | ||
walter.doerwald
|
r276 | self.globals = globals | ||
vivainio
|
r232 | self.errors = errors | ||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | if callable(self.expr): | ||
walter.doerwald
|
r349 | test = self.expr | ||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
walter.doerwald
|
r349 | expr = compile(self.expr, "ipipe-expression", "eval") | ||
vivainio
|
r232 | def test(item): | ||
walter.doerwald
|
r349 | return eval(expr, g, AttrNamespace(item)) | ||
vivainio
|
r232 | |||
ok = 0 | ||||
exc_info = None | ||||
walter.doerwald
|
r355 | for item in xiter(self.input): | ||
vivainio
|
r232 | try: | ||
if test(item): | ||||
yield item | ||||
ok += 1 | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
if self.errors == "drop": | ||||
vivainio
|
r208 | pass # Ignore errors | ||
vivainio
|
r232 | elif self.errors == "keep": | ||
yield item | ||||
elif self.errors == "keeperror": | ||||
yield exc | ||||
elif self.errors == "raise": | ||||
raise | ||||
elif self.errors == "raiseifallfail": | ||||
if exc_info is None: | ||||
exc_info = sys.exc_info() | ||||
if not ok and exc_info is not None: | ||||
raise exc_info[0], exc_info[1], exc_info[2] | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
vivainio
|
r225 | for part in xrepr(input, mode): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, " | ") | ||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
vivainio
|
r225 | for part in xrepr(self.expr, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "<%s.%s expr=%r at 0x%x>" % \ | ||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.expr, id(self)) | ||||
vivainio
|
r208 | |||
class ieval(Pipe): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | Evaluate an expression for each object in the input pipe. | ||
Examples: | ||||
>>> ils | ieval("_.abspath()") | ||||
>>> sys.path | ieval(ifile) | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r276 | def __init__(self, expr, globals=None, errors="raiseifallfail"): | ||
vivainio
|
r215 | """ | ||
Create an ``ieval`` object. ``expr`` can be a callable or a string | ||||
walter.doerwald
|
r276 | containing an expression. For the meaning of ``globals`` and | ||
``errors`` see ``ifilter``. | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | self.expr = expr | ||
walter.doerwald
|
r276 | self.globals = globals | ||
vivainio
|
r232 | self.errors = errors | ||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r208 | if callable(self.expr): | ||
walter.doerwald
|
r349 | do = self.expr | ||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
walter.doerwald
|
r349 | expr = compile(self.expr, "ipipe-expression", "eval") | ||
vivainio
|
r232 | def do(item): | ||
walter.doerwald
|
r349 | return eval(expr, g, AttrNamespace(item)) | ||
vivainio
|
r232 | |||
ok = 0 | ||||
exc_info = None | ||||
walter.doerwald
|
r355 | for item in xiter(self.input): | ||
vivainio
|
r232 | try: | ||
yield do(item) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
if self.errors == "drop": | ||||
vivainio
|
r208 | pass # Ignore errors | ||
vivainio
|
r232 | elif self.errors == "keep": | ||
yield item | ||||
elif self.errors == "keeperror": | ||||
yield exc | ||||
elif self.errors == "raise": | ||||
raise | ||||
elif self.errors == "raiseifallfail": | ||||
if exc_info is None: | ||||
exc_info = sys.exc_info() | ||||
if not ok and exc_info is not None: | ||||
raise exc_info[0], exc_info[1], exc_info[2] | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
vivainio
|
r225 | for part in xrepr(input, mode): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, " | ") | ||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
vivainio
|
r225 | for part in xrepr(self.expr, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "<%s.%s expr=%r at 0x%x>" % \ | ||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.expr, id(self)) | ||||
vivainio
|
r208 | |||
class ienum(Pipe): | ||||
walter.doerwald
|
r261 | """ | ||
Enumerate the input pipe (i.e. wrap each input object in an object | ||||
with ``index`` and ``object`` attributes). | ||||
Examples: | ||||
>>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object") | ||||
""" | ||||
walter.doerwald
|
r355 | def __iter__(self): | ||
vivainio
|
r209 | fields = ("index", "object") | ||
walter.doerwald
|
r355 | for (index, object) in enumerate(xiter(self.input)): | ||
vivainio
|
r209 | yield Fields(fields, index=index, object=object) | ||
vivainio
|
r208 | |||
class isort(Pipe): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | Sorts the input pipe. | ||
Examples: | ||||
>>> ils | isort("size") | ||||
>>> ils | isort("_.isdir(), _.lower()", reverse=True) | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r350 | def __init__(self, key=None, globals=None, reverse=False): | ||
vivainio
|
r215 | """ | ||
Create an ``isort`` object. ``key`` can be a callable or a string | ||||
walter.doerwald
|
r350 | containing an expression (or ``None`` in which case the items | ||
themselves will be sorted). If ``reverse`` is true the sort order | ||||
will be reversed. For the meaning of ``globals`` see ``ifilter``. | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | self.key = key | ||
walter.doerwald
|
r276 | self.globals = globals | ||
vivainio
|
r208 | self.reverse = reverse | ||
walter.doerwald
|
r355 | def __iter__(self): | ||
walter.doerwald
|
r350 | if self.key is None: | ||
walter.doerwald
|
r355 | items = sorted(xiter(self.input), reverse=self.reverse) | ||
walter.doerwald
|
r350 | elif callable(self.key): | ||
walter.doerwald
|
r355 | items = sorted(xiter(self.input), key=self.key, reverse=self.reverse) | ||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
walter.doerwald
|
r349 | key = compile(self.key, "ipipe-expression", "eval") | ||
def realkey(item): | ||||
return eval(key, g, AttrNamespace(item)) | ||||
walter.doerwald
|
r358 | items = sorted(xiter(self.input), key=realkey, reverse=self.reverse) | ||
vivainio
|
r208 | for item in items: | ||
yield item | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
vivainio
|
r208 | if mode == "header" or mode == "footer": | ||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
vivainio
|
r225 | for part in xrepr(input, mode): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, " | ") | ||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
vivainio
|
r225 | for part in xrepr(self.key, "default"): | ||
yield part | ||||
vivainio
|
r208 | if self.reverse: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
vivainio
|
r225 | for part in xrepr(True, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ")") | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __repr__(self): | ||||
vivainio
|
r209 | return "<%s.%s key=%r reverse=%r at 0x%x>" % \ | ||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.key, self.reverse, id(self)) | ||||
vivainio
|
r208 | |||
tab = 3 # for expandtabs() | ||||
def _format(field): | ||||
if isinstance(field, str): | ||||
text = repr(field.expandtabs(tab))[1:-1] | ||||
elif isinstance(field, unicode): | ||||
text = repr(field.expandtabs(tab))[2:-1] | ||||
elif isinstance(field, datetime.datetime): | ||||
# Don't use strftime() here, as this requires year >= 1900 | ||||
vivainio
|
r209 | text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | ||
(field.year, field.month, field.day, | ||||
field.hour, field.minute, field.second, field.microsecond) | ||||
vivainio
|
r208 | elif isinstance(field, datetime.date): | ||
text = "%04d-%02d-%02d" % (field.year, field.month, field.day) | ||||
else: | ||||
text = repr(field) | ||||
return text | ||||
class Display(object): | ||||
class __metaclass__(type): | ||||
def __ror__(self, input): | ||||
return input | self() | ||||
def __ror__(self, input): | ||||
self.input = input | ||||
return self | ||||
def display(self): | ||||
pass | ||||
class iless(Display): | ||||
cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS" | ||||
def display(self): | ||||
try: | ||||
pager = os.popen(self.cmd, "w") | ||||
try: | ||||
walter.doerwald
|
r415 | for item in xiter(self.input): | ||
first = False | ||||
for attr in xattrs(item, "default"): | ||||
if first: | ||||
first = False | ||||
else: | ||||
pager.write(" ") | ||||
attr = upgradexattr(attr) | ||||
if not isinstance(attr, SelfDescriptor): | ||||
pager.write(attr.name()) | ||||
pager.write("=") | ||||
pager.write(str(attr.value(item))) | ||||
vivainio
|
r208 | pager.write("\n") | ||
finally: | ||||
pager.close() | ||||
except Exception, exc: | ||||
print "%s: %s" % (exc.__class__.__name__, str(exc)) | ||||
vivainio
|
r247 | def xformat(value, mode, maxlength): | ||
align = None | ||||
walter.doerwald
|
r279 | full = True | ||
vivainio
|
r247 | width = 0 | ||
walter.doerwald
|
r269 | text = astyle.Text() | ||
walter.doerwald
|
r282 | for (style, part) in xrepr(value, mode): | ||
# only consider the first result | ||||
if align is None: | ||||
if isinstance(style, int): | ||||
# (style, text) really is (alignment, stop) | ||||
align = style | ||||
full = part | ||||
continue | ||||
else: | ||||
align = -1 | ||||
full = True | ||||
if not isinstance(style, int): | ||||
text.append((style, part)) | ||||
width += len(part) | ||||
vivainio
|
r247 | if width >= maxlength and not full: | ||
walter.doerwald
|
r269 | text.append((astyle.style_ellisis, "...")) | ||
vivainio
|
r247 | width += 3 | ||
break | ||||
if align is None: # default to left alignment | ||||
align = -1 | ||||
return (align, width, text) | ||||
vivainio
|
r208 | class idump(Display): | ||
vivainio
|
r247 | # The approximate maximum length of a column entry | ||
maxattrlength = 200 | ||||
# Style for column names | ||||
walter.doerwald
|
r269 | style_header = astyle.Style.fromstr("white:black:bold") | ||
vivainio
|
r247 | |||
vivainio
|
r208 | def __init__(self, *attrs): | ||
walter.doerwald
|
r355 | self.attrs = [upgradexattr(attr) for attr in attrs] | ||
vivainio
|
r208 | self.headerpadchar = " " | ||
self.headersepchar = "|" | ||||
self.datapadchar = " " | ||||
self.datasepchar = "|" | ||||
def display(self): | ||||
vivainio
|
r247 | stream = genutils.Term.cout | ||
allattrs = [] | ||||
walter.doerwald
|
r355 | attrset = set() | ||
vivainio
|
r247 | colwidths = {} | ||
rows = [] | ||||
walter.doerwald
|
r415 | for item in xiter(self.input): | ||
vivainio
|
r247 | row = {} | ||
vivainio
|
r250 | attrs = self.attrs | ||
if not attrs: | ||||
vivainio
|
r208 | attrs = xattrs(item, "default") | ||
walter.doerwald
|
r355 | for attr in attrs: | ||
if attr not in attrset: | ||||
allattrs.append(attr) | ||||
attrset.add(attr) | ||||
colwidths[attr] = len(attr.name()) | ||||
walter.doerwald
|
r255 | try: | ||
walter.doerwald
|
r355 | value = attr.value(item) | ||
walter.doerwald
|
r255 | except (KeyboardInterrupt, SystemExit): | ||
raise | ||||
except Exception, exc: | ||||
value = exc | ||||
vivainio
|
r247 | (align, width, text) = xformat(value, "cell", self.maxattrlength) | ||
walter.doerwald
|
r355 | colwidths[attr] = max(colwidths[attr], width) | ||
vivainio
|
r247 | # remember alignment, length and colored parts | ||
walter.doerwald
|
r355 | row[attr] = (align, width, text) | ||
vivainio
|
r247 | rows.append(row) | ||
stream.write("\n") | ||||
walter.doerwald
|
r355 | for (i, attr) in enumerate(allattrs): | ||
attrname = attr.name() | ||||
self.style_header(attrname).write(stream) | ||||
spc = colwidths[attr] - len(attrname) | ||||
vivainio
|
r247 | if i < len(colwidths)-1: | ||
stream.write(self.headerpadchar*spc) | ||||
stream.write(self.headersepchar) | ||||
stream.write("\n") | ||||
for row in rows: | ||||
walter.doerwald
|
r355 | for (i, attr) in enumerate(allattrs): | ||
(align, width, text) = row[attr] | ||||
spc = colwidths[attr] - width | ||||
vivainio
|
r247 | if align == -1: | ||
text.write(stream) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.datapadchar*spc) | ||||
elif align == 0: | ||||
walter.doerwald
|
r355 | spc = colwidths[attr] - width | ||
vivainio
|
r247 | spc1 = spc//2 | ||
spc2 = spc-spc1 | ||||
stream.write(self.datapadchar*spc1) | ||||
text.write(stream) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.datapadchar*spc2) | ||||
else: | ||||
stream.write(self.datapadchar*spc) | ||||
text.write(stream) | ||||
vivainio
|
r208 | if i < len(colwidths)-1: | ||
vivainio
|
r247 | stream.write(self.datasepchar) | ||
vivainio
|
r208 | stream.write("\n") | ||
walter.doerwald
|
r415 | class AttributeDetail(Table): | ||
vivainio
|
r214 | """ | ||
walter.doerwald
|
r415 | ``AttributeDetail`` objects are use for displaying a detailed list of object | ||
attributes. | ||||
vivainio
|
r214 | """ | ||
walter.doerwald
|
r355 | def __init__(self, object, descriptor): | ||
self.object = object | ||||
self.descriptor = descriptor | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def __iter__(self): | ||
return self.descriptor.iter(self.object) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r355 | def name(self): | ||
return self.descriptor.name() | ||||
def attrtype(self): | ||||
return self.descriptor.attrtype(self.object) | ||||
def valuetype(self): | ||||
return self.descriptor.valuetype(self.object) | ||||
def doc(self): | ||||
return self.descriptor.doc(self.object) | ||||
def shortdoc(self): | ||||
return self.descriptor.shortdoc(self.object) | ||||
def value(self): | ||||
return self.descriptor.value(self.object) | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r415 | def __xattrs__(self, mode="default"): | ||
walter.doerwald
|
r355 | attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()") | ||
if mode == "detail": | ||||
attrs += ("doc()",) | ||||
return attrs | ||||
walter.doerwald
|
r415 | def __xrepr__(self, mode="default"): | ||
walter.doerwald
|
r355 | yield (-1, True) | ||
walter.doerwald
|
r415 | valuetype = self.valuetype() | ||
if valuetype is not noitem: | ||||
for part in xrepr(valuetype): | ||||
yield part | ||||
yield (astyle.style_default, " ") | ||||
walter.doerwald
|
r355 | yield (astyle.style_default, self.attrtype()) | ||
walter.doerwald
|
r415 | yield (astyle.style_default, " ") | ||
walter.doerwald
|
r355 | yield (astyle.style_default, self.name()) | ||
yield (astyle.style_default, " of ") | ||||
for part in xrepr(self.object): | ||||
yield part | ||||
vivainio
|
r208 | |||
walter.doerwald
|
r272 | try: | ||
walter.doerwald
|
r541 | from ibrowse import ibrowse | ||
walter.doerwald
|
r272 | except ImportError: | ||
walter.doerwald
|
r541 | # No curses (probably Windows) | ||
walter.doerwald
|
r534 | try: | ||
walter.doerwald
|
r541 | from igrid import igrid | ||
walter.doerwald
|
r534 | except ImportError: | ||
walter.doerwald
|
r541 | # no wx eithevn do => use ``idump`` as the default display. | ||
walter.doerwald
|
r534 | defaultdisplay = idump | ||
else: | ||||
walter.doerwald
|
r541 | defaultdisplay = igrid | ||
__all__.append("igrid") | ||||
walter.doerwald
|
r272 | else: | ||
walter.doerwald
|
r541 | defaultdisplay = ibrowse | ||
__all__.append("ibrowse") | ||||
vivainio
|
r208 | |||
# If we're running under IPython, install an IPython displayhook that | ||||
# returns the object from Display.display(), else install a displayhook | ||||
# directly as sys.displayhook | ||||
walter.doerwald
|
r276 | api = None | ||
if ipapi is not None: | ||||
try: | ||||
api = ipapi.get() | ||||
except AttributeError: | ||||
pass | ||||
vivainio
|
r208 | |||
if api is not None: | ||||
def displayhook(self, obj): | ||||
if isinstance(obj, type) and issubclass(obj, Table): | ||||
obj = obj() | ||||
if isinstance(obj, Table): | ||||
obj = obj | defaultdisplay | ||||
if isinstance(obj, Display): | ||||
return obj.display() | ||||
else: | ||||
raise ipapi.TryNext | ||||
api.set_hook("result_display", displayhook) | ||||
else: | ||||
def installdisplayhook(): | ||||
_originalhook = sys.displayhook | ||||
def displayhook(obj): | ||||
if isinstance(obj, type) and issubclass(obj, Table): | ||||
obj = obj() | ||||
if isinstance(obj, Table): | ||||
obj = obj | defaultdisplay | ||||
if isinstance(obj, Display): | ||||
return obj.display() | ||||
else: | ||||
_originalhook(obj) | ||||
sys.displayhook = displayhook | ||||
installdisplayhook() | ||||