PageRenderTime 29ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/django/contrib/admindocs/utils.py

https://code.google.com/p/mango-py/
Python | 105 lines | 94 code | 6 blank | 5 comment | 11 complexity | 83b4c20b2731439cd37b3bf13202db7f MD5 | raw file
Possible License(s): BSD-3-Clause
  1. "Misc. utility functions/classes for admin documentation generator."
  2. import re
  3. from email.Parser import HeaderParser
  4. from email.Errors import HeaderParseError
  5. from django.utils.safestring import mark_safe
  6. from django.core.urlresolvers import reverse
  7. from django.utils.encoding import smart_str
  8. try:
  9. import docutils.core
  10. import docutils.nodes
  11. import docutils.parsers.rst.roles
  12. except ImportError:
  13. docutils_is_available = False
  14. else:
  15. docutils_is_available = True
  16. def trim_docstring(docstring):
  17. """
  18. Uniformly trims leading/trailing whitespace from docstrings.
  19. Based on http://www.python.org/peps/pep-0257.html#handling-docstring-indentation
  20. """
  21. if not docstring or not docstring.strip():
  22. return ''
  23. # Convert tabs to spaces and split into lines
  24. lines = docstring.expandtabs().splitlines()
  25. indent = min([len(line) - len(line.lstrip()) for line in lines if line.lstrip()])
  26. trimmed = [lines[0].lstrip()] + [line[indent:].rstrip() for line in lines[1:]]
  27. return "\n".join(trimmed).strip()
  28. def parse_docstring(docstring):
  29. """
  30. Parse out the parts of a docstring. Returns (title, body, metadata).
  31. """
  32. docstring = trim_docstring(docstring)
  33. parts = re.split(r'\n{2,}', docstring)
  34. title = parts[0]
  35. if len(parts) == 1:
  36. body = ''
  37. metadata = {}
  38. else:
  39. parser = HeaderParser()
  40. try:
  41. metadata = parser.parsestr(parts[-1])
  42. except HeaderParseError:
  43. metadata = {}
  44. body = "\n\n".join(parts[1:])
  45. else:
  46. metadata = dict(metadata.items())
  47. if metadata:
  48. body = "\n\n".join(parts[1:-1])
  49. else:
  50. body = "\n\n".join(parts[1:])
  51. return title, body, metadata
  52. def parse_rst(text, default_reference_context, thing_being_parsed=None):
  53. """
  54. Convert the string from reST to an XHTML fragment.
  55. """
  56. overrides = {
  57. 'doctitle_xform' : True,
  58. 'inital_header_level' : 3,
  59. "default_reference_context" : default_reference_context,
  60. "link_base" : reverse('django-admindocs-docroot').rstrip('/')
  61. }
  62. if thing_being_parsed:
  63. thing_being_parsed = smart_str("<%s>" % thing_being_parsed)
  64. parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
  65. destination_path=None, writer_name='html',
  66. settings_overrides=overrides)
  67. return mark_safe(parts['fragment'])
  68. #
  69. # reST roles
  70. #
  71. ROLES = {
  72. 'model' : '%s/models/%s/',
  73. 'view' : '%s/views/%s/',
  74. 'template' : '%s/templates/%s/',
  75. 'filter' : '%s/filters/#%s',
  76. 'tag' : '%s/tags/#%s',
  77. }
  78. def create_reference_role(rolename, urlbase):
  79. def _role(name, rawtext, text, lineno, inliner, options=None, content=None):
  80. if options is None: options = {}
  81. if content is None: content = []
  82. node = docutils.nodes.reference(rawtext, text, refuri=(urlbase % (inliner.document.settings.link_base, text.lower())), **options)
  83. return [node], []
  84. docutils.parsers.rst.roles.register_canonical_role(rolename, _role)
  85. def default_reference_role(name, rawtext, text, lineno, inliner, options=None, content=None):
  86. if options is None: options = {}
  87. if content is None: content = []
  88. context = inliner.document.settings.default_reference_context
  89. node = docutils.nodes.reference(rawtext, text, refuri=(ROLES[context] % (inliner.document.settings.link_base, text.lower())), **options)
  90. return [node], []
  91. if docutils_is_available:
  92. docutils.parsers.rst.roles.register_canonical_role('cmsreference', default_reference_role)
  93. docutils.parsers.rst.roles.DEFAULT_INTERPRETED_ROLE = 'cmsreference'
  94. for name, urlbase in ROLES.items():
  95. create_reference_role(name, urlbase)