jacobmason avatar jacobmason committed 6b47638 Merge

merge with trunk

Comments (0)

Files changed (86)

 ^env/
 \.DS_Store$
 ~$
+^utils/.*3\.py$
+^distribute-
 Release 1.1 (in development)
 ============================
 
+* Added Python 3.x support.
+
+
 Release 1.0.2 (in development)
 ==============================
 
+* Allow breaking long signatures, continuing with backlash-escaped
+  newlines.
+
+* Fix unwanted styling of C domain references (because of a namespace
+  clash with Pygments styles).
+
+* Allow references to PEPs and RFCs with explicit anchors.
+
+* #471: Fix LaTeX references to figures.
+
+* #482: When doing a non-exact search, match only the given type
+  of object.
+
+* #481: Apply non-exact search for Python reference targets with
+  ``.name`` for modules too.
+
+* #484: Fix crash when duplicating a parameter in an info field list.
+
+* #487: Fix setting the default role to one provided by the
+  ``oldcmarkup`` extension.
+
+* #488: Fix crash when json-py is installed, which provides a
+  ``json`` module but is incompatible to simplejson.
+
+* #480: Fix handling of target naming in intersphinx.
+
+* #486: Fix removal of ``!`` for all cross-reference roles.
+
+
 Release 1.0.1 (Jul 27, 2010)
 ============================
 
+Changes
+=======
+
+This file contains changes made by Daniel Neuhäuser, during the Google Summer
+of Code 2010, to port Sphinx to Python 3.x. Changes are ordered descending by
+date.
+
+May 16: - Added utils/convert.py which converts entire directories of python
+          files with 2to3 and names the converted files foo3.py.
+        - Modified the Makefile so that in case Python 3 is used the scripts in
+          utils get converted with utils/convert.py and are used instead of the
+          Python 2 scripts.
+
+May 10: Fixed a couple of tests and made several small changes.
+
+May 9: - Removed ez_setup.py which does not work with Python 3.x. and replaced
+         it with distribute_setup.py
+       - Use distribute (at least on 3.x) in order to run 2to3 automatically.
+       - Reverted some of the changes made in revision bac40c7c924c which
+         caused errors.
+       - Modified tests/run.py to test against the build created by
+         setup.py build in order to run the test suite with 3.x
+       - Several small changes to fix 3.x compatibilty.
+
+May 1: - Removed deprecated tuple parameter unpacking.
+       - Removed a pre-2.3 workaround for booleans because this creates a
+         deprecation warning for 3.x, in which you can't assign values to
+         booleans.
+       - Moved :func:`open()` calls out of the try-blocks, which fixes revision
+         c577c25bd44b.
+
+April 30: Made :cls:`sphinx.domains.cpp.DefExpr` unhashable as described by the
+          documentation because classes in 3.x don't inherit ``__hash__`` if
+	  they implement ``__eq__``.
+
+April 29: Removed several deprecated function/method calls.
 * Satchmo: http://www.satchmoproject.com/docs/svn/
 * Sphinx: http://sphinx.pocoo.org/
 * Sqlkit: http://sqlkit.argolinux.org/
+* Tau: http://www.tango-controls.org/static/tau/latest/doc/html/index.html
 * Total Open Station: http://tops.berlios.de/
 * WebFaction: http://docs.webfaction.com/
 
 
 include babel.cfg
 include Makefile
-include ez_setup.py
+include setup_distribute.py
 include sphinx-autogen.py
 include sphinx-build.py
 include sphinx-quickstart.py
 PYTHON ?= python
 
-export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx
+.PHONY: all check clean clean-pyc clean-patchfiles clean-backupfiles \
+        clean-generated pylint reindent test covertest build convert-utils
 
-.PHONY: all check clean clean-pyc clean-patchfiles pylint reindent test
+DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \
+             -i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \
+             -i .ropeproject -i doc/_build -i tests/path.py \
+             -i tests/coverage.py -i env -i utils/convert.py \
+             -i utils/reindent3.py -i utils/check_sources3.py -i .tox
 
-all: clean-pyc check test
+all: clean-pyc clean-backupfiles check test
 
+ifeq ($(PYTHON), python3)
+check: convert-utils
+	@$(PYTHON) utils/check_sources3.py $(DONT_CHECK) .
+else
 check:
-	@$(PYTHON) utils/check_sources.py -i build -i dist -i sphinx/style/jquery.js \
-		-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py -i .ropeproject \
-		-i doc/_build -i ez_setup.py -i tests/path.py -i tests/coverage.py \
-		-i env -i .tox .
+	@$(PYTHON) utils/check_sources.py $(DONT_CHECK) .
+endif
 
-clean: clean-pyc clean-patchfiles
+clean: clean-pyc clean-patchfiles clean-backupfiles clean-generated
 
 clean-pyc:
 	find . -name '*.pyc' -exec rm -f {} +
 	find . -name '*.pyo' -exec rm -f {} +
-	find . -name '*~' -exec rm -f {} +
 
 clean-patchfiles:
 	find . -name '*.orig' -exec rm -f {} +
 	find . -name '*.rej' -exec rm -f {} +
 
+clean-backupfiles:
+	find . -name '*~' -exec rm -f {} +
+	find . -name '*.bak' -exec rm -f {} +
+
+clean-generated:
+	rm -f utils/*3.py*
+
 pylint:
 	@pylint --rcfile utils/pylintrc sphinx
 
+ifeq ($(PYTHON), python3)
+reindent: convert-utils
+	@$(PYTHON) utils/reindent3.py -r -n .
+else
 reindent:
-	@$(PYTHON) utils/reindent.py -r -B .
+	@$(PYTHON) utils/reindent.py -r -n .
+endif
 
-test:
+test: build
 	@cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST)
 
-covertest:
-	@cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage --cover-package=sphinx $(TEST)
+covertest: build
+	@cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage \
+		--cover-package=sphinx $(TEST)
+
+build:
+	@$(PYTHON) setup.py build
+
+ifeq ($(PYTHON), python3)
+convert-utils:
+	@python3 utils/convert.py -i utils/convert.py utils/
+endif
 Or read them online at <http://sphinx.pocoo.org/>.
 
 
+Testing
+=======
+
+To run the tests with the interpreter available as ``python``, use::
+
+    make test
+
+If you want to use a different interpreter, e.g. ``python3``, use::
+
+    PYTHON=python3 make test
+
+
 Contributing
 ============
 
Add a comment to this file

custom_fixers/__init__.py

Empty file added.

custom_fixers/fix_alt_unicode.py

+from lib2to3.fixer_base import BaseFix
+from lib2to3.fixer_util import Name
+
+class FixAltUnicode(BaseFix):
+    PATTERN = """
+    func=funcdef< 'def' name='__unicode__'
+                  parameters< '(' NAME ')' > any+ >
+    """
+
+    def transform(self, node, results):
+        name = results['name']
+        name.replace(Name('__str__', prefix=name.prefix))

distribute_setup.py

+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from distribute_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+    from site import USER_SITE
+except ImportError:
+    USER_SITE = None
+
+try:
+    import subprocess
+
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        return subprocess.call(args) == 0
+
+except ImportError:
+    # will be used for python 2.3
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        # quoting arguments if windows
+        if sys.platform == 'win32':
+            def quote(arg):
+                if ' ' in arg:
+                    return '"%s"' % arg
+                return arg
+            args = [quote(arg) for arg in args]
+        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.13"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # installing
+        log.warn('Installing Distribute')
+        if not _python_cmd('setup.py', 'install'):
+            log.warn('Something went wrong during the installation.')
+            log.warn('See the error message above.')
+    finally:
+        os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # building an egg
+        log.warn('Building a Distribute egg in %s', to_dir)
+        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+    finally:
+        os.chdir(old_wd)
+    # returning the result
+    log.warn(egg)
+    if not os.path.exists(egg):
+        raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+                       % (version, sys.version_info[0], sys.version_info[1]))
+    if not os.path.exists(egg):
+        tarball = download_setuptools(version, download_base,
+                                      to_dir, download_delay)
+        _build_egg(egg, tarball, to_dir)
+    sys.path.insert(0, egg)
+    import setuptools
+    setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                   to_dir=os.curdir, download_delay=15, no_fake=True):
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    was_imported = 'pkg_resources' in sys.modules or \
+        'setuptools' in sys.modules
+    try:
+        try:
+            import pkg_resources
+            if not hasattr(pkg_resources, '_distribute'):
+                if not no_fake:
+                    _fake_setuptools()
+                raise ImportError
+        except ImportError:
+            return _do_download(version, download_base, to_dir, download_delay)
+        try:
+            pkg_resources.require("distribute>="+version)
+            return
+        except pkg_resources.VersionConflict:
+            e = sys.exc_info()[1]
+            if was_imported:
+                sys.stderr.write(
+                "The required version of distribute (>=%s) is not available,\n"
+                "and can't be installed while this script is running. Please\n"
+                "install a more recent version first, using\n"
+                "'easy_install -U distribute'."
+                "\n\n(Currently using %r)\n" % (version, e.args[0]))
+                sys.exit(2)
+            else:
+                del pkg_resources, sys.modules['pkg_resources']    # reload ok
+                return _do_download(version, download_base, to_dir,
+                                    download_delay)
+        except pkg_resources.DistributionNotFound:
+            return _do_download(version, download_base, to_dir,
+                                download_delay)
+    finally:
+        if not no_fake:
+            _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                        to_dir=os.curdir, delay=15):
+    """Download distribute from a specified location and return its filename
+
+    `version` should be a valid distribute version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download
+    attempt.
+    """
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    try:
+        from urllib.request import urlopen
+    except ImportError:
+        from urllib2 import urlopen
+    tgz_name = "distribute-%s.tar.gz" % version
+    url = download_base + tgz_name
+    saveto = os.path.join(to_dir, tgz_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            log.warn("Downloading %s", url)
+            src = urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = src.read()
+            dst = open(saveto, "wb")
+            dst.write(data)
+        finally:
+            if src:
+                src.close()
+            if dst:
+                dst.close()
+    return os.path.realpath(saveto)
+
+def _no_sandbox(function):
+    def __no_sandbox(*args, **kw):
+        try:
+            from setuptools.sandbox import DirectorySandbox
+            if not hasattr(DirectorySandbox, '_old'):
+                def violation(*args):
+                    pass
+                DirectorySandbox._old = DirectorySandbox._violation
+                DirectorySandbox._violation = violation
+                patched = True
+            else:
+                patched = False
+        except ImportError:
+            patched = False
+
+        try:
+            return function(*args, **kw)
+        finally:
+            if patched:
+                DirectorySandbox._violation = DirectorySandbox._old
+                del DirectorySandbox._old
+
+    return __no_sandbox
+
+def _patch_file(path, content):
+    """Will backup the file then patch it"""
+    existing_content = open(path).read()
+    if existing_content == content:
+        # already patched
+        log.warn('Already patched.')
+        return False
+    log.warn('Patching...')
+    _rename_path(path)
+    f = open(path, 'w')
+    try:
+        f.write(content)
+    finally:
+        f.close()
+    return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+def _same_content(path, content):
+    return open(path).read() == content
+
+def _rename_path(path):
+    new_name = path + '.OLD.%s' % time.time()
+    log.warn('Renaming %s into %s', path, new_name)
+    os.rename(path, new_name)
+    return new_name
+
+def _remove_flat_installation(placeholder):
+    if not os.path.isdir(placeholder):
+        log.warn('Unkown installation at %s', placeholder)
+        return False
+    found = False
+    for file in os.listdir(placeholder):
+        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+            found = True
+            break
+    if not found:
+        log.warn('Could not locate setuptools*.egg-info')
+        return
+
+    log.warn('Removing elements out of the way...')
+    pkg_info = os.path.join(placeholder, file)
+    if os.path.isdir(pkg_info):
+        patched = _patch_egg_dir(pkg_info)
+    else:
+        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+    if not patched:
+        log.warn('%s already patched.', pkg_info)
+        return False
+    # now let's move the files out of the way
+    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+        element = os.path.join(placeholder, element)
+        if os.path.exists(element):
+            _rename_path(element)
+        else:
+            log.warn('Could not find the %s element of the '
+                     'Setuptools distribution', element)
+    return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+def _after_install(dist):
+    log.warn('After install bootstrap.')
+    placeholder = dist.get_command_obj('install').install_purelib
+    _create_fake_setuptools_pkg_info(placeholder)
+
+def _create_fake_setuptools_pkg_info(placeholder):
+    if not placeholder or not os.path.exists(placeholder):
+        log.warn('Could not find the install location')
+        return
+    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+    setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+            (SETUPTOOLS_FAKED_VERSION, pyver)
+    pkg_info = os.path.join(placeholder, setuptools_file)
+    if os.path.exists(pkg_info):
+        log.warn('%s already exists', pkg_info)
+        return
+
+    log.warn('Creating %s', pkg_info)
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+
+    pth_file = os.path.join(placeholder, 'setuptools.pth')
+    log.warn('Creating %s', pth_file)
+    f = open(pth_file, 'w')
+    try:
+        f.write(os.path.join(os.curdir, setuptools_file))
+    finally:
+        f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
+
+def _patch_egg_dir(path):
+    # let's check if it's already patched
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    if os.path.exists(pkg_info):
+        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+            log.warn('%s already patched.', pkg_info)
+            return False
+    _rename_path(path)
+    os.mkdir(path)
+    os.mkdir(os.path.join(path, 'EGG-INFO'))
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+    return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+def _before_install():
+    log.warn('Before install bootstrap.')
+    _fake_setuptools()
+
+
+def _under_prefix(location):
+    if 'install' not in sys.argv:
+        return True
+    args = sys.argv[sys.argv.index('install')+1:]
+    for index, arg in enumerate(args):
+        for option in ('--root', '--prefix'):
+            if arg.startswith('%s=' % option):
+                top_dir = arg.split('root=')[-1]
+                return location.startswith(top_dir)
+            elif arg == option:
+                if len(args) > index:
+                    top_dir = args[index+1]
+                    return location.startswith(top_dir)
+        if arg == '--user' and USER_SITE is not None:
+            return location.startswith(USER_SITE)
+    return True
+
+
+def _fake_setuptools():
+    log.warn('Scanning installed packages')
+    try:
+        import pkg_resources
+    except ImportError:
+        # we're cool
+        log.warn('Setuptools or Distribute does not seem to be installed.')
+        return
+    ws = pkg_resources.working_set
+    try:
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+                                  replacement=False))
+    except TypeError:
+        # old distribute API
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+    if setuptools_dist is None:
+        log.warn('No setuptools distribution found')
+        return
+    # detecting if it was already faked
+    setuptools_location = setuptools_dist.location
+    log.warn('Setuptools installation detected at %s', setuptools_location)
+
+    # if --root or --preix was provided, and if
+    # setuptools is not located in them, we don't patch it
+    if not _under_prefix(setuptools_location):
+        log.warn('Not patching, --root or --prefix is installing Distribute'
+                 ' in another location')
+        return
+
+    # let's see if its an egg
+    if not setuptools_location.endswith('.egg'):
+        log.warn('Non-egg installation')
+        res = _remove_flat_installation(setuptools_location)
+        if not res:
+            return
+    else:
+        log.warn('Egg installation')
+        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+        if (os.path.exists(pkg_info) and
+            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+            log.warn('Already patched.')
+            return
+        log.warn('Patching...')
+        # let's create a fake egg replacing setuptools one
+        res = _patch_egg_dir(setuptools_location)
+        if not res:
+            return
+    log.warn('Patched done.')
+    _relaunch()
+
+
+def _relaunch():
+    log.warn('Relaunching...')
+    # we have to relaunch the process
+    # pip marker to avoid a relaunch bug
+    if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
+        sys.argv[0] = 'setup.py'
+    args = [sys.executable] + sys.argv
+    sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+    """Extract all members from the archive to the current working
+       directory and set owner, modification time and permissions on
+       directories afterwards. `path' specifies a different directory
+       to extract to. `members' is optional and must be a subset of the
+       list returned by getmembers().
+    """
+    import copy
+    import operator
+    from tarfile import ExtractError
+    directories = []
+
+    if members is None:
+        members = self
+
+    for tarinfo in members:
+        if tarinfo.isdir():
+            # Extract directories with a safe mode.
+            directories.append(tarinfo)
+            tarinfo = copy.copy(tarinfo)
+            tarinfo.mode = 448 # decimal for oct 0700
+        self.extract(tarinfo, path)
+
+    # Reverse sort directories.
+    if sys.version_info < (2, 4):
+        def sorter(dir1, dir2):
+            return cmp(dir1.name, dir2.name)
+        directories.sort(sorter)
+        directories.reverse()
+    else:
+        directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+    # Set correct owner, mtime and filemode on directories.
+    for tarinfo in directories:
+        dirpath = os.path.join(path, tarinfo.name)
+        try:
+            self.chown(tarinfo, dirpath)
+            self.utime(tarinfo, dirpath)
+            self.chmod(tarinfo, dirpath)
+        except ExtractError:
+            e = sys.exc_info()[1]
+            if self.errorlevel > 1:
+                raise
+            else:
+                self._dbg(1, "tarfile: %s" % e)
+
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    tarball = download_setuptools()
+    _install(tarball)
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])

doc/_templates/indexsidebar.html

   <input type="text" name="email" value="your@email"/>
   <input type="submit" name="sub" value="Subscribe" />
 </form>
-<p>or come to the <tt>#python-docs</tt> channel on FreeNode.</p>
+<p>or come to the <tt>#pocoo</tt> channel on FreeNode.</p>
 <p>You can also open an issue at the
   <a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.</p>
 files.  They also copy the reST source files in the directory ``_sources``
 under the output directory.
 
-The :class:`PickleHTMLBuilder` is a builtin subclass that implements the pickle
+The :class:`.PickleHTMLBuilder` is a builtin subclass that implements the pickle
 serialization interface.
 
 The files per source file have the extensions of
-:attr:`~SerializingHTMLBuilder.out_suffix`, and are arranged in directories
+:attr:`~.SerializingHTMLBuilder.out_suffix`, and are arranged in directories
 just as the source files are.  They unserialize to a dictionary (or dictionary
 like structure) with these keys:
 
 
 The special files are located in the root output directory.  They are:
 
-:attr:`SerializingHTMLBuilder.globalcontext_filename`
+:attr:`.SerializingHTMLBuilder.globalcontext_filename`
    A pickled dict with these keys:
 
    ``project``, ``copyright``, ``release``, ``version``
    ``titles``
       A dictionary of all documents' titles, as HTML strings.
 
-:attr:`SerializingHTMLBuilder.searchindex_filename`
+:attr:`.SerializingHTMLBuilder.searchindex_filename`
    An index that can be used for searching the documentation.  It is a pickled
    list with these entries:
 
      'template generator', '', 1),
 ]
 
+# We're not using intersphinx right now, but if we did, this would be part of
+# the mapping:
+intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)}
+
 
 # -- Extension interface -------------------------------------------------------
 
 
    A boolean that decides whether module names are prepended to all
    :term:`object` names (for object types where a "module" of some kind is
-   defined), e.g. for :rst:dir:`function` directives.  Default is ``True``.
+   defined), e.g. for :rst:dir:`py:function` directives.  Default is ``True``.
 
 .. confval:: show_authors
 
-   A boolean that decides whether :rst:dir:`moduleauthor` and :rst:dir:`sectionauthor`
-   directives produce any output in the built files.
+   A boolean that decides whether :rst:dir:`codeauthor` and
+   :rst:dir:`sectionauthor` directives produce any output in the built files.
 
 .. confval:: modindex_common_prefix
 
 These options influence HTML as well as HTML Help output, and other builders
 that use Sphinx' HTMLWriter class.
 
+.. XXX document html_context
+
 .. confval:: html_theme
 
    The "theme" that the HTML output should use.  See the :doc:`section about
    This will render the template ``customdownload.html`` as the page
    ``download.html``.
 
-   .. note::
-
-      Earlier versions of Sphinx had a value called :confval:`html_index` which
-      was a clumsy way of controlling the content of the "index" document.  If
-      you used this feature, migrate it by adding an ``'index'`` key to this
-      setting, with your custom template as the value, and in your custom
-      template, use ::
-
-         {% extend "defindex.html" %}
-         {% block tables %}
-         ... old template content ...
-         {% endblock %}
-
 .. confval:: html_domain_indices
 
    If true, generate domain-specific indices in addition to the general index.
 
    .. py:function:: spam(eggs)
                     ham(eggs)
+
+      Spam or ham the foo.
+
+This describes the two Python functions ``spam`` and ``ham``.  (Note that when
+signatures become too long, you can break them if you add a backslash to lines
+that are continued in the next line.  Example::
+
+   .. py:function:: filterwarnings(action, message='', category=Warning, \
+                                   module='', lineno=0, append=False)
       :noindex:
 
-      Spam or ham the foo.
+(This example also shows how to use the ``:noindex:`` flag.)
 
 The domains also provide roles that link back to these object descriptions.  For
 example, to link to one of the functions described in the example above, you
 .. rst:directive:: .. py:currentmodule:: name
 
    This directive tells Sphinx that the classes, functions etc. documented from
-   here are in the given module (like :rst:dir:`py:module`), but it will not create
-   index entries, an entry in the Global Module Index, or a link target for
-   :rst:role:`mod`.  This is helpful in situations where documentation for things in
-   a module is spread over multiple files or sections -- one location has the
-   :rst:dir:`py:module` directive, the others only :rst:dir:`py:currentmodule`.
+   here are in the given module (like :rst:dir:`py:module`), but it will not
+   create index entries, an entry in the Global Module Index, or a link target
+   for :rst:role:`py:mod`.  This is helpful in situations where documentation
+   for things in a module is spread over multiple files or sections -- one
+   location has the :rst:dir:`py:module` directive, the others only
+   :rst:dir:`py:currentmodule`.
 
 
 The following directives are provided for module and class contents:
 :mod:`codecs` module, ``:py:func:`open``` always refers to the built-in
 function, while ``:py:func:`.open``` refers to :func:`codecs.open`.
 
+A similar heuristic is used to determine whether the name is an attribute of the
+currently documented class.
+
 Also, if the name is prefixed with a dot, and no exact match is found, the
 target is taken as a suffix and all object names with that suffix are
 searched.  For example, ``:py:meth:`.TarFile.close``` references the
 ``tarfile``.  Since this can get ambiguous, if there is more than one possible
 match, you will get a warning from Sphinx.
 
-A similar heuristic is used to determine whether the name is an attribute of the
-currently documented class.
+Note that you can combine the ``~`` and ``.`` prefixes:
+``:py:meth:`~.TarFile.close``` will reference the ``tarfile.TarFile.close()``
+method, but the visible link caption will only be ``close()``.
 
 
 .. _c-domain:

doc/ext/appapi.rst

    standard Sphinx roles (see :ref:`xref-syntax`).
 
    This method is also available under the deprecated alias
-   :meth:`add_description_unit`.
+   ``add_description_unit``.
 
 .. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='')
 
    This allows to auto-document new types of objects.  See the source of the
    autodoc module for examples on how to subclass :class:`Documenter`.
 
+   .. XXX add real docs for Documenter and subclassing
+
    .. versionadded:: 0.6
 
 .. method:: Sphinx.add_autodoc_attrgetter(type, getter)

doc/ext/autodoc.rst

 auto-generated-looking pure API documentation.
 
 :mod:`autodoc` provides several directives that are versions of the usual
-:rst:dir:`module`, :rst:dir:`class` and so forth.  On parsing time, they import the
-corresponding module and extract the docstring of the given objects, inserting
-them into the page source under a suitable :rst:dir:`module`, :rst:dir:`class` etc.
-directive.
+:rst:dir:`py:module`, :rst:dir:`py:class` and so forth.  On parsing time, they
+import the corresponding module and extract the docstring of the given objects,
+inserting them into the page source under a suitable :rst:dir:`py:module`,
+:rst:dir:`py:class` etc.  directive.
 
 .. note::
 
-   Just as :rst:dir:`class` respects the current :rst:dir:`module`, :rst:dir:`autoclass`
-   will also do so, and likewise with :rst:dir:`method` and :rst:dir:`class`.
+   Just as :rst:dir:`py:class` respects the current :rst:dir:`py:module`,
+   :rst:dir:`autoclass` will also do so.  Likewise, :rst:dir:`automethod` will
+   respect the current :rst:dir:`py:class`.
 
 
 .. rst:directive:: automodule
-               autoclass
-               autoexception
+                   autoclass
+                   autoexception
 
    Document a module, class or exception.  All three directives will by default
    only insert the docstring of the object itself::
 
      .. versionadded:: 0.4
 
-   * The :rst:dir:`automodule`, :rst:dir:`autoclass` and :rst:dir:`autoexception` directives
-     also support a flag option called ``show-inheritance``.  When given, a list
-     of base classes will be inserted just below the class signature (when used
-     with :rst:dir:`automodule`, this will be inserted for every class that is
-     documented in the module).
+   * The :rst:dir:`automodule`, :rst:dir:`autoclass` and
+     :rst:dir:`autoexception` directives also support a flag option called
+     ``show-inheritance``.  When given, a list of base classes will be inserted
+     just below the class signature (when used with :rst:dir:`automodule`, this
+     will be inserted for every class that is documented in the module).
 
      .. versionadded:: 0.4
 
    * All autodoc directives support the ``noindex`` flag option that has the
-     same effect as for standard :rst:dir:`function` etc. directives: no index
-     entries are generated for the documented object (and all autodocumented
-     members).
+     same effect as for standard :rst:dir:`py:function` etc. directives: no
+     index entries are generated for the documented object (and all
+     autodocumented members).
 
      .. versionadded:: 0.4
 
    * :rst:dir:`automodule` also recognizes the ``synopsis``, ``platform`` and
-     ``deprecated`` options that the standard :rst:dir:`module` directive supports.
+     ``deprecated`` options that the standard :rst:dir:`py:module` directive
+     supports.
 
      .. versionadded:: 0.5
 
 
    ``"class"``
       Only the class' docstring is inserted.  This is the default.  You can
-      still document ``__init__`` as a separate method using :rst:dir:`automethod`
-      or the ``members`` option to :rst:dir:`autoclass`.
+      still document ``__init__`` as a separate method using
+      :rst:dir:`automethod` or the ``members`` option to :rst:dir:`autoclass`.
    ``"both"``
       Both the class' and the ``__init__`` method's docstring are concatenated
       and inserted.

doc/ext/inheritance.rst

 
    This directive has one or more arguments, each giving a module or class
    name.  Class names can be unqualified; in that case they are taken to exist
-   in the currently described module (see :rst:dir:`module`).
+   in the currently described module (see :rst:dir:`py:module`).
 
    For each given class, and each class in each given module, the base classes
    are determined.  Then, from all classes and their base classes, a graph is

doc/ext/intersphinx.rst

    To add links to modules and objects in the Python standard library
    documentation, use::
 
-      intersphinx_mapping = {'python': ('http://docs.python.org/', None)}
+      intersphinx_mapping = {'python': ('http://docs.python.org/3.2', None)}
 
    This will download the corresponding :file:`objects.inv` file from the
    Internet and generate links to the pages under the given URI.  The downloaded
    A second example, showing the meaning of a non-``None`` value of the second
    tuple item::
 
-      intersphinx_mapping = {'python': ('http://docs.python.org/',
+      intersphinx_mapping = {'python': ('http://docs.python.org/3.2',
                                         'python-inv.txt')}
 
    This will read the inventory from :file:`python-inv.txt` in the source
    directory, but still generate links to the pages under
-   ``http://docs.python.org/``.  It is up to you to update the inventory file as
+   ``http://docs.python.org/3.2``.  It is up to you to update the inventory file as
    new objects are added to the Python documentation.
 
 .. confval:: intersphinx_cache_limit
 
 .. note::
 
-   :mod:`sphinx.ext.mathbase` is not meant to be added to the
-   :confval:`extensions` config value, instead, use either
-   :mod:`sphinx.ext.pngmath` or :mod:`sphinx.ext.jsmath` as described below.
+   :mod:`.mathbase` is not meant to be added to the :confval:`extensions` config
+   value, instead, use either :mod:`sphinx.ext.pngmath` or
+   :mod:`sphinx.ext.jsmath` as described below.
 
 The input language for mathematics is LaTeX markup.  This is the de-facto
 standard for plain-text math notation and has the added advantage that no
 further translation is necessary when building LaTeX output.
 
-:mod:`mathbase` defines these new markup elements:
+:mod:`.mathbase` defines these new markup elements:
 
 .. rst:role:: math
 
 Prerequisites
 -------------
 
-Sphinx needs at least **Python 2.4** to run, as well as the docutils_ and
-Jinja2_ libraries.  Sphinx should work with docutils version 0.5 or some
-(not broken) SVN trunk snapshot.  If you like to have source code highlighting
-support, you must also install the Pygments_ library.
+Sphinx needs at least **Python 2.4** or **Python 3.1** to run, as well as the
+docutils_ and Jinja2_ libraries.  Sphinx should work with docutils version 0.5
+or some (not broken) SVN trunk snapshot.  If you like to have source code
+highlighting support, you must also install the Pygments_ library.
 
 .. _reStructuredText: http://docutils.sf.net/rst.html
 .. _docutils: http://docutils.sf.net/

doc/markup/inline.rst

 .. rst:role:: samp
 
    A piece of literal text, such as code.  Within the contents, you can use
-   curly braces to indicate a "variable" part, as in :rst:dir:`file`.  For
+   curly braces to indicate a "variable" part, as in :rst:role:`file`.  For
    example, in ``:samp:`print 1+{variable}```, the part ``variable`` would be
    emphasized.
 
 
    A reference to a Python Enhancement Proposal.  This generates appropriate
    index entries. The text "PEP *number*\ " is generated; in the HTML output,
-   this text is a hyperlink to an online copy of the specified PEP.
+   this text is a hyperlink to an online copy of the specified PEP.  You can
+   link to a specific section by saying ``:pep:`number#anchor```.
 
 .. rst:role:: rfc
 
    A reference to an Internet Request for Comments.  This generates appropriate
    index entries. The text "RFC *number*\ " is generated; in the HTML output,
-   this text is a hyperlink to an online copy of the specified RFC.
+   this text is a hyperlink to an online copy of the specified RFC.  You can
+   link to a specific section by saying ``:rfc:`number#anchor```.
 
 
 Note that there are no special roles for including hyperlinks as you can use

doc/markup/para.rst

    Example::
 
       .. versionadded:: 2.5
-         The `spam` parameter.
+         The *spam* parameter.
 
    Note that there must be no blank line between the directive head and the
    explanation; this is to make these blocks visually continuous in the markup.
 
 .. rst:directive:: .. versionchanged:: version
 
-   Similar to :rst:dir:`versionadded`, but describes when and what changed in the named
-   feature in some way (new parameters, changed side effects, etc.).
+   Similar to :rst:dir:`versionadded`, but describes when and what changed in
+   the named feature in some way (new parameters, changed side effects, etc.).
+
+.. rst:directive:: .. deprecated:: vesion
+
+   Similar to :rst:dir:`versionchanged`, but describes when the feature was
+   deprecated.  An explanation can also be given, for example to inform the
+   reader what should be used instead.  Example::
+
+      .. deprecated:: 3.1
+         Use :func:`spam` instead.
+
 
 --------------
 

doc/markup/toctree.rst

   :ref:`object descriptions <basic-domain-markup>`, and from :rst:dir:`index`
   directives.
 
-  The module index contains one entry per :rst:dir:`module` directive.
+  The Python module index contains one entry per :rst:dir:`py:module` directive.
 
   The search page contains a form that uses the generated JSON search index and
   JavaScript to full-text search the generated documents for search words; it

doc/templating.rst

   configuration value accordingly.
 
 * You can :ref:`write a custom builder <writing-builders>` that derives from
-  :class:`~sphinx.builders.StandaloneHTMLBuilder` and calls your template engine
-  of choice.
+  :class:`~sphinx.builders.html.StandaloneHTMLBuilder` and calls your template
+  engine of choice.
 
-* You can use the :class:`~sphinx.builders.PickleHTMLBuilder` that produces
+* You can use the :class:`~sphinx.builders.html.PickleHTMLBuilder` that produces
   pickle files with the page contents, and postprocess them using a custom tool,
   or use them in your Web application.
 
 
 .. data:: file_suffix
 
-   The value of the builder's :attr:`out_suffix` attribute, i.e. the file name
-   extension that the output files will get.  For a standard HTML builder, this
-   is usually ``.html``.
+   The value of the builder's :attr:`~.SerializingHTMLBuilder.out_suffix`
+   attribute, i.e. the file name extension that the output files will get.  For
+   a standard HTML builder, this is usually ``.html``.
 
 .. data:: has_source
 

ez_setup.py

-#!python
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
-    from ez_setup import use_setuptools
-    use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import sys
-DEFAULT_VERSION = "0.6c9"
-DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
-
-md5_data = {
-    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
-    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
-    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
-    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
-    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
-    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
-    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
-    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
-    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
-    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
-    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
-    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
-    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
-    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
-    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
-    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
-    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
-    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
-    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
-    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
-    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
-    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
-    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
-    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
-    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
-    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
-    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
-    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
-    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
-    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
-    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
-    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
-    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
-    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
-}
-
-import sys, os
-try: from hashlib import md5
-except ImportError: from md5 import md5
-
-def _validate_md5(egg_name, data):
-    if egg_name in md5_data:
-        digest = md5(data).hexdigest()
-        if digest != md5_data[egg_name]:
-            print >>sys.stderr, (
-                "md5 validation of %s failed!  (Possible download problem?)"
-                % egg_name
-            )
-            sys.exit(2)
-    return data
-
-def use_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
-    download_delay=15
-):
-    """Automatically find/download setuptools and make it available on sys.path
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end with
-    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
-    it is not already available.  If `download_delay` is specified, it should
-    be the number of seconds that will be paused before initiating a download,
-    should one be required.  If an older version of setuptools is installed,
-    this routine will print a message to ``sys.stderr`` and raise SystemExit in
-    an attempt to abort the calling script.
-    """
-    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
-    def do_download():
-        egg = download_setuptools(version, download_base, to_dir, download_delay)
-        sys.path.insert(0, egg)
-        import setuptools; setuptools.bootstrap_install_from = egg
-    try:
-        import pkg_resources
-    except ImportError:
-        return do_download()       
-    try:
-        pkg_resources.require("setuptools>="+version); return
-    except pkg_resources.VersionConflict, e:
-        if was_imported:
-            print >>sys.stderr, (
-            "The required version of setuptools (>=%s) is not available, and\n"
-            "can't be installed while this script is running. Please install\n"
-            " a more recent version first, using 'easy_install -U setuptools'."
-            "\n\n(Currently using %r)"
-            ) % (version, e.args[0])
-            sys.exit(2)
-        else:
-            del pkg_resources, sys.modules['pkg_resources']    # reload ok
-            return do_download()
-    except pkg_resources.DistributionNotFound:
-        return do_download()
-
-def download_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
-    delay = 15
-):
-    """Download setuptools from a specified location and return its filename
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end
-    with a '/'). `to_dir` is the directory where the egg will be downloaded.
-    `delay` is the number of seconds to pause before an actual download attempt.
-    """
-    import urllib2, shutil
-    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
-    url = download_base + egg_name
-    saveto = os.path.join(to_dir, egg_name)
-    src = dst = None
-    if not os.path.exists(saveto):  # Avoid repeated downloads
-        try:
-            from distutils import log
-            if delay:
-                log.warn("""
----------------------------------------------------------------------------
-This script requires setuptools version %s to run (even to display
-help).  I will attempt to download it for you (from
-%s), but
-you may need to enable firewall access for this script first.
-I will start the download in %d seconds.
-
-(Note: if this machine does not have network access, please obtain the file
-
-   %s
-
-and place it in this directory before rerunning this script.)
----------------------------------------------------------------------------""",
-                    version, download_base, delay, url
-                ); from time import sleep; sleep(delay)
-            log.warn("Downloading %s", url)
-            src = urllib2.urlopen(url)
-            # Read/write all in one block, so we don't create a corrupt file
-            # if the download is interrupted.
-            data = _validate_md5(egg_name, src.read())
-            dst = open(saveto,"wb"); dst.write(data)
-        finally:
-            if src: src.close()
-            if dst: dst.close()
-    return os.path.realpath(saveto)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-def main(argv, version=DEFAULT_VERSION):
-    """Install or upgrade setuptools and EasyInstall"""
-    try:
-        import setuptools
-    except ImportError:
-        egg = None
-        try:
-            egg = download_setuptools(version, delay=0)
-            sys.path.insert(0,egg)
-            from setuptools.command.easy_install import main
-            return main(list(argv)+[egg])   # we're done here
-        finally:
-            if egg and os.path.exists(egg):
-                os.unlink(egg)
-    else:
-        if setuptools.__version__ == '0.0.1':
-            print >>sys.stderr, (
-            "You have an obsolete version of setuptools installed.  Please\n"
-            "remove it from your system entirely before rerunning this script."
-            )
-            sys.exit(2)
-
-    req = "setuptools>="+version
-    import pkg_resources
-    try:
-        pkg_resources.require(req)
-    except pkg_resources.VersionConflict:
-        try:
-            from setuptools.command.easy_install import main
-        except ImportError:
-            from easy_install import main
-        main(list(argv)+[download_setuptools(delay=0)])
-        sys.exit(0) # try to force an exit
-    else:
-        if argv:
-            from setuptools.command.easy_install import main
-            main(argv)
-        else:
-            print "Setuptools version",version,"or greater has been installed."
-            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
-def update_md5(filenames):
-    """Update our built-in md5 registry"""
-
-    import re
-
-    for name in filenames:
-        base = os.path.basename(name)
-        f = open(name,'rb')
-        md5_data[base] = md5(f.read()).hexdigest()
-        f.close()
-
-    data = ["    %r: %r,\n" % it for it in md5_data.items()]
-    data.sort()
-    repl = "".join(data)
-
-    import inspect
-    srcfile = inspect.getsourcefile(sys.modules[__name__])
-    f = open(srcfile, 'rb'); src = f.read(); f.close()
-
-    match = re.search("\nmd5_data = {\n([^}]+)}", src)
-    if not match:
-        print >>sys.stderr, "Internal error!"
-        sys.exit(2)
-
-    src = src[:match.start(1)] + repl + src[match.end(1):]
-    f = open(srcfile,'w')
-    f.write(src)
-    f.close()
-
-
-if __name__=='__main__':
-    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
-        update_md5(sys.argv[2:])
-    else:
-        main(sys.argv[1:])
-
-
-
-
-
-
 try:
     from setuptools import setup, find_packages
 except ImportError:
-    import ez_setup
-    ez_setup.use_setuptools()
+    import distribute_setup
+    distribute_setup.use_setuptools()
     from setuptools import setup, find_packages
 
 import os
 requires = ['Pygments>=0.8', 'Jinja2>=2.2', 'docutils>=0.5']
 
 if sys.version_info < (2, 4):
-    print 'ERROR: Sphinx requires at least Python 2.4 to run.'
+    print('ERROR: Sphinx requires at least Python 2.4 to run.')
     sys.exit(1)
 
 if sys.version_info < (2, 5):
     },
     install_requires=requires,
     cmdclass=cmdclass,
+    use_2to3=True,
+    use_2to3_fixers=['custom_fixers'],
 )

sphinx/__init__.py

     :license: BSD, see LICENSE for details.
 """
 
+# Keep this file executable as-is in Python 3!
+# (Otherwise getting the version out of it from setup.py is impossible.)
+
 import sys
 from os import path
 
 
 def main(argv=sys.argv):
     if sys.version_info[:3] < (2, 4, 0):
-        print >>sys.stderr, \
-              'Error: Sphinx requires at least Python 2.4 to run.'
+        sys.stderr.write('Error: Sphinx requires at least '
+                         'Python 2.4 to run.\n')
         return 1
 
     try:
         from sphinx import cmdline
-    except ImportError, err:
+    except ImportError:
+        err = sys.exc_info()[1]
         errstr = str(err)
         if errstr.lower().startswith('no module named'):
             whichmod = errstr[16:]
                 whichmod = 'roman module (which is distributed with Docutils)'
                 hint = ('This can happen if you upgraded docutils using\n'
                         'easy_install without uninstalling the old version'
-                        'first.')
+                        'first.\n')
             else:
                 whichmod += ' module'
-            print >>sys.stderr, ('Error: The %s cannot be found. '
-                                 'Did you install Sphinx and its dependencies '
-                                 'correctly?' % whichmod)
+            sys.stderr.write('Error: The %s cannot be found. '
+                             'Did you install Sphinx and its dependencies '
+                             'correctly?\n' % whichmod)
             if hint:
-                print >> sys.stderr, hint
+                sys.stderr.write(hint)
             return 1
         raise
     return cmdline.main(argv)

sphinx/application.py

 from sphinx.util.console import bold
 
 
-# Directive is either new-style or old-style
-clstypes = (type, types.ClassType)
-
 # List of all known core events. Maps name to arguments description.
 events = {
     'builder-inited': '',

sphinx/builders/html.py

      movefile, ustrftime, copyfile
 from sphinx.util.nodes import inline_all_toctrees
 from sphinx.util.matching import patmatch, compile_matchers
-from sphinx.util.pycompat import any
+from sphinx.util.pycompat import any, b
 from sphinx.errors import SphinxError
 from sphinx.locale import _
 from sphinx.search import js_index
     out_suffix = '.html'
     link_suffix = '.html'  # defaults to matching out_suffix
     indexer_format = js_index
+    indexer_dumps_unicode = True
     supported_image_types = ['image/svg+xml', 'image/png',
                              'image/gif', 'image/jpeg']
     searchindex_filename = 'searchindex.js'
         cfgdict = dict((name, self.config[name])
                        for (name, desc) in self.config.values.iteritems()
                        if desc[1] == 'html')
-        self.config_hash = md5(str(cfgdict)).hexdigest()
-        self.tags_hash = md5(str(sorted(self.tags))).hexdigest()
+        self.config_hash = md5(unicode(cfgdict).encode('utf-8')).hexdigest()
+        self.tags_hash = md5(unicode(sorted(self.tags)).encode('utf-8')) \
+                .hexdigest()
         old_config_hash = old_tags_hash = ''
         try:
             fp = open(path.join(self.outdir, '.buildinfo'))
         """Utility: Render a lone doctree node."""
         if node is None:
             return {'fragment': ''}
-        doc = new_document('<partial node>')
+        doc = new_document(b('<partial node>'))
         doc.append(node)
 
         if self._publisher is None:
         self.info(bold('dumping object inventory... '), nonl=True)
         f = open(path.join(self.outdir, INVENTORY_FILENAME), 'wb')
         try:
-            f.write('# Sphinx inventory version 2\n')
-            f.write('# Project: %s\n' % self.config.project.encode('utf-8'))
-            f.write('# Version: %s\n' % self.config.version.encode('utf-8'))
-            f.write('# The remainder of this file is compressed using zlib.\n')
+            f.write((u'# Sphinx inventory version 2\n'
+                     u'# Project: %s\n'
+                     u'# Version: %s\n'
+                     u'# The remainder of this file is compressed using zlib.\n'
+                     % (self.config.project, self.config.version)
+                    ).encode('utf-8'))
             compressor = zlib.compressobj(9)
             for domainname, domain in self.env.domains.iteritems():
                 for name, dispname, type, docname, anchor, prio in \
                     if dispname == name:
                         dispname = u'-'
                     f.write(compressor.compress(
-                        '%s %s:%s %s %s %s\n' % (name.encode('utf-8'),
-                                                 domainname.encode('utf-8'),
-                                                 type.encode('utf-8'), prio,
-                                                 uri.encode('utf-8'),
-                                                 dispname.encode('utf-8'))))
+                        (u'%s %s:%s %s %s %s\n' % (name, domainname, type,
+                                                   prio, uri, dispname)
+                        ).encode('utf-8')))
             f.write(compressor.flush())
         finally:
             f.close()
         searchindexfn = path.join(self.outdir, self.searchindex_filename)
         # first write to a temporary file, so that if dumping fails,
         # the existing index won't be overwritten
-        f = open(searchindexfn + '.tmp', 'wb')
+        if self.indexer_dumps_unicode:
+            f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8')
+        else:
+            f = open(searchindexfn + '.tmp', 'wb')
         try:
             self.indexer.dump(f, self.indexer_format)
         finally:
     #: implements a `dump`, `load`, `dumps` and `loads` functions
     #: (pickle, simplejson etc.)
     implementation = None
+    implementation_dumps_unicode = False
 
     #: the filename for the global context file
     globalcontext_filename = None
             return docname[:-5] # up to sep
         return docname + SEP
 
+    def dump_context(self, context, filename):
+        if self.implementation_dumps_unicode:
+            f = codecs.open(filename, 'w', encoding='utf-8')
+        else:
+            f = open(filename, 'wb')
+        try:
+            # XXX: the third argument is pickle-specific!
+            self.implementation.dump(context, f, 2)
+        finally:
+            f.close()
+
     def handle_page(self, pagename, ctx, templatename='page.html',
                     outfilename=None, event_arg=None):
         ctx['current_page_name'] = pagename
                       ctx, event_arg)
 
         ensuredir(path.dirname(outfilename))
-        f = open(outfilename, 'wb')
-        try:
-            self.implementation.dump(ctx, f, 2)
-        finally:
-            f.close()
+        self.dump_context(ctx, outfilename)
 
         # if there is a source file, copy the source file for the
         # "show source" link
     def handle_finish(self):
         # dump the global context
         outfilename = path.join(self.outdir, self.globalcontext_filename)
-        f = open(outfilename, 'wb')
-        try:
-            self.implementation.dump(self.globalcontext, f, 2)
-        finally:
-            f.close()
+        self.dump_context(self.globalcontext, outfilename)
 
         # super here to dump the search index
         StandaloneHTMLBuilder.handle_finish(self)
     A Builder that dumps the generated HTML into pickle files.
     """
     implementation = pickle
+    implementation_dumps_unicode = False
     indexer_format = pickle
+    indexer_dumps_unicode = False
     name = 'pickle'
     out_suffix = '.fpickle'
     globalcontext_filename = 'globalcontext.pickle'
     A builder that dumps the generated HTML into JSON files.
     """
     implementation = jsonimpl
+    implementation_dumps_unicode = True
     indexer_format = jsonimpl
+    indexer_dumps_unicode = True
     name = 'json'
     out_suffix = '.fjson'
     globalcontext_filename = 'globalcontext.json'

sphinx/builders/htmlhelp.py

             def write_index(title, refs, subitems):
                 def write_param(name, value):
                     item = '    <param name="%s" value="%s">\n' % (name, value)
-                    f.write(item.encode('ascii', 'xmlcharrefreplace'))
+                    f.write(item.encode('ascii', 'xmlcharrefreplace')
+                            .decode('ascii'))
                 title = cgi.escape(title)
                 f.write('<LI> <OBJECT type="text/sitemap">\n')
                 write_param('Keyword', title)

sphinx/builders/qthelp.py

         for indexname, indexcls, content, collapse in self.domain_indices:
             item = section_template % {'title': indexcls.localname,
                                        'ref': '%s.html' % indexname}
-            sections.append(' '*4*4 + item)
-        sections = '\n'.join(sections)
+            sections.append((' ' * 4 * 4 + item).encode('utf-8'))
+        # sections may be unicode strings or byte strings, we have to make sure
+        # they are all byte strings before joining them
+        new_sections = []
+        for section in sections:
+            if isinstance(section, unicode):
+                new_sections.append(section.encode('utf-8'))
+            else:
+                new_sections.append(section)
+        sections = u'\n'.encode('utf-8').join(new_sections)
 
         # keywords
         keywords = []
             link = node['refuri']
             title = escape(node.astext()).replace('"','&quot;')
             item = section_template % {'title': title, 'ref': link}
-            item = ' '*4*indentlevel + item.encode('ascii', 'xmlcharrefreplace')
+            item = u' ' * 4 * indentlevel + item
             parts.append(item.encode('ascii', 'xmlcharrefreplace'))
         elif isinstance(node, nodes.bullet_list):
             for subnode in node:
 
 import os
 import re
+import sys
 from os import path
 
 from sphinx.errors import ConfigError
 from sphinx.util.osutil import make_filename
+from sphinx.util.pycompat import bytes, b, convert_with_2to3
 
-nonascii_re = re.compile(r'[\x80-\xff]')
+nonascii_re = re.compile(b(r'[\x80-\xff]'))
 
+CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s"
+if sys.version_info >= (3, 0):
+    CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?"
 
 class Config(object):
     """Configuration file abstraction."""
             config['tags'] = tags
             olddir = os.getcwd()
             try:
+                # we promise to have the config dir as current dir while the
+                # config file is executed
+                os.chdir(dirname)
+                # get config source
+                f = open(config_file, 'rb')
                 try:
-                    os.chdir(dirname)
-                    execfile(config['__file__'], config)
+                    source = f.read()
+                finally:
+                    f.close()
+                try:
+                    # compile to a code object, handle syntax errors
+                    try:
+                        code = compile(source, config_file, 'exec')
+                    except SyntaxError:
+                        if convert_with_2to3:
+                            # maybe the file uses 2.x syntax; try to refactor to
+                            # 3.x syntax using 2to3
+                            source = convert_with_2to3(config_file)
+                            code = compile(source, config_file, 'exec')
+                        else:
+                            raise
+                    exec code in config
                 except SyntaxError, err:
-                    raise ConfigError('There is a syntax error in your '
-                                      'configuration file: ' + str(err))
+                    raise ConfigError(CONFIG_SYNTAX_ERROR % err)
             finally:
                 os.chdir(olddir)
 
         # check all string values for non-ASCII characters in bytestrings,
         # since that can result in UnicodeErrors all over the place
         for name, value in self._raw_config.iteritems():
-            if isinstance(value, str) and nonascii_re.search(value):
+            if isinstance(value, bytes) and nonascii_re.search(value):
                 warn('the config value %r is set to a string with non-ASCII '
                      'characters; this can lead to Unicode errors occurring. '
-                     'Please use Unicode strings, e.g. u"Content".' % name)
+                     'Please use Unicode strings, e.g. %r.' % (name, u'Content')
+                )
 
     def init_values(self):
         config = self._raw_config

sphinx/directives/__init__.py

 
 
 # RE to strip backslash escapes
+nl_escape_re = re.compile(r'\\\n')
 strip_backslash_re = re.compile(r'\\(?=[^\\])')
 
 
         """
         Retrieve the signatures to document from the directive arguments.  By
         default, signatures are given as arguments, one per line.
+
+        Backslash-escaping of newlines is supported.
         """
+        lines = nl_escape_re.sub('', self.arguments[0]).split('\n')
         # remove backslashes to support (dummy) escapes; helps Vim highlighting
-        return [strip_backslash_re.sub('', sig.strip())
-                for sig in self.arguments[0].split('\n')]
+        return [strip_backslash_re.sub('', line.strip()) for line in lines]
 
     def handle_signature(self, sig, signode):
         """

sphinx/directives/code.py

         encoding = self.options.get('encoding', env.config.source_encoding)
         codec_info = codecs.lookup(encoding)
         try:
-            f = codecs.StreamReaderWriter(open(fn, 'U'),
+            f = codecs.StreamReaderWriter(open(fn, 'rb'),
                     codec_info[2], codec_info[3], 'strict')
             lines = f.readlines()
             f.close()

sphinx/domains/cpp.py

         return self.description
 
     def __str__(self):
-        return unicode(self.encode('utf-8'))
+        return unicode(self).encode('utf-8')
 
 
 class DefExpr(object):
     def __ne__(self, other):
         return not self.__eq__(other)
 
+    __hash__ = None
+
     def clone(self):
         """Close a definition expression node"""
         return deepcopy(self)

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()
+        env.domaindata['py']['objects'][modname] = (env.docname, 'module')
         targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
         self.state.document.note_explicit_target(targetnode)
         ret = [targetnode]
             if fn == docname:
                 del self.data['modules'][modname]
 
-    def find_obj(self, env, modname, classname, name, type, searchorder=0):
+    def find_obj(self, env, modname, classname, name, type, searchmode=0):
         """
         Find a Python object for "name", perhaps using the given module and/or
         classname.  Returns a list of (name, object entry) tuples.
         matches = []
 
         newname = None
-        if searchorder == 1:
-            if modname and classname and \
-                   modname + '.' + classname + '.' + name in objects:
-                newname = modname + '.' + classname + '.' + name
-            elif modname and modname + '.' + name in objects:
-                newname = modname + '.' + name
-            elif name in objects:
-                newname = name
-            else:
-                # "fuzzy" searching mode
-                searchname = '.' + name
-                matches = [(name, objects[name]) for name in objects
-                           if name.endswith(searchname)]
+        if searchmode == 1:
+            objtypes = self.objtypes_for_role(type)
+            if modname and classname:
+                fullname = modname + '.' + classname + '.' + name
+                if fullname in objects and objects[fullname][1] in objtypes:
+                    newname = fullname
+            if not newname:
+                if modname and modname + '.' + name in objects and \
+                   objects[modname + '.' + name][1] in objtypes:
+                    newname = modname + '.' + name
+                elif name in objects and objects[name][1] in objtypes:
+                    newname = name
+                else:
+                    # "fuzzy" searching mode
+                    searchname = '.' + name
+                    matches = [(name, objects[name]) for name in objects
+                               if name.endswith(searchname)
+                               and objects[name][1] in objtypes]
         else:
+            # NOTE: searching for exact match, object type is not considered
             if name in objects:
                 newname = name
+            elif type == 'mod':
+                # only exact matches allowed for modules
+                return []
             elif classname and classname + '.' + name in objects:
                 newname = classname + '.' + name
             elif modname and modname + '.' + name in objects:
 
     def resolve_xref(self, env, fromdocname, builder,
                      type, target, node, contnode):
-        if (type == 'mod' or
-            type == 'obj' and target in self.data['modules']):
-            docname, synopsis, platform, deprecated = \
-                self.data['modules'].get(target, ('','','', ''))
-            if not docname:
-                return None
-            else:
-                title = '%s%s%s' % ((platform and '(%s) ' % platform),
-                                    synopsis,
-                                    (deprecated and ' (deprecated)' or ''))
-                return make_refnode(builder, fromdocname, docname,
-                                    'module-' + target, contnode, title)
+        modname = node.get('py:module')
+        clsname = node.get('py:class')
+        searchmode = node.hasattr('refspecific') and 1 or 0
+        matches = self.find_obj(env, modname, clsname, target,
+                                type, searchmode)
+        if not matches:
+            return None
+        elif len(matches) > 1:
+            env.warn(fromdocname,
+                     'more than one target found for cross-reference '
+                     '%r: %s' % (target,
+                                 ', '.join(match[0] for match in matches)),
+                     node.line)
+        name, obj = matches[0]
+
+        if obj[1] == 'module':
+            # get additional info for modules
+            docname, synopsis, platform, deprecated = self.data['modules'][name]
+            assert docname == obj[0]
+            title = name
+            if synopsis:
+                title += ': ' + synopsis
+            if deprecated:
+                title += _(' (deprecated)')
+            if platform:
+                title += ' (' + platform + ')'
+            return make_refnode(builder, fromdocname, docname,
+                                'module-' + name, contnode, title)
         else:
-            modname = node.get('py:module')
-            clsname = node.get('py:class')
-            searchorder = node.hasattr('refspecific') and 1 or 0
-            matches = self.find_obj(env, modname, clsname, target,
-                                    type, searchorder)
-            if not matches:
-                return None
-            elif len(matches) > 1:
-                env.warn(fromdocname,
-                         'more than one target found for cross-reference '
-                         '%r: %s' % (target,
-                                     ', '.join(match[0] for match in matches)),
-                         node.line)
-            name, obj = matches[0]
             return make_refnode(builder, fromdocname, obj[0], name,
                                 contnode, name)
 

sphinx/domains/rst.py

     """
 
     def add_target_and_index(self, name, sig, signode):
-        targetname = name + '-' + self.objtype
+        targetname = self.objtype + '-' + name
         if targetname not in self.state.document.ids:
             signode['names'].append(targetname)
             signode['ids'].append(targetname)
             if (objtype, target) in objects:
                 return make_refnode(builder, fromdocname,
                                     objects[objtype, target],
-                                    target, contnode, target)
+                                    objtype + '-' + target,
+                                    contnode, target + ' ' + objtype)
 
     def get_objects(self):
         for (typ, name), docname in self.data['objects'].iteritems():
-            yield name, name, typ, docname, name, 1
+            yield name, name, typ, docname, typ + '-' + name, 1

sphinx/environment.py

 
 import re
 import os
+import sys
 import time
 import types
 import codecs
 from sphinx.util.nodes import clean_astext, make_refnode
 from sphinx.util.osutil import movefile, SEP, ustrftime
 from sphinx.util.matching import compile_matchers
-from sphinx.util.pycompat import all
+from sphinx.util.pycompat import all, class_types
 from sphinx.errors import SphinxError, ExtensionError
 from sphinx.locale import _
 
+fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
 
 orig_role_function = roles.role
 orig_directive_function = directives.directive
 
 # This is increased every time an environment attribute is added
 # or changed to properly invalidate pickle files.
-ENV_VERSION = 37
+ENV_VERSION = 38
 
 
 default_substitutions = set([
         self.warnfunc = warnfunc
     def write(self, text):
         if text.strip():
-            self.warnfunc(text, None, '')
+            self.warnfunc(text.strip(), None, '')
 
 
 class NoUri(Exception):
             if key.startswith('_') or \
                    isinstance(val, types.ModuleType) or \
                    isinstance(val, types.FunctionType) or \
-                   isinstance(val, (type, types.ClassType)):
+                   isinstance(val, class_types):
                 del self.config[key]
         try:
             pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL)
         If base is a path string, return absolute path under that.
         If suffix is not None, add it instead of config.source_suffix.
         """
+        docname = docname.replace(SEP, path.sep)
         suffix = suffix or self.config.source_suffix
         if base is True:
-            return path.join(self.srcdir,
-                             docname.replace(SEP, path.sep)) + suffix
+            return path.join(self.srcdir, docname) + suffix
         elif base is None:
-            return docname.replace(SEP, path.sep) + suffix
+            return docname + suffix
         else:
-            return path.join(base, docname.replace(SEP, path.sep)) + suffix
+            return path.join(base, docname) + suffix
 
     def find_files(self, config):
         """
 
         class SphinxSourceClass(FileInput):
             def decode(self_, data):
+                if isinstance(data, unicode):
+                    return data
                 return data.decode(self_.encoding, 'sphinx')
 
             def read(self_):
                         destination_class=NullOutput)
         pub.set_components(None, 'restructuredtext', None)
         pub.process_programmatic_settings(None, self.settings, None)
-        pub.set_source(None, src_path)
+        pub.set_source(None, src_path.encode(fs_encoding))
         pub.set_destination(None, None)