|
""" html - generating ad-hoc html out of source browser |
""" |
|
import py |
from py.xml import html, raw |
from compiler import ast |
import time |
from py.__.apigen.source.color import Tokenizer, PythonSchema |
|
class HtmlEnchanter(object): |
def __init__(self, mod): |
self.mod = mod |
self.create_caches() |
|
def create_caches(self): |
mod = self.mod |
linecache = {} |
for item in mod.get_children(): |
linecache[item.firstlineno] = item |
self.linecache = linecache |
|
def enchant_row(self, num, row): |
|
|
try: |
item = self.linecache[num] |
|
|
pos = row.find(item.name) |
assert pos != -1 |
end = len(item.name) + pos |
chunk = html.a(row[pos:end], href="#" + item.listnames(), |
name=item.listnames()) |
return [row[:pos], chunk, row[end:]] |
except KeyError: |
return [row] |
|
def prepare_line(text, tokenizer, encoding): |
""" adds html formatting to text items (list) |
|
only processes items if they're of a string type (or unicode) |
""" |
ret = [] |
for item in text: |
if type(item) in [str, unicode]: |
tokens = tokenizer.tokenize(item) |
for t in tokens: |
if not isinstance(t.data, unicode): |
data = unicode(t.data, encoding) |
else: |
data = t.data |
if t.type in ['keyword', 'alt_keyword', 'number', |
'string', 'comment']: |
ret.append(html.span(data, class_=t.type)) |
else: |
ret.append(data) |
else: |
ret.append(item) |
return ret |
|
class HTMLDocument(object): |
def __init__(self, encoding, tokenizer=None): |
self.encoding = encoding |
|
self.html = root = html.html() |
self.head = head = self.create_head() |
root.append(head) |
self.body = body = self.create_body() |
root.append(body) |
self.table, self.tbody = table, tbody = self.create_table() |
body.append(table) |
|
if tokenizer is None: |
tokenizer = Tokenizer(PythonSchema) |
self.tokenizer = tokenizer |
|
def create_head(self): |
return html.head( |
html.title('source view'), |
html.style(""" |
body, td { |
background-color: #FFF; |
color: black; |
font-family: monospace, Monaco; |
} |
|
table, tr { |
margin: 0px; |
padding: 0px; |
border-width: 0px; |
} |
|
a { |
color: blue; |
font-weight: bold; |
text-decoration: none; |
} |
|
a:hover { |
color: #005; |
} |
|
.lineno { |
text-align: right; |
color: #555; |
width: 3em; |
padding-right: 1em; |
border: 0px solid black; |
border-right-width: 1px; |
} |
|
.code { |
padding-left: 1em; |
white-space: pre; |
} |
|
.comment { |
color: purple; |
} |
|
.string { |
color: #777; |
} |
|
.keyword { |
color: blue; |
} |
|
.alt_keyword { |
color: green; |
} |
|
""", type='text/css'), |
) |
|
def create_body(self): |
return html.body() |
|
def create_table(self): |
table = html.table(cellpadding='0', cellspacing='0') |
tbody = html.tbody() |
table.append(tbody) |
return table, tbody |
|
def add_row(self, lineno, text): |
if text == ['']: |
text = [raw(' ')] |
else: |
text = prepare_line(text, self.tokenizer, self.encoding) |
self.tbody.append(html.tr(html.td(str(lineno), class_='lineno'), |
html.td(class_='code', *text))) |
|
def __unicode__(self): |
|
|
return self.html.unicode(indent=0) |
|
def create_html(mod): |
|
|
lines = mod.path.open().readlines() |
|
enchanter = HtmlEnchanter(mod) |
enc = get_module_encoding(mod.path) |
doc = HTMLDocument(enc) |
for i, row in enumerate(lines): |
row = enchanter.enchant_row(i + 1, row) |
doc.add_row(i + 1, row) |
return unicode(doc) |
|
style = html.style(""" |
|
body, p, td { |
background-color: #FFF; |
color: black; |
font-family: monospace, Monaco; |
} |
|
td.type { |
width: 2em; |
} |
|
td.name { |
width: 30em; |
} |
|
td.mtime { |
width: 13em; |
} |
|
td.size { |
text-alignment: right; |
} |
|
""") |
|
def create_dir_html(path, href_prefix=''): |
h = html.html( |
html.head( |
html.title('directory listing of %s' % (path,)), |
style, |
), |
) |
body = html.body( |
html.h1('directory listing of %s' % (path,)), |
) |
h.append(body) |
table = html.table() |
body.append(table) |
tbody = html.tbody() |
table.append(tbody) |
items = list(path.listdir()) |
items.sort(key=lambda p: p.basename) |
items.sort(key=lambda p: not p.check(dir=True)) |
for fpath in items: |
tr = html.tr() |
tbody.append(tr) |
td1 = html.td(fpath.check(dir=True) and 'D' or 'F', class_='type') |
tr.append(td1) |
href = fpath.basename |
if href_prefix: |
href = '%s%s' % (href_prefix, href) |
if fpath.check(dir=True): |
href += '/' |
td2 = html.td(html.a(fpath.basename, href=href), class_='name') |
tr.append(td2) |
td3 = html.td(time.strftime('%Y-%m-%d %H:%M:%S', |
time.gmtime(fpath.mtime())), class_='mtime') |
tr.append(td3) |
if fpath.check(dir=True): |
size = '' |
unit = '' |
else: |
size = fpath.size() |
unit = 'B' |
for u in ['kB', 'MB', 'GB', 'TB']: |
if size > 1024: |
size = round(size / 1024.0, 2) |
unit = u |
td4 = html.td('%s %s' % (size, unit), class_='size') |
tr.append(td4) |
return unicode(h) |
|
def create_unknown_html(path): |
h = html.html( |
html.head( |
html.title('Can not display page'), |
style, |
), |
html.body( |
html.p('The data URL (%s) does not contain Python code.' % (path,)) |
), |
) |
return h.unicode() |
|
_reg_enc = py.std.re.compile(r'coding[:=]\s*([-\w.]+)') |
def get_module_encoding(path): |
if hasattr(path, 'strpath'): |
path = path.strpath |
if path[-1] in ['c', 'o']: |
path = path[:-1] |
fpath = py.path.local(path) |
fp = fpath.open() |
lines = [] |
try: |
|
for i in range(2): |
lines.append(fp.readline()) |
finally: |
fp.close() |
match = _reg_enc.search('\n'.join(lines)) |
if match: |
return match.group(1) |
return 'ISO-8859-1' |
|
|