SmartyPants in Django Templates

John Gruber’s SmartyPants script is a great tool for converting a body of text into a more typographically correct and visually appealing version. Chad Miller’s Python port makes it really easy to implement this functionality as a template tag, but I wanted to take it a step further and use SmartyPants as a Markdown pre-processor, just as I did with Pygments.

The solution is actually very simple, but the actual RegEx required to do the job took me a bit of time to put together. The problem was to properly ignore code blocks and apply the SmartyPants filter on all areas outside the code examples. Here is the final Markdown pre-processor that I came up with:

class SmartyPantsPreprocessor(TextPreprocessor):
"""
A Markdown preprocessor that implements SmartyPants for converting plain
ASCII punctuation characters into typographically correct versions
"""
pattern = re.compile(r'(.+?)(@@.+?@@end|$)', re.S)

def run(self, lines):
def repl(m):
return smartyPants(m.group(1)) + m.group(2)

return self.pattern.sub(repl, lines)

The pattern looks for every piece of text that comes before a text block or before the end of the content, then filters the first part through SmartyPants, and passes the code blocks as they are. Finally, I make sure to register this processor before my Pygments pre-processor:

    md = Markdown()
md.textPreprocessors.insert(0, SmartyPantsPreprocessor())
md.textPreprocessors.insert(1, CodeBlockPreprocessor())

One last thing that I did was to implement Markdown2 instead of the old python-markdown library. This new version is much faster, and backwards compatible:

try:
from markdown2 import Markdown, TextPreprocessor
except ImportError:
from markdown import Markdown, TextPreprocessor

Good typography makes me happy!

Comments (2)

Speak Your Mind

  • Your address won't be shown, it will be used for Gravatar icons if available.

  • Markdown is allowed.

Header 1    Header 2
========    --------

*italic*    **bold**

> A single level blockquote
>> A nested quote

A link: [example](http://url.com "title")
Or a quick URL: <http://url.com>

1. Numbered list item 1
2. Numbered list item 2

* Unordered list item 1
* Unordered list item 2

Any paragraph with 4 spaces to 
the left is a preformatted code block

Language specific code blocks with 
syntax highlighting are supported too:

@@ python
import antigravity
@@ end