Commits

bmu committed a66ed40 Merge

merged with sphinx

  • Participants
  • Parent commits af85afc, f1f6416

Comments (0)

Files changed (30)

 48688502e78b09c03b877910b64368c5db9bb4ff 1.0.6
 f7f069b6d1e5cc2d4394420be9a4a3efc0cb4d47 1.0.7
 61cb589edeba5800c2bb9a4159c5986451d90a08 1.0.8
+0a63129ab59bf013068ea9da3382e567ed5400c3 1.1
-Release 1.1 (in development)
+Release 1.2 (in development)
 ============================
 
+
+Release 1.1 (Oct 9, 2011)
+=========================
+
 Incompatible changes
 --------------------
 
   - Section headings in :rst:dir:`only` directives are now correctly
     handled.
   - Added ``emphasize-lines`` option to source code directives.
+  - #678: C++ domain now supports superclasses.
 
 * HTML builder:
 
 Release 1.0.9 (in development)
 ==============================
 
+* #778: Fix "hide search matches" link on pages linked by search.
+
+* Fix the source positions referenced by the "viewcode" extension.
+
+
 Release 1.0.8 (Sep 23, 2011)
 ============================
 
      '', 1),
     ('man/sphinx-quickstart', 'sphinx-quickstart', 'Sphinx documentation '
      'template generator', '', 1),
+    ('man/sphinx-apidoc', 'sphinx-apidoc', 'Sphinx API doc generator tool',
+     '', 1),
 ]
 
 texinfo_documents = [

File doc/config.rst

    add the directory :file:`./locale` to this settting, the message catalogs
    (compiled from ``.po`` format using :program:`msgfmt`) must be in
    :file:`./locale/{language}/LC_MESSAGES/sphinx.mo`.  The text domain of
-   individual documents depends on their docname if they are top-level project
-   files and on their base directory otherwise.
+   individual documents depends on :confval:`gettext_compact`.
 
    The default is ``[]``.
 
+.. confval:: gettext_compact
+
+   .. versionadded:: 1.1
+
+   If true, a document's text domain is its docname if it is a top-level
+   project file and its very base directory otherwise.
+
+   By default, the document ``markup/code.rst`` ends up in the ``markup`` text
+   domain.  With this option set to ``False``, it is ``markup/code``.
+
 
 .. _html-options:
 

File doc/ext/autosummary.rst

 .. rst:directive:: autosummary
 
    Insert a table that contains links to documented items, and a short summary
-   blurb (the first sentence of the docstring) for each of them.  
+   blurb (the first sentence of the docstring) for each of them.
 
    The :rst:dir:`autosummary` directive can also optionally serve as a
    :rst:dir:`toctree` entry for the included items. Optionally, stub
 Read the Docs
     http://readthedocs.org is a documentation hosting service based around Sphinx.
     They will host sphinx documentation, along with supporting a number of other
-    features including version support, PDF generation, and more. The `Getting 
+    features including version support, PDF generation, and more. The `Getting
     Started <http://read-the-docs.readthedocs.org/en/latest/getting_started.html>`_
     guide is a good place to start.
 

File doc/intl.rst

 up automatically.
 
 An example: you have a document ``usage.rst`` in your Sphinx project.  The
-gettext builder will put its messages into ``usage.pot``.  Image you have
+gettext builder will put its messages into ``usage.pot``.  Imagine you have
 Spanish translations [2]_ on your hands in ``usage.po`` --- for your builds to
 be translated you need to follow these instructions:
 

File doc/invocation.rst

 
 The :program:`sphinx-build` script has several options:
 
+.. program:: sphinx-build
+
 .. option:: -b buildername
 
    The most important option: it selects a builder.  The most common builders
 .. describe:: SPHINXOPTS
 
    Additional options for :program:`sphinx-build`.
+
+
+.. _invocation-apidoc:
+
+Invocation of sphinx-apidoc
+===========================
+
+The :program:`sphinx-apidoc` generates completely automatic API documentation
+for a Python package.  It is called like this::
+
+     $ sphinx-apidoc [options] -o outputdir packagedir [pathnames]
+
+where *packagedir* is the path to the package to document, and *outputdir* is
+the directory where the generated sources are placed.  Any *pathnames* given
+are paths to be excluded ignored during generation.
+
+The :program:`sphinx-apidoc` script has several options:
+
+.. program:: sphinx-apidoc
+
+.. option:: -o outputdir
+
+   Gives the directory in which to place the generated output.
+
+.. option:: -f, --force
+
+   Normally, sphinx-apidoc does not overwrite any files.  Use this option to
+   force the overwrite of all files that it generates.
+
+.. option:: -n, --dry-run
+
+   With this option given, no files will be written at all.
+
+.. option:: -s suffix
+
+   This option selects the file name suffix of output files.  By default, this
+   is ``rst``.
+
+.. option:: -d maxdepth
+
+   This sets the maximum depth of the table of contents, if one is generated.
+
+.. option:: -T, --no-toc
+
+   This prevents the generation of a table-of-contents file ``modules.rst``.
+   This has no effect when :option:`--full` is given.
+
+.. option:: -F, --full
+
+   This option makes sphinx-apidoc create a full Sphinx project, using the same
+   mechanism as :program:`sphinx-quickstart`.  Most configuration values are set
+   to default values, but you can influence the most important ones using the
+   following options.
+
+.. option:: -H project
+
+   Sets the project name to put in generated files (see :confval:`project`).
+
+.. option:: -A author
+
+   Sets the author name(s) to put in generated files (see :confval:`copyright`).
+
+.. option:: -V version
+
+   Sets the project version to put in generated files (see :confval:`version`).
+
+.. option:: -R release
+
+   Sets the project release to put in generated files (see :confval:`release`).

File doc/man/sphinx-apidoc.rst

+:orphan:
+
+sphinx-apidoc manual page
+=========================
+
+Synopsis
+--------
+
+**sphinx-apidoc** [*options*] -o <*outputdir*> <*sourcedir*> [*pathnames* ...]
+
+
+Description
+-----------
+
+:program:`sphinx-apidoc` is a tool for automatic generation of Sphinx sources
+that, using the autodoc extension, document a whole package in the style of
+other automatic API documentation tools.
+
+*sourcedir* must point to a Python package.  Any *pathnames* given are paths to
+be excluded from the generation.
+
+
+Options
+-------
+
+-o <outputdir>  Directory to place the output files.  If it does not exist,
+                it is created.
+-f, --force     Usually, apidoc does not overwrite files, unless this option
+                is given.
+-n, --dry-run   If given, apidoc does not create any files.
+-s <suffix>     Suffix for the source files generated, default is ``rst``.
+-d <maxdepth>   Maximum depth for the generated table of contents file.
+-T, --no-toc    Do not create a table of contents file.
+-F, --full      If given, a full Sphinx project is generated (``conf.py``,
+                ``Makefile`` etc.) using sphinx-quickstart.
+
+These options are used with ``-F``:
+
+-H <project>    Project name to put into the configuration.
+-A <author>     Author name(s) to put into the configuration.
+-V <version>    Project version.
+-R <release>    Project release.
+
+
+See also
+--------
+
+:manpage:`sphinx-build(1)`
+
+
+Author
+------
+
+Etienne Desautels, <etienne.desautels@gmail.com>, Georg Brandl
+<georg@python.org> et al.

File doc/tutorial.rst

 
 and answer its questions.  (Be sure to say yes to the "autodoc" extension.)
 
+There is also an automatic "API documentation" generator called
+:program:`sphinx-apidoc`; see :ref:`invocation-apidoc` for details.
+
 
 Defining document structure
 ---------------------------
 to build HTML docs in the build directory you chose.  Execute ``make`` without
 an argument to see which targets are available.
 
+.. admonition:: How do I generate PDF documents?
+
+   ``make latexpdf`` runs the :mod:`LaTeX builder
+   <sphinx.builders.latex.LaTeXBuilder>` and readily invokes the pdfTeX
+   toolchain for you.
+
 
 Documenting objects
 -------------------
         'Operating System :: OS Independent',
         'Programming Language :: Python',
         'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 3',
         'Topic :: Documentation',
         'Topic :: Text Processing',
         'Topic :: Utilities',
     ],
     platforms='any',
-    packages=find_packages(),
+    packages=find_packages(exclude=['custom_fixers', 'test']),
     include_package_data=True,
     entry_points={
         'console_scripts': [

File sphinx/__init__.py

 import sys
 from os import path
 
-__version__  = '1.1pre'
-__released__ = '1.1 (hg)'  # used when Sphinx builds its own docs
+__version__  = '1.2pre'
+__released__ = '1.2 (hg)'  # used when Sphinx builds its own docs
 
 package_dir = path.abspath(path.dirname(__file__))
 

File sphinx/apidoc.py

     creates a modules index (named modules.<suffix>).
 
     This is derived from the "sphinx-autopackage" script, which is:
-    Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/.
+    Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/
 
-    :copyright: 2007-2011 by the Sphinx team, see AUTHORS.
+    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
     :license: BSD, see LICENSE for details.
 """
 import os
 
 INITPY = '__init__.py'
 
+
 def makename(package, module):
     """Join package and module with a dot."""
     # Both package and module can be None/empty.
         name = module
     return name
 
+
 def write_file(name, text, opts):
     """Write the output file for module/package <name>."""
-    fname = path.join(opts.destdir, "%s.%s" % (name, opts.suffix))
+    fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix))
     if opts.dryrun:
         print 'Would create file %s.' % fname
         return
         finally:
             f.close()
 
+
 def format_heading(level, text):
     """Create a heading of <level> [1, 2 or 3 supported]."""
     underlining = ['=', '-', '~', ][level-1] * len(text)
     return '%s\n%s\n\n' % (text, underlining)
 
+
 def format_directive(module, package=None):
     """Create the automodule directive and add the options."""
     directive = '.. automodule:: %s\n' % makename(package, module)
         directive += '    :%s:\n' % option
     return directive
 
+
 def create_module_file(package, module, opts):
     """Build the text of the file and write the file."""
     text = format_heading(1, '%s Module' % module)
     text += format_directive(module, package)
     write_file(makename(package, module), text, opts)
 
+
 def create_package_file(root, master_package, subroot, py_files, opts, subs):
     """Build the text of the file and write the file."""
     package = path.split(root)[-1]
 
     write_file(makename(master_package, subroot), text, opts)
 
-def create_modules_toc_file(master_package, modules, opts, name='modules'):
-    """
-    Create the module's index.
-    """
+
+def create_modules_toc_file(modules, opts, name='modules'):
+    """Create the module's index."""
     text = format_heading(1, '%s' % opts.header)
     text += '.. toctree::\n'
     text += '   :maxdepth: %s\n\n' % opts.maxdepth
 
     write_file(name, text, opts)
 
+
 def shall_skip(module):
-    """
-    Check if we want to skip this module.
-    """
-    # skip it, if there is nothing (or just \n or \r\n) in the file
-    return path.getsize(module) < 3
+    """Check if we want to skip this module."""
+    # skip it if there is nothing (or just \n or \r\n) in the file
+    return path.getsize(module) <= 2
+
 
 def recurse_tree(rootpath, excludes, opts):
     """
     """
     # use absolute path for root, as relative paths like '../../foo' cause
     # 'if "/." in root ...' to filter out *all* modules otherwise
-    rootpath = os.path.abspath(rootpath)
-    # check if the base directory is a package and get is name
+    rootpath = path.normpath(path.abspath(rootpath))
+    # check if the base directory is a package and get its name
     if INITPY in os.listdir(rootpath):
-        package_name = rootpath.split(path.sep)[-1]
+        root_package = rootpath.split(path.sep)[-1]
     else:
-        package_name = None
+        # otherwise, the base is a directory with packages
+        root_package = None
 
-    toc = []
-    tree = os.walk(rootpath, False)
-    for root, subs, files in tree:
-        # keep only the Python script files
-        py_files =  sorted([f for f in files if path.splitext(f)[1] == '.py'])
-        if INITPY in py_files:
+    toplevels = []
+    for root, subs, files in os.walk(rootpath):
+        if is_excluded(root, excludes):
+            del subs[:]
+            continue
+        # document only Python module files
+        py_files = sorted([f for f in files if path.splitext(f)[1] == '.py'])
+        is_pkg = INITPY in py_files
+        if is_pkg:
             py_files.remove(INITPY)
             py_files.insert(0, INITPY)
+        elif root != rootpath:
+            # only accept non-package at toplevel
+            del subs[:]
+            continue
         # remove hidden ('.') and private ('_') directories
-        subs = sorted([sub for sub in subs if sub[0] not in ['.', '_']])
-        # check if there are valid files to process
-        # TODO: could add check for windows hidden files
-        if "/." in root or "/_" in root \
-               or not py_files \
-               or is_excluded(root, excludes):
-            continue
-        if INITPY in py_files:
-            # we are in package ...
-            if (# ... with subpackage(s)
-                subs
-                or
-                # ... with some module(s)
-                len(py_files) > 1
-                or
-                # ... with a not-to-be-skipped INITPY file
-                not shall_skip(path.join(root, INITPY))
-               ):
-                subroot = root[len(rootpath):].lstrip(path.sep).\
-                          replace(path.sep, '.')
-                create_package_file(root, package_name, subroot,
+        subs[:] = sorted(sub for sub in subs if sub[0] not in ['.', '_'])
+
+        if is_pkg:
+            # we are in a package with something to document
+            if subs or len(py_files) > 1 or not \
+                shall_skip(path.join(root, INITPY)):
+                subpackage = root[len(rootpath):].lstrip(path.sep).\
+                    replace(path.sep, '.')
+                create_package_file(root, root_package, subpackage,
                                     py_files, opts, subs)
-                toc.append(makename(package_name, subroot))
-        elif root == rootpath:
+                toplevels.append(makename(root_package, subpackage))
+        else:
             # if we are at the root level, we don't require it to be a package
+            assert root == rootpath and root_package is None
             for py_file in py_files:
                 if not shall_skip(path.join(rootpath, py_file)):
                     module = path.splitext(py_file)[0]
-                    create_module_file(package_name, module, opts)
-                    toc.append(makename(package_name, module))
+                    create_module_file(root_package, module, opts)
+                    toplevels.append(module)
 
-    # create the module's index
-    if not opts.notoc:
-        create_modules_toc_file(package_name, toc, opts)
+    return toplevels
+
 
 def normalize_excludes(rootpath, excludes):
     """
     * otherwise it is joined with rootpath
     * with trailing slash
     """
-    sep = path.sep
     f_excludes = []
     for exclude in excludes:
         if not path.isabs(exclude) and not exclude.startswith(rootpath):
             exclude = path.join(rootpath, exclude)
-        if not exclude.endswith(sep):
-            exclude += sep
-        f_excludes.append(exclude)
+        f_excludes.append(path.normpath(exclude) + path.sep)
     return f_excludes
 
+
 def is_excluded(root, excludes):
     """
     Check if the directory is in the exclude list.
             return True
     return False
 
+
 def main(argv=sys.argv):
     """
     Parse and check the command line arguments.
 usage: %prog [options] -o <output_path> <module_path> [exclude_paths, ...]
 
 Look recursively in <module_path> for Python modules and packages and create
-a reST file with automodule directives per package in the <output_path>.
+one reST file with automodule directives per package in the <output_path>.
 
 Note: By default this script will not overwrite already created files.""")
 
                       help='Maximum depth of submodules to show in the TOC '
                       '(default: 4)', type='int', default=4)
     parser.add_option('-f', '--force', action='store_true', dest='force',
-                      help='Overwrite all the files')
+                      help='Overwrite all files')
     parser.add_option('-n', '--dry-run', action='store_true', dest='dryrun',
-                      help='Run the script without creating the files')
+                      help='Run the script without creating files')
     parser.add_option('-T', '--no-toc', action='store_true', dest='notoc',
-                      help='Don\'t create the table of contents file')
-    parser.add_option('-H', '--doc-header', action='store', dest='header',
-                      help='Documentation Header (default: Project)',
-                      default='Project')
+                      help='Don\'t create a table of contents file')
     parser.add_option('-s', '--suffix', action='store', dest='suffix',
                       help='file suffix (default: rst)', default='rst')
+    parser.add_option('-F', '--full', action='store_true', dest='full',
+                      help='Generate a full project with sphinx-quickstart')
+    parser.add_option('-H', '--doc-project', action='store', dest='header',
+                      help='Project name (default: root module name)')
+    parser.add_option('-A', '--doc-author', action='store', dest='author',
+                      type='str',
+                      help='Project author(s), used when --full is given')
+    parser.add_option('-V', '--doc-version', action='store', dest='version',
+                      help='Project version, used when --full is given')
+    parser.add_option('-R', '--doc-release', action='store', dest='release',
+                      help='Project release, used when --full is given, '
+                      'defaults to --doc-version')
 
     (opts, args) = parser.parse_args(argv[1:])
 
     if not args:
         parser.error('A package path is required.')
+
+    rootpath, excludes = args[0], args[1:]
     if not opts.destdir:
         parser.error('An output directory is required.')
-    rootpath, excludes = args[0], args[1:]
+    if opts.header is None:
+        opts.header = path.normpath(rootpath).split(path.sep)[-1]
+    if opts.suffix.startswith('.'):
+        opts.suffix = opts.suffix[1:]
     if not path.isdir(rootpath):
         print >>sys.stderr, '%s is not a directory.' % rootpath
         sys.exit(1)
     if not path.isdir(opts.destdir):
-        print '%s is not a valid output directory.' % opts.destdir
-        sys.exit(1)
+        if not opts.dryrun:
+            os.makedirs(opts.destdir)
     excludes = normalize_excludes(rootpath, excludes)
-    recurse_tree(rootpath, excludes, opts)
+    modules = recurse_tree(rootpath, excludes, opts)
+    if opts.full:
+        from sphinx import quickstart as qs
+        modules.sort()
+        prev_module = ''
+        text = ''
+        for module in modules:
+            if module.startswith(prev_module + '.'):
+                continue
+            prev_module = module
+            text += '   %s\n' % module
+        d = dict(
+            path = opts.destdir,
+            sep  = False,
+            dot  = '_',
+            project = opts.header,
+            author = opts.author or 'Author',
+            version = opts.version or '',
+            release = opts.release or opts.version or '',
+            suffix = '.' + opts.suffix,
+            master = 'index',
+            epub = True,
+            ext_autodoc = True,
+            ext_viewcode = True,
+            makefile = True,
+            batchfile = True,
+            mastertocmaxdepth = opts.maxdepth,
+            mastertoctree = text,
+        )
+        if not opts.dryrun:
+            qs.generate(d, silent=True, overwrite=opts.force)
+    elif not opts.notoc:
+        create_modules_toc_file(modules, opts)

File sphinx/builders/gettext.py

 
 from sphinx.builders import Builder
 from sphinx.util.nodes import extract_messages
-from sphinx.util.osutil import SEP, safe_relpath
+from sphinx.util.osutil import SEP, safe_relpath, ensuredir, find_catalog
 from sphinx.util.console import darkgreen
 
 POHEADER = ur"""
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: %(version)s\n"
+"Project-Id-Version: %(project)s %(version)s\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: %(ctime)s\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
         return
 
     def write_doc(self, docname, doctree):
-        catalog = self.catalogs[docname.split(SEP, 1)[0]]
+        catalog = self.catalogs[find_catalog(docname,
+                                             self.config.gettext_compact)]
 
         for node, msg in extract_messages(doctree):
             catalog.add(msg, node)
             # XXX should supply tz
             ctime = datetime.now().strftime('%Y-%m-%d %H:%M%z'),
         )
-        for section, catalog in self.status_iterator(
+        for textdomain, catalog in self.status_iterator(
                 self.catalogs.iteritems(), "writing message catalogs... ",
-                lambda (section, _):darkgreen(section), len(self.catalogs)):
+                lambda (textdomain, _): darkgreen(textdomain),
+                                        len(self.catalogs)):
 
-            pofn = path.join(self.outdir, section + '.pot')
+            # noop if config.gettext_compact is set
+            ensuredir(path.join(self.outdir, path.dirname(textdomain)))
+
+            pofn = path.join(self.outdir, textdomain + '.pot')
             pofile = open(pofn, 'w', encoding='utf-8')
             try:
                 pofile.write(POHEADER % data)

File sphinx/config.py

         linkcheck_ignore = ([], None),
         linkcheck_timeout = (None, None),
         linkcheck_workers = (5, None),
+
+        # gettext options
+        gettext_compact = (True, 'gettext'),
     )
 
     def __init__(self, dirname, filename, overrides, tags):

File sphinx/domains/cpp.py

     def __init__(self, description):
         self.description = description
 
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
     def __unicode__(self):
         return self.description
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
 
 class DefExpr(object):
 
-    def __unicode__(self):
-        raise NotImplementedError()
-
     def __eq__(self, other):
         if type(self) is not type(other):
             return False
     def __str__(self):
         return unicode(self).encode('utf-8')
 
+    def __unicode__(self):
+        raise NotImplementedError()
+
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, self)
 
     def get_name(self):
         return self.name.get_name()
 
-    def get_modifiers(self):
+    def get_modifiers(self, visibility='public'):
         rv = []
-        if self.visibility != 'public':
+        if self.visibility != visibility:
             rv.append(self.visibility)
         if self.static:
             rv.append(u'static')
 
 class ClassDefExpr(NamedDefExpr):
 
-    def __init__(self, name, visibility, static):
+    def __init__(self, name, visibility, static, bases):
         NamedDefExpr.__init__(self, name, visibility, static)
+        self.bases = bases
 
     def get_id(self):
         return self.name.get_id()
 
-    def __unicode__(self):
-        buf = self.get_modifiers()
+    def _tostring(self, visibility='public'):
+        buf = self.get_modifiers(visibility)
         buf.append(unicode(self.name))
+        if self.bases:
+            buf.append(u':')
+            buf.append(u', '.join(base._tostring('private')
+                                  for base in self.bases))
         return u' '.join(buf)
 
+    def __unicode__(self):
+        return self._tostring('public')
 
 class DefinitionParser(object):
 
 
     def parse_class(self):
         visibility, static = self._parse_visibility_static()
-        return ClassDefExpr(self._parse_type(), visibility, static)
+        name = self._parse_type()
+        bases = []
+        if self.skip_string(':'):
+            self.skip_ws()
+            while 1:
+                access = 'private'
+                if self.match(_visibility_re):
+                    access = self.matched_text
+                base = self._parse_type()
+                bases.append(ClassDefExpr(base, access, False, []))
+                if self.skip_string(','):
+                    self.skip_ws()
+                else:
+                    break
+        return ClassDefExpr(name, visibility, static, bases)
 
     def read_rest(self):
         rv = self.definition[self.pos:]
         pnode += nodes.Text(text)
         node += pnode
 
-    def attach_modifiers(self, node, obj):
-        if obj.visibility != 'public':
+    def attach_modifiers(self, node, obj, visibility='public'):
+        if obj.visibility != visibility:
             node += addnodes.desc_annotation(obj.visibility,
                                              obj.visibility)
             node += nodes.Text(' ')
         self.attach_modifiers(signode, cls)
         signode += addnodes.desc_annotation('class ', 'class ')
         self.attach_name(signode, cls.name)
+        if cls.bases:
+            signode += nodes.Text(' : ')
+            for base in cls.bases:
+                self.attach_modifiers(signode, base, 'private')
+                signode += nodes.emphasis(unicode(base.name),
+                                          unicode(base.name))
+                signode += nodes.Text(', ')
+            signode.pop()  # remove the trailing comma
 
 
 class CPPTypeObject(CPPObject):

File sphinx/domains/python.py

             env.domaindata['py']['modules'][modname] = \
                 (env.docname, self.options.get('synopsis', ''),
                  self.options.get('platform', ''), 'deprecated' in self.options)
-            # make a duplicate entry in 'objects' to facilitate searching for the
-            # module in PythonDomain.find_obj()
+            # make a duplicate entry in 'objects' to facilitate searching for
+            # the module in PythonDomain.find_obj()
             env.domaindata['py']['objects'][modname] = (env.docname, 'module')
-            targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
+            targetnode = nodes.target('', '', ids=['module-' + modname],
+                                      ismod=True)
             self.state.document.note_explicit_target(targetnode)
-            # the platform and synopsis aren't printed; in fact, they are only used
-            # in the modindex currently
+            # the platform and synopsis aren't printed; in fact, they are only
+            # used in the modindex currently
             ret.append(targetnode)
             indextext = _('%s (module)') % modname
             inode = addnodes.index(entries=[('single', indextext,

File sphinx/environment.py

      FilenameUniqDict
 from sphinx.util.nodes import clean_astext, make_refnode, extract_messages, \
      WarningStream
-from sphinx.util.osutil import movefile, SEP, ustrftime
+from sphinx.util.osutil import movefile, SEP, ustrftime, find_catalog
 from sphinx.util.matching import compile_matchers
 from sphinx.util.pycompat import all, class_types
 from sphinx.util.websupport import is_commentable
         settings, source = self.document.settings, self.document['source']
         # XXX check if this is reliable
         assert source.startswith(env.srcdir)
-        docname = os.path.splitext(source[len(env.srcdir):].lstrip(os.sep))[0]
-        section = docname.split(os.sep, 1)[0]
+        docname = path.splitext(path.relpath(source, env.srcdir))[0]
+        textdomain = find_catalog(docname,
+                                  self.document.settings.gettext_compact)
 
         # fetch translations
-        dirs = [path.join(env.srcdir, x)
-                for x in env.config.locale_dirs]
-        catalog, has_catalog = init_locale(dirs, env.config.language, section)
+        dirs = [path.join(env.srcdir, directory)
+                for directory in env.config.locale_dirs]
+        catalog, has_catalog = init_locale(dirs, env.config.language,
+                                           textdomain)
         if not has_catalog:
             return
 
         self.settings['input_encoding'] = self.config.source_encoding
         self.settings['trim_footnote_reference_space'] = \
             self.config.trim_footnote_reference_space
+        self.settings['gettext_compact'] = self.config.gettext_compact
 
         self.patch_lookup_functions()
 

File sphinx/pycode/__init__.py

         pos = self.source.tell()
         if not decoded:
             self.encoding = detect_encoding(self.source.readline)
+            self.source.seek(pos)
             self.code = self.source.read().decode(self.encoding)
             self.source.seek(pos)
             self.source = TextIOWrapper(self.source, self.encoding)

File sphinx/quickstart.py

    contain the root `toctree` directive.
 
 Welcome to %(project)s's documentation!
-===========%(underline)s=================
+===========%(project_underline)s=================
 
 Contents:
 
 .. toctree::
-   :maxdepth: 2
+   :maxdepth: %(mastertocmaxdepth)s
+
+%(mastertoctree)s
 
 Indices and tables
 ==================
     del _unicode_string_re, _convert_python_source
 
 
-def inner_main(args):
-    d = {}
-    texescape.init()
+def ask_user(d):
+    """Ask the user for quickstart values missing from *d*.
 
-    if not color_terminal():
-        nocolor()
+    Values are:
 
-    if len(args) > 3:
-        print 'Usage: sphinx-quickstart [root]'
-        sys.exit(1)
-    elif len(args) == 2:
-        d['path'] = args[1]
+    * path:      root path
+    * sep:       separate source and build dirs (bool)
+    * dot:       replacement for dot in _templates etc.
+    * project:   project name
+    * author:    author names
+    * version:   version of project
+    * release:   release of project
+    * suffix:    source file suffix
+    * master:    master document name
+    * epub:      use epub (bool)
+    * ext_*:     extensions to use (bools)
+    * makefile:  make Makefile
+    * batchfile: make command file
+    """
 
     print bold('Welcome to the Sphinx %s quickstart utility.') % __version__
     print '''
         if not d['path']:
             sys.exit(1)
 
-    print '''
+    if 'sep' not in d:
+        print '''
 You have two options for placing the build directory for Sphinx output.
 Either, you use a directory "_build" within the root path, or you separate
 "source" and "build" directories within the root path.'''
-    do_prompt(d, 'sep', 'Separate source and build directories (y/N)', 'n',
-              boolean)
+        do_prompt(d, 'sep', 'Separate source and build directories (y/N)', 'n',
+                  boolean)
 
-    print '''
+    if 'dot' not in d:
+        print '''
 Inside the root directory, two more directories will be created; "_templates"
 for custom HTML templates and "_static" for custom stylesheets and other static
 files. You can enter another prefix (such as ".") to replace the underscore.'''
-    do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok)
+        do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok)
 
-    print '''
+    if 'project' not in d:
+        print '''
 The project name will occur in several places in the built documentation.'''
-    do_prompt(d, 'project', 'Project name')
-    do_prompt(d, 'author', 'Author name(s)')
-    print '''
+        do_prompt(d, 'project', 'Project name')
+    if 'author' not in d:
+        do_prompt(d, 'author', 'Author name(s)')
+
+    if 'version' not in d:
+        print '''
 Sphinx has the notion of a "version" and a "release" for the
 software. Each version can have multiple releases. For example, for
 Python the version is something like 2.5 or 3.0, while the release is
 something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
 just set both to the same value.'''
-    do_prompt(d, 'version', 'Project version')
-    do_prompt(d, 'release', 'Project release', d['version'])
-    print '''
+        do_prompt(d, 'version', 'Project version')
+    if 'release' not in d:
+        do_prompt(d, 'release', 'Project release', d['version'])
+
+    if 'suffix' not in d:
+        print '''
 The file name suffix for source files. Commonly, this is either ".txt"
 or ".rst".  Only files with this suffix are considered documents.'''
-    do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix)
-    print '''
+        do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix)
+
+    if 'master' not in d:
+        print '''
 One document is special in that it is considered the top node of the
 "contents tree", that is, it is the root of the hierarchical structure
 of the documents. Normally, this is "index", but if your "index"
 document is a custom template, you can also set this to another filename.'''
-    do_prompt(d, 'master', 'Name of your master document (without suffix)',
-              'index')
+        do_prompt(d, 'master', 'Name of your master document (without suffix)',
+                  'index')
 
     while path.isfile(path.join(d['path'], d['master']+d['suffix'])) or \
           path.isfile(path.join(d['path'], 'source', d['master']+d['suffix'])):
         do_prompt(d, 'master', 'Please enter a new file name, or rename the '
                   'existing file and press Enter', d['master'])
 
-    print '''
+    if 'epub' not in d:
+        print '''
 Sphinx can also add configuration for epub output:'''
-    do_prompt(d, 'epub', 'Do you want to use the epub builder (y/N)',
-              'n', boolean)
+        do_prompt(d, 'epub', 'Do you want to use the epub builder (y/N)',
+                  'n', boolean)
 
-    print '''
+    if 'ext_autodoc' not in d:
+        print '''
 Please indicate if you want to use one of the following Sphinx extensions:'''
-    do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
-              'from modules (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets '
-              'in doctest blocks (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_intersphinx', 'intersphinx: link between Sphinx '
-              'documentation of different projects (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_todo', 'todo: write "todo" entries '
-              'that can be shown or hidden on build (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_coverage', 'coverage: checks for documentation '
-              'coverage (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_pngmath', 'pngmath: include math, rendered '
-              'as PNG images (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_jsmath', 'jsmath: include math, rendered in the '
-              'browser by JSMath (y/N)', 'n', boolean)
-    if d['ext_pngmath'] and d['ext_jsmath']:
-        print '''Note: pngmath and jsmath cannot be enabled at the same time.
+        do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
+                  'from modules (y/N)', 'n', boolean)
+    if 'ext_doctest' not in d:
+        do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets '
+                  'in doctest blocks (y/N)', 'n', boolean)
+    if 'ext_intersphinx' not in d:
+        do_prompt(d, 'ext_intersphinx', 'intersphinx: link between Sphinx '
+                  'documentation of different projects (y/N)', 'n', boolean)
+    if 'ext_todo' not in d:
+        do_prompt(d, 'ext_todo', 'todo: write "todo" entries '
+                  'that can be shown or hidden on build (y/N)', 'n', boolean)
+    if 'ext_coverage' not in d:
+        do_prompt(d, 'ext_coverage', 'coverage: checks for documentation '
+                  'coverage (y/N)', 'n', boolean)
+    if 'ext_pngmath' not in d:
+        do_prompt(d, 'ext_pngmath', 'pngmath: include math, rendered '
+                  'as PNG images (y/N)', 'n', boolean)
+    if 'ext_mathjax' not in d:
+        do_prompt(d, 'ext_mathjax', 'mathjax: include math, rendered in the '
+                  'browser by MathJax (y/N)', 'n', boolean)
+    if d['ext_pngmath'] and d['ext_mathjax']:
+        print '''Note: pngmath and mathjax cannot be enabled at the same time.
 pngmath has been deselected.'''
-    do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of '
-              'content based on config values (y/N)', 'n', boolean)
-    do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source code '
-              'of documented Python objects (y/N)', 'n', boolean)
-    print '''
+    if 'ext_ifconfig' not in d:
+        do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of '
+                  'content based on config values (y/N)', 'n', boolean)
+    if 'ext_viewcode' not in d:
+        do_prompt(d, 'ext_viewcode', 'viewcode: include links to the source '
+                  'code of documented Python objects (y/N)', 'n', boolean)
+
+    if 'makefile' not in d:
+        print '''
 A Makefile and a Windows command file can be generated for you so that you
 only have to run e.g. `make html' instead of invoking sphinx-build
 directly.'''
-    do_prompt(d, 'makefile', 'Create Makefile? (Y/n)', 'y', boolean)
-    do_prompt(d, 'batchfile', 'Create Windows command file? (Y/n)',
-              'y', boolean)
+        do_prompt(d, 'makefile', 'Create Makefile? (Y/n)', 'y', boolean)
+    if 'batchfile' not in d:
+        do_prompt(d, 'batchfile', 'Create Windows command file? (Y/n)',
+                  'y', boolean)
+    print
+
+
+def generate(d, overwrite=True, silent=False):
+    """Generate project based on values in *d*."""
+
+    texescape.init()
+
+    if 'mastertoctree' not in d:
+        d['mastertoctree'] = ''
+    if 'mastertocmaxdepth' not in d:
+        d['mastertocmaxdepth'] = 2
 
     d['project_fn'] = make_filename(d['project'])
     d['project_manpage'] = d['project_fn'].lower()
     d['now'] = time.asctime()
-    d['underline'] = len(d['project']) * '='
+    d['project_underline'] = len(d['project']) * '='
     d['extensions'] = ', '.join(
         repr('sphinx.ext.' + name)
         for name in ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage',
-                     'pngmath', 'jsmath', 'ifconfig', 'viewcode')
-        if d['ext_' + name])
+                     'pngmath', 'mathjax', 'ifconfig', 'viewcode')
+        if d.get('ext_' + name))
     d['copyright'] = time.strftime('%Y') + ', ' + d['author']
     d['author_texescaped'] = unicode(d['author']).\
                              translate(texescape.tex_escape_map)
     mkdir_p(path.join(srcdir, d['dot'] + 'templates'))
     mkdir_p(path.join(srcdir, d['dot'] + 'static'))
 
+    def write_file(fpath, mode, content):
+        if overwrite or not path.isfile(fpath):
+            print 'Creating file %s.' % fpath
+            f = open(fpath, mode, encoding='utf-8')
+            try:
+                f.write(content)
+            finally:
+                f.close()
+        else:
+            print 'File %s already exists, skipping.' % fpath
+
     conf_text = QUICKSTART_CONF % d
     if d['epub']:
         conf_text += EPUB_CONFIG % d
-    if d['ext_intersphinx']:
+    if d.get('ext_intersphinx'):
         conf_text += INTERSPHINX_CONFIG
 
-    f = open(path.join(srcdir, 'conf.py'), 'w', encoding='utf-8')
-    f.write(conf_text)
-    f.close()
+    write_file(path.join(srcdir, 'conf.py'), 'w', conf_text)
 
     masterfile = path.join(srcdir, d['master'] + d['suffix'])
-    f = open(masterfile, 'w', encoding='utf-8')
-    f.write(MASTER_FILE % d)
-    f.close()
+    write_file(masterfile, 'w', MASTER_FILE % d)
 
     if d['makefile']:
         d['rsrcdir'] = d['sep'] and 'source' or '.'
         d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
         # use binary mode, to avoid writing \r\n on Windows
-        f = open(path.join(d['path'], 'Makefile'), 'wb', encoding='utf-8')
-        f.write(MAKEFILE % d)
-        f.close()
+        write_file(path.join(d['path'], 'Makefile'), 'wb', MAKEFILE % d)
 
     if d['batchfile']:
         d['rsrcdir'] = d['sep'] and 'source' or '.'
         d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
-        f = open(path.join(d['path'], 'make.bat'), 'w', encoding='utf-8')
-        f.write(BATCHFILE % d)
-        f.close()
+        write_file(path.join(d['path'], 'make.bat'), 'w', BATCHFILE % d)
 
+    if silent:
+        return
     print
     print bold('Finished: An initial directory structure has been created.')
     print '''
 
 
 def main(argv=sys.argv):
+    if not color_terminal():
+        nocolor()
+
+    d = {}
+    if len(argv) > 3:
+        print 'Usage: sphinx-quickstart [root]'
+        sys.exit(1)
+    elif len(argv) == 2:
+        d['path'] = argv[1]
     try:
-        return inner_main(argv)
+        ask_user(d)
     except (KeyboardInterrupt, EOFError):
         print
         print '[Interrupted.]'
         return
+    generate(d)

File sphinx/themes/basic/static/doctools.js

           body.highlightText(this.toLowerCase(), 'highlighted');
         });
       }, 10);
-      $('<li class="highlight-link"><a href="javascript:Documentation.' +
-        'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
-          .appendTo($('.sidebar .this-page-menu'));
+      $('<p class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
+          .appendTo($('#searchbox'));
     }
   },
 
    * helper function to hide the search marks again
    */
   hideSearchWords : function() {
-    $('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
+    $('#searchbox .highlight-link').fadeOut(300);
     $('span.highlighted').removeClass('highlighted');
   },
 

File sphinx/themes/basic/static/websupport.js

     var context = $.extend({}, opts, comment);
     var div = $(renderTemplate(commentTemplate, context));
 
-    // If the user has voted on this comment, highblight the correct arrow.
+    // If the user has voted on this comment, highlight the correct arrow.
     if (comment.vote) {
       var direction = (comment.vote == 1) ? 'u' : 'd';
       div.find('#' + direction + 'v' + comment.id).hide();

File sphinx/util/nodes.py

     return key in self.children
 
 nodes.Node.__contains__ = _new_contains
+
+# monkey-patch Element.copy to copy the rawsource
+
+def _new_copy(self):
+    return self.__class__(self.rawsource, **self.attributes)
+
+nodes.Element.copy = _new_copy

File sphinx/util/osutil.py

         return os.path.relpath(path, start)
     except ValueError:
         return path
+
+def find_catalog(docname, compaction):
+    return docname.split(SEP, 1)[0] if compaction else docname

File sphinx/writers/latex.py

 
     def idescape(self, id):
         return unicode(id).translate(tex_replace_map).\
-            encode('ascii', 'backslashreplace').replace('\\', '_')
+            encode('ascii', 'backslashreplace').decode('ascii').\
+            replace('\\', '_')
 
     def generate_indices(self):
         def generate(content, collapsed):

File tests/test_cpp_domain.py

     assert unicode(parse('member_object', x)) == x
 
 
+def test_bases():
+    x = 'A'
+    assert unicode(parse('class', x)) == x
+
+    x = 'A : B'
+    assert unicode(parse('class', x)) == x
+
+    x = 'A : private B'
+    assert unicode(parse('class', x)) == 'A : B'
+
+    x = 'A : public B'
+    assert unicode(parse('class', x)) == x
+
+    x = 'A : B, C'
+    assert unicode(parse('class', x)) == x
+
+    x = 'A : B, protected C, D'
+    assert unicode(parse('class', x)) == x
+
+
 def test_operators():
     x = parse('function', 'void operator new [  ] ()')
     assert unicode(x) == 'void operator new[]()'

File tests/test_intersphinx.py

         'http://docs.python.org/': inv_file,
         'py3k': ('http://docs.python.org/py3k/', inv_file),
         'repoze.workflow': ('http://docs.repoze.org/workflow/', inv_file),
-        'django-taggit': ('http://django-taggit.readthedocs.org/en/latest/', inv_file)
+        'django-taggit': ('http://django-taggit.readthedocs.org/en/latest/',
+                          inv_file)
     }
 
     app.config.intersphinx_cache_limit = 0

File tests/test_markup.py

     yield (verify, u'Γ\\\\∞$', None,
            ur'\(\Gamma\)\textbackslash{}\(\infty\)\$')
     # in verbatim code fragments
-    yield (verify, u'::\n\n @Γ\\∞$[]', None,
-           u'\\begin{Verbatim}[commandchars=@\\[\\]]\n'
-           u'@PYGZat[]@(@Gamma@)\\@(@infty@)@$@PYGZlb[]@PYGZrb[]\n'
+    yield (verify, u'::\n\n @Γ\\∞${}', None,
+           u'\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n'
+           u'@\\(\\Gamma\\)\\PYGZbs{}\\(\\infty\\)\\$\\PYGZob{}\\PYGZcb{}\n'
            u'\\end{Verbatim}')
     # in URIs
     yield (verify_re, u'`test <http://example.com/~me/>`_', None,

File tests/test_quickstart.py

 
 import sys
 import time
-import __builtin__
 
 from util import *
 
         'Project version': '0.1',
     }
     qs.term_input = mock_raw_input(answers)
-    qs.inner_main([])
+    d = {}
+    qs.ask_user(d)
+    qs.generate(d)
 
     conffile = tempdir / 'conf.py'
     assert conffile.isfile()
         'todo': 'n',
         'coverage': 'no',
         'pngmath': 'N',
-        'jsmath': 'no',
+        'mathjax': 'no',
         'ifconfig': 'no',
         'viewcode': 'no',
         'Create Makefile': 'no',
     }
     qs.term_input = mock_raw_input(answers, needanswer=True)
     qs.TERM_ENCODING = 'utf-8'
-    qs.inner_main([])
+    d = {}
+    qs.ask_user(d)
+    qs.generate(d)
 
     conffile = tempdir / 'source' / 'conf.py'
     assert conffile.isfile()

File tests/test_websupport.py

     # functools is new in 2.5
     wraps = lambda f: (lambda w: w)
 
-from nose import SkipTest
-
 from sphinx.websupport import WebSupport
 from sphinx.websupport.errors import *
 from sphinx.websupport.storage import StorageBackend
 from util import *
 
 
-raise SkipTest('websupport tests are currently not working')
-
 default_settings = {'builddir': os.path.join(test_root, 'websupport'),
                     'status': StringIO(),
                     'warning': StringIO()}
     comments = data['comments']
     children = comments[0]['children']
     assert len(comments) == 2
-    assert comments[1]['text'] == 'Hidden comment'
+    assert comments[1]['text'] == '<p>Hidden comment</p>\n'
     assert len(children) == 2
-    assert children[1]['text'] == 'Hidden child test comment'
+    assert children[1]['text'] == '<p>Hidden child test comment</p>\n'
 
     # Access the comments without being a moderator.
     data = support.get_data(first_node.id)
     comments = data['comments']
     children = comments[0]['children']
     assert len(comments) == 1
-    assert comments[0]['text'] == 'First test comment'
+    assert comments[0]['text'] == '<p>First test comment</p>\n'
     assert len(children) == 1
-    assert children[0]['text'] == 'Child test comment'
+    assert children[0]['text'] == '<p>Child test comment</p>\n'
 
 
 @skip_if(sqlalchemy_missing, 'needs sqlalchemy')
     comment = get_comment()
     support.delete_comment(comment['id'], username='user_two',
                            moderator=True)
-    comment = get_comment()
-    assert comment['username'] == '[deleted]'
-    assert comment['text'] == '[deleted]'
+    raises(IndexError, get_comment)
 
 
 @skip_if(sqlalchemy_missing, 'needs sqlalchemy')
         filter(Comment.username == 'user_two').all()
     assert len(comments) == 0
     votes = session.query(CommentVote).\
-        filter(CommentVote.username == 'user_two')
-    assert len(comments) == 0
+        filter(CommentVote.username == 'user_two').all()
+    assert len(votes) == 0
     comments = session.query(Comment).\
         filter(Comment.username == 'new_user_two').all()
     assert len(comments) == 1
     votes = session.query(CommentVote).\
-        filter(CommentVote.username == 'new_user_two')
-    assert len(comments) == 1
+        filter(CommentVote.username == 'new_user_two').all()
+    assert len(votes) == 0
 
 
 called = False
     session.close()
     accepted = support.add_comment('Accepted Comment', node_id=node.id,
                                    displayed=False)
-    rejected = support.add_comment('Rejected comment', node_id=node.id,
+    deleted  = support.add_comment('Comment to delete', node_id=node.id,
                                    displayed=False)
     # Make sure the moderation_callback is called.
     assert called == True
     # Make sure the user must be a moderator.
     raises(UserNotAuthorizedError, support.accept_comment, accepted['id'])
-    raises(UserNotAuthorizedError, support.reject_comment, accepted['id'])
+    raises(UserNotAuthorizedError, support.delete_comment, deleted['id'])
     support.accept_comment(accepted['id'], moderator=True)
-    support.reject_comment(rejected['id'], moderator=True)
+    support.delete_comment(deleted['id'], moderator=True)
     comments = support.get_data(node.id)['comments']
     assert len(comments) == 1
     comments = support.get_data(node.id, moderator=True)['comments']