PageRenderTime 25ms CodeModel.GetById 8ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/docs/_ext/djangodocs.py

Relevant Search: With Applications for Solr and Elasticsearch

For more in depth reading about search, ranking and generally everything you could ever want to know about how lucene, elasticsearch or solr work under the hood I highly suggest this book. Easily one of the most interesting technical books I have read in a long time. If you are tasked with solving search relevance problems even if not in Solr or Elasticsearch it should be your first reference. Amazon Affiliate Link
https://code.google.com/p/mango-py/
Python | 248 lines | 199 code | 23 blank | 26 comment | 13 complexity | 22b26aab5d1cf0bc4c18c26d9a872966 MD5 | raw file
  1"""
  2Sphinx plugins for Django documentation.
  3"""
  4import os
  5import re
  6
  7from docutils import nodes, transforms
  8try:
  9    import json
 10except ImportError:
 11    try:
 12        import simplejson as json
 13    except ImportError:
 14        try:
 15            from django.utils import simplejson as json
 16        except ImportError:
 17            json = None
 18
 19from sphinx import addnodes, roles
 20from sphinx.builders.html import StandaloneHTMLBuilder
 21from sphinx.writers.html import SmartyPantsHTMLTranslator
 22from sphinx.util.console import bold
 23from sphinx.util.compat import Directive
 24
 25# RE for option descriptions without a '--' prefix
 26simple_option_desc_re = re.compile(
 27    r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
 28
 29def setup(app):
 30    app.add_crossref_type(
 31        directivename = "setting",
 32        rolename      = "setting",
 33        indextemplate = "pair: %s; setting",
 34    )
 35    app.add_crossref_type(
 36        directivename = "templatetag",
 37        rolename      = "ttag",
 38        indextemplate = "pair: %s; template tag"
 39    )
 40    app.add_crossref_type(
 41        directivename = "templatefilter",
 42        rolename      = "tfilter",
 43        indextemplate = "pair: %s; template filter"
 44    )
 45    app.add_crossref_type(
 46        directivename = "fieldlookup",
 47        rolename      = "lookup",
 48        indextemplate = "pair: %s; field lookup type",
 49    )
 50    app.add_description_unit(
 51        directivename = "django-admin",
 52        rolename      = "djadmin",
 53        indextemplate = "pair: %s; django-admin command",
 54        parse_node    = parse_django_admin_node,
 55    )
 56    app.add_description_unit(
 57        directivename = "django-admin-option",
 58        rolename      = "djadminopt",
 59        indextemplate = "pair: %s; django-admin command-line option",
 60        parse_node    = parse_django_adminopt_node,
 61    )
 62    app.add_config_value('django_next_version', '0.0', True)
 63    app.add_directive('versionadded', VersionDirective)
 64    app.add_directive('versionchanged', VersionDirective)
 65    app.add_transform(SuppressBlockquotes)
 66    app.add_builder(DjangoStandaloneHTMLBuilder)
 67
 68
 69class VersionDirective(Directive):
 70    has_content = True
 71    required_arguments = 1
 72    optional_arguments = 1
 73    final_argument_whitespace = True
 74    option_spec = {}
 75
 76    def run(self):
 77        env = self.state.document.settings.env
 78        arg0 = self.arguments[0]
 79        is_nextversion = env.config.django_next_version == arg0
 80        ret = []
 81        node = addnodes.versionmodified()
 82        ret.append(node)
 83        if not is_nextversion:
 84            if len(self.arguments) == 1:
 85                linktext = 'Please, see the release notes </releases/%s>' % (arg0)
 86                xrefs = roles.XRefRole()('doc', linktext, linktext, self.lineno, self.state)
 87                node.extend(xrefs[0])
 88            node['version'] = arg0
 89        else:
 90            node['version'] = "Development version"
 91        node['type'] = self.name
 92        if len(self.arguments) == 2:
 93            inodes, messages = self.state.inline_text(self.arguments[1], self.lineno+1)
 94            node.extend(inodes)
 95            if self.content:
 96                self.state.nested_parse(self.content, self.content_offset, node)
 97            ret = ret + messages
 98        env.note_versionchange(node['type'], node['version'], node, self.lineno)
 99        return ret
100
101
102class SuppressBlockquotes(transforms.Transform):
103    """
104    Remove the default blockquotes that encase indented list, tables, etc.
105    """
106    default_priority = 300
107
108    suppress_blockquote_child_nodes = (
109        nodes.bullet_list,
110        nodes.enumerated_list,
111        nodes.definition_list,
112        nodes.literal_block,
113        nodes.doctest_block,
114        nodes.line_block,
115        nodes.table
116    )
117
118    def apply(self):
119        for node in self.document.traverse(nodes.block_quote):
120            if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
121                node.replace_self(node.children[0])
122
123class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
124    """
125    Django-specific reST to HTML tweaks.
126    """
127
128    # Don't use border=1, which docutils does by default.
129    def visit_table(self, node):
130        self.body.append(self.starttag(node, 'table', CLASS='docutils'))
131
132    # <big>? Really?
133    def visit_desc_parameterlist(self, node):
134        self.body.append('(')
135        self.first_param = 1
136
137    def depart_desc_parameterlist(self, node):
138        self.body.append(')')
139
140    #
141    # Don't apply smartypants to literal blocks
142    #
143    def visit_literal_block(self, node):
144        self.no_smarty += 1
145        SmartyPantsHTMLTranslator.visit_literal_block(self, node)
146
147    def depart_literal_block(self, node):
148        SmartyPantsHTMLTranslator.depart_literal_block(self, node)
149        self.no_smarty -= 1
150
151    #
152    # Turn the "new in version" stuff (versionadded/versionchanged) into a
153    # better callout -- the Sphinx default is just a little span,
154    # which is a bit less obvious that I'd like.
155    #
156    # FIXME: these messages are all hardcoded in English. We need to change
157    # that to accomodate other language docs, but I can't work out how to make
158    # that work.
159    #
160    version_text = {
161        'deprecated':       'Deprecated in Django %s',
162        'versionchanged':   'Changed in Django %s',
163        'versionadded':     'New in Django %s',
164    }
165
166    def visit_versionmodified(self, node):
167        self.body.append(
168            self.starttag(node, 'div', CLASS=node['type'])
169        )
170        title = "%s%s" % (
171            self.version_text[node['type']] % node['version'],
172            len(node) and ":" or "."
173        )
174        self.body.append('<span class="title">%s</span> ' % title)
175
176    def depart_versionmodified(self, node):
177        self.body.append("</div>\n")
178
179    # Give each section a unique ID -- nice for custom CSS hooks
180    def visit_section(self, node):
181        old_ids = node.get('ids', [])
182        node['ids'] = ['s-' + i for i in old_ids]
183        node['ids'].extend(old_ids)
184        SmartyPantsHTMLTranslator.visit_section(self, node)
185        node['ids'] = old_ids
186
187def parse_django_admin_node(env, sig, signode):
188    command = sig.split(' ')[0]
189    env._django_curr_admin_command = command
190    title = "django-admin.py %s" % sig
191    signode += addnodes.desc_name(title, title)
192    return sig
193
194def parse_django_adminopt_node(env, sig, signode):
195    """A copy of sphinx.directives.CmdoptionDesc.parse_signature()"""
196    from sphinx.domains.std import option_desc_re
197    count = 0
198    firstname = ''
199    for m in option_desc_re.finditer(sig):
200        optname, args = m.groups()
201        if count:
202            signode += addnodes.desc_addname(', ', ', ')
203        signode += addnodes.desc_name(optname, optname)
204        signode += addnodes.desc_addname(args, args)
205        if not count:
206            firstname = optname
207        count += 1
208    if not count:
209        for m in simple_option_desc_re.finditer(sig):
210            optname, args = m.groups()
211            if count:
212                signode += addnodes.desc_addname(', ', ', ')
213            signode += addnodes.desc_name(optname, optname)
214            signode += addnodes.desc_addname(args, args)
215            if not count:
216                firstname = optname
217            count += 1
218    if not firstname:
219        raise ValueError
220    return firstname
221
222
223class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder):
224    """
225    Subclass to add some extra things we need.
226    """
227
228    name = 'djangohtml'
229
230    def finish(self):
231        super(DjangoStandaloneHTMLBuilder, self).finish()
232        if json is None:
233            self.warn("cannot create templatebuiltins.js due to missing simplejson dependency")
234            return
235        self.info(bold("writing templatebuiltins.js..."))
236        xrefs = self.env.domaindata["std"]["objects"]
237        templatebuiltins = {
238            "ttags": [n for ((t, n), (l, a)) in xrefs.items()
239                        if t == "templatetag" and l == "ref/templates/builtins"],
240            "tfilters": [n for ((t, n), (l, a)) in xrefs.items()
241                        if t == "templatefilter" and l == "ref/templates/builtins"],
242        }
243        outfilename = os.path.join(self.outdir, "templatebuiltins.js")
244        f = open(outfilename, 'wb')
245        f.write('var django_template_builtins = ')
246        json.dump(templatebuiltins, f)
247        f.write(';\n')
248        f.close();