| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | |
|---|
| 3 | """ |
|---|
| 4 | PyLucid content processors |
|---|
| 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 6 | |
|---|
| 7 | Tools around content: |
|---|
| 8 | |
|---|
| 9 | - apply a markup to a content |
|---|
| 10 | - render a django template |
|---|
| 11 | - redirect warnings |
|---|
| 12 | |
|---|
| 13 | Last commit info: |
|---|
| 14 | ~~~~~~~~~ |
|---|
| 15 | $LastChangedDate$ |
|---|
| 16 | $Rev$ |
|---|
| 17 | $Author$ |
|---|
| 18 | |
|---|
| 19 | :copyleft: 2007-2008 by the PyLucid team, see AUTHORS for more details. |
|---|
| 20 | :license: GNU GPL v3 or above, see LICENSE for more details |
|---|
| 21 | """ |
|---|
| 22 | |
|---|
| 23 | import re |
|---|
| 24 | |
|---|
| 25 | if __name__ == "__main__": |
|---|
| 26 | # For doctest only |
|---|
| 27 | import os |
|---|
| 28 | os.environ["DJANGO_SETTINGS_MODULE"] = "PyLucid.settings" |
|---|
| 29 | |
|---|
| 30 | from django.conf import settings |
|---|
| 31 | from django.template import Template, Context |
|---|
| 32 | from django.utils.safestring import mark_safe |
|---|
| 33 | from django.utils.encoding import smart_str, force_unicode |
|---|
| 34 | |
|---|
| 35 | from PyLucid.system.response import SimpleStringIO |
|---|
| 36 | |
|---|
| 37 | # use the undocumented django function to add the "lucidTag" to the tag library. |
|---|
| 38 | # see ./PyLucid/defaulttags/__init__.py |
|---|
| 39 | from django.template import add_to_builtins |
|---|
| 40 | add_to_builtins('PyLucid.template_addons') |
|---|
| 41 | |
|---|
| 42 | #______________________________________________________________________________ |
|---|
| 43 | # MARKUP |
|---|
| 44 | |
|---|
| 45 | BLOCK_RE = re.compile("\n{2,}") |
|---|
| 46 | |
|---|
| 47 | LINK_RE = re.compile( |
|---|
| 48 | r'''(?<!=")(?P<url>(http|ftp|svn|irc)://(?P<title>[^\s\<]+))(?uimx)''' |
|---|
| 49 | ) |
|---|
| 50 | |
|---|
| 51 | def fallback_markup(content): |
|---|
| 52 | """ |
|---|
| 53 | A simplest markup, build only paragraphs. |
|---|
| 54 | >>> fallback_markup("line one\\nline two\\n\\nnext block") |
|---|
| 55 | '<p>line one<br />\\nline two</p>\\n\\n<p>next block</p>' |
|---|
| 56 | |
|---|
| 57 | >>> fallback_markup("url: http://pylucid.org END") |
|---|
| 58 | '<p>url: <a href="http://pylucid.org">pylucid.org</a> END</p>' |
|---|
| 59 | """ |
|---|
| 60 | content = content.replace("\r\n", "\n").replace("\r","\n") |
|---|
| 61 | blocks = BLOCK_RE.split(content) |
|---|
| 62 | blocks = [line.replace("\n", "<br />\n") for line in blocks] |
|---|
| 63 | content = "<p>" + "</p>\n\n<p>".join(blocks) + "</p>" |
|---|
| 64 | content = LINK_RE.sub(r'<a href="\g<url>">\g<title></a>', content) |
|---|
| 65 | return content |
|---|
| 66 | |
|---|
| 67 | def apply_tinytextile(content, context): |
|---|
| 68 | """ tinyTextile markup """ |
|---|
| 69 | from PyLucid.system.markups.tinyTextile import TinyTextileParser |
|---|
| 70 | out_obj = SimpleStringIO() |
|---|
| 71 | markup_parser = TinyTextileParser(out_obj, context) |
|---|
| 72 | markup_parser.parse(content) |
|---|
| 73 | return out_obj.getvalue() |
|---|
| 74 | |
|---|
| 75 | |
|---|
| 76 | def apply_textile(content, page_msg): |
|---|
| 77 | """ Original textile markup """ |
|---|
| 78 | try: |
|---|
| 79 | import textile |
|---|
| 80 | except ImportError: |
|---|
| 81 | page_msg( |
|---|
| 82 | "Markup error: The Python textile library isn't installed." |
|---|
| 83 | " Download: http://cheeseshop.python.org/pypi/textile" |
|---|
| 84 | ) |
|---|
| 85 | return fallback_markup(content) |
|---|
| 86 | else: |
|---|
| 87 | return force_unicode(textile.textile( |
|---|
| 88 | smart_str(content), |
|---|
| 89 | encoding=settings.DEFAULT_CHARSET, |
|---|
| 90 | output=settings.DEFAULT_CHARSET |
|---|
| 91 | )) |
|---|
| 92 | |
|---|
| 93 | def apply_markdown(content, page_msg): |
|---|
| 94 | """ Markdown markup """ |
|---|
| 95 | try: |
|---|
| 96 | import markdown |
|---|
| 97 | except ImportError: |
|---|
| 98 | page_msg( |
|---|
| 99 | "Markup error: The Python markdown library isn't installed." |
|---|
| 100 | " Download: http://sourceforge.net/projects/python-markdown/" |
|---|
| 101 | ) |
|---|
| 102 | return fallback_markup(content) |
|---|
| 103 | else: |
|---|
| 104 | # unicode support only in markdown v1.7 or above. |
|---|
| 105 | # version_info exist only in markdown v1.6.2rc-2 or above. |
|---|
| 106 | if getattr(markdown, "version_info", None) < (1,7): |
|---|
| 107 | return force_unicode(markdown.markdown(smart_str(content))) |
|---|
| 108 | else: |
|---|
| 109 | return markdown.markdown(content) |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | def apply_restructuretext(content, page_msg): |
|---|
| 113 | try: |
|---|
| 114 | from docutils.core import publish_parts |
|---|
| 115 | except ImportError: |
|---|
| 116 | page_msg( |
|---|
| 117 | "Markup error: The Python docutils library isn't installed." |
|---|
| 118 | " Download: http://docutils.sourceforge.net/" |
|---|
| 119 | ) |
|---|
| 120 | return fallback_markup(content) |
|---|
| 121 | else: |
|---|
| 122 | docutils_settings = getattr( |
|---|
| 123 | settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {} |
|---|
| 124 | ) |
|---|
| 125 | parts = publish_parts( |
|---|
| 126 | source=content, writer_name="html4css1", |
|---|
| 127 | settings_overrides=docutils_settings |
|---|
| 128 | ) |
|---|
| 129 | return parts["fragment"] |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | |
|---|
| 133 | def apply_creole(content): |
|---|
| 134 | """ |
|---|
| 135 | Use python-creole: |
|---|
| 136 | http://code.google.com/p/python-creole/ |
|---|
| 137 | |
|---|
| 138 | We used verbose=1 for inser error information (e.g. not existing macro) |
|---|
| 139 | into the generated page |
|---|
| 140 | """ |
|---|
| 141 | from PyLucid.system.markups import PyLucid_creole_macros |
|---|
| 142 | from PyLucid.system.markups.creole import Parser |
|---|
| 143 | from PyLucid.system.markups.creole.creole2html import HtmlEmitter |
|---|
| 144 | |
|---|
| 145 | # Create document tree from creole markup |
|---|
| 146 | document = Parser(content).parse() |
|---|
| 147 | |
|---|
| 148 | # Build html code from document tree |
|---|
| 149 | return HtmlEmitter(document, macros=PyLucid_creole_macros, verbose=0).emit() |
|---|
| 150 | |
|---|
| 151 | from PyLucid.models import Page |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | |
|---|
| 155 | def apply_markup(content, context, markup_no): |
|---|
| 156 | """ |
|---|
| 157 | Apply to the content the given markup. |
|---|
| 158 | Makrups IDs defined in |
|---|
| 159 | ./PyLucid/models.py |
|---|
| 160 | """ |
|---|
| 161 | request = context["request"] |
|---|
| 162 | page_msg = request.page_msg |
|---|
| 163 | |
|---|
| 164 | if markup_no == Page.MARKUP_TINYTEXTILE: # PyLucid's TinyTextile |
|---|
| 165 | content = apply_tinytextile(content, context) |
|---|
| 166 | |
|---|
| 167 | elif markup_no == Page.MARKUP_TEXTILE: # Textile (original) |
|---|
| 168 | content = apply_textile(content, page_msg) |
|---|
| 169 | |
|---|
| 170 | elif markup_no == Page.MARKUP_MARKDOWN: |
|---|
| 171 | content = apply_markdown(content, page_msg) |
|---|
| 172 | |
|---|
| 173 | elif markup_no == Page.MARKUP_REST: |
|---|
| 174 | content = apply_restructuretext(content, page_msg) |
|---|
| 175 | |
|---|
| 176 | elif markup_no == Page.MARKUP_CREOLE: |
|---|
| 177 | content = apply_creole(content) |
|---|
| 178 | |
|---|
| 179 | return mark_safe(content) # turn djngo auto-escaping off |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | #______________________________________________________________________________ |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | def render_string_template(content, context, autoescape=True): |
|---|
| 186 | """ |
|---|
| 187 | Render a template. |
|---|
| 188 | """ |
|---|
| 189 | context2 = Context(context, autoescape) |
|---|
| 190 | template = Template(content) |
|---|
| 191 | html = template.render(context2) |
|---|
| 192 | return html |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | |
|---|
| 196 | if __name__ == "__main__": |
|---|
| 197 | import doctest |
|---|
| 198 | doctest.testmod( |
|---|
| 199 | # verbose=True |
|---|
| 200 | verbose=False |
|---|
| 201 | ) |
|---|
| 202 | print "DocTest end." |
|---|