summaryrefslogtreecommitdiff
path: root/docs/_ext
diff options
context:
space:
mode:
Diffstat (limited to 'docs/_ext')
-rw-r--r--docs/_ext/applyxrefs.py88
-rw-r--r--docs/_ext/djangodocs.py146
-rw-r--r--docs/_ext/literals_to_xrefs.py171
3 files changed, 405 insertions, 0 deletions
diff --git a/docs/_ext/applyxrefs.py b/docs/_ext/applyxrefs.py
new file mode 100644
index 0000000000..3809088c1f
--- /dev/null
+++ b/docs/_ext/applyxrefs.py
@@ -0,0 +1,88 @@
+"""Adds xref targets to the top of files."""
+
+import sys
+import os
+
+testing = False
+
+DONT_TOUCH = (
+ './index.txt',
+ )
+
+def target_name(fn):
+ if fn.endswith('.txt'):
+ fn = fn[:-4]
+ return '_' + fn.lstrip('./').replace('/', '-')
+
+def process_file(fn, lines):
+ lines.insert(0, '\n')
+ lines.insert(0, '.. %s:\n' % target_name(fn))
+ try:
+ f = open(fn, 'w')
+ except IOError:
+ print("Can't open %s for writing. Not touching it." % fn)
+ return
+ try:
+ f.writelines(lines)
+ except IOError:
+ print("Can't write to %s. Not touching it." % fn)
+ finally:
+ f.close()
+
+def has_target(fn):
+ try:
+ f = open(fn, 'r')
+ except IOError:
+ print("Can't open %s. Not touching it." % fn)
+ return (True, None)
+ readok = True
+ try:
+ lines = f.readlines()
+ except IOError:
+ print("Can't read %s. Not touching it." % fn)
+ readok = False
+ finally:
+ f.close()
+ if not readok:
+ return (True, None)
+
+ #print fn, len(lines)
+ if len(lines) < 1:
+ print("Not touching empty file %s." % fn)
+ return (True, None)
+ if lines[0].startswith('.. _'):
+ return (True, None)
+ return (False, lines)
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+
+ if len(argv) == 1:
+ argv.extend('.')
+
+ files = []
+ for root in argv[1:]:
+ for (dirpath, dirnames, filenames) in os.walk(root):
+ files.extend([(dirpath, f) for f in filenames])
+ files.sort()
+ files = [os.path.join(p, fn) for p, fn in files if fn.endswith('.txt')]
+ #print files
+
+ for fn in files:
+ if fn in DONT_TOUCH:
+ print("Skipping blacklisted file %s." % fn)
+ continue
+
+ target_found, lines = has_target(fn)
+ if not target_found:
+ if testing:
+ print '%s: %s' % (fn, lines[0]),
+ else:
+ print "Adding xref to %s" % fn
+ process_file(fn, lines)
+ else:
+ print "Skipping %s: already has a xref" % fn
+
+if __name__ == '__main__':
+ sys.exit(main()) \ No newline at end of file
diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py
new file mode 100644
index 0000000000..2375be481d
--- /dev/null
+++ b/docs/_ext/djangodocs.py
@@ -0,0 +1,146 @@
+"""
+Sphinx plugins for Django documentation.
+"""
+
+import docutils.nodes
+import docutils.transforms
+import sphinx
+import sphinx.addnodes
+import sphinx.builder
+import sphinx.directives
+import sphinx.environment
+import sphinx.htmlwriter
+
+def setup(app):
+ app.add_crossref_type(
+ directivename = "setting",
+ rolename = "setting",
+ indextemplate = "pair: %s; setting",
+ )
+ app.add_crossref_type(
+ directivename = "templatetag",
+ rolename = "ttag",
+ indextemplate = "pair: %s; template tag"
+ )
+ app.add_crossref_type(
+ directivename = "templatefilter",
+ rolename = "tfilter",
+ indextemplate = "pair: %s; template filter"
+ )
+ app.add_crossref_type(
+ directivename = "fieldlookup",
+ rolename = "lookup",
+ indextemplate = "pair: %s, field lookup type",
+ )
+ app.add_description_unit(
+ directivename = "django-admin",
+ rolename = "djadmin",
+ indextemplate = "pair: %s; django-admin command",
+ parse_node = parse_django_admin_node,
+ )
+ app.add_description_unit(
+ directivename = "django-admin-option",
+ rolename = "djadminopt",
+ indextemplate = "pair: %s; django-admin command-line option",
+ parse_node = lambda env, sig, signode: sphinx.directives.parse_option_desc(signode, sig),
+ )
+ app.add_transform(SuppressBlockquotes)
+
+ # Monkeypatch PickleHTMLBuilder so that it doesn't die in Sphinx 0.4.2
+ if sphinx.__version__ == '0.4.2':
+ monkeypatch_pickle_builder()
+
+class SuppressBlockquotes(docutils.transforms.Transform):
+ """
+ Remove the default blockquotes that encase indented list, tables, etc.
+ """
+ default_priority = 300
+
+ suppress_blockquote_child_nodes = (
+ docutils.nodes.bullet_list,
+ docutils.nodes.enumerated_list,
+ docutils.nodes.definition_list,
+ docutils.nodes.literal_block,
+ docutils.nodes.doctest_block,
+ docutils.nodes.line_block,
+ docutils.nodes.table
+ )
+
+ def apply(self):
+ for node in self.document.traverse(docutils.nodes.block_quote):
+ if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
+ node.replace_self(node.children[0])
+
+class DjangoHTMLTranslator(sphinx.htmlwriter.SmartyPantsHTMLTranslator):
+ """
+ Django-specific reST to HTML tweaks.
+ """
+
+ # Don't use border=1, which docutils does by default.
+ def visit_table(self, node):
+ self.body.append(self.starttag(node, 'table', CLASS='docutils'))
+
+ # Give each section a unique ID -- nice for custom CSS hooks
+ # This is different on docutils 0.5 vs. 0.4...
+
+ # The docutils 0.4 override.
+ if hasattr(sphinx.htmlwriter.SmartyPantsHTMLTranslator, 'start_tag_with_title'):
+ def start_tag_with_title(self, node, tagname, **atts):
+ node = {
+ 'classes': node.get('classes', []),
+ 'ids': ['s-%s' % i for i in node.get('ids', [])]
+ }
+ return self.starttag(node, tagname, **atts)
+
+ # The docutils 0.5 override.
+ else:
+ def visit_section(self, node):
+ old_ids = node.get('ids', [])
+ node['ids'] = ['s-' + i for i in old_ids]
+ sphinx.htmlwriter.SmartyPantsHTMLTranslator.visit_section(self, node)
+ node['ids'] = old_ids
+
+def parse_django_admin_node(env, sig, signode):
+ command = sig.split(' ')[0]
+ env._django_curr_admin_command = command
+ title = "django-admin.py %s" % sig
+ signode += sphinx.addnodes.desc_name(title, title)
+ return sig
+
+def monkeypatch_pickle_builder():
+ import shutil
+ from os import path
+ try:
+ import cPickle as pickle
+ except ImportError:
+ import pickle
+ from sphinx.util.console import bold
+
+ def handle_finish(self):
+ # dump the global context
+ outfilename = path.join(self.outdir, 'globalcontext.pickle')
+ f = open(outfilename, 'wb')
+ try:
+ pickle.dump(self.globalcontext, f, 2)
+ finally:
+ f.close()
+
+ self.info(bold('dumping search index...'))
+ self.indexer.prune(self.env.all_docs)
+ f = open(path.join(self.outdir, 'searchindex.pickle'), 'wb')
+ try:
+ self.indexer.dump(f, 'pickle')
+ finally:
+ f.close()
+
+ # copy the environment file from the doctree dir to the output dir
+ # as needed by the web app
+ shutil.copyfile(path.join(self.doctreedir, sphinx.builder.ENV_PICKLE_FILENAME),
+ path.join(self.outdir, sphinx.builder.ENV_PICKLE_FILENAME))
+
+ # touch 'last build' file, used by the web application to determine
+ # when to reload its environment and clear the cache
+ open(path.join(self.outdir, sphinx.builder.LAST_BUILD_FILENAME), 'w').close()
+
+ sphinx.builder.PickleHTMLBuilder.handle_finish = handle_finish
+
diff --git a/docs/_ext/literals_to_xrefs.py b/docs/_ext/literals_to_xrefs.py
new file mode 100644
index 0000000000..569193c72d
--- /dev/null
+++ b/docs/_ext/literals_to_xrefs.py
@@ -0,0 +1,171 @@
+"""
+Runs through a reST file looking for old-style literals, and helps replace them
+with new-style references.
+"""
+
+import re
+import sys
+import shelve
+
+refre = re.compile(r'``([^`\s]+?)``')
+
+ROLES = (
+ 'attr',
+ 'class',
+ "djadmin",
+ 'data',
+ 'exc',
+ 'file',
+ 'func',
+ 'lookup',
+ 'meth',
+ 'mod' ,
+ "djadminopt",
+ "ref",
+ "setting",
+ "term",
+ "tfilter",
+ "ttag",
+
+ # special
+ "skip"
+)
+
+ALWAYS_SKIP = [
+ "NULL",
+ "True",
+ "False",
+]
+
+def fixliterals(fname):
+ data = open(fname).read()
+
+ last = 0
+ new = []
+ storage = shelve.open("/tmp/literals_to_xref.shelve")
+ lastvalues = storage.get("lastvalues", {})
+
+ for m in refre.finditer(data):
+
+ new.append(data[last:m.start()])
+ last = m.end()
+
+ line_start = data.rfind("\n", 0, m.start())
+ line_end = data.find("\n", m.end())
+ prev_start = data.rfind("\n", 0, line_start)
+ next_end = data.find("\n", line_end + 1)
+
+ # Skip always-skip stuff
+ if m.group(1) in ALWAYS_SKIP:
+ new.append(m.group(0))
+ continue
+
+ # skip when the next line is a title
+ next_line = data[m.end():next_end].strip()
+ if next_line[0] in "!-/:-@[-`{-~" and all(c == next_line[0] for c in next_line):
+ new.append(m.group(0))
+ continue
+
+ sys.stdout.write("\n"+"-"*80+"\n")
+ sys.stdout.write(data[prev_start+1:m.start()])
+ sys.stdout.write(colorize(m.group(0), fg="red"))
+ sys.stdout.write(data[m.end():next_end])
+ sys.stdout.write("\n\n")
+
+ replace_type = None
+ while replace_type is None:
+ replace_type = raw_input(
+ colorize("Replace role: ", fg="yellow")
+ ).strip().lower()
+ if replace_type and replace_type not in ROLES:
+ replace_type = None
+
+ if replace_type == "":
+ new.append(m.group(0))
+ continue
+
+ if replace_type == "skip":
+ new.append(m.group(0))
+ ALWAYS_SKIP.append(m.group(1))
+ continue
+
+ default = lastvalues.get(m.group(1), m.group(1))
+ if default.endswith("()") and replace_type in ("class", "func", "meth"):
+ default = default[:-2]
+ replace_value = raw_input(
+ colorize("Text <target> [", fg="yellow") + default + colorize("]: ", fg="yellow")
+ ).strip()
+ if not replace_value:
+ replace_value = default
+ new.append(":%s:`%s`" % (replace_type, replace_value))
+ lastvalues[m.group(1)] = replace_value
+
+ new.append(data[last:])
+ open(fname, "w").write("".join(new))
+
+ storage["lastvalues"] = lastvalues
+ storage.close()
+
+#
+# The following is taken from django.utils.termcolors and is copied here to
+# avoid the dependancy.
+#
+
+
+def colorize(text='', opts=(), **kwargs):
+ """
+ Returns your text, enclosed in ANSI graphics codes.
+
+ Depends on the keyword arguments 'fg' and 'bg', and the contents of
+ the opts tuple/list.
+
+ Returns the RESET code if no parameters are given.
+
+ Valid colors:
+ 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
+
+ Valid options:
+ 'bold'
+ 'underscore'
+ 'blink'
+ 'reverse'
+ 'conceal'
+ 'noreset' - string will not be auto-terminated with the RESET code
+
+ Examples:
+ colorize('hello', fg='red', bg='blue', opts=('blink',))
+ colorize()
+ colorize('goodbye', opts=('underscore',))
+ print colorize('first line', fg='red', opts=('noreset',))
+ print 'this should be red too'
+ print colorize('and so should this')
+ print 'this should not be red'
+ """
+ color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
+ foreground = dict([(color_names[x], '3%s' % x) for x in range(8)])
+ background = dict([(color_names[x], '4%s' % x) for x in range(8)])
+
+ RESET = '0'
+ opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
+
+ text = str(text)
+ code_list = []
+ if text == '' and len(opts) == 1 and opts[0] == 'reset':
+ return '\x1b[%sm' % RESET
+ for k, v in kwargs.iteritems():
+ if k == 'fg':
+ code_list.append(foreground[v])
+ elif k == 'bg':
+ code_list.append(background[v])
+ for o in opts:
+ if o in opt_dict:
+ code_list.append(opt_dict[o])
+ if 'noreset' not in opts:
+ text = text + '\x1b[%sm' % RESET
+ return ('\x1b[%sm' % ';'.join(code_list)) + text
+
+if __name__ == '__main__':
+ try:
+ fixliterals(sys.argv[1])
+ except (KeyboardInterrupt, SystemExit):
+ print \ No newline at end of file