Skip to content

Instantly share code, notes, and snippets.

@guangningyu
Created December 6, 2016 14:42
Show Gist options
  • Save guangningyu/055e1aa9c9b6c484fba013c62a3d8ff9 to your computer and use it in GitHub Desktop.
Save guangningyu/055e1aa9c9b6c484fba013c62a3d8ff9 to your computer and use it in GitHub Desktop.
Generate HTML format file containing tables, images and paragraphs using Python.
#!/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(' ','&nbsp;')
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