markup.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """
  2. The tags of the django.contrib.markup package, because somebody decided
  3. it was just too good to be in Django...
  4. Set of "markup" template filters for Django. These filters transform plain text
  5. markup syntaxes to HTML; currently there is support for:
  6. * Textile, which requires the PyTextile library available at
  7. http://loopcore.com/python-textile/
  8. * Markdown, which requires the Python-markdown library from
  9. http://www.freewisdom.org/projects/python-markdown
  10. * reStructuredText, which requires docutils from http://docutils.sf.net/
  11. """
  12. from django import template
  13. from django.conf import settings
  14. from django.utils.encoding import force_bytes, force_text
  15. from django.utils.safestring import mark_safe
  16. register = template.Library()
  17. @register.filter(is_safe=True)
  18. def textile(value):
  19. try:
  20. import textile
  21. except ImportError:
  22. if settings.DEBUG:
  23. raise template.TemplateSyntaxError("Error in 'textile' filter: The Python textile library isn't installed.")
  24. return force_text(value)
  25. else:
  26. return mark_safe(force_text(textile.textile(force_bytes(value), encoding='utf-8', output='utf-8')))
  27. @register.filter(is_safe=True)
  28. def markdown(value, arg=''):
  29. """
  30. Runs Markdown over a given value, optionally using various
  31. extensions python-markdown supports.
  32. Syntax::
  33. {{ value|markdown:"extension1_name,extension2_name..." }}
  34. To enable safe mode, which strips raw HTML and only returns HTML
  35. generated by actual Markdown syntax, pass "safe" as the first
  36. extension in the list.
  37. If the version of Markdown in use does not support extensions,
  38. they will be silently ignored.
  39. """
  40. import warnings
  41. warnings.warn('The markdown filter has been deprecated',
  42. category=DeprecationWarning)
  43. try:
  44. import markdown
  45. except ImportError:
  46. if settings.DEBUG:
  47. raise template.TemplateSyntaxError("Error in 'markdown' filter: The Python markdown library isn't installed.")
  48. return force_text(value)
  49. else:
  50. markdown_vers = getattr(markdown, "version_info", 0)
  51. if markdown_vers < (2, 1):
  52. if settings.DEBUG:
  53. raise template.TemplateSyntaxError(
  54. "Error in 'markdown' filter: Django does not support versions of the Python markdown library < 2.1.")
  55. return force_text(value)
  56. else:
  57. extensions = [e for e in arg.split(",") if e]
  58. if extensions and extensions[0] == "safe":
  59. extensions = extensions[1:]
  60. return mark_safe(markdown.markdown(
  61. force_text(value), extensions, safe_mode=True, enable_attributes=False))
  62. else:
  63. return mark_safe(markdown.markdown(
  64. force_text(value), extensions, safe_mode=False))
  65. @register.filter(is_safe=True)
  66. def restructuredtext(value):
  67. import warnings
  68. warnings.warn('The restructuredtext filter has been deprecated',
  69. category=DeprecationWarning)
  70. try:
  71. from docutils.core import publish_parts
  72. except ImportError:
  73. if settings.DEBUG:
  74. raise template.TemplateSyntaxError("Error in 'restructuredtext' filter: The Python docutils library isn't installed.")
  75. return force_text(value)
  76. else:
  77. docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
  78. parts = publish_parts(source=force_bytes(value), writer_name="html4css1", settings_overrides=docutils_settings)
  79. return mark_safe(force_text(parts["fragment"]))