Summary

This is a Python implementation of John Gruber's [Markdown](http://daringfireball.net/projects/markdown/). The current version of python-markdown implements all Markdown syntax features and fully passes [Markdown Test Suite 1.0](http://six.pairlist.net/pipermail/markdown-discuss/2004-December/000909.html). It also supports footnotes (see [this thread](http://six.pairlist.net/pipermail/markdown-discuss/2005-August/001480.html)) and attributes (see [this thread](http://six.pairlist.net/pipermail/markdown-discuss/2005-August/001486.html)). Python-Markdown defaults to ignoring middle-word emphasis through underscore, but this it can be switched off. (See [this thread](http://six.pairlist.net/pipermail/markdown-discuss/2005-October/001610.html) for discussion.) If you find something missing, [submit a bug report](http://sourceforge.net/tracker/?func=add&group_id=153041&atid=790198) or send me an email (qaramazov-at-gmail.com). Better yet, send me a patch.

Installation

[Download](http://sourceforge.net/project/showfiles.php?group_id=153041) the zip file and extract the files. If you want to install markdown as as a module into your python tree, run "sudo python setup.py install" from a directory where you unzip the files. (You typically need to be root to install modules this way - hence use of "sudo". If you don't have root access, it probably doesn't make sense for you to "install" markdown this way - just put the markdown.py file somewhere and make sure that directory is in your path later.)

Command Line Usage

To use markdown.py by itself, run it as python markdown.py or python markdown.py > If you are using Python 2.3 or higher, you can also use advanced command line options to specify encoding or to run extensions. $ python markdown.py usage: markdown.py INPUTFILE [options] options: -h, --help show this help message and exit -f OUTPUT_FILE, --file=OUTPUT_FILE write output to OUTPUT_FILE -e ENCODING, --encoding=ENCODING encoding for input and output files -q, --quiet suppress all messages -v, --verbose print info messages -s, --safe same mode (strip user's HTML tag) --noisy print debug messages -x EXTENSION, --extension=EXTENSION load extension EXTENSION For an extension to be ran this way it must be provided in a module named ``mdx_{extensionname}.py`` which should be in your python path, e.g. ``mdx_footnotes.py``. It can then be invoked as by name (the part after "mdx_"): python markdown.py -x footnotes text_with_footnotes.txt output.html If the extension supports config options (see below), you can also pass them in as well: python markdown.py -x "footnotes(PLACE_MARKER=~~~~~~~~)"

Using the Module

To use markdown as a module: import markdown html = markdown.markdown(your_text_string) Alternatively, if you want to pass more options: import markdown md = Markdown(text, extensions=['footnotes'], extension_configs= {'footnotes' : ('PLACE_MARKER','~~~~~~~~')} encoding='utf8', safe_mode = True) return md.toString() or, if you want to process multiple strings: md = Markdown(text=None) md.toString(text) Note that if you are using Markdown on a web system which will transform text provided by untrusted users, you may want to use "safe_mode=True" option (see above) which ensures that user's HTML tags are removed. (They can still create links using Markdown syntax.)

Writing Extensions

The functionality of the script can be extended without changing the code, by inserting additional pre-processors, post-processors or inline patterns into Markdown's pipeline. **Pre-processors** operate on lines of source text and are run in the beginning. It is sufficient to write a class with a run() method that takes a list of text lines as a parameter and returns the same or a new list. An instance of the preprocessor can then be inserted into the markdown pipeline. Preprocessor classes must extend ``markdown.Preprocessor``. class SamplePreprocessor (markdown.Preprocessor) : def run(self, lines) : for i in range(len(lines)) : if lines[i].startswith(SOMETHING) : lines[i] = do_something(lines[i]) return lines md_instance.preprocessors.insert(SOME_INDEX, SamplePreprocessor()) **Post-processors** operate on a NanoDom tree and run at the very end. They need to implement a "run" method that takes a pointer to a NanoDom document. Postprocessor classes must extend ``markdown.Postprocessor``. class SamplePostprocessor (markdown.Postprocessor): def run(self, doc) : doc.documentElement.appendChild(doc.createElement("new")) md_instance.postprocessors.insert(SOME_INDEX, SamplePostprocessor()) Finally, **inline patterns** can be added. Each inline pattern includes a regular expression pattern and a method for turning a match object into a DOM fragment class MyCustomPattern (markdown.Pattern) : def handleMatch(self, m, doc) : el = doc.createElement('custom') el.setAttribute('stuff', m.group(3)) return el new_pattern = MyCustomPattern(r'your regular expression here') md_instance.inlinePatterns.insert(SOME_INDEX, new_pattern) Preprocessors, patterns and postprocessors need to then be wrapped together into an extension, which should be implemented as a class that extends markdown.Extension and should over-ride the ``extendMarkdown()`` method. ``extendMarkdown()`` is called during markdown construction, giving the extension a pointer to the markdown object (the ``md`` parameters) and markdown's global variables (``md_globals``), which in theory gives the extension an option of changing anything it cares to change. However, what it really should be doing is inserting preprocessors, postprocessors and patterns into the markdown pipeline: def extendMarkdown(self, md, md_globals) : self.md = md # Insert a preprocessor before ReferencePreprocessor index = md.preprocessors.index(md_globals['REFERENCE_PREPROCESSOR']) preprocessor = FootnotePreprocessor(self) preprocessor.md = md md.preprocessors.insert(index, preprocessor) If the extension uses any parameters that the use may want to change, they should be stored in self.config in the following format: self.config = {parameter_1_name : [value1, description1], parameter_2_name : [value2, description2] } When stored this way the config parameters can be over-riden from the command line or at the time Markdown is instantiated: markdown.py -x myextension(SOME_PARAM=2) inputfile.txt > output.txt Note that parameters should always be assumed to be set to string values, and should be converted at the run time, e.g. i += int(self.getConfig("SOME_PARAM")) Each extension should ideally be placed in its own module starting with ``mdx_`` prefix (e.g. ``mdx_footnotes.py``). The module must provide a module-level function called ``makeExtensions`` that takes as an optional parameter a list of configuration over-rides and returns an instance of the extension. E.g.: def makeExtension(configs=None) : return FootnoteExtension(configs=configs) See the implementation of footnote support distributed with the markdown script (mdx_footnotes.py) for an example of using all three in combination to provide reasonably complex additional functionality. (I use a pre-processor to collect footnote definitions, an inline pattern to handle uses of footnotes inside the text and a post-processor to attach the HTML of the actual footnotes at the end of the document) The RSS extension (mdx_rss.py, also included), which generates an RSS file from markdown source is a simpler extension but provides an example of extending markdown to generate arbitrary XML rather than HTML. Other extensions: * [Table-of-contents extension](extensions/mdx_toc.py) by Chris Clark (inserts a table of contents), upgraded by Yuri. * [Title extension](extensions/mdx_title.py) by Chris Clark (inserts a title element) * [WikiLinks](http://achinghead.com/archives/67/adding-wikilinks-to-markdown-in-python/) by Waylan Limberg (not yet upgraded)

Using Markdown with Django

Install markdown and make sure it is in your path. Include 'django.contrib.markup' in INSTALLED_APPS in your settings.py. You will then need to load the markup module in a template: {% load markup %} After that, you should be able to use markdown filter in that template as follows by putting "|markdown" after a variable, e.g.: {{ post.body|markdown }} If you want to use markdown with extensions or want an option of disabling HTML (e.g., in comments) edit django/contrib/markup/templatetags/markup.py file in your django tree replacing the definition of markdown() function with the following: def markdown(value, arg=''): try: import markdown except ImportError: if settings.DEBUG: raise (template.TemplateSyntaxError, "Error in {% markdown %} filter: " + "The markdown library isn't installed.") else : from django.utils.html import escape, linebreaks return linebreaks(escape(value)) else: extensions=arg.split(",") if len(extensions) > 0 and extensions[0] == "safe" : extensions = extensions[1:] safe_mode = True else : safe_mode = False return markdown.markdown(value, extensions, safe_mode=safe_mode) (This code snippet has been adapted from one proposed by [Waylan Limberg](http://achinghead.com/).) You should then be able to load extensions by listing them in quotes separated by comas: {{ post.body|markdown:"imagelinks,footnotes" }} If you want to disable HTML, include "safe" as the first argument: {{ post.body|markdown:"safe" }}

Credits

* The first version of this script was written by [Manfred Stienstra](http://www.dwerg.net/), who is responsible for about a quarter of the code. * Daniel Krech provided the setup.py script. * G. Clark Haynes submitted a patch for indented lists. * Tiago Cogumbreiro submitted an email autolink fix. * Sergej Chodarev submitted a patch for treatment of `
` tags. * Chris Clark submitted a patch to handle `` syntax and a reg ex for "smart" emphasis (ignoring underscores within a word). * Steward Midwinter wrote command-line parser and cleaned up comments. * Many other people helped by reporting bugs.

License

The code is dual-licensed under [GPL](http://www.gnu.org/copyleft/gpl.html) and [BSD License](http://www.opensource.org/licenses/bsd-license.php). Other licensing arrangements can be discussed.

Contact Info

Email qaramazov [at] gmail.com if you have any questions or spot any bugs. (Feel free to write in English, Russian, Portuguese or Spanish.) Or subscribe to [python-markdown-discuss](http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss).

Recent Changes

Oct 11, 2006: Releasing v. 1.6 with a whole bunch of changes (since May 15), including: - Fixed a bug that caused some text to be lost after comments. - Added exception for PHP tags when handling html blocks. - Incorporated Sergej Chodarev's patch to fix a problem with ampersand normalization and html blocks. - Switched to using optparse. Added proper support for unicode. - Fixed the