diff --git a/.hgignore b/.hgignore
index 612c93310..b68cccf91 100644
--- a/.hgignore
+++ b/.hgignore
@@ -2,6 +2,7 @@
.*\.egg
.*\.so
.dir-locals.el
+^\.tox
\.DS_Store$
^build/
^dist/
@@ -14,3 +15,5 @@
^env/
\.DS_Store$
~$
+^utils/.*3\.py$
+^distribute-
diff --git a/CHANGES b/CHANGES
index 4be9eed82..3417d9aa7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,69 @@
-Release 1.0 (in development)
+Release 1.1 (in development)
============================
+* Added Python 3.x support.
+
+
+Release 1.0.2 (Aug 14, 2010)
+============================
+
+* #490: Fix cross-references to objects of types added by the
+ :func:`~.Sphinx.add_object_type` API function.
+
+* Fix handling of doc field types for different directive types.
+
+* 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)
+============================
+
+* #470: Fix generated target names for reST domain objects; they
+ are not in the same namespace.
+
+* #266: Add Bengali language.
+
+* #473: Fix a bug in parsing JavaScript object names.
+
+* #474: Fix building with SingleHTMLBuilder when there is no toctree.
+
+* Fix display names for objects linked to by intersphinx with
+ explicit targets.
+
+* Fix building with the JSON builder.
+
+* Fix hyperrefs in object descriptions for LaTeX.
+
+
+Release 1.0 (Jul 23, 2010)
+==========================
+
Incompatible changes
--------------------
@@ -15,9 +78,10 @@ Incompatible changes
- JavaScript
- reStructuredText
-* The old markup for defining and linking to C directives will not work
- anymore without activating the :mod:`~sphinx.ext.oldcmarkup`
- extension.
+* The old markup for defining and linking to C directives is now
+ deprecated. It will not work anymore in future versions without
+ activating the :mod:`~sphinx.ext.oldcmarkup` extension; in Sphinx
+ 1.0, it is activated by default.
* Removed support for old dependency versions; requirements are now:
@@ -80,6 +144,9 @@ Features added
- Added :confval:`html_show_copyright` config value.
- Added :confval:`latex_show_pagerefs` and :confval:`latex_show_urls`
config values.
+ - The behavior of :confval:`html_file_suffix` changed slightly: the
+ empty string now means "no suffix" instead of "default suffix", use
+ ``None`` for "default suffix".
* New builders:
diff --git a/CHANGES.DasIch b/CHANGES.DasIch
new file mode 100644
index 000000000..3f7167263
--- /dev/null
+++ b/CHANGES.DasIch
@@ -0,0 +1,36 @@
+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.
diff --git a/EXAMPLES b/EXAMPLES
index c618b8bf9..778b235e1 100644
--- a/EXAMPLES
+++ b/EXAMPLES
@@ -12,7 +12,7 @@ interesting examples.
Documentation using the default theme
-------------------------------------
-* APSW: http://apsw.googlecode.com/svn/publish/index.html
+* APSW: http://apidoc.apsw.googlecode.com/hg/index.html
* ASE: https://wiki.fysik.dtu.dk/ase/
* boostmpi: http://documen.tician.de/boostmpi/
* Calibre: http://calibre.kovidgoyal.net/user_manual/
@@ -38,6 +38,7 @@ Documentation using the default theme
* PyCuda: http://documen.tician.de/pycuda/
* Pyevolve: http://pyevolve.sourceforge.net/
* Pylo: http://documen.tician.de/pylo/
+* PyMQI: http://packages.python.org/pymqi/
* PyPubSub: http://pubsub.sourceforge.net/
* pyrticle: http://documen.tician.de/pyrticle/
* Python: http://docs.python.org/
@@ -96,6 +97,7 @@ Documentation using the sphinxdoc theme
* 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/
@@ -109,6 +111,8 @@ Documentation using another builtin theme
* pip: http://pip.openplans.org/ (nature)
* Programmieren mit PyGTK und Glade (German):
http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo)
+* Spring Python: http://springpython.webfactional.com/current/sphinx/index.html
+ (nature)
* sqlparse: http://python-sqlparse.googlecode.com/svn/docs/api/index.html
(agogo)
* libLAS: http://liblas.org/ (nature)
@@ -139,6 +143,7 @@ Documentation using a custom theme/integrated in a site
* Self: http://selflanguage.org/
* SQLAlchemy: http://www.sqlalchemy.org/docs/
* tinyTiM: http://tinytim.sourceforge.net/docs/2.0/
+* tipfy: http://www.tipfy.org/docs/
* Werkzeug: http://werkzeug.pocoo.org/documentation/dev/
* WFront: http://discorporate.us/projects/WFront/
diff --git a/MANIFEST.in b/MANIFEST.in
index 25cbc334f..cfc44c17e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -7,7 +7,7 @@ include TODO
include babel.cfg
include Makefile
-include ez_setup.py
+include distribute_setup.py
include sphinx-autogen.py
include sphinx-build.py
include sphinx-quickstart.py
diff --git a/Makefile b/Makefile
index 90f7c3d46..09aa3c962 100644
--- a/Makefile
+++ b/Makefile
@@ -1,35 +1,63 @@
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 .
+ @$(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
diff --git a/README b/README
index bb2dea9d6..e31d6b936 100644
--- a/README
+++ b/README
@@ -26,6 +26,18 @@ Then, direct your browser to ``_build/html/index.html``.
Or read them online at .
+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
============
diff --git a/custom_fixers/__init__.py b/custom_fixers/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/custom_fixers/fix_alt_unicode.py b/custom_fixers/fix_alt_unicode.py
new file mode 100644
index 000000000..55175e90f
--- /dev/null
+++ b/custom_fixers/fix_alt_unicode.py
@@ -0,0 +1,12 @@
+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))
diff --git a/distribute_setup.py b/distribute_setup.py
new file mode 100644
index 000000000..37117b34e
--- /dev/null
+++ b/distribute_setup.py
@@ -0,0 +1,485 @@
+#!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:])
diff --git a/doc/Makefile b/doc/Makefile
index ff3cb22b3..aa3ecb61a 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -16,22 +16,22 @@ ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) \
help:
@echo "Please use \`make ' where is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files called index.html in directories"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files called index.html in directories"
@echo " singlehtml to make one big HTML file"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " pickle to make pickle files"
- @echo " json to make json files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make Qt help files and project"
- @echo " devhelp to make Devhelp files and project"
- @echo " epub to make an epub file"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run pdflatex"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview over all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " pickle to make pickle files"
+ @echo " json to make json files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make Qt help files and project"
+ @echo " devhelp to make Devhelp files and project"
+ @echo " epub to make an epub file"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run pdflatex"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview over all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
clean:
-rm -rf _build/*
diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html
index a268ec6ef..85b8fba95 100644
--- a/doc/_templates/indexsidebar.html
+++ b/doc/_templates/indexsidebar.html
@@ -23,6 +23,6 @@ are also available.
diff --git a/doc/builders.rst b/doc/builders.rst
index 5aefac442..4f95b6147 100644
--- a/doc/builders.rst
+++ b/doc/builders.rst
@@ -267,11 +267,11 @@ All serialization builders outputs one file per source file and a few special
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:
@@ -302,7 +302,7 @@ 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``
@@ -321,7 +321,7 @@ The special files are located in the root output directory. They are:
``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:
diff --git a/doc/conf.py b/doc/conf.py
index b268a13f0..b3a1cda79 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -34,9 +34,9 @@ epub_author = 'Georg Brandl'
epub_publisher = 'http://sphinx.pocoo.org/'
epub_scheme = 'url'
epub_identifier = epub_publisher
-epub_pre_files = [('index', 'Welcome')]
+epub_pre_files = [('index.html', 'Welcome')]
epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js',
- '_static/jquery.js', '_static/searchtools.js',
+ '_static/jquery.js', '_static/searchtools.js', '_static/underscore.js',
'_static/basic.css', 'search.html']
latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
@@ -64,6 +64,10 @@ man_pages = [
'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 -------------------------------------------------------
diff --git a/doc/config.rst b/doc/config.rst
index d0fe9cdde..e0fbeb46e 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -283,6 +283,7 @@ Project information
Currently supported languages are:
+ * ``bn`` -- Bengali
* ``ca`` -- Catalan
* ``cs`` -- Czech
* ``da`` -- Danish
@@ -345,12 +346,12 @@ Project information
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
@@ -387,6 +388,8 @@ Options for HTML output
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
@@ -552,19 +555,6 @@ that use Sphinx' HTMLWriter class.
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.
@@ -626,8 +616,8 @@ that use Sphinx' HTMLWriter class.
.. confval:: html_file_suffix
- If nonempty, this is the file name suffix for generated HTML files. The
- default is ``".html"``.
+ This is the file name suffix for generated HTML files. The default is
+ ``".html"``.
.. versionadded:: 0.4
@@ -768,8 +758,8 @@ the `Dublin Core metadata `_.
.. confval:: epub_post_files
Additional files that should be inserted after the text generated by Sphinx.
- It is a list of tuples containing the file name and the title. The default
- value is ``[]``.
+ It is a list of tuples containing the file name and the title. This option
+ can be used to add an appendix. The default value is ``[]``.
.. confval:: epub_exclude_files
@@ -782,6 +772,12 @@ the `Dublin Core metadata `_.
be an integer greater than zero. The default value is 3. Note: A deeply
nested table of contents may be difficult to navigate.
+.. confval:: epub_tocdup
+
+ This flag determines if a toc entry is inserted again at the beginning of
+ it's nested toc listing. This allows easier navitation to the top of
+ a chapter, but can be confusing because it mixes entries of differnet
+ depth in one list. The default value is ``True``.
.. _latex-options:
diff --git a/doc/domains.rst b/doc/domains.rst
index c64930a24..8cd7a0c7d 100644
--- a/doc/domains.rst
+++ b/doc/domains.rst
@@ -52,10 +52,19 @@ flag ``:noindex:``. An example using a Python domain directive::
.. py:function:: spam(eggs)
ham(eggs)
- :noindex:
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:
+
+(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
could say ::
@@ -138,11 +147,12 @@ declarations:
.. 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:
@@ -363,6 +373,9 @@ dot, this order is reversed. For example, in the documentation of Python's
: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
@@ -370,8 +383,9 @@ 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:
diff --git a/doc/ext/appapi.rst b/doc/ext/appapi.rst
index 402dd72f0..2717c6a8e 100644
--- a/doc/ext/appapi.rst
+++ b/doc/ext/appapi.rst
@@ -210,7 +210,7 @@ the following public API:
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='')
@@ -272,6 +272,8 @@ the following public API:
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)
diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst
index bd725cfaa..a1d9d98fb 100644
--- a/doc/ext/autodoc.rst
+++ b/doc/ext/autodoc.rst
@@ -27,20 +27,21 @@ two locations for documentation, while at the same time avoiding
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::
@@ -83,6 +84,9 @@ directive.
will document all non-private member functions and properties (that is,
those whose name doesn't start with ``_``).
+ For modules, ``__all__`` will be respected when looking for members; the
+ order of the members will also be the order in ``__all__``.
+
You can also give an explicit list of members; only these will then be
documented::
@@ -127,23 +131,24 @@ directive.
.. 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
@@ -213,8 +218,8 @@ There are also new config values that you can set:
``"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.
diff --git a/doc/ext/inheritance.rst b/doc/ext/inheritance.rst
index 76388a94c..cdd017917 100644
--- a/doc/ext/inheritance.rst
+++ b/doc/ext/inheritance.rst
@@ -17,7 +17,7 @@ It adds this directive:
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
diff --git a/doc/ext/intersphinx.rst b/doc/ext/intersphinx.rst
index 29b4057f1..7997472a7 100644
--- a/doc/ext/intersphinx.rst
+++ b/doc/ext/intersphinx.rst
@@ -9,7 +9,21 @@
.. versionadded:: 0.5
This extension can generate automatic links to the documentation of objects in
-other projects. This works as follows:
+other projects.
+
+Usage is simple: whenever Sphinx encounters a cross-reference that has no
+matching target in the current documentation set, it looks for targets in the
+documentation sets configured in :confval:`intersphinx_mapping`. A reference
+like ``:py:class:`zipfile.ZipFile``` can then link to the Python documentation
+for the ZipFile class, without you having to specify where it is located
+exactly.
+
+When using the "new" format (see below), you can even force lookup in a foreign
+set by prefixing the link target appropriately. A link like ``:ref:`comparison
+manual ``` will then link to the label "comparisons" in the
+doc set "python", if it exists.
+
+Behind the scenes, this works as follows:
* Each Sphinx HTML build creates a file named :file:`objects.inv` that contains
a mapping from object names to URIs relative to the HTML set's root.
@@ -70,7 +84,7 @@ linking:
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
@@ -80,12 +94,12 @@ linking:
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
diff --git a/doc/ext/math.rst b/doc/ext/math.rst
index b9f6ab12b..f2896c39c 100644
--- a/doc/ext/math.rst
+++ b/doc/ext/math.rst
@@ -17,15 +17,15 @@ if possible, reuse that support too.
.. 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
diff --git a/doc/faq.rst b/doc/faq.rst
index 613283c5d..5869e3af8 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -134,6 +134,16 @@ some notes:
and Bookworm_. For bookworm you can download the source from
http://code.google.com/p/threepress/ and run your own local server.
+* Large floating divs are not displayed properly.
+ If they cover more than one page, the div is only shown on the first page.
+ In that case you can copy the :file:`epub.css` from the
+ ``sphinx/themes/epub/static/`` directory to your local ``_static/``
+ directory and remove the float settings.
+
+* Files that are inserted outside of the ``toctree`` directive must be manually
+ included. This sometimes applies to appendixes, e.g. the glossary or
+ the indices. You can add them with the :confval:`epub_post_files` option.
+
.. _Epubcheck: http://code.google.com/p/epubcheck/
.. _Calibre: http://calibre-ebook.com/
.. _FBreader: http://www.fbreader.org/
diff --git a/doc/intro.rst b/doc/intro.rst
index 33f97a3f8..c85fbbad3 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -45,13 +45,15 @@ See the :ref:`pertinent section in the FAQ list `.
Prerequisites
-------------
-Sphinx needs at least **Python 2.4** to run. If you like to have source code
-highlighting support, you must also install the Pygments_ library, which you can
-do via setuptools' easy_install. Sphinx should work with docutils version 0.4
-or some (not broken) SVN trunk snapshot.
+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
-.. _Pygments: http://pygments.org
+.. _docutils: http://docutils.sf.net/
+.. _Jinja2: http://jinja.pocoo.org/2/
+.. _Pygments: http://pygments.org/
Usage
diff --git a/doc/markup/inline.rst b/doc/markup/inline.rst
index bb1ed68ec..4b704228f 100644
--- a/doc/markup/inline.rst
+++ b/doc/markup/inline.rst
@@ -260,7 +260,7 @@ in a different style:
.. 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.
@@ -274,13 +274,15 @@ The following roles generate external links:
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
diff --git a/doc/markup/para.rst b/doc/markup/para.rst
index be06f6365..ecc6b4a6b 100644
--- a/doc/markup/para.rst
+++ b/doc/markup/para.rst
@@ -42,15 +42,25 @@ units as well as normal text:
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.
+
--------------
diff --git a/doc/markup/toctree.rst b/doc/markup/toctree.rst
index 474427d72..2c0a418a2 100644
--- a/doc/markup/toctree.rst
+++ b/doc/markup/toctree.rst
@@ -151,7 +151,7 @@ The special document names (and pages generated for them) are:
:ref:`object descriptions `, 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
diff --git a/doc/templating.rst b/doc/templating.rst
index 6880663d3..193a90bd9 100644
--- a/doc/templating.rst
+++ b/doc/templating.rst
@@ -21,10 +21,10 @@ No. You have several other options:
configuration value accordingly.
* You can :ref:`write a custom builder ` 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.
@@ -261,9 +261,9 @@ in the future.
.. 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
diff --git a/ez_setup.py b/ez_setup.py
deleted file mode 100644
index d24e845e5..000000000
--- a/ez_setup.py
+++ /dev/null
@@ -1,276 +0,0 @@
-#!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:])
-
-
-
-
-
-
diff --git a/setup.py b/setup.py
index de805b7ef..fe4066b80 100644
--- a/setup.py
+++ b/setup.py
@@ -2,8 +2,8 @@
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
@@ -47,7 +47,7 @@ A development egg can be found `here
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):
@@ -178,6 +178,7 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
'Topic :: Documentation',
'Topic :: Text Processing',
'Topic :: Utilities',
@@ -197,4 +198,6 @@ setup(
},
install_requires=requires,
cmdclass=cmdclass,
+ use_2to3=True,
+ use_2to3_fixers=['custom_fixers'],
)
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 37b6ecef7..1ea2e7bf7 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -9,11 +9,14 @@
: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
-__version__ = '1.0b2+'
-__released__ = '1.0b2' # used when Sphinx builds its own docs
+__version__ = '1.1pre'
+__released__ = '1.1 (hg)' # used when Sphinx builds its own docs
package_dir = path.abspath(path.dirname(__file__))
@@ -35,13 +38,14 @@ if '+' in __version__ or 'pre' in __version__:
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:]
@@ -54,14 +58,14 @@ def main(argv=sys.argv):
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)
diff --git a/sphinx/application.py b/sphinx/application.py
index 3ffd86c26..b3d2aebc4 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -37,9 +37,6 @@ from sphinx.util.osutil import ENOENT
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': '',
@@ -109,7 +106,9 @@ class Sphinx(object):
if self.confdir is None:
self.confdir = self.srcdir
- # load all extension modules
+ # backwards compatibility: activate old C markup
+ self.setup_extension('sphinx.ext.oldcmarkup')
+ # load all user-given extension modules
for extension in self.config.extensions:
self.setup_extension(extension)
# the config file itself can be an extension
diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py
index 9767391e0..aea07d4d1 100644
--- a/sphinx/builders/epub.py
+++ b/sphinx/builders/epub.py
@@ -11,15 +11,17 @@
"""
import os
+import re
import codecs
-from os import path
import zipfile
+from os import path
from docutils import nodes
-from docutils.transforms import Transform
+from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.util.osutil import EEXIST
+from sphinx.util.smartypants import sphinx_smarty_pants as ssp
# (Fragment) templates from which the metainfo files content.opf, toc.ncx,
@@ -119,29 +121,10 @@ _media_types = {
'.ttf': 'application/x-font-ttf',
}
-
-# The transform to show link targets
-
-class VisibleLinksTransform(Transform):
- """
- Add the link target of referances to the text, unless it is already
- present in the description.
- """
-
- # This transform must run after the references transforms
- default_priority = 680
-
- def apply(self):
- for ref in self.document.traverse(nodes.reference):
- uri = ref.get('refuri', '')
- if ( uri.startswith('http:') or uri.startswith('https:') or \
- uri.startswith('ftp:') ) and uri not in ref.astext():
- uri = _link_target_template % {'uri': uri}
- if uri:
- idx = ref.parent.index(ref) + 1
- link = nodes.inline(uri, uri)
- link['classes'].append(_css_link_target_class)
- ref.parent.insert(idx, link)
+# Regular expression to match colons only in local fragment identifiers.
+# If the URI contains a colon before the #,
+# it is an external link that should not change.
+_refuri_re = re.compile("([^#:]*#)(.*)")
# The epub publisher
@@ -170,7 +153,6 @@ class EpubBuilder(StandaloneHTMLBuilder):
# the output files for epub must be .html only
self.out_suffix = '.html'
self.playorder = 0
- self.app.add_transform(VisibleLinksTransform)
def get_theme_config(self):
return self.config.epub_theme, {}
@@ -194,17 +176,20 @@ class EpubBuilder(StandaloneHTMLBuilder):
"""Collect section titles, their depth in the toc and the refuri."""
# XXX: is there a better way than checking the attribute
# toctree-l[1-8] on the parent node?
- if isinstance(doctree, nodes.reference):
+ if isinstance(doctree, nodes.reference) and doctree.has_key('refuri'):
+ refuri = doctree['refuri']
+ if refuri.startswith('http://') or refuri.startswith('https://') \
+ or refuri.startswith('irc:') or refuri.startswith('mailto:'):
+ return result
classes = doctree.parent.attributes['classes']
- level = 1
- for l in range(8, 0, -1): # or range(1, 8)?
- if (_toctree_template % l) in classes:
- level = l
- result.append({
- 'level': level,
- 'refuri': self.esc(doctree['refuri']),
- 'text': self.esc(doctree.astext())
- })
+ for level in range(8, 0, -1): # or range(1, 8)?
+ if (_toctree_template % level) in classes:
+ result.append({
+ 'level': level,
+ 'refuri': self.esc(refuri),
+ 'text': ssp(self.esc(doctree.astext()))
+ })
+ break
else:
for elem in doctree.children:
result = self.get_refnodes(elem, result)
@@ -220,21 +205,97 @@ class EpubBuilder(StandaloneHTMLBuilder):
self.refnodes.insert(0, {
'level': 1,
'refuri': self.esc(self.config.master_doc + '.html'),
- 'text': self.esc(self.env.titles[self.config.master_doc].astext())
+ 'text': ssp(self.esc(
+ self.env.titles[self.config.master_doc].astext()))
})
for file, text in reversed(self.config.epub_pre_files):
self.refnodes.insert(0, {
'level': 1,
- 'refuri': self.esc(file + '.html'),
- 'text': self.esc(text)
+ 'refuri': self.esc(file),
+ 'text': ssp(self.esc(text))
})
for file, text in self.config.epub_post_files:
self.refnodes.append({
'level': 1,
- 'refuri': self.esc(file + '.html'),
- 'text': self.esc(text)
+ 'refuri': self.esc(file),
+ 'text': ssp(self.esc(text))
})
+ def fix_fragment(self, match):
+ """Return a href attribute with colons replaced by hyphens.
+ """
+ return match.group(1) + match.group(2).replace(':', '-')
+
+ def fix_ids(self, tree):
+ """Replace colons with hyphens in href and id attributes.
+ Some readers crash because they interpret the part as a
+ transport protocol specification.
+ """
+ for node in tree.traverse(nodes.reference):
+ if 'refuri' in node:
+ m = _refuri_re.match(node['refuri'])
+ if m:
+ node['refuri'] = self.fix_fragment(m)
+ if 'refid' in node:
+ node['refid'] = node['refid'].replace(':', '-')
+ for node in tree.traverse(addnodes.desc_signature):
+ ids = node.attributes['ids']
+ newids = []
+ for id in ids:
+ newids.append(id.replace(':', '-'))
+ node.attributes['ids'] = newids
+
+ def add_visible_links(self, tree):
+ """Append visible link targets after external links.
+ """
+ for node in tree.traverse(nodes.reference):
+ uri = node.get('refuri', '')
+ if (uri.startswith('http:') or uri.startswith('https:') or
+ uri.startswith('ftp:')) and uri not in node.astext():
+ uri = _link_target_template % {'uri': uri}
+ if uri:
+ idx = node.parent.index(node) + 1
+ link = nodes.inline(uri, uri)
+ link['classes'].append(_css_link_target_class)
+ node.parent.insert(idx, link)
+
+ def write_doc(self, docname, doctree):
+ """Write one document file.
+ This method is overwritten in order to fix fragment identifiers
+ and to add visible external links.
+ """
+ self.fix_ids(doctree)
+ self.add_visible_links(doctree)
+ return StandaloneHTMLBuilder.write_doc(self, docname, doctree)
+
+ def fix_genindex(self, tree):
+ """Fix href attributes for genindex pages.
+ """
+ # XXX: modifies tree inline
+ # Logic modeled from themes/basic/genindex.html
+ for key, columns in tree:
+ for entryname, (links, subitems) in columns:
+ for (i, link) in enumerate(links):
+ m = _refuri_re.match(link)
+ if m:
+ links[i] = self.fix_fragment(m)
+ for subentryname, subentrylinks in subitems:
+ for (i, link) in enumerate(subentrylinks):
+ m = _refuri_re.match(link)
+ if m:
+ subentrylinks[i] = self.fix_fragment(m)
+
+ def handle_page(self, pagename, addctx, templatename='page.html',
+ outfilename=None, event_arg=None):
+ """Create a rendered page.
+ This method is overwritten for genindex pages in order to fix
+ href link attributes.
+ """
+ if pagename.startswith('genindex'):
+ self.fix_genindex(addctx['genindexentries'])
+ StandaloneHTMLBuilder.handle_page(self, pagename, addctx, templatename,
+ outfilename, event_arg)
+
# Finish by building the epub file
def handle_finish(self):
@@ -380,7 +441,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
navstack.append(navlist)
navlist = []
level += 1
- if lastnode:
+ if lastnode and self.config.epub_tocdup:
# Insert starting point in subtoc with same playOrder
navlist.append(self.new_navpoint(lastnode, level, False))
navlist.append(self.new_navpoint(node, level))
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 6b3eada79..5a7d49cd0 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -30,12 +30,12 @@ from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __version__
-from sphinx.util import copy_static_entry
+from sphinx.util import jsonimpl, copy_static_entry
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
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
@@ -47,14 +47,6 @@ from sphinx.util.console import bold, darkgreen, brown
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
SmartyPantsHTMLTranslator
-try:
- import json
-except ImportError:
- try:
- import simplejson as json
- except ImportError:
- json = None
-
#: the filename for the inventory of objects
INVENTORY_FILENAME = 'objects.inv'
#: the filename for the "last build" file (for serializing builders)
@@ -71,6 +63,7 @@ class StandaloneHTMLBuilder(Builder):
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'
@@ -99,7 +92,7 @@ class StandaloneHTMLBuilder(Builder):
self.init_templates()
self.init_highlighter()
self.init_translator_class()
- if self.config.html_file_suffix:
+ if self.config.html_file_suffix is not None:
self.out_suffix = self.config.html_file_suffix
if self.config.html_link_suffix is not None:
@@ -154,8 +147,9 @@ class StandaloneHTMLBuilder(Builder):
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'))
@@ -207,7 +201,7 @@ class StandaloneHTMLBuilder(Builder):
"""Utility: Render a lone doctree node."""
if node is None:
return {'fragment': ''}
- doc = new_document('')
+ doc = new_document(b(''))
doc.append(node)
if self._publisher is None:
@@ -735,10 +729,12 @@ class StandaloneHTMLBuilder(Builder):
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 \
@@ -750,11 +746,9 @@ class StandaloneHTMLBuilder(Builder):
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()
@@ -766,7 +760,10 @@ class StandaloneHTMLBuilder(Builder):
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:
@@ -855,8 +852,14 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
def get_doc_context(self, docname, body, metatags):
# no relation links...
toc = self.env.get_toctree_for(self.config.master_doc, self, False)
- self.fix_refuris(toc)
- toc = self.render_partial(toc)['fragment']
+ # if there is no toctree, toc is None
+ if toc:
+ self.fix_refuris(toc)
+ toc = self.render_partial(toc)['fragment']
+ display_toc = True
+ else:
+ toc = ''
+ display_toc = False
return dict(
parents = [],
prev = None,
@@ -869,7 +872,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
rellinks = [],
sourcename = '',
toc = toc,
- display_toc = True,
+ display_toc = display_toc,
)
def write(self, *ignored):
@@ -917,6 +920,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
#: 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
@@ -939,6 +943,17 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
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
@@ -952,11 +967,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
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
@@ -969,11 +980,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
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)
@@ -993,7 +1000,9 @@ class PickleHTMLBuilder(SerializingHTMLBuilder):
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'
@@ -1007,15 +1016,17 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
"""
A builder that dumps the generated HTML into JSON files.
"""
- implementation = json
- indexer_format = json
+ implementation = jsonimpl
+ implementation_dumps_unicode = True
+ indexer_format = jsonimpl
+ indexer_dumps_unicode = True
name = 'json'
out_suffix = '.fjson'
globalcontext_filename = 'globalcontext.json'
searchindex_filename = 'searchindex.json'
def init(self):
- if json is None:
+ if jsonimpl.json is None:
raise SphinxError(
'The module simplejson (or json in Python >= 2.6) '
'is not available. The JSONHTMLBuilder builder will not work.')
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 538f4c848..e3a58e724 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -258,7 +258,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
def write_index(title, refs, subitems):
def write_param(name, value):
item = ' \n' % (name, value)
- f.write(item.encode('ascii', 'xmlcharrefreplace'))
+ f.write(item.encode('ascii', 'xmlcharrefreplace')
+ .decode('ascii'))
title = cgi.escape(title)
f.write('