ipipe.py
1841 lines
| 59.3 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: | ||||
vivainio
|
r220 | * ``Table``s: These objects produce items. Examples are ``ls`` (listing the | ||
vivainio
|
r208 | current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing | ||
vivainio
|
r209 | user account) and ``igrp`` (listing user groups). A ``Table`` must be the | ||
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 | ||||
vivainio
|
r220 | display objects will be used. One example is ``browse`` 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 | ||||
implement the method ``__xattrs__(self, mode)``. This method must return a | ||||
sequence of attribute names. This sequence may also contain integers, which | ||||
will be treated as sequence indizes. Also supported is ``None``, which uses | ||||
the object itself and callables which will be called with the object as the | ||||
an argument. If ``__xattrs__()`` isn't implemented ``(None,)`` will be used as | ||||
the attribute sequence (i.e. the object itself (it's ``repr()`` format) will | ||||
be being displayed. The global function ``xattrs()`` implements this | ||||
functionality. | ||||
vivainio
|
r225 | * When an object ``foo`` is displayed in the header, footer or table cell of the | ||
browser ``foo.__xrepr__(mode)`` is called. Mode can be ``"header"`` or | ||||
``"footer"`` for the header or footer line and ``"cell"`` for a table cell. | ||||
``__xrepr__()```must return an iterable (e.g. by being a generator) which | ||||
produces the following items: The first item should be a tuple containing | ||||
the alignment (-1 left aligned, 0 centered and 1 right aligned) and whether | ||||
the complete output must be displayed or if the browser 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 other output ``__xrepr__()`` | ||||
may produce is tuples of ``Style```objects and text (which contain the text | ||||
walter.doerwald
|
r269 | representation of the object; see the ``astyle`` module). If ``__xrepr__()`` | ||
recursively outputs a data structure the function ``xrepr(object, mode)`` can | ||||
be used and ``"default"`` must be passed as the mode in these calls. This in | ||||
turn calls the ``__xrepr__()`` method on ``object`` (or uses ``repr(object)`` | ||||
as the string representation if ``__xrepr__()`` doesn't exist). | ||||
vivainio
|
r214 | |||
* Objects that can be iterated by ``Pipe``s must implement the method | ||||
``__xiter__(self, mode)``. ``mode`` can take the following values: | ||||
- ``"default"``: This is the default value and ist always used by pipeline | ||||
expressions. Other values are only used in the browser. | ||||
- ``None``: This value is passed by the browser. The object must return an | ||||
iterable of ``XMode`` objects describing all modes supported by the object. | ||||
(This should never include ``"default"`` or ``None``). | ||||
- Any other value that the object supports. | ||||
The global function ``xiter()`` can be called to get such an iterator. If | ||||
the method ``_xiter__`` isn't implemented, ``xiter()`` falls back to | ||||
``__iter__``. In addition to that, dictionaries and modules receive special | ||||
treatment (returning an iterator over ``(key, value)`` pairs). This makes it | ||||
possible to use dictionaries and modules in pipeline expressions, for example: | ||||
>>> 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 | ||||
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. | ||||
""" | ||||
code = compile(codestring, "_eval", "eval") | ||||
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
|
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 | ||||
end (i.e. the last item produced by the iterator)). | ||||
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): | ||
if g is None: | ||||
if ipapi is not None: | ||||
fperez
|
r284 | return ipapi.get().user_ns | ||
walter.doerwald
|
r276 | else: | ||
return globals() | ||||
return g | ||||
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) | ||||
def __iter__(self): | ||||
return xiter(self, "default") | ||||
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
|
r274 | def _getattr(obj, name, default=noitem): | ||
vivainio
|
r208 | """ | ||
Internal helper for getting an attribute of an item. If ``name`` is ``None`` | ||||
return the object itself. If ``name`` is an integer, use ``__getitem__`` | ||||
instead. If the attribute or item does not exist, return ``default``. | ||||
""" | ||||
if name is None: | ||||
return obj | ||||
elif isinstance(name, basestring): | ||||
vivainio
|
r237 | if name.endswith("()"): | ||
return getattr(obj, name[:-2], default)() | ||||
else: | ||||
return getattr(obj, name, default) | ||||
vivainio
|
r208 | elif callable(name): | ||
vivainio
|
r231 | try: | ||
return name(obj) | ||||
except AttributeError: | ||||
return default | ||||
vivainio
|
r208 | else: | ||
try: | ||||
return obj[name] | ||||
except IndexError: | ||||
return default | ||||
def _attrname(name): | ||||
""" | ||||
Internal helper that gives a proper name for the attribute ``name`` | ||||
(which might be ``None`` or an ``int``). | ||||
""" | ||||
if name is None: | ||||
return "_" | ||||
elif isinstance(name, basestring): | ||||
return name | ||||
elif callable(name): | ||||
walter.doerwald
|
r254 | return getattr(name, "__xname__", name.__name__) | ||
vivainio
|
r208 | else: | ||
return str(name) | ||||
def xrepr(item, mode): | ||||
try: | ||||
func = item.__xrepr__ | ||||
vivainio
|
r214 | except AttributeError: | ||
vivainio
|
r225 | pass | ||
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)) | ||
vivainio
|
r225 | return | ||
if item is None: | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_none, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, bool): | ||
walter.doerwald
|
r269 | yield (astyle.style_type_bool, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, str): | ||
if mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item.expandtabs(tab))[1:-1]) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, unicode): | ||
if mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item.expandtabs(tab))[2:-1]) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, (int, long, float)): | ||
yield (1, True) | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_number, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, complex): | ||
walter.doerwald
|
r269 | yield (astyle.style_type_number, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, datetime.datetime): | ||
if mode == "cell": | ||||
# Don't use strftime() here, as this requires year >= 1900 | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, | ||
vivainio
|
r225 | "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | ||
(item.year, item.month, item.day, | ||||
item.hour, item.minute, item.second, | ||||
item.microsecond), | ||||
) | ||||
else: | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, datetime.date): | ||
if mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, | ||
vivainio
|
r225 | "%04d-%02d-%02d" % (item.year, item.month, item.day)) | ||
else: | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, datetime.time): | ||
if mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, | ||
vivainio
|
r225 | "%02d:%02d:%02d.%06d" % \ | ||
(item.hour, item.minute, item.second, item.microsecond)) | ||||
else: | ||||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, datetime.timedelta): | ||
walter.doerwald
|
r269 | yield (astyle.style_type_datetime, repr(item)) | ||
vivainio
|
r225 | elif isinstance(item, Exception): | ||
if item.__class__.__module__ == "exceptions": | ||||
classname = item.__class__.__name__ | ||||
else: | ||||
walter.doerwald
|
r262 | classname = "%s.%s" % \ | ||
vivainio
|
r225 | (item.__class__.__module__, item.__class__.__name__) | ||
if mode == "header" or mode == "footer": | ||||
walter.doerwald
|
r269 | yield (astyle.style_error, "%s: %s" % (classname, item)) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_error, classname) | ||
vivainio
|
r225 | elif isinstance(item, (list, tuple)): | ||
if mode == "header" or mode == "footer": | ||||
if item.__class__.__module__ == "__builtin__": | ||||
classname = item.__class__.__name__ | ||||
else: | ||||
classname = "%s.%s" % \ | ||||
(item.__class__.__module__,item.__class__.__name__) | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, | ||
vivainio
|
r225 | "<%s object with %d items at 0x%x>" % \ | ||
(classname, len(item), id(item))) | ||||
else: | ||||
walter.doerwald
|
r279 | yield (-1, False) | ||
vivainio
|
r225 | if isinstance(item, list): | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "[") | ||
vivainio
|
r225 | end = "]" | ||
else: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, "(") | ||
vivainio
|
r225 | end = ")" | ||
for (i, subitem) in enumerate(item): | ||||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
vivainio
|
r225 | for part in xrepr(subitem, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, end) | ||
vivainio
|
r225 | elif isinstance(item, (dict, types.DictProxyType)): | ||
if mode == "header" or mode == "footer": | ||||
if item.__class__.__module__ == "__builtin__": | ||||
classname = item.__class__.__name__ | ||||
else: | ||||
classname = "%s.%s" % \ | ||||
(item.__class__.__module__,item.__class__.__name__) | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, | ||
vivainio
|
r225 | "<%s object with %d items at 0x%x>" % \ | ||
(classname, len(item), id(item))) | ||||
else: | ||||
walter.doerwald
|
r279 | yield (-1, False) | ||
vivainio
|
r225 | if isinstance(item, dict): | ||
walter.doerwald
|
r269 | yield (astyle.style_default, "{") | ||
vivainio
|
r225 | end = "}" | ||
else: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, "dictproxy((") | ||
vivainio
|
r225 | end = "})" | ||
for (i, (key, value)) in enumerate(item.iteritems()): | ||||
if i: | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ", ") | ||
vivainio
|
r225 | for part in xrepr(key, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, ": ") | ||
vivainio
|
r225 | for part in xrepr(value, "default"): | ||
yield part | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, end) | ||
vivainio
|
r225 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(item)) | ||
vivainio
|
r208 | |||
def xattrs(item, mode): | ||||
try: | ||||
func = item.__xattrs__ | ||||
except AttributeError: | ||||
vivainio
|
r252 | if mode == "detail": | ||
return dir(item) | ||||
else: | ||||
return (None,) | ||||
vivainio
|
r208 | else: | ||
vivainio
|
r231 | try: | ||
return func(mode) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception: | ||||
return (None,) | ||||
vivainio
|
r208 | |||
def xiter(item, mode): | ||||
if mode == "detail": | ||||
def items(): | ||||
for name in xattrs(item, mode): | ||||
yield XAttr(item, name) | ||||
return items() | ||||
try: | ||||
func = item.__xiter__ | ||||
except AttributeError: | ||||
vivainio
|
r225 | if isinstance(item, (dict, types.DictProxyType)): | ||
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) | ||
elif isinstance(item, basestring): | ||||
if not len(item): | ||||
raise ValueError("can't enter empty string") | ||||
lines = item.splitlines() | ||||
if len(lines) <= 1: | ||||
raise ValueError("can't enter one line string") | ||||
return iter(lines) | ||||
return iter(item) | ||||
else: | ||||
return iter(func(mode)) # iter() just to be safe | ||||
class ichain(Pipe): | ||||
""" | ||||
Chains multiple ``Table``s into one. | ||||
""" | ||||
def __init__(self, *iters): | ||||
self.iters = iters | ||||
def __xiter__(self, mode): | ||||
return itertools.chain(*self.iters) | ||||
def __xrepr__(self, mode): | ||||
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 | |||
vivainio
|
r237 | def __add_(self, other): | ||
return ifile(path._base(self) + other) | ||||
vivainio
|
r208 | |||
vivainio
|
r237 | def __radd_(self, other): | ||
return ifile(other + path._base(self)) | ||||
def __div_(self, other): | ||||
return ifile(path.__div__(self, other)) | ||||
def getcwd(): | ||||
return ifile(path.path.getcwd()) | ||||
walter.doerwald
|
r275 | getcwd.__doc__ = path.path.getcwd.__doc__ | ||
vivainio
|
r237 | getcwd = staticmethod(getcwd) | ||
def abspath(self): | ||||
return ifile(path.path.abspath(self)) | ||||
walter.doerwald
|
r275 | abspath.__doc__ = path.path.abspath.__doc__ | ||
vivainio
|
r237 | |||
def normcase(self): | ||||
return ifile(path.path.normcase(self)) | ||||
walter.doerwald
|
r275 | normcase.__doc__ = path.path.normcase.__doc__ | ||
vivainio
|
r237 | |||
def normpath(self): | ||||
return ifile(path.path.normpath(self)) | ||||
walter.doerwald
|
r275 | normpath.__doc__ = path.path.normpath.__doc__ | ||
vivainio
|
r237 | |||
def realpath(self): | ||||
return ifile(path.path.realpath(self)) | ||||
walter.doerwald
|
r275 | realpath.__doc__ = path.path.realpath.__doc__ | ||
vivainio
|
r237 | |||
def expanduser(self): | ||||
return ifile(path.path.expanduser(self)) | ||||
walter.doerwald
|
r275 | expanduser.__doc__ = path.path.expanduser.__doc__ | ||
vivainio
|
r237 | |||
def expandvars(self): | ||||
return ifile(path.path.expandvars(self)) | ||||
walter.doerwald
|
r275 | expandvars.__doc__ = path.path.expandvars.__doc__ | ||
vivainio
|
r237 | |||
def dirname(self): | ||||
return ifile(path.path.dirname(self)) | ||||
walter.doerwald
|
r275 | dirname.__doc__ = path.path.dirname.__doc__ | ||
vivainio
|
r237 | |||
parent = property(dirname, None, None, path.path.parent.__doc__) | ||||
def splitpath(self): | ||||
(parent, child) = path.path.splitpath(self) | ||||
return (ifile(parent), child) | ||||
walter.doerwald
|
r275 | splitpath.__doc__ = path.path.splitpath.__doc__ | ||
vivainio
|
r237 | |||
def splitdrive(self): | ||||
(drive, rel) = path.path.splitdrive(self) | ||||
return (ifile(drive), rel) | ||||
walter.doerwald
|
r275 | splitdrive.__doc__ = path.path.splitdrive.__doc__ | ||
vivainio
|
r237 | |||
def splitext(self): | ||||
(filename, ext) = path.path.splitext(self) | ||||
return (ifile(filename), ext) | ||||
walter.doerwald
|
r275 | splitext.__doc__ = path.path.splitext.__doc__ | ||
vivainio
|
r237 | |||
if hasattr(path.path, "splitunc"): | ||||
def splitunc(self): | ||||
(unc, rest) = path.path.splitunc(self) | ||||
return (ifile(unc), rest) | ||||
walter.doerwald
|
r275 | splitunc.__doc__ = path.path.splitunc.__doc__ | ||
vivainio
|
r237 | |||
def _get_uncshare(self): | ||||
unc, r = os.path.splitunc(self) | ||||
return ifile(unc) | ||||
uncshare = property( | ||||
_get_uncshare, None, None, | ||||
""" The UNC mount point for this path. | ||||
This is empty for paths on local drives. """) | ||||
def joinpath(self, *args): | ||||
return ifile(path.path.joinpath(self, *args)) | ||||
walter.doerwald
|
r275 | joinpath.__doc__ = path.path.joinpath.__doc__ | ||
vivainio
|
r237 | |||
def splitall(self): | ||||
return map(ifile, path.path.splitall(self)) | ||||
walter.doerwald
|
r275 | splitall.__doc__ = path.path.splitall.__doc__ | ||
vivainio
|
r237 | |||
def relpath(self): | ||||
return ifile(path.path.relpath(self)) | ||||
walter.doerwald
|
r275 | relpath.__doc__ = path.path.relpath.__doc__ | ||
vivainio
|
r237 | |||
def relpathto(self, dest): | ||||
return ifile(path.path.relpathto(self, dest)) | ||||
walter.doerwald
|
r275 | relpathto.__doc__ = path.path.relpathto.__doc__ | ||
vivainio
|
r237 | |||
def listdir(self, pattern=None): | ||||
return [ifile(child) for child in path.path.listdir(self, pattern)] | ||||
walter.doerwald
|
r275 | listdir.__doc__ = path.path.listdir.__doc__ | ||
vivainio
|
r237 | |||
def dirs(self, pattern=None): | ||||
return [ifile(child) for child in path.path.dirs(self, pattern)] | ||||
walter.doerwald
|
r275 | dirs.__doc__ = path.path.dirs.__doc__ | ||
vivainio
|
r237 | |||
def files(self, pattern=None): | ||||
return [ifile(child) for child in path.path.files(self, pattern)] | ||||
walter.doerwald
|
r275 | files.__doc__ = path.path.files.__doc__ | ||
vivainio
|
r237 | |||
def walk(self, pattern=None): | ||||
for child in path.path.walk(self, pattern): | ||||
yield ifile(child) | ||||
walter.doerwald
|
r275 | walk.__doc__ = path.path.walk.__doc__ | ||
vivainio
|
r237 | |||
def walkdirs(self, pattern=None): | ||||
for child in path.path.walkdirs(self, pattern): | ||||
yield ifile(child) | ||||
walter.doerwald
|
r275 | walkdirs.__doc__ = path.path.walkdirs.__doc__ | ||
vivainio
|
r237 | |||
def walkfiles(self, pattern=None): | ||||
for child in path.path.walkfiles(self, pattern): | ||||
yield ifile(child) | ||||
walter.doerwald
|
r275 | walkfiles.__doc__ = path.path.walkfiles.__doc__ | ||
vivainio
|
r237 | |||
def glob(self, pattern): | ||||
return map(ifile, path.path.glob(self, pattern)) | ||||
walter.doerwald
|
r275 | glob.__doc__ = path.path.glob.__doc__ | ||
vivainio
|
r237 | |||
if hasattr(os, 'readlink'): | ||||
def readlink(self): | ||||
return ifile(path.path.readlink(self)) | ||||
walter.doerwald
|
r275 | readlink.__doc__ = path.path.readlink.__doc__ | ||
vivainio
|
r237 | |||
def readlinkabs(self): | ||||
return ifile(path.path.readlinkabs(self)) | ||||
walter.doerwald
|
r275 | readlinkabs.__doc__ = path.path.readlinkabs.__doc__ | ||
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") | ||||
def getmimetype(self): | ||||
vivainio
|
r237 | return mimetypes.guess_type(self.basename())[0] | ||
vivainio
|
r208 | mimetype = property(getmimetype, None, None, "MIME type") | ||
def getencoding(self): | ||||
vivainio
|
r237 | return mimetypes.guess_type(self.basename())[1] | ||
vivainio
|
r208 | encoding = property(getencoding, None, None, "Compression") | ||
vivainio
|
r237 | def __repr__(self): | ||
return "ifile(%s)" % path._base.__repr__(self) | ||||
vivainio
|
r208 | |||
vivainio
|
r237 | defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate") | ||
vivainio
|
r208 | |||
def __xattrs__(self, mode): | ||||
if mode == "detail": | ||||
vivainio
|
r209 | return ( | ||
vivainio
|
r237 | "name", "basename()", "abspath()", "realpath()", | ||
"type", "mode", "modestr", "stat()", "lstat()", | ||||
vivainio
|
r209 | "uid", "gid", "owner", "group", "dev", "nlink", | ||
"ctime", "mtime", "atime", "cdate", "mdate", "adate", | ||||
vivainio
|
r237 | "size", "blocks", "blksize", "isdir()", "islink()", | ||
vivainio
|
r209 | "mimetype", "encoding" | ||
) | ||||
vivainio
|
r237 | return self.defaultattrs | ||
vivainio
|
r208 | |||
def __xrepr__(self, mode): | ||||
vivainio
|
r237 | try: | ||
if self.isdir(): | ||||
name = "idir" | ||||
walter.doerwald
|
r269 | style = astyle.style_dir | ||
vivainio
|
r237 | else: | ||
name = "ifile" | ||||
walter.doerwald
|
r269 | style = astyle.style_file | ||
vivainio
|
r237 | except IOError: | ||
vivainio
|
r208 | name = "ifile" | ||
walter.doerwald
|
r269 | style = astyle.style_default | ||
vivainio
|
r237 | if mode == "cell" or mode in "header" or mode == "footer": | ||
vivainio
|
r240 | abspath = repr(path._base(self.normpath())) | ||
vivainio
|
r237 | if abspath.startswith("u"): | ||
abspath = abspath[2:-1] | ||||
else: | ||||
abspath = abspath[1:-1] | ||||
if mode == "cell": | ||||
yield (style, abspath) | ||||
else: | ||||
yield (style, "%s(%s)" % (name, abspath)) | ||||
vivainio
|
r225 | else: | ||
vivainio
|
r237 | yield (style, repr(self)) | ||
vivainio
|
r208 | |||
def __xiter__(self, mode): | ||||
vivainio
|
r237 | if self.isdir(): | ||
yield iparentdir(self / os.pardir) | ||||
for child in sorted(self.listdir()): | ||||
yield child | ||||
vivainio
|
r208 | else: | ||
f = self.open("rb") | ||||
for line in f: | ||||
yield line | ||||
f.close() | ||||
class iparentdir(ifile): | ||||
vivainio
|
r237 | def __xrepr__(self, mode): | ||
if mode == "cell": | ||||
walter.doerwald
|
r269 | yield (astyle.style_dir, os.pardir) | ||
vivainio
|
r237 | else: | ||
for part in ifile.__xrepr__(self, mode): | ||||
yield part | ||||
vivainio
|
r208 | |||
class ils(Table): | ||||
vivainio
|
r215 | """ | ||
walter.doerwald
|
r261 | List the current (or a specific) directory. | ||
Examples: | ||||
>>> ils | ||||
>>> ils("/usr/local/lib/python2.4") | ||||
>>> ils("~") | ||||
vivainio
|
r215 | """ | ||
vivainio
|
r208 | def __init__(self, base=os.curdir): | ||
self.base = os.path.expanduser(base) | ||||
def __xiter__(self, mode): | ||||
return xiter(ifile(self.base), mode) | ||||
def __xrepr__(self, mode): | ||||
vivainio
|
r237 | return ifile(self.base).__xrepr__(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 | ||||
def __xiter__(self, mode): | ||||
for name in glob.glob(self.glob): | ||||
yield ifile(name) | ||||
def __xrepr__(self, mode): | ||||
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 | ||||
def __xiter__(self, mode): | ||||
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)) | ||||
def __xrepr__(self, mode): | ||||
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 | ||||
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") | ||||
def __xattrs__(self, mode): | ||||
return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell") | ||||
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) | ||||
def __xrepr__(self, mode): | ||||
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 | ||||
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") | ||||
def __xattrs__(self, mode): | ||||
return ("name", "passwd", "gid", "mem") | ||||
def __xrepr__(self, mode): | ||||
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 | |||
def __xiter__(self, mode): | ||||
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. | ||||
""" | ||||
vivainio
|
r208 | def __xiter__(self, mode): | ||
for entry in grp.getgrall(): | ||||
yield igrpentry(entry.gr_name) | ||||
def __xrepr__(self, mode): | ||||
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): | ||||
self.__fieldnames = fieldnames | ||||
for (key, value) in fields.iteritems(): | ||||
setattr(self, key, value) | ||||
vivainio
|
r208 | |||
def __xattrs__(self, mode): | ||||
vivainio
|
r209 | return self.__fieldnames | ||
vivainio
|
r208 | |||
vivainio
|
r209 | def __xrepr__(self, mode): | ||
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, ", ") | ||
yield (astyle.style_default, f) | ||||
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, ", ") | ||
yield (astyle.style_default, f) | ||||
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 | |||
def __xiter__(self, mode): | ||||
vivainio
|
r209 | return list.__iter__(self) | ||
def __xrepr__(self, mode): | ||||
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): | ||
def __xattrs__(self, mode): | ||||
return xrange(len(self)) | ||||
def __xrepr__(self, mode): | ||||
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 | """ | ||
vivainio
|
r208 | def __xiter__(self, mode): | ||
vivainio
|
r209 | fields = ("key", "value") | ||
for (key, value) in os.environ.iteritems(): | ||||
yield Fields(fields, key=key, value=value) | ||||
vivainio
|
r208 | |||
def __xrepr__(self, mode): | ||||
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 | ||
def __xiter__(self, mode): | ||||
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 | |||
def __xrepr__(self, mode): | ||||
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 | ||||
self._pipe = None | ||||
def __xiter__(self, mode): | ||||
self._pipe = os.popen(self.cmd) | ||||
for l in self._pipe: | ||||
yield l.rstrip("\r\n") | ||||
vivainio
|
r209 | self._pipe.close() | ||
self._pipe = None | ||||
vivainio
|
r208 | |||
def __del__(self): | ||||
if self._pipe is not None and not self._pipe.closed: | ||||
self._pipe.close() | ||||
self._pipe = None | ||||
def __xrepr__(self, mode): | ||||
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 | |||
def __xiter__(self, mode): | ||||
if callable(self.expr): | ||||
vivainio
|
r232 | def test(item): | ||
return self.expr(item) | ||||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
vivainio
|
r232 | def test(item): | ||
walter.doerwald
|
r276 | return eval(self.expr, g, AttrNamespace(item)) | ||
vivainio
|
r232 | |||
ok = 0 | ||||
exc_info = None | ||||
for item in xiter(self.input, mode): | ||||
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 | |||
def __xrepr__(self, mode): | ||||
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 | |||
def __xiter__(self, mode): | ||||
if callable(self.expr): | ||||
vivainio
|
r232 | def do(item): | ||
return self.expr(item) | ||||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
vivainio
|
r232 | def do(item): | ||
walter.doerwald
|
r276 | return eval(self.expr, g, AttrNamespace(item)) | ||
vivainio
|
r232 | |||
ok = 0 | ||||
exc_info = None | ||||
for item in xiter(self.input, mode): | ||||
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 | |||
def __xrepr__(self, mode): | ||||
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") | ||||
""" | ||||
vivainio
|
r208 | def __xiter__(self, mode): | ||
vivainio
|
r209 | fields = ("index", "object") | ||
vivainio
|
r208 | for (index, object) in enumerate(xiter(self.input, mode)): | ||
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
|
r276 | def __init__(self, key, globals=None, reverse=False): | ||
vivainio
|
r215 | """ | ||
Create an ``isort`` object. ``key`` can be a callable or a string | ||||
containing an expression. If ``reverse`` is true the sort order will | ||||
walter.doerwald
|
r276 | 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 | ||
def __xiter__(self, mode): | ||||
if callable(self.key): | ||||
vivainio
|
r209 | items = sorted( | ||
xiter(self.input, mode), | ||||
key=self.key, | ||||
reverse=self.reverse | ||||
) | ||||
vivainio
|
r208 | else: | ||
walter.doerwald
|
r276 | g = getglobals(self.globals) | ||
vivainio
|
r208 | def key(item): | ||
walter.doerwald
|
r276 | return eval(self.key, g, AttrNamespace(item)) | ||
vivainio
|
r209 | items = sorted( | ||
xiter(self.input, mode), | ||||
key=key, | ||||
reverse=self.reverse | ||||
) | ||||
vivainio
|
r208 | for item in items: | ||
yield item | ||||
def __xrepr__(self, mode): | ||||
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: | ||||
for item in xiter(self.input, "default"): | ||||
attrs = xattrs(item, "default") | ||||
vivainio
|
r209 | attrs = ["%s=%s" % (a, _format(_getattr(item, a))) for a in attrs] | ||
pager.write(" ".join(attrs)) | ||||
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): | ||
self.attrs = attrs | ||||
self.headerpadchar = " " | ||||
self.headersepchar = "|" | ||||
self.datapadchar = " " | ||||
self.datasepchar = "|" | ||||
def display(self): | ||||
vivainio
|
r247 | stream = genutils.Term.cout | ||
allattrs = [] | ||||
allattrset = set() | ||||
colwidths = {} | ||||
rows = [] | ||||
for item in xiter(self.input, "default"): | ||||
row = {} | ||||
vivainio
|
r250 | attrs = self.attrs | ||
if not attrs: | ||||
vivainio
|
r208 | attrs = xattrs(item, "default") | ||
vivainio
|
r247 | for attrname in attrs: | ||
if attrname not in allattrset: | ||||
allattrs.append(attrname) | ||||
allattrset.add(attrname) | ||||
colwidths[attrname] = len(_attrname(attrname)) | ||||
walter.doerwald
|
r255 | try: | ||
value = _getattr(item, attrname, None) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
value = exc | ||||
vivainio
|
r247 | (align, width, text) = xformat(value, "cell", self.maxattrlength) | ||
colwidths[attrname] = max(colwidths[attrname], width) | ||||
# remember alignment, length and colored parts | ||||
row[attrname] = (align, width, text) | ||||
rows.append(row) | ||||
stream.write("\n") | ||||
for (i, attrname) in enumerate(allattrs): | ||||
self.style_header(_attrname(attrname)).write(stream) | ||||
spc = colwidths[attrname] - len(_attrname(attrname)) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.headerpadchar*spc) | ||||
stream.write(self.headersepchar) | ||||
stream.write("\n") | ||||
for row in rows: | ||||
vivainio
|
r208 | for (i, attrname) in enumerate(allattrs): | ||
vivainio
|
r247 | (align, width, text) = row[attrname] | ||
spc = colwidths[attrname] - width | ||||
if align == -1: | ||||
text.write(stream) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.datapadchar*spc) | ||||
elif align == 0: | ||||
spc = colwidths[attrname] - width | ||||
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") | ||
class XMode(object): | ||||
vivainio
|
r214 | """ | ||
An ``XMode`` object describes one enter mode available for an object | ||||
""" | ||||
vivainio
|
r208 | def __init__(self, object, mode, title=None, description=None): | ||
vivainio
|
r214 | """ | ||
Create a new ``XMode`` object for the object ``object``. This object | ||||
must support the enter mode ``mode`` (i.e. ``object.__xiter__(mode)`` | ||||
must return an iterable). ``title`` and ``description`` will be | ||||
displayed in the browser when selecting among the available modes. | ||||
""" | ||||
vivainio
|
r208 | self.object = object | ||
self.mode = mode | ||||
self.title = title | ||||
self.description = description | ||||
def __repr__(self): | ||||
vivainio
|
r209 | return "<%s.%s object mode=%r at 0x%x>" % \ | ||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.mode, id(self)) | ||||
vivainio
|
r208 | |||
def __xrepr__(self, mode): | ||||
if mode == "header" or mode == "footer": | ||||
walter.doerwald
|
r269 | yield (astyle.style_default, self.title) | ||
vivainio
|
r230 | else: | ||
walter.doerwald
|
r269 | yield (astyle.style_default, repr(self)) | ||
vivainio
|
r208 | |||
def __xattrs__(self, mode): | ||||
if mode == "detail": | ||||
return ("object", "mode", "title", "description") | ||||
return ("title", "description") | ||||
def __xiter__(self, mode): | ||||
return xiter(self.object, self.mode) | ||||
class XAttr(object): | ||||
def __init__(self, object, name): | ||||
self.name = _attrname(name) | ||||
try: | ||||
self.value = _getattr(object, name) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
if exc.__class__.__module__ == "exceptions": | ||||
self.value = exc.__class__.__name__ | ||||
else: | ||||
vivainio
|
r209 | self.value = "%s.%s" % \ | ||
(exc.__class__.__module__, exc.__class__.__name__) | ||||
vivainio
|
r208 | self.type = self.value | ||
else: | ||||
t = type(self.value) | ||||
if t.__module__ == "__builtin__": | ||||
self.type = t.__name__ | ||||
else: | ||||
self.type = "%s.%s" % (t.__module__, t.__name__) | ||||
doc = None | ||||
if isinstance(name, basestring): | ||||
vivainio
|
r237 | if name.endswith("()"): | ||
doc = getattr(getattr(object, name[:-2]), "__doc__", None) | ||||
vivainio
|
r208 | else: | ||
vivainio
|
r237 | try: | ||
meta = getattr(type(object), name) | ||||
except AttributeError: | ||||
pass | ||||
else: | ||||
if isinstance(meta, property): | ||||
doc = getattr(meta, "__doc__", None) | ||||
vivainio
|
r208 | elif callable(name): | ||
vivainio
|
r237 | doc = getattr(name, "__doc__", None) | ||
vivainio
|
r238 | if isinstance(doc, basestring): | ||
doc = doc.strip() | ||||
vivainio
|
r237 | self.doc = doc | ||
vivainio
|
r208 | |||
def __xattrs__(self, mode): | ||||
return ("name", "type", "doc", "value") | ||||
walter.doerwald
|
r272 | try: | ||
from ibrowse import ibrowse | ||||
except ImportError: | ||||
vivainio
|
r214 | # No curses (probably Windows) => use ``idump`` as the default display. | ||
vivainio
|
r208 | defaultdisplay = idump | ||
walter.doerwald
|
r272 | else: | ||
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() | ||||