Skip to content

Instantly share code, notes, and snippets.

@tkhduracell
Last active August 29, 2015 13:57
Show Gist options
  • Save tkhduracell/9539269 to your computer and use it in GitHub Desktop.
Save tkhduracell/9539269 to your computer and use it in GitHub Desktop.
A small Python class to build Bootstrap html documents with a pretty function syntax.
from datetime import datetime
import os
import types
import functools
import my_utils
class PyStrapper:
name = ""
output = ""
output_handler = False
output_element_stack = []
def __init__(self, output_file="default.html", name="My Report"):
self.name = name
self.output = output_file
try:
self.output_handler = open(output_file, "w")
except Exception as e:
raise Exception("Can not read file: "+output_file + "\n" + str(e))
def __repr__(self):
return "%s: name=%s, output=%s" % (self.__class__.__name__,self.name, self.output)
def write(self, str):
self.output_handler.write(str)
def init(self):
supported = ["section", "nav", "article", "aside", "header", "footer", "address", "main", "p", "hr", "pre", "blockquote", "ol", "ul", "li", "dl", "dt","dd", "dd",
"figure", "figcaption", "div", "a", "em", "strong", "small", "s", "cite", "q", "dfn", "abbr" "title", "data", "time", "datetime", "code", "var", "samp", "kbd",
"sub", "sup", "i", "b", "u", "mark", "ruby", "rt", "rp", "bdi", "bdo", "span" "classlangdir", "br", "wbr", "ins", "del", "img ", "iframe", "embed", "object",
"param", "object", "video", "audio", "source", "video", "audio", "track", "video", "audio", "canvas", "map", "area", "area", "map", "svg", "math", "table",
"caption", "colgroup", "col", "tbody", "thead", "tfoot", "tr", "td", "th", "form", "fieldset", "legend", "fieldset", "label", "input", "button", "select",
"datalist", "optgroup", "option", "select", "datalist", "textarea", "keygen", "output", "progress", "meter", "details", "summary", "details", "menuitem", "menu"]
supported.extend(["h%d" % (s,) for s in range(1,7)])
def bind_to_class(func, name, obj, tag):
func.__name__ = name
setattr(obj.__class__, func.__name__, functools.partial(func, obj, tag))
for tag in sorted(supported):
def dynamic_begin(self, the_tag):
self.wrapper_begin(the_tag)
return self
bind_to_class(dynamic_begin, tag+"_begin", self, tag)
def dynamic_end(self, the_tag):
self.wrapper_end(the_tag)
return self
bind_to_class(dynamic_end, tag+"_end", self, tag)
def dynamic_plain(self, the_tag, *args, **kwargs):
if len(args) > 1:
raise Exception("Multiple content not supported, [0,1]")
if len(args) == 1:
kwargs['_content'] = args[0]
self.plain_element(the_tag, kwargs)
return self
bind_to_class(dynamic_plain, tag, self, tag)
return self
def begin(self):
header = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><!--MY_TITLE--></title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.js"></script>
<style>
html {
position: relative;
min-height: 100%;
}
body {
margin-top: 60px;
}
</style>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"><!--MY_TITLE--></a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<!--<li class='active' ><a href="index.php">Start</a></li>-->
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="starter-template">
<!-- content goes here -->
"""
self.write(header.replace("<!--MY_TITLE-->", self.name, 2))
self.init()
return self
def end(self):
footer = """
<hr>
<footer class="text-muted small">
<span class="pull-left">%s <br>&copy; Filip Lindqvist 2014</span>
<span class="pull-right">Report generated %s</span>
</footer>
</div><!-- /.container -->
</body>
</html>
"""
self.write(footer % (self.__class__.__name__,datetime.today().strftime("%Y-%m-%d %H:%M:%S"),))
self.output_handler.close()
return self
def wrapper_begin(self, tag):
self.output_element_stack.append(tag)
self.write("<%s>" % (tag,))
return self
def wrapper_end(self, tag):
if self.output_element_stack[-1] is tag:
self.output_element_stack.pop()
self.write("</%s>\n" % (tag,))
return self
else:
raise Exception("Not in a %s, stack: %s" % (tag, str(self.output_element_stack)))
def plain_element(self, tag, attr):
attribute_str = " ".join(
[("%s=\"%s\"" % (key,value))
for key, value in attr.items()
if key not in ("_content")
]
)
if "_content" in attr:
content = attr['_content']
self.write("<%s %s>%s</%s>\n" % (tag, attribute_str, content, tag))
else:
self.write("<%s %s/>\n" % (tag, attribute_str))
return self
def main():
(PyStrapper("test.html", "My Test Report").begin()
.br()
.h3("h3. Bootstrap heading")
.p("This is a sample unordered list")
.ul_begin()
.li("test1")
.li("test2")
.ul_end()
.p("This is a sample ordered list", style="color:blue")
.ol_begin()
.li("test1")
.li("test2")
.ol_end()
.end())
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment