Skip to content

Instantly share code, notes, and snippets.

@markomanninen
Forked from jiffyclub/runtests.py
Last active August 29, 2015 13:59
Show Gist options
  • Save markomanninen/11003784 to your computer and use it in GitHub Desktop.
Save markomanninen/11003784 to your computer and use it in GitHub Desktop.
Text output to html table format via tagpy dependency
from IPython.core.magic import register_line_magic
from IPython.display import HTML
from tagpy import helper as h, table
@register_line_magic
def runtests(line):
"""
The %runtests magic searches your IPython namespace for functions
with names that begin with 'test'. It will attempt to run these
functions (calling them with no arguments), and report whether they
pass, fail (raise an AssertionError), or error (raise any other
kind of error).
For tests that fail or error %runtests will show the exception raised
but not the traceback, so write informative messages!
"""
import collections
import time
ip = get_ipython()
tests = {}
# collect tests
# search will only find functions that start with 'test'
for k, v in ip.user_ns.iteritems():
if k.startswith('test') and isinstance(v, collections.Callable):
tests[k] = v
tbl = table(CLASS='data')
tbl.addColGroup(h.col(), h.col())
tbl.addCaption('Collected {} tests.\n'.format(len(tests)))
tbl.addHeadRow(h.tr(h.th('Test function name'), h.th('Status')))
# run tests
ok = 0
fail = {}
error = {}
t1 = time.time()
for name, func in tests.iteritems():
try:
func()
except AssertionError as e:
msg = 'failed'
fail[name] = e
except Exception as e:
msg = 'error'
error[name] = e
else:
msg = 'successful'
ok += 1
tbl.addBodyRow(h.tr(h.td(name), h.td(msg), Class=msg))
t2 = time.time()
# print info on any failures
if fail:
tbl.addBodyRows(h.tr(h.th("Failed", span=2)))
trs = []
for name, e in fail.iteritems():
trs.append(h.tr(h.td(name), h.td(repr(e))))
tbl.addBodyRows(*trs, CLASS='failures')
# print info on any errors
if error:
tbl.addBodyRows(h.tr(h.th("Errors", span=2)))
trs = []
for name, e in error.iteritems():
trs.append(h.tr(h.td(name), h.td(repr(e))))
tbl.addBodyRows(*trs, CLASS='errors')
# summary and timer of the tests
tbl.addFootRow(h.tr(h.td('Successful', Class="right"), h.td('{}'.format(ok))))
tbl.addFootRow(h.tr(h.td('Failed', Class="right"), h.td('{}'.format(len(fail)))))
tbl.addFootRow(h.tr(h.td('Errors', Class="right"), h.td('{}'.format(len(error)))))
tbl.addFootRow(h.tr(h.td("Excecution", Class="right"), h.td('{:.3g} seconds'.format(t2 - t1))))
return HTML(str(tbl))
"""
tagpy : Simple html tag generator / factory
"""
class TAG(object):
""" Base tag class """
def __init__(self, *args, **kw):
self._name = self.__class__.__name__.lower()
self._attributes = dict([k.lower(), str(w)] for k, w in kw.iteritems())
self._in = []
self._left = []
self._right = []
map(self.__lshift__, args)
def getName(self):
return self._name
def setName(self, name):
self._name = name
return self
def getAttribute(self, key):
return self._attributes[key] if self._attributes.has_key(key) else None
def setAttribute(self, key, value):
self._attributes[key] = value
return self
def rcontent(self, item):
return self.__rshift__(item)
def __rshift__(self, item):
item._in.append(item.__item__(self))
return item
def content(self, item):
return self.__lshift__(item)
def __lshift__(self, item):
self._in.append(self.__item__(item))
return self
def prepend(self, item):
return self.__radd__(item)
def left(self, item):
return self.__radd__(item)
def __radd__(self, item):
self._left.append(self.__item__(item))
return self
def append(self, item):
return self.__add__(item)
def right(self, item):
return self.__add__(item)
def __add__(self, item):
self._right.append(self.__item__(item))
return self
def __item__(self, item):
if callable(item):
item = item()
elif not issubclass(type(item), TAG):
item = str(item)
return item
def renderAttributes(self):
attr = ''
if self._attributes:
attr = ''.join([' %s="%s"' % (k, v) for k, v in self._attributes.iteritems()])
return attr
def __str__(self):
if self._in:
in_elements = ''.join([str(item) for item in self._in])
element = '<%s%s>%s</%s>' % (self._name, self.renderAttributes(), in_elements, self._name)
else:
element = '<%s%s/>' % (self._name, self.renderAttributes())
left = ''
if self._left:
left = ''.join(map(str, self._left))
right = ''
if self._right:
right = ''.join(map(str, self._right))
return left + element + right
class htmlHelper(object):
""" Tag generation factory """
def __getattr__(self, tag):
""" This method only gets called for attributes (ie. tags in this application) that don't exist yet. """
if self.__dict__.has_key(tag):
return self.__dict__[tag]
else:
self.__dict__[tag] = type(tag, (TAG,), {})
return self.__dict__[tag]
def table(*args, **kw):
global helper
"""
This function presents the idea of extending tags for simpler generation of some
html element groups. Table has several group of tags in well defined structure. Caption
header should be right after table and before thead. Colgroup, tfoot, tbody, tr, td and th
elements has certain order which are handled by extended table class returned by this function.
Same idea could be used to create unordered lists and menu or other custom html widgets.
Use in this way:
from tagpy import helper as h, table
"""
class table(type(helper.table())):
""" Extend base table tag class """
def __init__(self, *args, **kw):
super(self.__class__, self).__init__(*args, **kw)
def addCaption(self, caption, **kw):
if not self.__dict__.has_key('caption'):
self.caption = helper.caption(**kw)
self.caption.content(caption)
return self
def addColGroup(self, *cols, **kw):
"""
http://www.w3.org/TR/CSS2/tables.html#columns
"""
if not self.__dict__.has_key('colgroup'):
self.colgroup = helper.colgroup(**kw)
for col in cols:
self.colgroup.content(col)
return self
def addHeadRow(self, *trs, **kw):
if not self.__dict__.has_key('thead'):
self.thead = helper.thead(**kw)
for tr in trs:
self.thead.content(tr)
return self
def addFootRow(self, *trs, **kw):
if not self.__dict__.has_key('tfoot'):
self.tfoot = helper.tfoot(**kw)
for tr in trs:
self.tfoot.content(tr)
return self
def addBodyRow(self, *trs, **kw):
if not self.__dict__.has_key('tbody'):
self.tbody = helper.tbody(**kw)
for tr in trs:
self.tbody.content(tr)
return self
def addBodyRows(self, *trs, **kw):
if not self.__dict__.has_key('tbodys'):
self.tbodys = []
self.tbodys.append(helper.tbody(*trs, **kw))
return self
def __str__(self):
self._in = []
if self.__dict__.has_key('caption'):
self.content(self.caption)
if self.__dict__.has_key('colgroup'):
self.content(self.colgroup)
if self.__dict__.has_key('thead'):
self.content(self.thead)
if self.__dict__.has_key('tfoot'):
self.content(self.tfoot)
if self.__dict__.has_key('tbody'):
self.content(self.tbody)
if self.__dict__.has_key('tbodys'):
map(self.content, self.tbodys)
return super(self.__class__, self).__str__()
return table(*args, **kw)
"""
All tag elements are accessible via readily constructed factory variable. This helper
should be imported from the module in this wise: from tagpy import helper as h
"""
helper = htmlHelper()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment