Permalink
Browse files

added tests for registering extensions, updated docs, fixed some pep8…

… stuff
  • Loading branch information...
1 parent 685d388 commit 25812f7b1b5e8b3227cacb91654ab1535767333a @dcolish committed Aug 14, 2010
Showing with 160 additions and 20 deletions.
  1. +5 −1 docs/index.rst
  2. +65 −15 flaskext/markdown.py
  3. +47 −0 tests/mdx_simple.py
  4. +43 −4 tests/test_markdown.py
View
@@ -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
View
@@ -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):
@@ -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
View
@@ -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")
@@ -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():
@@ -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()
@@ -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.