Skip to content

Commit

Permalink
added tests for registering extensions, updated docs, fixed some pep8…
Browse files Browse the repository at this point in the history
… stuff
  • Loading branch information
dcolish committed Aug 14, 2010
1 parent 685d388 commit 25812f7
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 20 deletions.
6 changes: 5 additions & 1 deletion docs/index.rst
Expand Up @@ -45,13 +45,17 @@ You can also do

{{ mkd|markdown }}


Optionally, you can keep a reference to the Markdown instance and use that
to register custom extensions by calling :func:`Markdown.register_extension` or
decorating the extension class with :func:`Markdown.extend`

API Reference
-------------

.. autoclass:: Markdown
:members:


.. _`Flask`: http://flask.pocoo.org/
.. _`Markdown`: http://www.freewisdom.org/projects/python-markdown/
.. _`Github`: http://www.github.com/dcolish/flask-markdown
80 changes: 65 additions & 15 deletions flaskext/markdown.py
Expand Up @@ -18,28 +18,46 @@
You can also do::
{{ mymarkdown | markdown}}
{{ mymarkdown|markdown}}
Optionally, you can keep a reference to the Markdown instance and use that
to register custom extensions by calling :func:`register_extension` or
decorating the extension class with :func:`extend`
:copyright: (c) 2010 by Dan Colish.
:license: BSD, MIT see LICENSE for more details.
"""
from __future__ import absolute_import
from flask import Markup
from inspect import getmodule
import markdown as md
from markdown import (
blockprocessors,
Extension,
preprocessors,
)


__all__ = ['blockprocessors', 'Extension', 'Markdown', 'preprocessors']


class Markdown(object):
"""
Simple wrapper class for Markdown objects, any options that are available
for markdown may be passed as keyword arguments like so::
Markdown(app,
extensions=['footnotes'],
extension_configs={'footnotes': ('PLACE_MARKER','~~~~~~~~')},
safe_mode=True,
output_format='html4',
)
md = Markdown(app,
extensions=['footnotes'],
extension_configs={'footnotes': ('PLACE_MARKER','~~~~~~~~')},
safe_mode=True,
output_format='html4',
)
You can then call :func:`register_extension` to load custom extensions into
the Markdown instance or use the :func:`extend` decorator
:param app: Your Flask app instance
:param markdown_options: Keyword args for the Markdown instance
"""

def __init__(self, app, **markdown_options):
Expand All @@ -50,19 +68,51 @@ def __init__(self, app, **markdown_options):
def __call__(self, stream):
return Markup(self._instance.convert(stream))

def makeExtension(self, configs={}):
def extend(self, configs=None):
"""
Decorator for registering macros
You must either force the decorated class to be imported
or define it in the same file you instanciate Markdown
or define it in the same file you instantiate Markdown.
To register a simple extension you could do::
from flaskext.markdown import Extension, Markdown
from preprocessors import SimplePreprocessor
markdown_instance = Markdown(app)
@markdown_instance.make_extension()
class SimpleExtension(Extension):
def extendMarkdown(self, md, md_globals):
md.preprocessors.add('prover_block',
SimplePreprocessor(md),
'_begin')
md.registerExtension(self)
:param configs: A dictionary of options for the extension being registered
"""

def decorator(ext_cls):
return self.registerExtension(ext_cls, configs)
return self.register_extension(ext_cls, configs)
return decorator

def registerExtension(self, ext_cls, configs=None):
"""This will register an extension class with self._instance"""
def register_extension(self, ext_cls, configs=None):
"""
This will register an extension class with self._instance. You may pass
any additional configs required for your extension
It is best to call this when starting your Flask app, ie.::
from .mdx_simpl import SimpleExtension
md = Markdown(app)
md.register_extension(SimpleExtension)
Any additional configuration arguments can be added to configs and will
be passed through to the extension you are registering
:param configs: A dictionary of options for the extension being regsitered
:param ext_cls: The class name of your extension
"""
instance = ext_cls()
self._instance.registerExtensions([instance], configs)
module = getmodule(ext_cls)
module.makeExtension = ext_cls
return ext_cls
47 changes: 47 additions & 0 deletions tests/mdx_simple.py
@@ -0,0 +1,47 @@
"""
Simple Extension for Python-Markdown
=============================================
A simple example:
[[[
This is now a paragraph div
]]]
"""
from cgi import escape
import re
import markdown


class SimpleExtension(markdown.Extension):
def extendMarkdown(self, md, md_globals):
md.preprocessors.add('prover_block',
SimplePreprocessor(md),
'_begin')
md.registerExtension(self)


class SimplePreprocessor(markdown.preprocessors.Preprocessor):

RE = re.compile(r'(?P<begin>^\[{3,})[ ]*\n(?P<content>.*?)'
'(?P<end>^\]{3,})[ ]*$',
re.MULTILINE | re.DOTALL)
WRAP = """<div><p>{0}</p></div>"""

def __init__(self, md):
markdown.preprocessors.Preprocessor.__init__(self, md)

def run(self, lines):
text = "\n".join(lines)
while 1:
m = self.RE.search(text)
if m:
content = m.group('content').strip()
output = self.WRAP.format(escape(content, quote=True))
placeholder = self.markdown.htmlStash.store(output,
safe=True)
text = '%s\n%s\n%s' % (text[:m.start()], placeholder,
text[m.end():])
else:
break
return text.split("\n")
47 changes: 43 additions & 4 deletions tests/test_markdown.py
@@ -1,12 +1,15 @@
from flask import Flask, render_template_string

from flaskext.markdown import Markdown

from flaskext.markdown import Extension, Markdown
from mdx_simple import SimpleExtension, SimplePreprocessor

app = Flask(__name__)
app.debug = True
md = Markdown(app)


def run_client():
app = Flask(__name__)
app.debug = True
md = Markdown(app)

@app.route('/test_inline')
def view_render_inline():
Expand All @@ -24,6 +27,30 @@ def view_render_in_block():
tmp = u'{% filter markdown %}This is a *markdown* block{% endfilter %}'
return render_template_string(tmp)

@app.route('/test_register')
def view_render_registered_extension():
md.register_extension(SimpleExtension)

text = """[[[
This is now a paragraph div
]]]"""
return render_template_string(u"{{ text|markdown }}", text=text)

@app.route('/test_extend')
def view_render_decorated_extension():
@md.extend()
class SimpleExtension(Extension):
def extendMarkdown(self, md, md_globals):
md.preprocessors.add('prover_block',
SimplePreprocessor(md),
'_begin')
md.registerExtension(self)

text = """[[[
This is now a paragraph div
]]]"""
return render_template_string(u"{{ text|markdown }}", text=text)

return app.test_client()


Expand All @@ -43,3 +70,15 @@ def test_render_in_block():
client = run_client()
resp = client.open('/test_in_block')
assert resp.data == '<p>This is a <em>markdown</em> block</p>'


def test_render_register_extension():
client = run_client()
resp = client.open('/test_register')
assert resp.data == "<div><p>This is now a paragraph div</p></div>"


def test_render_extend_decorator():
client = run_client()
resp = client.open('/test_extend')
assert resp.data == "<div><p>This is now a paragraph div</p></div>"

0 comments on commit 25812f7

Please sign in to comment.