JIRA: BOTTLENECKS-29
[bottlenecks.git] / vstf / vstf / common / pyhtml.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 from sys import stdout, modules
12
13 doc_type = '<!DOCTYPE HTML>\n'
14 default_title = "Html Page"
15 charset = '<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />\n'
16
17 html4_tags = {'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo', 'big',
18               'blockquote', 'body', 'br', 'button', 'caption', 'cite', 'code', 'col',
19               'colgroup', 'dd', 'del', 'div', 'dfn', 'dl', 'dt', 'em', 'fieldset',
20               'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head',
21               'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd',
22               'label', 'legend', 'li', 'link', 'map', 'menu', 'menuitem', 'meta',
23               'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'p',
24               'param', 'pre', 'q', 'samp', 'script', 'select', 'small', 'span', 'strong',
25               'style', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th',
26               'thead', 'title', 'tr', 'tt', 'ul', 'var'}
27 disused_tags = {'isindex', 'font', 'dir', 's', 'strike',
28                 'u', 'center', 'basefont', 'applet', 'xmp'}
29 html5_tags = {'article', 'aside', 'audio', 'bdi', 'canvas', 'command', 'datalist', 'details',
30               'dialog', 'embed', 'figcaption', 'figure', 'footer', 'header',
31               'keygen', 'mark', 'meter', 'nav', 'output', 'progress', 'rp', 'rt', 'ruby',
32               'section', 'source', 'summary', 'details', 'time', 'track', 'video', 'wbr'}
33
34 nl = '\n'
35 tags = html4_tags | disused_tags | html5_tags
36
37 __all__ = [x.title() for x in tags] + ['PyHtml', 'space']
38
39 self_close = {'input', 'img', 'link', 'br'}
40
41
42 def space(n):
43     return ' ' * n
44
45
46 class Tag(list):
47     tag_name = ''
48
49     def __init__(self, *args, **kwargs):
50         self.attributes = kwargs
51         if self.tag_name:
52             name = self.tag_name
53             self.is_seq = False
54         else:
55             name = 'sequence'
56             self.is_seq = True
57         self._id = kwargs.get('id', name)
58         for arg in args:
59             self.add_obj(arg)
60
61     def __iadd__(self, obj):
62         if isinstance(obj, Tag) and obj.is_seq:
63             for o in obj:
64                 self.add_obj(o)
65         else:
66             self.add_obj(obj)
67         return self
68
69     def add_obj(self, obj):
70         if not isinstance(obj, Tag):
71             obj = str(obj)
72         _id = self.set_id(obj)
73         setattr(self, _id, obj)
74         self.append(obj)
75
76     def set_id(self, obj):
77         if isinstance(obj, Tag):
78             _id = obj._id
79             obj_lst = filter(lambda t: isinstance(
80                 t, Tag) and t._id.startswith(_id), self)
81         else:
82             _id = 'content'
83             obj_lst = filter(lambda t: not isinstance(t, Tag), self)
84         length = len(obj_lst)
85         if obj_lst:
86             _id = '%s_%03i' % (_id, length)
87         if isinstance(obj, Tag):
88             obj._id = _id
89         return _id
90
91     def __add__(self, obj):
92         if self.tag_name:
93             return Tag(self, obj)
94         self.add_obj(obj)
95         return self
96
97     def __lshift__(self, obj):
98         if isinstance(obj, Tag):
99             self += obj
100             return obj
101         print "unknown obj: %s " % obj
102         return self
103
104     def render(self):
105         result = ''
106         if self.tag_name:
107             result += '<%s%s%s>' % (self.tag_name,
108                                     self._render_attr(), self._self_close() * ' /')
109         if not self._self_close():
110             isnl = True
111             for c in self:
112                 if isinstance(c, Tag):
113                     result += isnl * nl
114                     isnl = False
115                     result += c.render()
116                 else:
117                     result += c
118             if self.tag_name:
119                 result += '</%s>' % self.tag_name
120         result += nl
121         return result
122
123     def _render_attr(self):
124         result = ''
125         for key, value in self.attributes.iteritems():
126             if key != 'txt' and key != 'open':
127                 if key == 'cl':
128                     key = 'class'
129                 result += ' %s="%s"' % (key, value)
130         return result
131
132     def _self_close(self):
133         return self.tag_name in self_close
134
135 """
136 def tag_factory(tag):
137     class F(Tag):
138         tag_name = tag
139
140     F.__name__ = tag.title()
141     return F
142
143
144 THIS = modules[__name__]
145
146 for t in tags:
147     setattr(THIS, t.title(), tag_factory(t))
148 """
149 THIS = modules[__name__]
150 for t in tags:
151     obj = type(t.title(), (Tag, ), {'tag_name': t})
152     setattr(THIS, t.title(), obj)
153
154
155 def _render_style(style):
156     result = ''
157     for item in style:
158         result += item
159         result += '\n{\n'
160         values = style[item]
161         for key, value in values.iteritems():
162             result += "    %s: %s;\n" % (key, value)
163         result += '}\n'
164     if result:
165         result = '\n' + result
166     return result
167
168
169 class PyHtml(Tag):
170     tag_name = 'html'
171
172     def __init__(self, title=default_title):
173         self._id = 'html'
174         self += Head()
175         self += Body()
176         self.attributes = dict(xmlns='http://www.w3.org/1999/xhtml', lang='en')
177         self.head += Title(title)
178
179     def __iadd__(self, obj):
180         if isinstance(obj, Head) or isinstance(obj, Body):
181             self.add_obj(obj)
182         elif isinstance(obj, Meta) or isinstance(obj, Link):
183             self.head += obj
184         else:
185             self.body += obj
186             _id = self.set_id(obj)
187             setattr(self, _id, obj)
188         return self
189
190     def add_js(self, *arg):
191         for f in arg:
192             self.head += Script(type='text/javascript', src=f)
193
194     def add_css(self, *arg):
195         for f in arg:
196             self.head += Link(rel='stylesheet', type='text/css', href=f)
197
198     def output(self, name=''):
199         if name:
200             fil = open(name, 'w')
201         else:
202             fil = stdout
203         fil.write(self.as_string())
204         fil.flush()
205         if name:
206             fil.close()
207
208     def as_string(self):
209         return doc_type + self.render()
210
211     def add_style(self, style):
212         self.head += Style(_render_style(style))
213
214     def add_table(self, data):
215         table = self << Table()
216         rows = len(data)
217         cols = len(zip(*data))
218
219         for i in range(rows):
220             tr = table << Tr()
221             tr << Th(data[i][0])
222             for j in range(1, cols):
223                 tr << Td(data[i][j])