Created
December 6, 2016 14:42
-
-
Save guangningyu/055e1aa9c9b6c484fba013c62a3d8ff9 to your computer and use it in GitHub Desktop.
Generate HTML format file containing tables, images and paragraphs using Python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
This module provides a few classes to easily generate HTML code | |
for tables, images and paragraphs. | |
""" | |
__version__ = '0.2' | |
__date__ = '2016-04-13' | |
__author__ = 'Guangning Yu' | |
class TableCell(): | |
def __init__(self, text="", bgcolor=None, width=None, height=None, | |
align=None, valign=None, char=None, charoff=None, | |
header=None, colspan=None, rowspan=None, hidden=False, | |
padding_left=5, padding_right=5, color=None, font_weight=None): | |
"""TableCell constructor""" | |
self.text = text | |
self.orig_value = text | |
# cell attributes | |
self.bgcolor = bgcolor | |
self.width = width | |
self.height = height | |
self.align = align | |
self.valign = valign | |
self.char = char | |
self.charoff = charoff | |
self.colspan = colspan | |
self.rowspan = rowspan | |
# style | |
self.color = color | |
self.padding_left = padding_left | |
self.padding_right = padding_right | |
self.font_weight = font_weight | |
# custom attributes | |
self.header = header | |
self.hidden = hidden | |
self.attr = {} | |
def set_font_color(self, color_nm): | |
self.color = get_color(color_nm) | |
return self | |
def set_bg_color(self, color_nm): | |
self.bgcolor = get_color(color_nm) | |
return self | |
def set_bold(self): | |
self.font_weight = 'bold' | |
return self | |
def __str__(self): | |
"""return the HTML code for the table cell""" | |
# deal with the attributes | |
if self.bgcolor: self.attr['bgcolor'] = self.bgcolor | |
if self.width: self.attr['width'] = self.width | |
if self.height: self.attr['height'] = self.height | |
if self.align: self.attr['align'] = self.align | |
if self.valign: self.attr['valign'] = self.valign | |
if self.char: self.attr['char'] = self.char | |
if self.charoff: self.attr['charoff'] = self.charoff | |
if self.colspan: self.attr['colspan'] = self.colspan | |
if self.rowspan: self.attr['rowspan'] = self.rowspan | |
self.attr['style'] = 'padding-left: %spx; padding-right: %spx' % (self.padding_left, self.padding_right) | |
if self.color: self.attr['style'] += '; color: %s' % self.color | |
if self.font_weight: self.attr['style'] += '; font-weight: %s' % self.font_weight | |
attr_str = "" | |
for attr in self.attr.keys(): | |
attr_str += ' %s="%s"' % (attr, self.attr[attr]) | |
# deal with the content text | |
if self.text: | |
text = str(self.text) | |
else: | |
text = " " | |
# return the HTML code | |
if not self.hidden: | |
if self.header: | |
return ' <TH%s>%s</TH>\n' % (attr_str, text) | |
else: | |
return ' <TD%s>%s</TD>\n' % (attr_str, text) | |
else: | |
return '' | |
class TableRow(): | |
def __init__(self, cells=None): | |
"""TableRow constructor""" | |
self.cells = [TableCell(cell) if not isinstance(cell, TableCell) else cell for cell in cells] | |
def __str__(self): | |
"""return the HTML code for the table row""" | |
result = "" | |
result += '<TR>\n' | |
for cell in self.cells: | |
result += str(cell) | |
result += '</TR>\n' | |
return result | |
class Table(): | |
def __init__(self, rows=None, width="800", border="1", cellspacing="0", cellpadding=None, | |
font_family="微软雅黑", font_size="11px", table_border="1px solid #000000", border_collapse="collapse"): | |
"""Table constructor""" | |
self.rows = [TableRow(row) if not isinstance(row, TableRow) else row for row in rows] | |
# table attributes | |
self.width = width | |
self.border = border | |
self.cellspacing = cellspacing | |
self.cellpadding = cellpadding | |
# style attributes | |
self.font_family = font_family | |
self.font_size = font_size | |
self.table_border = table_border | |
self.border_collapse = border_collapse | |
# init attribute dict | |
self.attr = {} | |
def get_cells(self, rows_idx=None, cols_idx=None): | |
cell_list = [] | |
if rows_idx: | |
rows_idx = [int(i)-1 for i in str(rows_idx).strip().split(',')] | |
if cols_idx: | |
cols_idx = [int(i)-1 for i in str(cols_idx).strip().split(',')] | |
for row in self.rows: | |
for cell in row.cells: | |
row_idx = self.rows.index(row) | |
col_idx = row.cells.index(cell) | |
if rows_idx and cols_idx == None: | |
if row_idx in rows_idx: | |
cell_list.append(cell) | |
elif rows_idx == None and cols_idx: | |
if col_idx in cols_idx: | |
cell_list.append(cell) | |
elif rows_idx and cols_idx: | |
if row_idx in rows_idx and col_idx in cols_idx: | |
cell_list.append(cell) | |
return cell_list | |
def get_all_cells(self): | |
cell_list = [] | |
for row in self.rows: | |
for cell in row.cells: | |
cell_list.append(cell) | |
return cell_list | |
def set_row_header(self, rows_idx): | |
for cell in self.get_cells(rows_idx=rows_idx): | |
cell.header = True | |
return self | |
def set_color(self, rows_idx=None, cols_idx=None, color_nm=None): | |
for cell in self.get_cells(rows_idx=rows_idx, cols_idx=cols_idx): | |
cell.bgcolor = get_color(color_nm) | |
return self | |
def set_hidden(self, rows_idx=None, cols_idx=None): | |
for cell in self.get_cells(rows_idx=rows_idx, cols_idx=cols_idx): | |
cell.hidden = True | |
return self | |
def set_row_color(self, rows_idx, color_nm): | |
return self.set_color(rows_idx=rows_idx, cols_idx=None, color_nm=color_nm) | |
def set_row_bold(self, rows_idx): | |
for cell in self.get_cells(rows_idx=rows_idx): | |
cell.font_weight = 'bold' | |
return self | |
def set_row_font_color(self, rows_idx, color_nm): | |
for cell in self.get_cells(rows_idx=rows_idx): | |
cell.color = get_color(color_nm) | |
return self | |
def set_pct(self, rows_idx=None, cols_idx=None, num_digits=2): | |
for cell in self.get_cells(rows_idx=rows_idx, cols_idx=cols_idx): | |
if not cell.header: | |
try: | |
formatter = '.' + str(num_digits) + 'f' | |
format_text = format(float(cell.orig_value)*100, formatter) | |
cell.text = format_text + '%' | |
except Exception as e: | |
continue | |
return self | |
def set_num(self, rows_idx=None, cols_idx=None, num_digits=0): | |
for cell in self.get_cells(rows_idx=rows_idx, cols_idx=cols_idx): | |
if not cell.header: | |
try: | |
formatter = '.' + str(num_digits) + 'f' | |
format_text = format(float(cell.orig_value), formatter) | |
dig = format_text.split('.')[0] | |
cell.text = '{:,}'.format(int(dig)) | |
try: | |
dec = format_text.split('.')[1] | |
cell.text += '.%s' % dec | |
except Exception as e: | |
next | |
except Exception as e: | |
continue | |
return self | |
def set_col_pct(self, cols_idx, num_digits=2): | |
return self.set_pct(rows_idx=None, cols_idx=cols_idx, num_digits=num_digits) | |
def set_col_num(self, cols_idx, num_digits=0): | |
return self.set_num(rows_idx=None, cols_idx=cols_idx, num_digits=num_digits) | |
def set_col_align_left(self, cols_idx): | |
for cell in self.get_cells(cols_idx=cols_idx): | |
if not cell.header: | |
cell.align = 'left' | |
return self | |
def set_col_align_right(self, cols_idx): | |
for cell in self.get_cells(cols_idx=cols_idx): | |
if not cell.header: | |
cell.align = 'right' | |
return self | |
def set_row_align_right(self, rows_idx): | |
for cell in self.get_cells(rows_idx=rows_idx): | |
if not cell.header: | |
cell.align = 'right' | |
return self | |
def set_col_align_center(self, cols_idx): | |
for cell in self.get_cells(cols_idx=cols_idx): | |
if not cell.header: | |
cell.align = 'center' | |
return self | |
def set_scale(self, rows_idx=None, cols_idx=None, scale=1): | |
for cell in self.get_cells(rows_idx=rows_idx, cols_idx=cols_idx): | |
if not cell.header: | |
try: | |
cell.orig_value = str(float(cell.orig_value)/float(scale)) | |
except Exception as e: | |
continue | |
return self | |
def set_col_scale(self, cols_idx, scale): | |
return self.set_scale(rows_idx=None, cols_idx=cols_idx, scale=scale) | |
def set_col_format_blank(self, cols_idx, format=' - '): | |
for cell in self.get_cells(cols_idx=cols_idx): | |
if not cell.header: | |
try: | |
if float(cell.orig_value) == 0: | |
cell.text = format | |
except Exception as e: | |
continue | |
return self | |
def set_col_sort(self, cols_idx, sort_order=None): | |
if sort_order: | |
col_idx = cols_idx - 1 | |
items = sort_order.strip().replace(";",",").split(',') | |
new_rows = [] | |
# 1.add headers | |
for row in self.rows: | |
if row.cells[0].header: | |
new_rows.append(row) | |
row.drop = True | |
else: | |
row.drop = False | |
self.rows = [row for row in self.rows if not row.drop] | |
# 2.add rows that need to be sorted | |
for item in items: | |
for row in self.rows: | |
if row.cells[col_idx].text == item: | |
new_rows.append(row) | |
row.drop = True | |
else: | |
row.drop = False | |
self.rows = [row for row in self.rows if not row.drop] | |
# 3.add the left rows | |
for row in self.rows: | |
new_rows.append(row) | |
# 4.return the sorted rows | |
self.rows = new_rows | |
return self | |
return self | |
def set_rowspan(self, tgt_row_idx, tgt_col_idx, rowspan): | |
tgt_row_idx = int(tgt_row_idx) - 1 | |
tgt_col_idx = int(tgt_col_idx) - 1 | |
for row in self.rows: | |
for cell in row.cells: | |
row_idx = self.rows.index(row) | |
col_idx = row.cells.index(cell) | |
if row_idx == tgt_row_idx and col_idx == tgt_col_idx: | |
cell.rowspan = rowspan | |
elif row_idx > tgt_row_idx and row_idx < tgt_row_idx + int(rowspan) and col_idx == tgt_col_idx: | |
cell.hidden = True | |
return self | |
def set_colspan(self, tgt_row_idx, tgt_col_idx, colspan): | |
tgt_row_idx = int(tgt_row_idx) - 1 | |
tgt_col_idx = int(tgt_col_idx) - 1 | |
for row in self.rows: | |
for cell in row.cells: | |
row_idx = self.rows.index(row) | |
col_idx = row.cells.index(cell) | |
if row_idx == tgt_row_idx and col_idx == tgt_col_idx: | |
cell.colspan = colspan | |
elif row_idx == tgt_row_idx and col_idx > tgt_col_idx and col_idx < tgt_col_idx + int(colspan): | |
cell.hidden = True | |
return self | |
def set_width(self, width): | |
self.width = str(width) | |
return self | |
def set_font_size(self, size): | |
self.font_size = size | |
return self | |
def __str__(self): | |
"""return the HTML code for the table""" | |
result = "" | |
# deal with the table attributes | |
if self.width: self.attr['width'] = self.width | |
if self.border: self.attr['border'] = self.border | |
if self.cellspacing: self.attr['cellspacing'] = self.cellspacing | |
if self.cellpadding: self.attr['cellpadding'] = self.cellpadding | |
self.attr['style'] = 'font-family:%s; font-size:%s; border:%s; border-collapse:%s' % (self.font_family, self.font_size, self.table_border, self.border_collapse) | |
attr_str = "" | |
for attr in self.attr.keys(): | |
attr_str += ' %s="%s"' % (attr, self.attr[attr]) | |
result += '<TABLE%s>\n' % attr_str | |
# apply the row attributes | |
for row in self.rows: | |
result += str(row) | |
# end of the table | |
result += '</TABLE>' | |
result += '<BR>' | |
return result | |
class Paragraph(): | |
def __init__(self, text="", color="#000000", font_family="微软雅黑", font_style="normal", | |
font_size="11", font_weight="normal", margin="3", align="left"): | |
"""Paragraph constructor""" | |
self.text = text | |
self.color = color | |
self.font_family = font_family | |
self.font_style = font_style | |
self.font_size = font_size | |
self.font_weight = font_weight | |
self.margin = margin | |
self.align = align | |
def set_color(self, color): | |
self.color = get_color(color) | |
return self | |
def set_align(self, align): | |
self.align = align | |
return self | |
def set_bold(self): | |
self.font_weight = 'bold' | |
return self | |
def set_italic(self): | |
self.font_style = 'italic' | |
return self | |
def set_font_size(self, size): | |
self.font_size = size | |
return self | |
def __str__(self): | |
"""return the HTML code for the paragraph""" | |
result = "" | |
result += '<p style="font-family:%s; color:%s; font-size:%spx; font-weight:%s; font-style:%s; margin:%s" align="%s">\n' % (self.font_family, self.color, self.font_size, self.font_weight, self.font_style, self.margin, self.align) | |
for line in self.text: | |
line = line.replace(' ',' ') | |
result += '%s<BR>\n' % line | |
result += '</p>\n' | |
return result | |
class Image(): | |
def __init__(self, src=None, alt=None, width=None, height=None, hspace=None, vspace=None): | |
"""Image constructor""" | |
self.src = src.strip().split('/')[-1] | |
self.alt = alt if alt else self.src | |
self.width = width | |
self.height = height | |
self.hspace = hspace | |
self.vspace = vspace | |
self.attr = {} | |
def __str__(self): | |
"""return the HTML code for the image""" | |
if self.src: self.attr['src'] = 'cid:' + self.src | |
if self.alt: self.attr['alt'] = self.alt | |
if self.width: self.attr['width'] = self.width | |
if self.height: self.attr['height'] = self.height | |
if self.hspace: self.attr['hspace'] = self.hspace | |
if self.vspace: self.attr['vspace'] = self.vspace | |
attr_str = "" | |
for attr in self.attr.keys(): | |
attr_str += ' %s="%s"' % (attr, self.attr[attr]) | |
result = '' | |
result += '<IMG%s>' % attr_str | |
#result += '<BR>\n' | |
#result += '<BR>\n' | |
return result | |
def get_color(color): | |
color = str(color).upper() | |
color_dict = { | |
'RED': '#FF0000' | |
,'ORANGE': '#FFC000' | |
,'YELLOW': '#FFFF00' | |
,'GREEN': '#92D050' | |
,'BLUE': '#00B0F0' | |
,'PURPLE': '#8064A2' | |
,'WHITE': '#FFFFFF' | |
,'BLACK': '#000000' | |
,'GREY': '#BFBFBF' | |
,'LIGHTBLUE': '#CAE1FF' | |
,'PINK': '#FDE4D0' | |
} | |
if color in color_dict.keys(): | |
return color_dict[color] | |
else: | |
return color |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment