[Python-checkins] r61331 - in doctools/trunk/sphinx: _jinja.py application.py builder.py config.py directives.py environment.py quickstart.py roles.py static/sphinxdoc.css

georg.brandl python-checkins at python.org
Sun Mar 9 19:18:42 CET 2008


Author: georg.brandl
Date: Sun Mar  9 19:18:41 2008
New Revision: 61331

Modified:
   doctools/trunk/sphinx/   (props changed)
   doctools/trunk/sphinx/_jinja.py
   doctools/trunk/sphinx/application.py
   doctools/trunk/sphinx/builder.py
   doctools/trunk/sphinx/config.py
   doctools/trunk/sphinx/directives.py
   doctools/trunk/sphinx/environment.py
   doctools/trunk/sphinx/quickstart.py
   doctools/trunk/sphinx/roles.py
   doctools/trunk/sphinx/static/sphinxdoc.css
Log:
* Allow registering arbitrary cross-referencing directives/roles.
* Allow labels anywhere, and allow giving an explicit caption in :ref: links.
* Some fixes to the sphinxdoc style.
* Add an option to show author information in the output.
* Search user-defined templates in the order they occur in the config
  (thanks Nick).


Modified: doctools/trunk/sphinx/_jinja.py
==============================================================================
--- doctools/trunk/sphinx/_jinja.py	(original)
+++ doctools/trunk/sphinx/_jinja.py	Sun Mar  9 19:18:41 2008
@@ -25,12 +25,19 @@
     paths, or from an absolute path.
     """
 
-    def __init__(self, paths):
-        self.searchpaths = map(path.abspath, paths)
+    def __init__(self, basepath, extpaths):
+        self.basepath = path.abspath(basepath)
+        self.extpaths = map(path.abspath, extpaths)
+        self.searchpaths = self.extpaths + [self.basepath]
 
     def get_source(self, environment, name, parent):
         name = name.replace('/', path.sep)
-        if path.isabs(name):
+        if name.startswith('!'):
+            name = name[1:]
+            if not path.exists(path.join(self.basepath, name)):
+                raise TemplateNotFound(name)
+            filename = path.join(self.basepath, name)
+        elif path.isabs(name):
             if not path.exists(name):
                 raise TemplateNotFound(name)
             filename = name

Modified: doctools/trunk/sphinx/application.py
==============================================================================
--- doctools/trunk/sphinx/application.py	(original)
+++ doctools/trunk/sphinx/application.py	Sun Mar  9 19:18:41 2008
@@ -18,8 +18,10 @@
 from docutils.parsers.rst import directives, roles
 
 import sphinx
+from sphinx.roles import xfileref_role
 from sphinx.config import Config
 from sphinx.builder import builtin_builders
+from sphinx.directives import desc_directive, additional_xref_types
 from sphinx.util.console import bold
 
 
@@ -185,3 +187,9 @@
 
     def add_role(self, name, role):
         roles.register_canonical_role(name, role)
+
+    def add_description_unit(self, directivename, rolename, indexdesc='',
+                             parse_node=None):
+        additional_xref_types[directivename] = (rolename, indexdesc, parse_node)
+        directives.register_directive(directivename, desc_directive)
+        roles.register_canonical_role(rolename, xfileref_role)

Modified: doctools/trunk/sphinx/builder.py
==============================================================================
--- doctools/trunk/sphinx/builder.py	(original)
+++ doctools/trunk/sphinx/builder.py	Sun Mar  9 19:18:41 2008
@@ -79,10 +79,9 @@
 
         # load templates
         self.templates = {}
-        templates_path = [path.join(path.dirname(__file__), 'templates')]
-        templates_path.extend(self.config.templates_path)
-        templates_path.reverse()
-        self.jinja_env = Environment(loader=SphinxFileSystemLoader(templates_path),
+        base_templates_path = path.join(path.dirname(__file__), 'templates')
+        loader = SphinxFileSystemLoader(base_templates_path, self.config.templates_path)
+        self.jinja_env = Environment(loader=loader,
                                      # disable traceback, more likely that something
                                      # in the application is broken than in the templates
                                      friendly_traceback=False)
@@ -438,13 +437,11 @@
 
         # additional pages from conf.py
         for pagename, template in self.config.html_additional_pages.items():
-            template = path.join(self.srcdir, template)
             self.handle_page(pagename, {}, template)
 
         # the index page
         indextemplate = self.config.html_index
         if indextemplate:
-            indextemplate = path.join(self.srcdir, indextemplate)
             self.handle_page('index', {'indextemplate': indextemplate}, 'index.html')
 
         # copy static files
@@ -515,7 +512,7 @@
         ctx['hasdoc'] = lambda name: name in self.env.all_docs
         sidebarfile = self.config.html_sidebars.get(pagename)
         if sidebarfile:
-            ctx['customsidebar'] = path.join(self.srcdir, sidebarfile)
+            ctx['customsidebar'] = sidebarfile
         ctx.update(addctx)
 
         output = self.get_template(templatename).render(ctx)

Modified: doctools/trunk/sphinx/config.py
==============================================================================
--- doctools/trunk/sphinx/config.py	(original)
+++ doctools/trunk/sphinx/config.py	Sun Mar  9 19:18:41 2008
@@ -20,7 +20,7 @@
     # the values are: (default, needs fresh doctrees if changed)
 
     # If you add a value here, don't forget to include it in the
-    # quickstart.py file template as well!
+    # quickstart.py file template as well as in the docs!
 
     config_values = dict(
         # general substitutions
@@ -41,6 +41,7 @@
         unused_docs = ([], True),
         add_function_parentheses = (True, True),
         add_module_names = (True, True),
+        show_authors = (False, True),
         pygments_style = ('sphinx', False),
 
         # HTML options

Modified: doctools/trunk/sphinx/directives.py
==============================================================================
--- doctools/trunk/sphinx/directives.py	(original)
+++ doctools/trunk/sphinx/directives.py	Sun Mar  9 19:18:41 2008
@@ -310,21 +310,30 @@
                                          targetname, targetname)
                     env.note_reftarget('option', optname, targetname)
                 continue
-            elif desctype == 'envvar':
+            elif desctype == 'describe':
                 signode.clear()
                 signode += addnodes.desc_name(sig, sig)
+                continue
+            else:
+                # another registered generic x-ref directive
+                rolename, indextext, parse_node = additional_xref_types[desctype]
+                if parse_node:
+                    parse_node(sig, signode)
+                else:
+                    signode.clear()
+                    signode += addnodes.desc_name(sig, sig)
                 if not noindex:
-                    targetname = 'envvar-' + sig
+                    targetname = '%s-%s' % (rolename, sig)
                     signode['ids'].append(targetname)
                     state.document.note_explicit_target(signode)
-                    env.note_index_entry('pair', 'environment variable; %s' % sig,
-                                         targetname, targetname)
-                    env.note_reftarget('envvar', sig, targetname)
+                    if indextext:
+                        env.note_index_entry('pair', '%s; %s' % (indextext, sig),
+                                             targetname, targetname)
+                    env.note_reftarget(rolename, sig, targetname)
+                # don't use object indexing below
                 continue
-            else:
-                # for "describe": use generic fallback
-                raise ValueError
         except ValueError, err:
+            # signature parsing failed
             signode.clear()
             signode += addnodes.desc_name(sig, sig)
             continue             # we don't want an index entry here
@@ -384,15 +393,22 @@
     'cvar',
     # the odd one
     'opcode',
-    # the generic ones
-    'cmdoption', # for command line options
-    'envvar', # for environment variables
+    # for command line options
+    'cmdoption',
+    # the generic one
     'describe',
+    'envvar',
 ]
 
 for _name in desctypes:
     directives.register_directive(_name, desc_directive)
 
+# Generic cross-reference types; they can be registered in the application
+additional_xref_types = {
+    # directive name: (role name, index text)
+    'envvar': ('envvar', 'environment variable', None),
+}
+
 
 # ------ versionadded/versionchanged -----------------------------------------------
 
@@ -526,8 +542,23 @@
 
 def author_directive(name, arguments, options, content, lineno,
                      content_offset, block_text, state, state_machine):
-    # The author directives aren't included in the built document
-    return []
+    # Show authors only if the show_authors option is on
+    env = state.document.settings.env
+    if not env.config.show_authors:
+        return []
+    para = nodes.paragraph()
+    emph = nodes.emphasis()
+    para += emph
+    if name == 'sectionauthor':
+        text = 'Section author: '
+    elif name == 'moduleauthor':
+        text = 'Module author: '
+    else:
+        text = 'Author: '
+    emph += nodes.Text(text, text)
+    inodes, messages = state.inline_text(arguments[0], lineno)
+    emph.extend(inodes)
+    return [para] + messages
 
 author_directive.arguments = (1, 0, 1)
 directives.register_directive('sectionauthor', author_directive)

Modified: doctools/trunk/sphinx/environment.py
==============================================================================
--- doctools/trunk/sphinx/environment.py	(original)
+++ doctools/trunk/sphinx/environment.py	Sun Mar  9 19:18:41 2008
@@ -44,6 +44,7 @@
 
 from sphinx import addnodes
 from sphinx.util import get_matching_docs, SEP
+from sphinx.directives import additional_xref_types
 
 default_settings = {
     'embed_stylesheet': False,
@@ -56,7 +57,7 @@
 
 # This is increased every time a new environment attribute is added
 # to properly invalidate pickle files.
-ENV_VERSION = 16
+ENV_VERSION = 17
 
 
 def walk_depth(node, depth, maxdepth):
@@ -226,6 +227,7 @@
         self.filemodules = {}       # docname -> [modules]
         self.modules = {}           # modname -> docname, synopsis, platform, deprecated
         self.labels = {}            # labelname -> docname, labelid, sectionname
+        self.anonlabels = {}        # labelname -> docname, labelid
         self.reftargets = {}        # (type, name) -> docname, labelid
                                     # where type is term, token, option, envvar
 
@@ -471,13 +473,19 @@
                 continue
             labelid = document.nameids[name]
             node = document.ids[labelid]
-            if not isinstance(node, nodes.section):
-                # e.g. desc-signatures
+            if name.isdigit() or node.has_key('refuri') or \
+                   node.tagname.startswith('desc_'):
+                # ignore footnote labels, labels automatically generated from a
+                # link and description units
                 continue
-            sectname = node[0].astext() # node[0] == title node
             if name in self.labels:
                 self.warn(docname, 'duplicate label %s, ' % name +
                           'other instance in %s' % self.doc2path(self.labels[name][0]))
+            self.anonlabels[name] = docname, labelid
+            if not isinstance(node, nodes.section):
+                # anonymous-only labels
+                continue
+            sectname = node[0].astext() # node[0] == title node
             self.labels[name] = docname, labelid, sectname
 
     def note_toctree(self, docname, toctreenode):
@@ -654,23 +662,37 @@
             typ = node['reftype']
             target = node['reftarget']
 
+            reftarget_roles = set(('token', 'term', 'option'))
+            # add all custom xref types too
+            reftarget_roles.update(i[0] for i in additional_xref_types.values())
+
             try:
                 if typ == 'ref':
-                    # reference to the named label; the final node will contain the
-                    # section name after the label
-                    docname, labelid, sectname = self.labels.get(target, ('','',''))
-                    if not docname:
-                        newnode = doctree.reporter.system_message(
-                            2, 'undefined label: %s' % target)
-                        #self.warn(fromdocname, 'undefined label: %s' % target)
+                    if node['refcaption']:
+                        # reference to anonymous label; the reference uses the supplied
+                        # link caption
+                        docname, labelid = self.anonlabels.get(target, ('',''))
+                        sectname = node.astext()
+                        if not docname:
+                            newnode = doctree.reporter.system_message(
+                                2, 'undefined label: %s' % target)
                     else:
+                        # reference to the named label; the final node will contain the
+                        # section name after the label
+                        docname, labelid, sectname = self.labels.get(target, ('','',''))
+                        if not docname:
+                            newnode = doctree.reporter.system_message(
+                                2, 'undefined label: %s -- if you don\'t ' % target +
+                                'give a link caption the label must precede a section '
+                                'header.')
+                    if docname:
                         newnode = nodes.reference('', '')
                         innernode = nodes.emphasis(sectname, sectname)
                         if docname == fromdocname:
                             newnode['refid'] = labelid
                         else:
-                            # set more info in contnode in case the following call
-                            # raises NoUri, the builder will have to resolve these
+                            # set more info in contnode in case the get_relative_uri call
+                            # raises NoUri, the builder will then have to resolve these
                             contnode = addnodes.pending_xref('')
                             contnode['refdocname'] = docname
                             contnode['refsectname'] = sectname
@@ -693,7 +715,7 @@
                             newnode['refuri'] = builder.get_relative_uri(
                                 fromdocname, docname) + '#' + labelid
                         newnode.append(contnode)
-                elif typ in ('token', 'term', 'envvar', 'option'):
+                elif typ in reftarget_roles:
                     docname, labelid = self.reftargets.get((typ, target), ('', ''))
                     if not docname:
                         if typ == 'term':

Modified: doctools/trunk/sphinx/quickstart.py
==============================================================================
--- doctools/trunk/sphinx/quickstart.py	(original)
+++ doctools/trunk/sphinx/quickstart.py	Sun Mar  9 19:18:41 2008
@@ -78,6 +78,10 @@
 # unit titles (such as .. function::).
 #add_module_names = True
 
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
 # The name of the Pygments (syntax highlighting) style to use.
 pygments_style = 'sphinx'
 
@@ -103,14 +107,14 @@
 # typographically correct entities.
 #html_use_smartypants = True
 
-# Content template for the index page, filename relative to this file.
+# Content template for the index page.
 #html_index = ''
 
-# Custom sidebar templates, maps page names to filenames relative to this file.
+# Custom sidebar templates, maps document names to template names.
 #html_sidebars = {}
 
 # Additional templates that should be rendered to pages, maps page names to
-# filenames relative to this file.
+# template names.
 #html_additional_pages = {}
 
 # If true, the reST sources are included in the HTML build as _sources/<name>.

Modified: doctools/trunk/sphinx/roles.py
==============================================================================
--- doctools/trunk/sphinx/roles.py	(original)
+++ doctools/trunk/sphinx/roles.py	Sun Mar  9 19:18:41 2008
@@ -17,6 +17,7 @@
 from sphinx import addnodes
 
 ws_re = re.compile(r'\s+')
+caption_ref_re = re.compile(r'^([^<]+?)\s*<(.+)>$')
 
 generic_docroles = {
     'command' : nodes.strong,
@@ -127,6 +128,21 @@
         pnode['refspecific'] = True
     if typ == 'term':
         pnode['reftarget'] = ws_re.sub(' ', text).lower()
+    elif typ == 'ref':
+        brace = text.find('<')
+        if brace != -1:
+            pnode['refcaption'] = True
+            m = caption_ref_re.match(text)
+            if not m:
+                # fallback
+                pnode['reftarget'] = text[brace+1:]
+                text = text[:brace]
+            else:
+                pnode['reftarget'] = m.group(2)
+                text = m.group(1)
+        else:
+            pnode['refcaption'] = False
+            pnode['reftarget'] = ws_re.sub('', text)
     elif typ == 'option':
         if text[0] in '-/':
             pnode['reftarget'] = text[1:]

Modified: doctools/trunk/sphinx/static/sphinxdoc.css
==============================================================================
--- doctools/trunk/sphinx/static/sphinxdoc.css	(original)
+++ doctools/trunk/sphinx/static/sphinxdoc.css	Sun Mar  9 19:18:41 2008
@@ -64,11 +64,24 @@
 
 tt.descclassname {
     background-color: transparent;
+    border: 0;
 }
 
-tt.xref, a tt {
+tt.xref {
     background-color: transparent;
     font-weight: bold;
+    border: 0;
+}
+
+a tt {
+    background-color: transparent;
+    font-weight: bold;
+    border: 0;
+    color: #CA7900;
+}
+
+a tt:hover {
+    color: #2491CF;
 }
 
 dl {
@@ -99,19 +112,10 @@
     background-color: #fbe54e;
 }
 
-/*
-dt {
-    margin-top: 0.8em;
-}
-
-dd p.first {
-    margin-top: 0;
-}
-
-dd p.last {
-    margin-bottom: 0;
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
 }
-*/
 
 pre {
     line-height: 120%;
@@ -122,10 +126,6 @@
     text-decoration: underline;
 }
 
-div.syntax {
-    background-color: transparent;
-}
-
 div.document {
     background-color: white;
     text-align: left;
@@ -226,6 +226,10 @@
     border-right: 1px solid #ccc;
 }
 
+div.body a {
+    text-decoration: underline;
+}
+
 div.sidebar {
     margin: 0;
     padding: 0.5em 15px 15px 0;
@@ -447,3 +451,50 @@
     background-color: #ccc;
     color: white!important;
 }
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+form.pfform {
+    margin: 10px 0 20px 0;
+}
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}


More information about the Python-checkins mailing list