diff --git a/test/Django-2.1.15/docs/_ext/djangodocs.py b/test/Django-2.1.15/docs/_ext/djangodocs.py new file mode 100644 index 0000000..d33d48a --- /dev/null +++ b/test/Django-2.1.15/docs/_ext/djangodocs.py @@ -0,0 +1,376 @@ +""" +Sphinx plugins for Django documentation. +""" +import json +import os +import re + +from docutils import nodes +from docutils.parsers.rst import Directive +from docutils.statemachine import ViewList +from sphinx import addnodes +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.directives import CodeBlock +from sphinx.domains.std import Cmdoption +from sphinx.errors import ExtensionError +from sphinx.util import logging +from sphinx.util.console import bold +from sphinx.writers.html import HTMLTranslator + +logger = logging.getLogger(__name__) +# RE for option descriptions without a '--' prefix +simple_option_desc_re = re.compile( + r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)') + + +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_object_type( + directivename="django-admin", + rolename="djadmin", + indextemplate="pair: %s; django-admin command", + parse_node=parse_django_admin_node, + ) + app.add_directive('django-admin-option', Cmdoption) + app.add_config_value('django_next_version', '0.0', True) + app.add_directive('versionadded', VersionDirective) + app.add_directive('versionchanged', VersionDirective) + app.add_builder(DjangoStandaloneHTMLBuilder) + app.set_translator('djangohtml', DjangoHTMLTranslator) + app.set_translator('json', DjangoHTMLTranslator) + app.add_node( + ConsoleNode, + html=(visit_console_html, None), + latex=(visit_console_dummy, depart_console_dummy), + man=(visit_console_dummy, depart_console_dummy), + text=(visit_console_dummy, depart_console_dummy), + texinfo=(visit_console_dummy, depart_console_dummy), + ) + app.add_directive('console', ConsoleDirective) + app.connect('html-page-context', html_page_context_hook) + return {'parallel_read_safe': True} + + +class VersionDirective(Directive): + has_content = True + required_arguments = 1 + optional_arguments = 1 + final_argument_whitespace = True + option_spec = {} + + def run(self): + if len(self.arguments) > 1: + msg = """Only one argument accepted for directive '{directive_name}::'. + Comments should be provided as content, + not as an extra argument.""".format(directive_name=self.name) + raise self.error(msg) + + env = self.state.document.settings.env + ret = [] + node = addnodes.versionmodified() + ret.append(node) + + if self.arguments[0] == env.config.django_next_version: + node['version'] = "Development version" + else: + node['version'] = self.arguments[0] + + node['type'] = self.name + if self.content: + self.state.nested_parse(self.content, self.content_offset, node) + try: + env.get_domain('changeset').note_changeset(node) + except ExtensionError: + # Sphinx < 1.8: Domain 'changeset' is not registered + env.note_versionchange(node['type'], node['version'], node, self.lineno) + return ret + + +class DjangoHTMLTranslator(HTMLTranslator): + """ + Django-specific reST to HTML tweaks. + """ + + # Don't use border=1, which docutils does by default. + def visit_table(self, node): + self.context.append(self.compact_p) + self.compact_p = True + self._table_row_index = 0 # Needed by Sphinx + self.body.append(self.starttag(node, 'table', CLASS='docutils')) + + def depart_table(self, node): + self.compact_p = self.context.pop() + self.body.append('\n') + + def visit_desc_parameterlist(self, node): + self.body.append('(') # by default sphinx puts around the "(" + self.first_param = 1 + self.optional_param_level = 0 + self.param_separator = node.child_text_separator + self.required_params_left = sum(isinstance(c, addnodes.desc_parameter) for c in node.children) + + def depart_desc_parameterlist(self, node): + self.body.append(')') + + # + # Turn the "new in version" stuff (versionadded/versionchanged) into a + # better callout -- the Sphinx default is just a little span, + # which is a bit less obvious that I'd like. + # + # FIXME: these messages are all hardcoded in English. We need to change + # that to accommodate other language docs, but I can't work out how to make + # that work. + # + version_text = { + 'versionchanged': 'Changed in Django %s', + 'versionadded': 'New in Django %s', + } + + def visit_versionmodified(self, node): + self.body.append( + self.starttag(node, 'div', CLASS=node['type']) + ) + version_text = self.version_text.get(node['type']) + if version_text: + title = "%s%s" % ( + version_text % node['version'], + ":" if len(node) else "." + ) + self.body.append('%s ' % title) + + def depart_versionmodified(self, node): + self.body.append("\n") + + # Give each section a unique ID -- nice for custom CSS hooks + def visit_section(self, node): + old_ids = node.get('ids', []) + node['ids'] = ['s-' + i for i in old_ids] + node['ids'].extend(old_ids) + super().visit_section(node) + node['ids'] = old_ids + + +def parse_django_admin_node(env, sig, signode): + command = sig.split(' ')[0] + env.ref_context['std:program'] = command + title = "django-admin %s" % sig + signode += addnodes.desc_name(title, title) + return command + + +class DjangoStandaloneHTMLBuilder(StandaloneHTMLBuilder): + """ + Subclass to add some extra things we need. + """ + + name = 'djangohtml' + + def finish(self): + super().finish() + logger.info(bold("writing templatebuiltins.js...")) + xrefs = self.env.domaindata["std"]["objects"] + templatebuiltins = { + "ttags": [ + n for ((t, n), (k, a)) in xrefs.items() + if t == "templatetag" and k == "ref/templates/builtins" + ], + "tfilters": [ + n for ((t, n), (k, a)) in xrefs.items() + if t == "templatefilter" and k == "ref/templates/builtins" + ], + } + outfilename = os.path.join(self.outdir, "templatebuiltins.js") + with open(outfilename, 'w') as fp: + fp.write('var django_template_builtins = ') + json.dump(templatebuiltins, fp) + fp.write(';\n') + + +class ConsoleNode(nodes.literal_block): + """ + Custom node to override the visit/depart event handlers at registration + time. Wrap a literal_block object and defer to it. + """ + tagname = 'ConsoleNode' + + def __init__(self, litblk_obj): + self.wrapped = litblk_obj + + def __getattr__(self, attr): + if attr == 'wrapped': + return self.__dict__.wrapped + return getattr(self.wrapped, attr) + + +def visit_console_dummy(self, node): + """Defer to the corresponding parent's handler.""" + self.visit_literal_block(node) + + +def depart_console_dummy(self, node): + """Defer to the corresponding parent's handler.""" + self.depart_literal_block(node) + + +def visit_console_html(self, node): + """Generate HTML for the console directive.""" + if self.builder.name in ('djangohtml', 'json') and node['win_console_text']: + # Put a mark on the document object signaling the fact the directive + # has been used on it. + self.document._console_directive_used_flag = True + uid = node['uid'] + self.body.append('''\ +
+ + + + +
\n''' % {'id': uid}) + try: + self.visit_literal_block(node) + except nodes.SkipNode: + pass + self.body.append('
\n') + + self.body.append('
\n' % {'id': uid}) + win_text = node['win_console_text'] + highlight_args = {'force': True} + if 'linenos' in node: + linenos = node['linenos'] + else: + linenos = win_text.count('\n') >= self.highlightlinenothreshold - 1 + + def warner(msg): + self.builder.warn(msg, (self.builder.current_docname, node.line)) + + highlighted = self.highlighter.highlight_block( + win_text, 'doscon', warn=warner, linenos=linenos, **highlight_args + ) + self.body.append(highlighted) + self.body.append('
\n') + self.body.append('
\n') + raise nodes.SkipNode + else: + self.visit_literal_block(node) + + +class ConsoleDirective(CodeBlock): + """ + A reStructuredText directive which renders a two-tab code block in which + the second tab shows a Windows command line equivalent of the usual + Unix-oriented examples. + """ + required_arguments = 0 + # The 'doscon' Pygments formatter needs a prompt like this. '>' alone + # won't do it because then it simply paints the whole command line as a + # grey comment with no highlighting at all. + WIN_PROMPT = r'...\> ' + + def run(self): + + def args_to_win(cmdline): + changed = False + out = [] + for token in cmdline.split(): + if token[:2] == './': + token = token[2:] + changed = True + elif token[:2] == '~/': + token = '%HOMEPATH%\\' + token[2:] + changed = True + elif token == 'make': + token = 'make.bat' + changed = True + if '://' not in token and 'git' not in cmdline: + out.append(token.replace('/', '\\')) + changed = True + else: + out.append(token) + if changed: + return ' '.join(out) + return cmdline + + def cmdline_to_win(line): + if line.startswith('# '): + return 'REM ' + args_to_win(line[2:]) + if line.startswith('$ # '): + return 'REM ' + args_to_win(line[4:]) + if line.startswith('$ ./manage.py'): + return 'manage.py ' + args_to_win(line[13:]) + if line.startswith('$ manage.py'): + return 'manage.py ' + args_to_win(line[11:]) + if line.startswith('$ ./runtests.py'): + return 'runtests.py ' + args_to_win(line[15:]) + if line.startswith('$ ./'): + return args_to_win(line[4:]) + if line.startswith('$ python3'): + return 'py ' + args_to_win(line[9:]) + if line.startswith('$ python'): + return 'py ' + args_to_win(line[8:]) + if line.startswith('$ '): + return args_to_win(line[2:]) + return None + + def code_block_to_win(content): + bchanged = False + lines = [] + for line in content: + modline = cmdline_to_win(line) + if modline is None: + lines.append(line) + else: + lines.append(self.WIN_PROMPT + modline) + bchanged = True + if bchanged: + return ViewList(lines) + return None + + env = self.state.document.settings.env + self.arguments = ['console'] + lit_blk_obj = super().run()[0] + + # Only do work when the djangohtml HTML Sphinx builder is being used, + # invoke the default behavior for the rest. + if env.app.builder.name not in ('djangohtml', 'json'): + return [lit_blk_obj] + + lit_blk_obj['uid'] = '%s' % env.new_serialno('console') + # Only add the tabbed UI if there is actually a Windows-specific + # version of the CLI example. + win_content = code_block_to_win(self.content) + if win_content is None: + lit_blk_obj['win_console_text'] = None + else: + self.content = win_content + lit_blk_obj['win_console_text'] = super().run()[0].rawsource + + # Replace the literal_node object returned by Sphinx's CodeBlock with + # the ConsoleNode wrapper. + return [ConsoleNode(lit_blk_obj)] + + +def html_page_context_hook(app, pagename, templatename, context, doctree): + # Put a bool on the context used to render the template. It's used to + # control inclusion of console-tabs.css and activation of the JavaScript. + # This way it's include only from HTML files rendered from reST files where + # the ConsoleDirective is used. + context['include_console_assets'] = getattr(doctree, '_console_directive_used_flag', False)