2 # -*- coding: iso-8859-1 -*-
\r
4 HTML.py - v0.04 2009-07-28 Philippe Lagadec
\r
6 This module provides a few classes to easily generate HTML code such as tables
\r
9 Project website: http://www.decalage.info/python/html
\r
11 License: CeCILL (open-source GPL compatible), see source code for details.
\r
12 http://www.cecill.info
\r
15 __version__ = '0.04'
\r
16 __date__ = '2009-07-28'
\r
17 __author__ = 'Philippe Lagadec'
\r
19 #--- LICENSE ------------------------------------------------------------------
\r
21 # Copyright Philippe Lagadec - see http://www.decalage.info/contact for contact info
\r
23 # This module provides a few classes to easily generate HTML tables and lists.
\r
25 # This software is governed by the CeCILL license under French law and
\r
26 # abiding by the rules of distribution of free software. You can use,
\r
27 # modify and/or redistribute the software under the terms of the CeCILL
\r
28 # license as circulated by CEA, CNRS and INRIA at the following URL
\r
29 # "http://www.cecill.info".
\r
31 # A copy of the CeCILL license is also provided in these attached files:
\r
32 # Licence_CeCILL_V2-en.html and Licence_CeCILL_V2-fr.html
\r
34 # As a counterpart to the access to the source code and rights to copy,
\r
35 # modify and redistribute granted by the license, users are provided only
\r
36 # with a limited warranty and the software's author, the holder of the
\r
37 # economic rights, and the successive licensors have only limited
\r
40 # In this respect, the user's attention is drawn to the risks associated
\r
41 # with loading, using, modifying and/or developing or reproducing the
\r
42 # software by the user in light of its specific status of free software,
\r
43 # that may mean that it is complicated to manipulate, and that also
\r
44 # therefore means that it is reserved for developers and experienced
\r
45 # professionals having in-depth computer knowledge. Users are therefore
\r
46 # encouraged to load and test the software's suitability as regards their
\r
47 # requirements in conditions enabling the security of their systems and/or
\r
48 # data to be ensured and, more generally, to use and operate it in the
\r
49 # same conditions as regards security.
\r
51 # The fact that you are presently reading this means that you have had
\r
52 # knowledge of the CeCILL license and that you accept its terms.
\r
55 #--- CHANGES ------------------------------------------------------------------
\r
57 # 2008-10-06 v0.01 PL: - First version
\r
58 # 2008-10-13 v0.02 PL: - added cellspacing and cellpadding to table
\r
59 # - added functions to ease one-step creation of tables
\r
61 # 2009-07-21 v0.03 PL: - added column attributes and styles (first attempt)
\r
62 # (thanks to an idea submitted by Michal Cernoevic)
\r
63 # 2009-07-28 v0.04 PL: - improved column styles, workaround for Mozilla
\r
66 #-------------------------------------------------------------------------------
\r
68 # - method to return a generator (yield each row) instead of a single string
\r
69 # - unicode support (input and output)
\r
70 # - escape text in cells (optional)
\r
71 # - constants for standard colors
\r
72 # - use lxml to generate well-formed HTML ?
\r
73 # - add classes/functions to generate a HTML page, paragraphs, headings, etc...
\r
76 #--- THANKS --------------------------------------------------------------------
\r
78 # - Michal Cernoevic, for the idea of column styles.
\r
80 #--- REFERENCES ----------------------------------------------------------------
\r
82 # HTML 4.01 specs: http://www.w3.org/TR/html4/struct/tables.html
\r
84 # Colors: http://www.w3.org/TR/html4/types.html#type-color
\r
86 # Columns alignement and style, one of the oldest and trickiest bugs in Mozilla:
\r
87 # https://bugzilla.mozilla.org/show_bug.cgi?id=915
\r
90 #--- CONSTANTS -----------------------------------------------------------------
\r
92 # Table style to get thin black lines in Mozilla/Firefox instead of 3D borders
\r
93 TABLE_STYLE_THINBORDER = "border: 1px solid #000000; border-collapse: collapse;"
\r
94 #TABLE_STYLE_THINBORDER = "border: 1px solid #000000;"
\r
97 #=== CLASSES ===================================================================
\r
99 class TableCell (object):
\r
101 a TableCell object is used to create a cell in a HTML table. (TD or TH)
\r
104 - text: text in the cell (may contain HTML tags). May be any object which
\r
105 can be converted to a string using str().
\r
106 - header: bool, false for a normal data cell (TD), true for a header cell (TH)
\r
107 - bgcolor: str, background color
\r
108 - width: str, width
\r
109 - align: str, horizontal alignement (left, center, right, justify or char)
\r
110 - char: str, alignment character, decimal point if not specified
\r
111 - charoff: str, see HTML specs
\r
112 - valign: str, vertical alignment (top|middle|bottom|baseline)
\r
113 - style: str, CSS style
\r
114 - attribs: dict, additional attributes for the TD/TH tag
\r
116 Reference: http://www.w3.org/TR/html4/struct/tables.html#h-11.2.6
\r
119 def __init__(self, text="", bgcolor=None, header=False, width=None,
\r
120 align=None, char=None, charoff=None, valign=None, style=None,
\r
122 """TableCell constructor"""
\r
124 self.bgcolor = bgcolor
\r
125 self.header = header
\r
129 self.charoff = charoff
\r
130 self.valign = valign
\r
132 self.attribs = attribs
\r
137 """return the HTML code for the table cell as a string"""
\r
139 if self.bgcolor: self.attribs['bgcolor'] = self.bgcolor
\r
140 if self.width: self.attribs['width'] = self.width
\r
141 if self.align: self.attribs['align'] = self.align
\r
142 if self.char: self.attribs['char'] = self.char
\r
143 if self.charoff: self.attribs['charoff'] = self.charoff
\r
144 if self.valign: self.attribs['valign'] = self.valign
\r
145 if self.style: self.attribs['style'] = self.style
\r
146 for attr in self.attribs:
\r
147 attribs_str += ' %s="%s"' % (attr, self.attribs[attr])
\r
149 text = str(self.text)
\r
151 # An empty cell should at least contain a non-breaking space
\r
154 return ' <TH%s>%s</TH>\n' % (attribs_str, text)
\r
156 return ' <TD%s>%s</TD>\n' % (attribs_str, text)
\r
158 #-------------------------------------------------------------------------------
\r
160 class TableRow (object):
\r
162 a TableRow object is used to create a row in a HTML table. (TR tag)
\r
165 - cells: list, tuple or any iterable, containing one string or TableCell
\r
166 object for each cell
\r
167 - header: bool, true for a header row (TH), false for a normal data row (TD)
\r
168 - bgcolor: str, background color
\r
169 - col_align, col_valign, col_char, col_charoff, col_styles: see Table class
\r
170 - attribs: dict, additional attributes for the TR tag
\r
172 Reference: http://www.w3.org/TR/html4/struct/tables.html#h-11.2.5
\r
175 def __init__(self, cells=None, bgcolor=None, header=False, attribs=None,
\r
176 col_align=None, col_valign=None, col_char=None,
\r
177 col_charoff=None, col_styles=None):
\r
178 """TableCell constructor"""
\r
179 self.bgcolor = bgcolor
\r
181 self.header = header
\r
182 self.col_align = col_align
\r
183 self.col_valign = col_valign
\r
184 self.col_char = col_char
\r
185 self.col_charoff = col_charoff
\r
186 self.col_styles = col_styles
\r
187 self.attribs = attribs
\r
192 """return the HTML code for the table row as a string"""
\r
194 if self.bgcolor: self.attribs['bgcolor'] = self.bgcolor
\r
195 for attr in self.attribs:
\r
196 attribs_str += ' %s="%s"' % (attr, self.attribs[attr])
\r
197 result = ' <TR%s>\n' % attribs_str
\r
198 for cell in self.cells:
\r
199 col = self.cells.index(cell) # cell column index
\r
200 if not isinstance(cell, TableCell):
\r
201 cell = TableCell(cell, header=self.header)
\r
202 # apply column alignment if specified:
\r
203 if self.col_align and cell.align==None:
\r
204 cell.align = self.col_align[col]
\r
205 if self.col_char and cell.char==None:
\r
206 cell.char = self.col_char[col]
\r
207 if self.col_charoff and cell.charoff==None:
\r
208 cell.charoff = self.col_charoff[col]
\r
209 if self.col_valign and cell.valign==None:
\r
210 cell.valign = self.col_valign[col]
\r
211 # apply column style if specified:
\r
212 if self.col_styles and cell.style==None:
\r
213 cell.style = self.col_styles[col]
\r
214 result += str(cell)
\r
215 result += ' </TR>\n'
\r
218 #-------------------------------------------------------------------------------
\r
220 class Table (object):
\r
222 a Table object is used to create a HTML table. (TABLE tag)
\r
225 - rows: list, tuple or any iterable, containing one iterable or TableRow
\r
226 object for each row
\r
227 - header_row: list, tuple or any iterable, containing the header row (optional)
\r
228 - border: str or int, border width
\r
229 - style: str, table style in CSS syntax (thin black borders by default)
\r
230 - width: str, width of the table on the page
\r
231 - attribs: dict, additional attributes for the TABLE tag
\r
232 - col_width: list or tuple defining width for each column
\r
233 - col_align: list or tuple defining horizontal alignment for each column
\r
234 - col_char: list or tuple defining alignment character for each column
\r
235 - col_charoff: list or tuple defining charoff attribute for each column
\r
236 - col_valign: list or tuple defining vertical alignment for each column
\r
237 - col_styles: list or tuple of HTML styles for each column
\r
239 Reference: http://www.w3.org/TR/html4/struct/tables.html#h-11.2.1
\r
242 def __init__(self, rows=None, border='1', style=None, width=None,
\r
243 cellspacing=None, cellpadding=4, attribs=None, header_row=None,
\r
244 col_width=None, col_align=None, col_valign=None,
\r
245 col_char=None, col_charoff=None, col_styles=None):
\r
246 """TableCell constructor"""
\r
247 self.border = border
\r
249 # style for thin borders by default
\r
250 if style == None: self.style = TABLE_STYLE_THINBORDER
\r
252 self.cellspacing = cellspacing
\r
253 self.cellpadding = cellpadding
\r
254 self.header_row = header_row
\r
256 if not rows: self.rows = []
\r
257 self.attribs = attribs
\r
258 if not attribs: self.attribs = {}
\r
259 self.col_width = col_width
\r
260 self.col_align = col_align
\r
261 self.col_char = col_char
\r
262 self.col_charoff = col_charoff
\r
263 self.col_valign = col_valign
\r
264 self.col_styles = col_styles
\r
267 """return the HTML code for the table as a string"""
\r
269 if self.border: self.attribs['border'] = self.border
\r
270 if self.style: self.attribs['style'] = self.style
\r
271 if self.width: self.attribs['width'] = self.width
\r
272 if self.cellspacing: self.attribs['cellspacing'] = self.cellspacing
\r
273 if self.cellpadding: self.attribs['cellpadding'] = self.cellpadding
\r
274 for attr in self.attribs:
\r
275 attribs_str += ' %s="%s"' % (attr, self.attribs[attr])
\r
276 result = '<TABLE%s>\n' % attribs_str
\r
277 # insert column tags and attributes if specified:
\r
279 for width in self.col_width:
\r
280 result += ' <COL width="%s">\n' % width
\r
281 # The following code would also generate column attributes for style
\r
282 # and alignement according to HTML4 specs,
\r
283 # BUT it is not supported completely (only width) on Mozilla Firefox:
\r
284 # see https://bugzilla.mozilla.org/show_bug.cgi?id=915
\r
285 ## n_cols = max(len(self.col_styles), len(self.col_width),
\r
286 ## len(self.col_align), len(self.col_valign))
\r
287 ## for i in range(n_cols):
\r
290 ## if self.col_styles[i]:
\r
291 ## col += ' style="%s"' % self.col_styles[i]
\r
294 ## if self.col_width[i]:
\r
295 ## col += ' width="%s"' % self.col_width[i]
\r
298 ## if self.col_align[i]:
\r
299 ## col += ' align="%s"' % self.col_align[i]
\r
302 ## if self.col_valign[i]:
\r
303 ## col += ' valign="%s"' % self.col_valign[i]
\r
305 ## result += '<COL%s>\n' % col
\r
306 # First insert a header row if specified:
\r
307 if self.header_row:
\r
308 if not isinstance(self.header_row, TableRow):
\r
309 result += str(TableRow(self.header_row, header=True))
\r
311 result += str(self.header_row)
\r
312 # Then all data rows:
\r
313 for row in self.rows:
\r
314 if not isinstance(row, TableRow):
\r
315 row = TableRow(row)
\r
316 # apply column alignments and styles to each row if specified:
\r
317 # (Mozilla bug workaround)
\r
318 if self.col_align and not row.col_align:
\r
319 row.col_align = self.col_align
\r
320 if self.col_char and not row.col_char:
\r
321 row.col_char = self.col_char
\r
322 if self.col_charoff and not row.col_charoff:
\r
323 row.col_charoff = self.col_charoff
\r
324 if self.col_valign and not row.col_valign:
\r
325 row.col_valign = self.col_valign
\r
326 if self.col_styles and not row.col_styles:
\r
327 row.col_styles = self.col_styles
\r
329 result += '</TABLE>'
\r
333 #-------------------------------------------------------------------------------
\r
335 class List (object):
\r
337 a List object is used to create an ordered or unordered list in HTML.
\r
341 - lines: list, tuple or any iterable, containing one string for each line
\r
342 - ordered: bool, choice between an ordered (OL) or unordered list (UL)
\r
343 - attribs: dict, additional attributes for the OL/UL tag
\r
345 Reference: http://www.w3.org/TR/html4/struct/lists.html
\r
348 def __init__(self, lines=None, ordered=False, start=None, attribs=None):
\r
349 """List constructor"""
\r
354 self.ordered = ordered
\r
357 self.attribs = attribs
\r
362 """return the HTML code for the list as a string"""
\r
364 if self.start: self.attribs['start'] = self.start
\r
365 for attr in self.attribs:
\r
366 attribs_str += ' %s="%s"' % (attr, self.attribs[attr])
\r
367 if self.ordered: tag = 'OL'
\r
369 result = '<%s%s>\n' % (tag, attribs_str)
\r
370 for line in self.lines:
\r
371 result += ' <LI>%s\n' % str(line)
\r
372 result += '</%s>\n' % tag
\r
376 ##class Link (object):
\r
378 ## a Link object is used to create link in HTML. (<a> tag)
\r
381 ## - text: str, text of the link
\r
382 ## - url: str, URL of the link
\r
383 ## - attribs: dict, additional attributes for the A tag
\r
385 ## Reference: http://www.w3.org/TR/html4
\r
388 ## def __init__(self, text, url=None, attribs=None):
\r
389 ## """Link constructor"""
\r
390 ## self.text = text
\r
393 ## self.attribs = attribs
\r
395 ## self.attribs = {}
\r
397 ## def __str__(self):
\r
398 ## """return the HTML code for the link as a string"""
\r
399 ## attribs_str = ""
\r
400 ## if self.url: self.attribs['href'] = self.url
\r
401 ## for attr in self.attribs:
\r
402 ## attribs_str += ' %s="%s"' % (attr, self.attribs[attr])
\r
403 ## return '<a%s>%s</a>' % (attribs_str, text)
\r
406 #=== FUNCTIONS ================================================================
\r
408 # much simpler definition of a link as a function:
\r
409 def Link(text, url):
\r
410 return '<a href="%s">%s</a>' % (url, text)
\r
412 def link(text, url):
\r
413 return '<a href="%s">%s</a>' % (url, text)
\r
415 def table(*args, **kwargs):
\r
416 'return HTML code for a table as a string. See Table class for parameters.'
\r
417 return str(Table(*args, **kwargs))
\r
419 def list(*args, **kwargs):
\r
420 'return HTML code for a list as a string. See List class for parameters.'
\r
421 return str(List(*args, **kwargs))
\r
424 #=== MAIN =====================================================================
\r
426 # Show sample usage when this file is launched as a script.
\r
428 if __name__ == '__main__':
\r
430 # open an HTML file to show output in a browser
\r
431 f = open('test.html', 'w')
\r
434 t.rows.append(TableRow(['A', 'B', 'C'], header=True))
\r
435 t.rows.append(TableRow(['D', 'E', 'F']))
\r
436 t.rows.append(('i', 'j', 'k'))
\r
437 f.write(str(t) + '<p>\n')
\r
444 ], width='100%', header_row=('col1', 'col2'),
\r
445 col_width=('', '75%'))
\r
446 f.write(str(t2) + '<p>\n')
\r
450 t2.rows.append(['5', '6'])
\r
451 t2.rows[1][1] = TableCell('new', bgcolor='red')
\r
452 t2.rows.append(TableRow(['7', '8'], attribs={'align': 'center'}))
\r
453 f.write(str(t2) + '<p>\n')
\r
457 # sample table with column attributes and styles:
\r
459 ['Smith', 'John', 30, 4.5],
\r
460 ['Carpenter', 'Jack', 47, 7],
\r
461 ['Johnson', 'Paul', 62, 10.55],
\r
463 htmlcode = HTML.table(table_data,
\r
464 header_row = ['Last name', 'First name', 'Age', 'Score'],
\r
465 col_width=['', '20%', '10%', '10%'],
\r
466 col_align=['left', 'center', 'right', 'char'],
\r
467 col_styles=['font-size: large', '', 'font-size: small', 'background-color:yellow'])
\r
468 f.write(htmlcode + '<p>\n')
\r
472 def gen_table_squares(n):
\r
474 Generator to create table rows for integers from 1 to n
\r
476 ## # First, header row:
\r
477 ## yield TableRow(('x', 'square(x)'), header=True, bgcolor='blue')
\r
478 ## # Then all rows:
\r
479 for x in range(1, n+1):
\r
482 t = Table(rows=gen_table_squares(10), header_row=('x', 'square(x)'))
\r
483 f.write(str(t) + '<p>\n')
\r
486 l = List(['aaa', 'bbb', 'ccc'])
\r
487 f.write(str(l) + '<p>\n')
\r
489 f.write(str(l) + '<p>\n')
\r
491 f.write(str(l) + '<p>\n')
\r