ipipe.py
2292 lines
| 68.7 KiB
| text/x-python
|
PythonLexer
ville
|
r988 | # -*- 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:: | ||||
>>> ienv | isort("key.lower()") | ||||
This gives a listing of all environment variables sorted by name. | ||||
There are three types of objects in a pipeline expression: | ||||
* ``Table``s: These objects produce items. Examples are ``ils`` (listing the | ||||
current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing | ||||
user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the | ||||
first object in a pipe expression. | ||||
* ``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). | ||||
* ``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 | ||||
display objects will be used. One example is ``ibrowse`` which is a ``curses`` | ||||
based browser. | ||||
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)`` 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:: | ||||
>>> import sys | ||||
>>> sys | ifilter("isinstance(value, int)") | idump | ||||
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 | ||||
refer to the object to be filtered or sorted via the variable ``_`` and to any | ||||
of the attributes of the object, i.e.:: | ||||
>>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()") | ||||
does the same as:: | ||||
>>> 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 | ||||
""" | ||||
import sys, os, os.path, stat, glob, new, csv, datetime, types | ||||
import itertools, mimetypes, StringIO | ||||
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 | ||||
from IPython.external import simplegeneric | ||||
import path | ||||
try: | ||||
from IPython import genutils, generics | ||||
except ImportError: | ||||
genutils = None | ||||
generics = None | ||||
from IPython import ipapi | ||||
__all__ = [ | ||||
"ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp", | ||||
"icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum", | ||||
"ienv", "ihist", "ialias", "icap", "idump", "iless" | ||||
] | ||||
os.stat_float_times(True) # enable microseconds | ||||
class AttrNamespace(object): | ||||
""" | ||||
Helper class that is used for providing a namespace for evaluating | ||||
expressions containing attribute names of an object. | ||||
""" | ||||
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 | ||||
# 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 | ||||
try: | ||||
eval("_", None, AttrNamespace(None)) | ||||
except TypeError: | ||||
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. | ||||
""" | ||||
if isinstance(codestring, basestring): | ||||
code = compile(codestring, "_eval", "eval") | ||||
else: | ||||
code = codestring | ||||
newlocals = {} | ||||
for name in code.co_names: | ||||
try: | ||||
newlocals[name] = _locals[name] | ||||
except KeyError: | ||||
pass | ||||
return real_eval(code, _globals, newlocals) | ||||
noitem = object() | ||||
def item(iterator, index, default=noitem): | ||||
""" | ||||
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 items 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() | ||||
if default is noitem: | ||||
raise IndexError(index) | ||||
else: | ||||
return default | ||||
def getglobals(g): | ||||
""" | ||||
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. | ||||
""" | ||||
if g is None: | ||||
if ipapi is not None: | ||||
api = ipapi.get() | ||||
if api is not None: | ||||
return api.user_ns | ||||
return globals() | ||||
return g | ||||
class Descriptor(object): | ||||
""" | ||||
A ``Descriptor`` object is used for describing the attributes of objects. | ||||
""" | ||||
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): | ||||
""" | ||||
Return the name of this attribute for display by a ``Display`` object | ||||
(e.g. as a column title). | ||||
""" | ||||
key = self.key() | ||||
if key is None: | ||||
return "_" | ||||
return str(key) | ||||
def attrtype(self, obj): | ||||
""" | ||||
Return the type of this attribute (i.e. something like "attribute" or | ||||
"method"). | ||||
""" | ||||
def valuetype(self, obj): | ||||
""" | ||||
Return the type of this attribute value of the object ``obj``. | ||||
""" | ||||
def value(self, obj): | ||||
""" | ||||
Return the value of this attribute of the object ``obj``. | ||||
""" | ||||
def doc(self, obj): | ||||
""" | ||||
Return the documentation for this attribute. | ||||
""" | ||||
def shortdoc(self, obj): | ||||
""" | ||||
Return a short documentation for this attribute (defaulting to the | ||||
first line). | ||||
""" | ||||
doc = self.doc(obj) | ||||
if doc is not None: | ||||
doc = doc.strip().splitlines()[0].strip() | ||||
return doc | ||||
def iter(self, obj): | ||||
""" | ||||
Return an iterator for this attribute of the object ``obj``. | ||||
""" | ||||
return xiter(self.value(obj)) | ||||
class SelfDescriptor(Descriptor): | ||||
""" | ||||
A ``SelfDescriptor`` describes the object itself. | ||||
""" | ||||
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): | ||||
""" | ||||
An ``AttributeDescriptor`` describes a simple attribute of an object. | ||||
""" | ||||
__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): | ||||
""" | ||||
An ``IndexDescriptor`` describes an "attribute" of an object that is fetched | ||||
via ``__getitem__``. | ||||
""" | ||||
__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): | ||||
""" | ||||
A ``MethodDescriptor`` describes a method of an object that can be called | ||||
without argument. Note that this method shouldn't change the object. | ||||
""" | ||||
__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): | ||||
""" | ||||
An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but | ||||
doesn't return an attribute values (because this value might be e.g. a large | ||||
list). | ||||
""" | ||||
__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): | ||||
""" | ||||
An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't | ||||
return an attribute values (because this value might be e.g. a large list). | ||||
""" | ||||
__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): | ||||
""" | ||||
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. | ||||
""" | ||||
__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) | ||||
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). | ||||
""" | ||||
# 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 | ||||
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): | ||||
# autoinstantiate right hand side | ||||
if isinstance(other, type) and issubclass(other, (Table, Display)): | ||||
other = other() | ||||
# treat simple strings and functions as ``ieval`` instances | ||||
elif not isinstance(other, Display) and not isinstance(other, Table): | ||||
other = ieval(other) | ||||
# forward operations to the right hand side | ||||
return other.__ror__(self) | ||||
def __add__(self, other): | ||||
# autoinstantiate right hand side | ||||
if isinstance(other, type) and issubclass(other, Table): | ||||
other = other() | ||||
return ichain(self, other) | ||||
def __radd__(self, other): | ||||
# autoinstantiate left hand side | ||||
if isinstance(other, type) and issubclass(other, Table): | ||||
other = other() | ||||
return ichain(other, self) | ||||
class Pipe(Table): | ||||
""" | ||||
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. | ||||
""" | ||||
class __metaclass__(Table.__metaclass__): | ||||
def __ror__(self, input): | ||||
return input | self() | ||||
def __ror__(self, input): | ||||
# autoinstantiate left hand side | ||||
if isinstance(input, type) and issubclass(input, Table): | ||||
input = input() | ||||
self.input = input | ||||
return self | ||||
def xrepr(item, mode="default"): | ||||
""" | ||||
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. | ||||
""" | ||||
try: | ||||
func = item.__xrepr__ | ||||
except AttributeError: | ||||
yield (astyle.style_default, repr(item)) | ||||
else: | ||||
try: | ||||
for x in func(mode): | ||||
yield x | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception: | ||||
yield (astyle.style_default, repr(item)) | ||||
xrepr = simplegeneric.generic(xrepr) | ||||
def xrepr_none(self, mode="default"): | ||||
yield (astyle.style_type_none, repr(self)) | ||||
xrepr.when_object(None)(xrepr_none) | ||||
def xrepr_noitem(self, mode="default"): | ||||
yield (2, True) | ||||
yield (astyle.style_nodata, "<?>") | ||||
xrepr.when_object(noitem)(xrepr_noitem) | ||||
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__ | ||||
else: | ||||
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))) | ||||
else: | ||||
yield (-1, False) | ||||
if isinstance(self, list): | ||||
yield (astyle.style_default, "[") | ||||
end = "]" | ||||
else: | ||||
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__ | ||||
else: | ||||
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))) | ||||
else: | ||||
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) | ||||
def upgradexattr(attr): | ||||
""" | ||||
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``. | ||||
""" | ||||
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"): | ||||
""" | ||||
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 descriptors (see the class | ||||
``Descriptor`` for more info). The ``__xattrs__`` method may also return | ||||
attribute descriptor strings (and ``None``) which will be converted to real | ||||
descriptors by ``upgradexattr()``. | ||||
""" | ||||
try: | ||||
func = item.__xattrs__ | ||||
except AttributeError: | ||||
if mode == "detail": | ||||
for attrname in dir(item): | ||||
yield AttributeDescriptor(attrname) | ||||
else: | ||||
yield selfdescriptor | ||||
else: | ||||
for attr in func(mode): | ||||
yield upgradexattr(attr) | ||||
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) | ||||
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 | ||||
def xiter(item): | ||||
""" | ||||
Generic function that implements iteration for pipeline expression. If no | ||||
implementation is registered for ``item`` ``xiter`` falls back to ``iter``. | ||||
""" | ||||
try: | ||||
func = item.__xiter__ | ||||
except AttributeError: | ||||
if _isdict(item): | ||||
def items(item): | ||||
fields = ("key", "value") | ||||
for (key, value) in item.iteritems(): | ||||
yield Fields(fields, key=key, value=value) | ||||
return items(item) | ||||
elif isinstance(item, new.module): | ||||
def items(item): | ||||
fields = ("key", "value") | ||||
for key in sorted(item.__dict__): | ||||
yield Fields(fields, key=key, value=getattr(item, key)) | ||||
return items(item) | ||||
elif _isstr(item): | ||||
if not item: | ||||
raise ValueError("can't enter empty string") | ||||
lines = item.splitlines() | ||||
if len(lines) == 1: | ||||
def iterone(item): | ||||
yield item | ||||
return iterone(item) | ||||
else: | ||||
return iter(lines) | ||||
return iter(item) | ||||
else: | ||||
return iter(func()) # iter() just to be safe | ||||
xiter = simplegeneric.generic(xiter) | ||||
class ichain(Pipe): | ||||
""" | ||||
Chains multiple ``Table``s into one. | ||||
""" | ||||
def __init__(self, *iters): | ||||
self.iters = iters | ||||
def __iter__(self): | ||||
return itertools.chain(*self.iters) | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
for (i, item) in enumerate(self.iters): | ||||
if i: | ||||
yield (astyle.style_default, "+") | ||||
if isinstance(item, Pipe): | ||||
yield (astyle.style_default, "(") | ||||
for part in xrepr(item, mode): | ||||
yield part | ||||
if isinstance(item, Pipe): | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
args = ", ".join([repr(it) for it in self.iters]) | ||||
return "%s.%s(%s)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, args) | ||||
class ifile(path.path): | ||||
""" | ||||
file (or directory) object. | ||||
""" | ||||
def getmode(self): | ||||
return self.stat().st_mode | ||||
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"), | ||||
] | ||||
lstat = self.lstat() | ||||
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) | ||||
type = property(gettype, None, None, "file type (file, directory, link, etc.)") | ||||
def getmodestr(self): | ||||
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]) | ||||
modestr = property(getmodestr, None, None, "Access mode as string") | ||||
def getblocks(self): | ||||
return self.stat().st_blocks | ||||
blocks = property(getblocks, None, None, "File size in blocks") | ||||
def getblksize(self): | ||||
return self.stat().st_blksize | ||||
blksize = property(getblksize, None, None, "Filesystem block size") | ||||
def getdev(self): | ||||
return self.stat().st_dev | ||||
dev = property(getdev) | ||||
def getnlink(self): | ||||
return self.stat().st_nlink | ||||
nlink = property(getnlink, None, None, "Number of links") | ||||
def getuid(self): | ||||
return self.stat().st_uid | ||||
uid = property(getuid, None, None, "User id of file owner") | ||||
def getgid(self): | ||||
return self.stat().st_gid | ||||
gid = property(getgid, None, None, "Group id of file owner") | ||||
def getowner(self): | ||||
stat = self.stat() | ||||
try: | ||||
return pwd.getpwuid(stat.st_uid).pw_name | ||||
except KeyError: | ||||
return stat.st_uid | ||||
owner = property(getowner, None, None, "Owner name (or id)") | ||||
def getgroup(self): | ||||
stat = self.stat() | ||||
try: | ||||
return grp.getgrgid(stat.st_gid).gr_name | ||||
except KeyError: | ||||
return stat.st_gid | ||||
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 mimetype(self): | ||||
""" | ||||
Return MIME type guessed from the extension. | ||||
""" | ||||
return mimetypes.guess_type(self.basename())[0] | ||||
def encoding(self): | ||||
""" | ||||
Return guessed compression (like "compress" or "gzip"). | ||||
""" | ||||
return mimetypes.guess_type(self.basename())[1] | ||||
def __repr__(self): | ||||
return "ifile(%s)" % path._base.__repr__(self) | ||||
if sys.platform == "win32": | ||||
defaultattrs = (None, "type", "size", "modestr", "mdate") | ||||
else: | ||||
defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate") | ||||
def __xattrs__(self, mode="default"): | ||||
if mode == "detail": | ||||
return ( | ||||
"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()", | ||||
) | ||||
else: | ||||
return self.defaultattrs | ||||
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) | ||||
# 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 | ||||
if mode in ("cell", "header", "footer"): | ||||
abspath = repr(path._base(self.normpath())) | ||||
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)) | ||||
else: | ||||
yield (style, repr(self)) | ||||
xrepr.when_type(ifile)(xrepr_ifile) | ||||
class ils(Table): | ||||
""" | ||||
List the current (or a specified) directory. | ||||
Examples:: | ||||
>>> ils | ||||
>>> ils("/usr/local/lib/python2.4") | ||||
>>> ils("~") | ||||
""" | ||||
def __init__(self, base=os.curdir, dirs=True, files=True): | ||||
self.base = os.path.expanduser(base) | ||||
self.dirs = dirs | ||||
self.files = files | ||||
def __iter__(self): | ||||
base = ifile(self.base) | ||||
yield (base / os.pardir).abspath() | ||||
for child in sorted(base.listdir()): | ||||
if self.dirs: | ||||
if self.files: | ||||
yield child | ||||
else: | ||||
if child.isdir(): | ||||
yield child | ||||
elif self.files: | ||||
if not child.isdir(): | ||||
yield child | ||||
def __xrepr__(self, mode="default"): | ||||
return xrepr(ifile(self.base), mode) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self.base) | ||||
class iglob(Table): | ||||
""" | ||||
List all files and directories matching a specified pattern. | ||||
(See ``glob.glob()`` for more info.). | ||||
Examples:: | ||||
>>> iglob("*.py") | ||||
""" | ||||
def __init__(self, glob): | ||||
self.glob = glob | ||||
def __iter__(self): | ||||
for name in glob.glob(self.glob): | ||||
yield ifile(name) | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer" or mode == "cell": | ||||
yield (astyle.style_default, | ||||
"%s(%r)" % (self.__class__.__name__, self.glob)) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self.glob) | ||||
class iwalk(Table): | ||||
""" | ||||
List all files and directories in a directory and it's subdirectory:: | ||||
>>> iwalk | ||||
>>> iwalk("/usr/local/lib/python2.4") | ||||
>>> iwalk("~") | ||||
""" | ||||
def __init__(self, base=os.curdir, dirs=True, files=True): | ||||
self.base = os.path.expanduser(base) | ||||
self.dirs = dirs | ||||
self.files = files | ||||
def __iter__(self): | ||||
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="default"): | ||||
if mode == "header" or mode == "footer" or mode == "cell": | ||||
yield (astyle.style_default, | ||||
"%s(%r)" % (self.__class__.__name__, self.base)) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self.base) | ||||
class ipwdentry(object): | ||||
""" | ||||
``ipwdentry`` objects encapsulate entries in the Unix user account and | ||||
password database. | ||||
""" | ||||
def __init__(self, id): | ||||
self._id = id | ||||
self._entry = None | ||||
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 | ||||
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="default"): | ||||
return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell") | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self._id) | ||||
class ipwd(Table): | ||||
""" | ||||
List all entries in the Unix user account and password database. | ||||
Example:: | ||||
>>> ipwd | isort("uid") | ||||
""" | ||||
def __iter__(self): | ||||
for entry in pwd.getpwall(): | ||||
yield ipwdentry(entry.pw_name) | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer" or mode == "cell": | ||||
yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
class igrpentry(object): | ||||
""" | ||||
``igrpentry`` objects encapsulate entries in the Unix group database. | ||||
""" | ||||
def __init__(self, id): | ||||
self._id = id | ||||
self._entry = None | ||||
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 | ||||
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="default"): | ||||
return ("name", "passwd", "gid", "mem") | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer" or mode == "cell": | ||||
yield (astyle.style_default, "group ") | ||||
try: | ||||
yield (astyle.style_default, self.name) | ||||
except KeyError: | ||||
if isinstance(self._id, basestring): | ||||
yield (astyle.style_default, self.name_id) | ||||
else: | ||||
yield (astyle.style_type_number, str(self._id)) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __iter__(self): | ||||
for member in self.mem: | ||||
yield ipwdentry(member) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self._id) | ||||
class igrp(Table): | ||||
""" | ||||
This ``Table`` lists all entries in the Unix group database. | ||||
""" | ||||
def __iter__(self): | ||||
for entry in grp.getgrall(): | ||||
yield igrpentry(entry.gr_name) | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
class Fields(object): | ||||
def __init__(self, fieldnames, **fields): | ||||
self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames] | ||||
for (key, value) in fields.iteritems(): | ||||
setattr(self, key, value) | ||||
def __xattrs__(self, mode="default"): | ||||
return self.__fieldnames | ||||
def __xrepr__(self, mode="default"): | ||||
yield (-1, False) | ||||
if mode == "header" or mode == "cell": | ||||
yield (astyle.style_default, self.__class__.__name__) | ||||
yield (astyle.style_default, "(") | ||||
for (i, f) in enumerate(self.__fieldnames): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
yield (astyle.style_default, f.name()) | ||||
yield (astyle.style_default, "=") | ||||
for part in xrepr(getattr(self, f), "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
elif mode == "footer": | ||||
yield (astyle.style_default, self.__class__.__name__) | ||||
yield (astyle.style_default, "(") | ||||
for (i, f) in enumerate(self.__fieldnames): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
yield (astyle.style_default, f.name()) | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
class FieldTable(Table, list): | ||||
def __init__(self, *fields): | ||||
Table.__init__(self) | ||||
list.__init__(self) | ||||
self.fields = fields | ||||
def add(self, **fields): | ||||
self.append(Fields(self.fields, **fields)) | ||||
def __xrepr__(self, mode="default"): | ||||
yield (-1, False) | ||||
if mode == "header" or mode == "footer": | ||||
yield (astyle.style_default, self.__class__.__name__) | ||||
yield (astyle.style_default, "(") | ||||
for (i, f) in enumerate(self.__fieldnames): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
yield (astyle.style_default, f) | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
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)) | ||||
class List(list): | ||||
def __xattrs__(self, mode="default"): | ||||
return xrange(len(self)) | ||||
def __xrepr__(self, mode="default"): | ||||
yield (-1, False) | ||||
if mode == "header" or mode == "cell" or mode == "footer" or mode == "default": | ||||
yield (astyle.style_default, self.__class__.__name__) | ||||
yield (astyle.style_default, "(") | ||||
for (i, item) in enumerate(self): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
for part in xrepr(item, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
class ienv(Table): | ||||
""" | ||||
List environment variables. | ||||
Example:: | ||||
>>> ienv | ||||
""" | ||||
def __iter__(self): | ||||
fields = ("key", "value") | ||||
for (key, value) in os.environ.iteritems(): | ||||
yield Fields(fields, key=key, value=value) | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "cell": | ||||
yield (astyle.style_default, "%s()" % self.__class__.__name__) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
class ihist(Table): | ||||
""" | ||||
IPython input history | ||||
Example:: | ||||
>>> ihist | ||||
>>> ihist(True) (raw mode) | ||||
""" | ||||
def __init__(self, raw=True): | ||||
self.raw = raw | ||||
def __iter__(self): | ||||
api = ipapi.get() | ||||
if self.raw: | ||||
for line in api.IP.input_hist_raw: | ||||
yield line.rstrip("\n") | ||||
else: | ||||
for line in api.IP.input_hist: | ||||
yield line.rstrip("\n") | ||||
class Alias(object): | ||||
""" | ||||
Entry in the alias table | ||||
""" | ||||
def __init__(self, name, args, command): | ||||
self.name = name | ||||
self.args = args | ||||
self.command = command | ||||
def __xattrs__(self, mode="default"): | ||||
return ("name", "args", "command") | ||||
class ialias(Table): | ||||
""" | ||||
IPython alias list | ||||
Example:: | ||||
>>> ialias | ||||
""" | ||||
def __iter__(self): | ||||
api = ipapi.get() | ||||
for (name, (args, command)) in api.IP.alias_table.iteritems(): | ||||
yield Alias(name, args, command) | ||||
class icsv(Pipe): | ||||
""" | ||||
This ``Pipe`` turns the input (with must be a pipe outputting lines | ||||
or an ``ifile``) into lines of CVS columns. | ||||
""" | ||||
def __init__(self, **csvargs): | ||||
""" | ||||
Create an ``icsv`` object. ``cvsargs`` will be passed through as | ||||
keyword arguments to ``cvs.reader()``. | ||||
""" | ||||
self.csvargs = csvargs | ||||
def __iter__(self): | ||||
input = self.input | ||||
if isinstance(input, ifile): | ||||
input = input.open("rb") | ||||
reader = csv.reader(input, **self.csvargs) | ||||
for line in reader: | ||||
yield List(line) | ||||
def __xrepr__(self, mode="default"): | ||||
yield (-1, False) | ||||
if mode == "header" or mode == "footer": | ||||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
for part in xrepr(input, mode): | ||||
yield part | ||||
yield (astyle.style_default, " | ") | ||||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
for (i, (name, value)) in enumerate(self.csvargs.iteritems()): | ||||
if i: | ||||
yield (astyle.style_default, ", ") | ||||
yield (astyle.style_default, name) | ||||
yield (astyle.style_default, "=") | ||||
for part in xrepr(value, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
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)) | ||||
class ix(Table): | ||||
""" | ||||
Execute a system command and list its output as lines | ||||
(similar to ``os.popen()``). | ||||
Examples:: | ||||
>>> ix("ps x") | ||||
>>> ix("find .") | ifile | ||||
""" | ||||
def __init__(self, cmd): | ||||
self.cmd = cmd | ||||
self._pipeout = None | ||||
def __iter__(self): | ||||
(_pipein, self._pipeout) = os.popen4(self.cmd) | ||||
_pipein.close() | ||||
for l in self._pipeout: | ||||
yield l.rstrip("\r\n") | ||||
self._pipeout.close() | ||||
self._pipeout = None | ||||
def __del__(self): | ||||
if self._pipeout is not None and not self._pipeout.closed: | ||||
self._pipeout.close() | ||||
self._pipeout = None | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
yield (astyle.style_default, | ||||
"%s(%r)" % (self.__class__.__name__, self.cmd)) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self.cmd) | ||||
class ifilter(Pipe): | ||||
""" | ||||
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) | ||||
""" | ||||
def __init__(self, expr, globals=None, errors="raiseifallfail"): | ||||
""" | ||||
Create an ``ifilter`` object. ``expr`` can be a callable or a string | ||||
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: | ||||
``"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). | ||||
""" | ||||
self.expr = expr | ||||
self.globals = globals | ||||
self.errors = errors | ||||
def __iter__(self): | ||||
if callable(self.expr): | ||||
test = self.expr | ||||
else: | ||||
g = getglobals(self.globals) | ||||
expr = compile(self.expr, "ipipe-expression", "eval") | ||||
def test(item): | ||||
return eval(expr, g, AttrNamespace(item)) | ||||
ok = 0 | ||||
exc_info = None | ||||
for item in xiter(self.input): | ||||
try: | ||||
if test(item): | ||||
yield item | ||||
ok += 1 | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
if self.errors == "drop": | ||||
pass # Ignore errors | ||||
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] | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
for part in xrepr(input, mode): | ||||
yield part | ||||
yield (astyle.style_default, " | ") | ||||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
for part in xrepr(self.expr, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "<%s.%s expr=%r at 0x%x>" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.expr, id(self)) | ||||
class ieval(Pipe): | ||||
""" | ||||
Evaluate an expression for each object in the input pipe. | ||||
Examples:: | ||||
>>> ils | ieval("_.abspath()") | ||||
>>> sys.path | ieval(ifile) | ||||
""" | ||||
def __init__(self, expr, globals=None, errors="raiseifallfail"): | ||||
""" | ||||
Create an ``ieval`` object. ``expr`` can be a callable or a string | ||||
containing an expression. For the meaning of ``globals`` and | ||||
``errors`` see ``ifilter``. | ||||
""" | ||||
self.expr = expr | ||||
self.globals = globals | ||||
self.errors = errors | ||||
def __iter__(self): | ||||
if callable(self.expr): | ||||
do = self.expr | ||||
else: | ||||
g = getglobals(self.globals) | ||||
expr = compile(self.expr, "ipipe-expression", "eval") | ||||
def do(item): | ||||
return eval(expr, g, AttrNamespace(item)) | ||||
ok = 0 | ||||
exc_info = None | ||||
for item in xiter(self.input): | ||||
try: | ||||
yield do(item) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
if self.errors == "drop": | ||||
pass # Ignore errors | ||||
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] | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
for part in xrepr(input, mode): | ||||
yield part | ||||
yield (astyle.style_default, " | ") | ||||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
for part in xrepr(self.expr, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "<%s.%s expr=%r at 0x%x>" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.expr, id(self)) | ||||
class ienum(Pipe): | ||||
""" | ||||
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") | ||||
""" | ||||
def __iter__(self): | ||||
fields = ("index", "object") | ||||
for (index, object) in enumerate(xiter(self.input)): | ||||
yield Fields(fields, index=index, object=object) | ||||
class isort(Pipe): | ||||
""" | ||||
Sorts the input pipe. | ||||
Examples:: | ||||
>>> ils | isort("size") | ||||
>>> ils | isort("_.isdir(), _.lower()", reverse=True) | ||||
""" | ||||
def __init__(self, key=None, globals=None, reverse=False): | ||||
""" | ||||
Create an ``isort`` object. ``key`` can be a callable or a string | ||||
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``. | ||||
""" | ||||
self.key = key | ||||
self.globals = globals | ||||
self.reverse = reverse | ||||
def __iter__(self): | ||||
if self.key is None: | ||||
items = sorted(xiter(self.input), reverse=self.reverse) | ||||
elif callable(self.key): | ||||
items = sorted(xiter(self.input), key=self.key, reverse=self.reverse) | ||||
else: | ||||
g = getglobals(self.globals) | ||||
key = compile(self.key, "ipipe-expression", "eval") | ||||
def realkey(item): | ||||
return eval(key, g, AttrNamespace(item)) | ||||
items = sorted(xiter(self.input), key=realkey, reverse=self.reverse) | ||||
for item in items: | ||||
yield item | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
input = getattr(self, "input", None) | ||||
if input is not None: | ||||
for part in xrepr(input, mode): | ||||
yield part | ||||
yield (astyle.style_default, " | ") | ||||
yield (astyle.style_default, "%s(" % self.__class__.__name__) | ||||
for part in xrepr(self.key, "default"): | ||||
yield part | ||||
if self.reverse: | ||||
yield (astyle.style_default, ", ") | ||||
for part in xrepr(True, "default"): | ||||
yield part | ||||
yield (astyle.style_default, ")") | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "<%s.%s key=%r reverse=%r at 0x%x>" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, | ||||
self.key, self.reverse, id(self)) | ||||
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 | ||||
text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \ | ||||
(field.year, field.month, field.day, | ||||
field.hour, field.minute, field.second, field.microsecond) | ||||
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 __init__(self, input=None): | ||||
self.input = input | ||||
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): | ||||
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))) | ||||
pager.write("\n") | ||||
finally: | ||||
pager.close() | ||||
except Exception, exc: | ||||
print "%s: %s" % (exc.__class__.__name__, str(exc)) | ||||
class _RedirectIO(object): | ||||
def __init__(self,*args,**kwargs): | ||||
""" | ||||
Map the system output streams to self. | ||||
""" | ||||
self.stream = StringIO.StringIO() | ||||
self.stdout = sys.stdout | ||||
sys.stdout = self | ||||
self.stderr = sys.stderr | ||||
sys.stderr = self | ||||
def write(self, text): | ||||
""" | ||||
Write both to screen and to self. | ||||
""" | ||||
self.stream.write(text) | ||||
self.stdout.write(text) | ||||
if "\n" in text: | ||||
self.stdout.flush() | ||||
def writelines(self, lines): | ||||
""" | ||||
Write lines both to screen and to self. | ||||
""" | ||||
self.stream.writelines(lines) | ||||
self.stdout.writelines(lines) | ||||
self.stdout.flush() | ||||
def restore(self): | ||||
""" | ||||
Restore the default system streams. | ||||
""" | ||||
self.stdout.flush() | ||||
self.stderr.flush() | ||||
sys.stdout = self.stdout | ||||
sys.stderr = self.stderr | ||||
class icap(Table): | ||||
""" | ||||
Execute a python string and capture any output to stderr/stdout. | ||||
Examples:: | ||||
>>> import time | ||||
>>> icap("for i in range(10): print i, time.sleep(0.1)") | ||||
""" | ||||
def __init__(self, expr, globals=None): | ||||
self.expr = expr | ||||
self.globals = globals | ||||
log = _RedirectIO() | ||||
try: | ||||
exec(expr, getglobals(globals)) | ||||
finally: | ||||
log.restore() | ||||
self.stream = log.stream | ||||
def __iter__(self): | ||||
self.stream.seek(0) | ||||
for line in self.stream: | ||||
yield line.rstrip("\r\n") | ||||
def __xrepr__(self, mode="default"): | ||||
if mode == "header" or mode == "footer": | ||||
yield (astyle.style_default, | ||||
"%s(%r)" % (self.__class__.__name__, self.expr)) | ||||
else: | ||||
yield (astyle.style_default, repr(self)) | ||||
def __repr__(self): | ||||
return "%s.%s(%r)" % \ | ||||
(self.__class__.__module__, self.__class__.__name__, self.expr) | ||||
def xformat(value, mode, maxlength): | ||||
align = None | ||||
full = True | ||||
width = 0 | ||||
text = astyle.Text() | ||||
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) | ||||
if width >= maxlength and not full: | ||||
text.append((astyle.style_ellisis, "...")) | ||||
width += 3 | ||||
break | ||||
if align is None: # default to left alignment | ||||
align = -1 | ||||
return (align, width, text) | ||||
import astyle | ||||
class idump(Display): | ||||
# The approximate maximum length of a column entry | ||||
maxattrlength = 200 | ||||
# Style for column names | ||||
style_header = astyle.Style.fromstr("white:black:bold") | ||||
def __init__(self, input=None, *attrs): | ||||
Display.__init__(self, input) | ||||
self.attrs = [upgradexattr(attr) for attr in attrs] | ||||
self.headerpadchar = " " | ||||
self.headersepchar = "|" | ||||
self.datapadchar = " " | ||||
self.datasepchar = "|" | ||||
def display(self): | ||||
stream = genutils.Term.cout | ||||
allattrs = [] | ||||
attrset = set() | ||||
colwidths = {} | ||||
rows = [] | ||||
for item in xiter(self.input): | ||||
row = {} | ||||
attrs = self.attrs | ||||
if not attrs: | ||||
attrs = xattrs(item, "default") | ||||
for attr in attrs: | ||||
if attr not in attrset: | ||||
allattrs.append(attr) | ||||
attrset.add(attr) | ||||
colwidths[attr] = len(attr.name()) | ||||
try: | ||||
value = attr.value(item) | ||||
except (KeyboardInterrupt, SystemExit): | ||||
raise | ||||
except Exception, exc: | ||||
value = exc | ||||
(align, width, text) = xformat(value, "cell", self.maxattrlength) | ||||
colwidths[attr] = max(colwidths[attr], width) | ||||
# remember alignment, length and colored parts | ||||
row[attr] = (align, width, text) | ||||
rows.append(row) | ||||
stream.write("\n") | ||||
for (i, attr) in enumerate(allattrs): | ||||
attrname = attr.name() | ||||
self.style_header(attrname).write(stream) | ||||
spc = colwidths[attr] - len(attrname) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.headerpadchar*spc) | ||||
stream.write(self.headersepchar) | ||||
stream.write("\n") | ||||
for row in rows: | ||||
for (i, attr) in enumerate(allattrs): | ||||
(align, width, text) = row[attr] | ||||
spc = colwidths[attr] - width | ||||
if align == -1: | ||||
text.write(stream) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.datapadchar*spc) | ||||
elif align == 0: | ||||
spc = colwidths[attr] - 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) | ||||
if i < len(colwidths)-1: | ||||
stream.write(self.datasepchar) | ||||
stream.write("\n") | ||||
class AttributeDetail(Table): | ||||
""" | ||||
``AttributeDetail`` objects are use for displaying a detailed list of object | ||||
attributes. | ||||
""" | ||||
def __init__(self, object, descriptor): | ||||
self.object = object | ||||
self.descriptor = descriptor | ||||
def __iter__(self): | ||||
return self.descriptor.iter(self.object) | ||||
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) | ||||
def __xattrs__(self, mode="default"): | ||||
attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()") | ||||
if mode == "detail": | ||||
attrs += ("doc()",) | ||||
return attrs | ||||
def __xrepr__(self, mode="default"): | ||||
yield (-1, True) | ||||
valuetype = self.valuetype() | ||||
if valuetype is not noitem: | ||||
for part in xrepr(valuetype): | ||||
yield part | ||||
yield (astyle.style_default, " ") | ||||
yield (astyle.style_default, self.attrtype()) | ||||
yield (astyle.style_default, " ") | ||||
yield (astyle.style_default, self.name()) | ||||
yield (astyle.style_default, " of ") | ||||
for part in xrepr(self.object): | ||||
yield part | ||||
try: | ||||
from ibrowse import ibrowse | ||||
except ImportError: | ||||
# No curses (probably Windows) => try igrid | ||||
try: | ||||
from igrid import igrid | ||||
except ImportError: | ||||
# no wx either => use ``idump`` as the default display. | ||||
defaultdisplay = idump | ||||
else: | ||||
defaultdisplay = igrid | ||||
__all__.append("igrid") | ||||
else: | ||||
defaultdisplay = ibrowse | ||||
__all__.append("ibrowse") | ||||
# If we're running under IPython, register our objects with IPython's | ||||
# generic function ``result_display``, else install a displayhook | ||||
# directly as sys.displayhook | ||||
if generics is not None: | ||||
def display_display(obj): | ||||
return obj.display() | ||||
generics.result_display.when_type(Display)(display_display) | ||||
def display_tableobject(obj): | ||||
return display_display(defaultdisplay(obj)) | ||||
generics.result_display.when_type(Table)(display_tableobject) | ||||
def display_tableclass(obj): | ||||
return display_tableobject(obj()) | ||||
generics.result_display.when_type(Table.__metaclass__)(display_tableclass) | ||||
else: | ||||
def installdisplayhook(): | ||||
_originalhook = sys.displayhook | ||||
def displayhook(obj): | ||||
if isinstance(obj, type) and issubclass(obj, Table): | ||||
obj = obj() | ||||
if isinstance(obj, Table): | ||||
obj = defaultdisplay(obj) | ||||
if isinstance(obj, Display): | ||||
return obj.display() | ||||
else: | ||||
_originalhook(obj) | ||||
sys.displayhook = displayhook | ||||
installdisplayhook() | ||||