Skip to content

Instantly share code, notes, and snippets.

@mdamien
Last active March 19, 2019 10:41
Show Gist options
  • Select an option

  • Save mdamien/81d84b025b6f40e7754835ee1db6167d to your computer and use it in GitHub Desktop.

Select an option

Save mdamien/81d84b025b6f40e7754835ee1db6167d to your computer and use it in GitHub Desktop.
html templating with python (now http://github.com/mdamien/lys)
from html42 import H, render
def _base(content='', title_prefix=''):
return render(H.html() / (
H.head() / (
H.meta(charset="utf-8"),
H.meta(content="width=device-width, initial-scale=1", name="viewport"),
H.title() / (title_prefix + "Chrome Extensions Archive"),
H.link(href="/style.css", media="screen", rel="stylesheet", type="text/css"),
),
H.body() / (
H.a(href='/') / (H.h1() / "Chrome Extensions Archive"),
H.div(style='text-align: right') /
H.a(href="https://github.com/mdamien/chrome-extensions-archive") /
"github.com/mdamien/chrome-extensions-archive",
H.hr(),
content,
),
))
print(render(_base('hello world'))
import html, types
def render(node):
assert node is not None # TODO: None => '' ?
if type(node) in (tuple, list, types.GeneratorType):
return ''.join(render(child) for child in node)
if type(node) == str:
return html.escape(node)
children_rendered = ''
if node.children:
children_rendered = render(node.children)
attrs_rendered = ''
if node.attrs:
# TODO: really, should I ignore the None values ?
# TODO: class_, is_, ...
attrs_rendered = ' ' + ' '.join(
html.escape(key.replace('class_', 'class')) + '="' + html.escape(value) + '"'
for key, value in node.attrs.items()
if value is not None)
if node.tag in ('br', 'img', 'hr'):
assert not node.children
return '<{tag}{attrs} />'.format(tag=node.tag, attrs=attrs_rendered)
return '<{tag}{attrs}>{children}</{tag}>'.format(
tag=node.tag, children=children_rendered, attrs=attrs_rendered)
class Node:
def __init__(self, tag, attrs=None, children=None):
assert tag
self.tag = tag
self.attrs = attrs
self.children = children
def __truediv__(self, children):
if type(children) not in (tuple, list):
children = (children,)
self.children = children
return self
def __str__(self):
return render(self)
class _H:
def __getattr__(self, tag):
return lambda **attrs: Node(tag, attrs)
H = _H()
  • django integration example
  • auto-converter from HTML and Django Templates (and other templating languages)
  • self-closing tags (br, img,..)
  • special attributes (class, is,..)
  • custom anchor point for children
  • support escaped string (markdown rendered, javascript,...)

other ideas:

  • use beautifulsoup to store the node ? nice querying, prettify,..

  • what to do with the a() / b() / c() trap ?

  • also a() / b() + c() trap, change operator to high priority instead ?

    • content can go as first arg too (H.span('the dress is green'))
      • if this is used, forbid a new / since it's counter-intuitive
  • less typing

    • H.span is valid too
    • H('#main.red.big')to create <div id='main' class='red big'>
  • change main letter to L ?

  • safe execution (sandbox) so user write the stuff directly



ideas after making a website:

TypeError: call() takes from 1 to 2 positional arguments but 3 were given

=> do not return the Lys object directly, do str(node) befores

BASIC "HELP ME PLEASE" MODE WHERE IT PREVENT BASIC ERROR (mystyped css, atributes,...)

would be nice to have live editing (save the round trip from chrome)

autogenerated class names

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment