-
-
Save habnabit/5374379 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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 <[email protected]>' | |
""" | |
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