Skip to content

Instantly share code, notes, and snippets.

@habnabit
Forked from liftoff/htmltag.py
Created April 12, 2013 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save habnabit/5374379 to your computer and use it in GitHub Desktop.
Save habnabit/5374379 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
#
# Copyright 2013 Liftoff Software Corporation
#
# For license information see LICENSE.txt
# Meta
__version__ = '1.0.0'
__version_info__ = (1, 0, 0)
__license__ = "Apache 2.0"
__author__ = 'Dan McDougall <daniel.mcdougall@liftoffsoftware.com>'
"""
htmltag.py - A library for wrapping whatever strings you want in HTML tags.
Example::
>>> from htmltag import strong
>>> print(strong("SO STRONG!"))
<strong>SO STRONG!</strong>
What tags are supported? All of them! An important facet of HTML5 is the
ability to use your own custom tags. For example::
>>> from htmltag import foobar
>>> foobar('Custom tag example')
'<foobar>Custom tag example</foobar>'
To add attributes inside your tag just pass them as keyword arguments::
>>> from htmltag import a
>>> print(a('awesome software', href='http://liftoffsoftware.com/'))
<a href="http://liftoffsoftware.com/">awesome software</a>
You can combine multiple tags to create a larger HTML string like so::
>>> print(
table(
tr(td('100'), td('200'), id="row1"),
tr(td('150'), td('250'), id="row2"),
)
)
'<table><tr id="row1"><td>100</td><td>200</td></tr><tr id="row2"><td>150</td><td>250</td></tr></table>'
.. note:: If you're going to do something like the above please use a *real* template language/module instead of `htmltag`. You're *probably* "doing it wrong" if you end up with something like the above in your code. For example, try Tornado's template engine (http://www.tornadoweb.org/en/stable/template.html).
..
TODO: fixme
Special characters that cause trouble like, '<', '>', and '&' will be
automatically converted into HTML entities. If you are passing a string that
already has these entities escaped and don't want them double-escaped just wrap
your string in :class:`htmltag.Escaped` like so::
>>> from htmltag import Escaped, a
>>> txt = Escaped("<strong>I am already escaped. Don't escape me!</strong>")
>>> a(txt, href="http://liftoffsoftware.com/")
'<a href="http://liftoffsoftware.com/"><strong>I am already escaped. Don\'t escape me!</strong></a>'
"""
import markupsafe
import sys
from types import ModuleType
class TagWrap(object):
"""
Lets you wrap whatever string you want in whatever tag you want.
"""
def __init__(self, tagname, **kwargs):
self.tagname = tagname
def wrap(self, tag, *args, **kwargs):
"""
Returns *string* wrapped in HTML tags like so::
>>> b = TagWrap('b')
>>> print(b('bold text'))
<b>bold text</b>
To add attributes to the tag you can pass them as keyword args:
>>> a = TagWrap('a')
>>> print(a('awesome software', href='http://liftoffsoftware.com/'))
<a href="http://liftoffsoftware.com/">awesome software</a>
.. note:: Will automatically convert '<', '>', and '&' into HTML entities.
"""
combined = ''.join(markupsafe.escape(s) for s in args)
tagstart = tag
if kwargs:
tagstart += ' '
for key, value in kwargs.items():
tagstart = tagstart + '{}="{}" '.format(key, markupsafe.escape(value))
tagstart = tagstart.rstrip()
return markupsafe.Markup("<{}>{}</{}>".format(tagstart, combined, tag))
def __call__(self, *args, **kwargs):
return self.wrap(self.tagname, *args, **kwargs)
def __getitem__(self, k):
if isinstance(k, str):
if k.startswith('__') and k.endswith("__"):
raise AttributeError
return getattr(self, k)
else:
raise ImportError("Using IPython? Ignore that ^ traceback stuff.")
class SelfWrap(ModuleType):
"""
This is the magic that lets us do things like::
>>> from htmltag import span
"""
def __init__(self, tagname, *args, **kwargs):
self.tagname = tagname
# This is necessary for reload() to work:
for attr in ["__builtins__", "__doc__", "__name__", "__package__"]:
setattr(self, attr, getattr(tagname, attr, None))
self.__path__ = [] # Required for Python 3.3
# So we don't overwrite these with a TagWrap instance:
self.SelfWrap = SelfWrap
def __getattr__(self, name): # "from htmltag import a" <--*name* will be 'a'
ret = TagWrap(name)
setattr(self, name, ret)
return ret
def __call__(self, *args, **kwargs):
# This turns the 'a' in "from htmltag import a" into a callable:
return TagWrap(self.tagname, *args, **kwargs)
if __name__ == "__main__":
print("Don't run me directly silly!")
sys.exit(1)
else:
self = sys.modules[__name__]
sys.modules[__name__] = SelfWrap(self)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment