summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2014-02-02 08:05:59 +0100
committerGeorg Brandl <georg@python.org>2014-02-02 08:05:59 +0100
commit532e6db1f0d4f8ae9cc8a8d54cfa70ef3e98682a (patch)
tree83f7335b6987875de37581ab440a9080dad7e886
parent30a55f86b29a482110e84805c4942ad88c18f986 (diff)
parentfb9dd2d0012e1229719685167bd6dc33e7b39005 (diff)
downloadsphinx-532e6db1f0d4f8ae9cc8a8d54cfa70ef3e98682a.tar.gz
merge with stable
-rw-r--r--AUTHORS1
-rw-r--r--CHANGES59
-rw-r--r--EXAMPLES2
-rw-r--r--doc/conf.py1
-rw-r--r--doc/config.rst35
-rw-r--r--doc/domains.rst33
-rw-r--r--doc/ext/autodoc.rst24
-rw-r--r--doc/ext/example_google.py223
-rw-r--r--doc/ext/example_google.rst15
-rw-r--r--doc/ext/example_numpy.py272
-rw-r--r--doc/ext/example_numpy.rst15
-rw-r--r--doc/ext/napoleon.rst375
-rw-r--r--doc/ext/oldcmarkup.rst35
-rw-r--r--doc/extdev/appapi.rst11
-rw-r--r--doc/extensions.rst2
-rw-r--r--doc/install.rst6
-rw-r--r--doc/intro.rst2
-rw-r--r--doc/invocation.rst15
-rw-r--r--doc/markup/code.rst39
-rw-r--r--setup.py12
-rw-r--r--sphinx/__init__.py11
-rw-r--r--sphinx/addnodes.py5
-rw-r--r--sphinx/apidoc.py10
-rw-r--r--sphinx/application.py25
-rw-r--r--sphinx/builders/devhelp.py2
-rw-r--r--sphinx/builders/epub.py16
-rw-r--r--sphinx/builders/gettext.py2
-rw-r--r--sphinx/builders/html.py23
-rw-r--r--sphinx/builders/htmlhelp.py9
-rw-r--r--sphinx/builders/linkcheck.py7
-rw-r--r--sphinx/builders/qthelp.py2
-rw-r--r--sphinx/builders/texinfo.py2
-rw-r--r--sphinx/builders/text.py2
-rw-r--r--sphinx/builders/xml.py2
-rw-r--r--sphinx/cmdline.py113
-rw-r--r--sphinx/config.py39
-rw-r--r--sphinx/directives/code.py37
-rw-r--r--sphinx/domains/c.py2
-rw-r--r--sphinx/domains/cpp.py4
-rw-r--r--sphinx/domains/python.py19
-rw-r--r--sphinx/domains/std.py2
-rw-r--r--sphinx/environment.py11
-rw-r--r--sphinx/ext/autodoc.py45
-rw-r--r--sphinx/ext/autosummary/__init__.py2
-rw-r--r--sphinx/ext/autosummary/generate.py11
-rw-r--r--sphinx/ext/coverage.py2
-rw-r--r--sphinx/ext/doctest.py6
-rw-r--r--sphinx/ext/graphviz.py10
-rw-r--r--sphinx/ext/ifconfig.py2
-rw-r--r--sphinx/ext/inheritance_diagram.py2
-rw-r--r--sphinx/ext/intersphinx.py4
-rw-r--r--sphinx/ext/napoleon/__init__.py375
-rw-r--r--sphinx/ext/napoleon/docstring.py714
-rw-r--r--sphinx/ext/napoleon/iterators.py244
-rw-r--r--sphinx/ext/oldcmarkup.py67
-rw-r--r--sphinx/ext/pngmath.py8
-rw-r--r--sphinx/ext/todo.py1
-rw-r--r--sphinx/highlighting.py18
-rw-r--r--sphinx/make_mode.py121
-rw-r--r--sphinx/pycode/__init__.py13
-rw-r--r--sphinx/pycode/pgen2/driver.py2
-rw-r--r--sphinx/pycode/pgen2/grammar.py13
-rw-r--r--sphinx/pycode/pgen2/literals.py3
-rw-r--r--sphinx/pycode/pgen2/parse.c89
-rw-r--r--sphinx/pycode/pgen2/pgen.py17
-rw-r--r--sphinx/pycode/pgen2/tokenize.py9
-rw-r--r--sphinx/quickstart.py129
-rw-r--r--sphinx/roles.py6
-rw-r--r--sphinx/setup_command.py9
-rw-r--r--sphinx/texinputs/Makefile28
-rw-r--r--sphinx/themes/agogo/layout.html50
-rw-r--r--sphinx/themes/agogo/static/agogo.css_t11
-rw-r--r--sphinx/themes/basic/layout.html10
-rw-r--r--sphinx/themes/basic/searchbox.html2
-rw-r--r--sphinx/themes/basic/sourcelink.html12
-rw-r--r--sphinx/themes/basic/static/basic.css_t18
-rw-r--r--sphinx/themes/default/static/default.css_t5
-rw-r--r--sphinx/themes/epub/static/epub.css4
-rw-r--r--sphinx/themes/haiku/layout.html6
-rw-r--r--sphinx/themes/nature/static/nature.css_t6
-rw-r--r--sphinx/themes/pyramid/layout.html2
-rw-r--r--sphinx/themes/pyramid/static/pyramid.css_t5
-rw-r--r--sphinx/themes/scrolls/layout.html4
-rw-r--r--sphinx/themes/scrolls/static/scrolls.css_t4
-rw-r--r--sphinx/themes/sphinxdoc/static/sphinxdoc.css_t6
-rw-r--r--sphinx/themes/traditional/static/traditional.css_t8
-rw-r--r--sphinx/transforms.py3
-rw-r--r--sphinx/util/__init__.py6
-rw-r--r--sphinx/util/docfields.py12
-rw-r--r--sphinx/util/docstrings.py4
-rw-r--r--sphinx/util/inspect.py15
-rw-r--r--sphinx/util/jsonimpl.py20
-rw-r--r--sphinx/util/matching.py2
-rw-r--r--sphinx/util/osutil.py18
-rw-r--r--sphinx/util/pycompat.py187
-rw-r--r--sphinx/versioning.py3
-rw-r--r--sphinx/writers/html.py44
-rw-r--r--sphinx/writers/latex.py17
-rw-r--r--sphinx/writers/manpage.py5
-rw-r--r--sphinx/writers/texinfo.py7
-rw-r--r--sphinx/writers/text.py7
-rwxr-xr-xtests/coverage.py68
-rw-r--r--tests/etree13/ElementTree.py7
-rw-r--r--tests/etree13/HTMLTreeBuilder.py3
-rwxr-xr-xtests/path.py2
-rw-r--r--tests/root/autodoc.txt2
-rw-r--r--tests/root/autodoc_missing_imports.py9
-rw-r--r--tests/root/conf.py10
-rw-r--r--tests/root/includes.txt1
-rw-r--r--tests/root/objects.txt9
-rw-r--r--tests/root/special/code.py4
-rwxr-xr-xtests/run.py1
-rw-r--r--tests/test_autodoc.py11
-rw-r--r--tests/test_build_gettext.py11
-rw-r--r--tests/test_build_html.py5
-rw-r--r--tests/test_build_latex.py5
-rw-r--r--tests/test_build_texinfo.py5
-rw-r--r--tests/test_config.py8
-rw-r--r--tests/test_doctest.py3
-rw-r--r--tests/test_intersphinx.py4
-rw-r--r--tests/test_intl.py13
-rw-r--r--tests/test_napoleon.py190
-rw-r--r--tests/test_napoleon_docstring.py259
-rw-r--r--tests/test_napoleon_iterators.py346
-rw-r--r--tests/test_only_directive.py3
-rw-r--r--tests/test_quickstart.py1
-rw-r--r--tests/test_versioning.py1
-rw-r--r--tests/test_websupport.py7
-rw-r--r--tests/util.py9
-rw-r--r--tox.ini11
-rwxr-xr-xutils/check_sources.py25
-rwxr-xr-xutils/reindent.py29
132 files changed, 3974 insertions, 1063 deletions
diff --git a/AUTHORS b/AUTHORS
index 2a9dbbac..24b9be74 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -32,6 +32,7 @@ Other contributors, listed alphabetically, are:
* Christopher Perkins -- autosummary integration
* Benjamin Peterson -- unittests
* T. Powers -- HTML output improvements
+* Rob Ruana -- napoleon extension
* Stefan Seefeld -- toctree improvements
* Shibukawa Yoshiki -- pluggable search API and Japanese search
* Antonio Valentino -- qthelp builder
diff --git a/CHANGES b/CHANGES
index d043ce4f..2f4da53a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,30 +1,40 @@
-Release 1.2.2 (in development)
-==============================
-
-Bugs fixed
-----------
-
-* PR#211: When checking for existence of the :confval:`html_logo` file, check
- the full relative path and not the basename.
-* PR#212: Fix traceback with autodoc and ``__init__`` methods without docstring.
-* PR#213: Fix a missing import in the setup command.
-* #1357: Option names documented by :rst:dir:`option` are now again allowed to
- not start with a dash or slash, and referencing them will work correctly.
-* #1358: Fix handling of image paths outside of the source directory when using
- the "wildcard" style reference.
-
-Documentation
--------------
-
-* Extended the :ref:`documentation about building extensions <dev-extensions>`.
+Release 1.3 (in development)
+============================
+Incompatible changes
+--------------------
-Release 1.2.1 (released Jan 19, 2014)
-=====================================
+* Dropped support for Python 2.5 and 3.1.
+* Removed the ``sphinx.ext.oldcmarkup`` extension.
+* The deprecated config values ``exclude_trees``, ``exclude_dirnames`` and
+ ``unused_docs`` have been removed.
+* A new node, ``sphinx.addnodes.literal_strong``, has been added, for text that
+ should appear literally (i.e. no smart quotes) in strong font. Custom writers
+ will have to be adapted to handle this node.
+
+New features
+------------
+
+* Added ``sphinx.ext.napoleon`` extension for NumPy and Google style docstring
+ support.
+* PR#202: Allow "." and "~" prefixed references in ``:param:`` doc fields
+ for Python.
+* PR#184: Add :confval:`autodoc_mock_imports`, allowing to mock imports of
+ external modules that need not be present when autodocumenting.
+* #925: Allow list-typed config values to be provided on the command line,
+ like ``-D key=val1,val2``.
+* #668: Allow line numbering of ``code-block`` and ``literalinclude`` directives
+ to start at an arbitrary line number, with a new ``lineno-start`` option.
+* PR#172: The :rst:dir:`code-block` and :rst:dir:`literalinclude` directives now
+ can have a ``filename`` option that shows a filename before the code in the
+ output.
+* Prompt for the document language in sphinx-quickstart.
Bugs fixed
----------
+* #1174: Fix smart quotes being applied inside roles like :rst:role:`program` or
+ :rst:role:`makevar`.
* #1335: Fix autosummary template overloading with exclamation prefix like
``{% extends "!autosummary/class.rst" %}`` cause infinite recursive function
call. This was caused by PR#181.
@@ -102,11 +112,18 @@ Bugs fixed
* #1323: Fix emitting empty ``<ul>`` tags in the HTML writer, which is not
valid HTML.
* #1147: Don't emit a sidebar search box in the "singlehtml" builder.
+* PR#211: When checking for existence of the :confval:`html_logo` file, check
+ the full relative path and not the basename.
+* #1357: Option names documented by :rst:dir:`option` are now again allowed to
+ not start with a dash or slash, and referencing them will work correctly.
+* #1358: Fix handling of image paths outside of the source directory when using
+ the "wildcard" style reference.
Documentation
-------------
* #1325: Added a "Intersphinx" tutorial section. (:file:`doc/tutorial.rst`)
+* Extended the :ref:`documentation about building extensions <dev-extensions>`.
Release 1.2 (released Dec 10, 2013)
diff --git a/EXAMPLES b/EXAMPLES
index df940688..62c97842 100644
--- a/EXAMPLES
+++ b/EXAMPLES
@@ -79,6 +79,7 @@ Documentation using a customized version of the default theme
* IFM: http://fluffybunny.memebot.com/ifm-docs/index.html
* LEPL: http://www.acooke.org/lepl/
* Mayavi: http://code.enthought.com/projects/mayavi/docs/development/html/mayavi
+* NICOS: http://trac.frm2.tum.de/nicos/doc/nicos-master/index.html
* NOC: http://redmine.nocproject.org/projects/noc
* NumPy: http://docs.scipy.org/doc/numpy/reference/
* OpenCV: http://docs.opencv.org/
@@ -113,7 +114,6 @@ Documentation using the sphinxdoc theme
http://python-wild-magic.googlecode.com/svn/doc/html/index.html
* Reteisi: http://www.reteisi.org/contents.html
* Satchmo: http://www.satchmoproject.com/docs/dev/
-* Sphinx: http://sphinx-doc.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/
diff --git a/doc/conf.py b/doc/conf.py
index 08149fba..9932c8ed 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -5,6 +5,7 @@
import re
import sphinx
+
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
'sphinx.ext.autosummary', 'sphinx.ext.extlinks']
diff --git a/doc/config.rst b/doc/config.rst
index 192fc202..1b196abb 100644
--- a/doc/config.rst
+++ b/doc/config.rst
@@ -45,7 +45,8 @@ Important points to note:
* There is a special object named ``tags`` available in the config file.
It can be used to query and change the tags (see :ref:`tags`). Use
``tags.has('tag')`` to query, ``tags.add('tag')`` and ``tags.remove('tag')``
- to change.
+ to change. Only tags set via the ``-t`` command-line option or via
+ ``tags.add('tag')`` can be queried using ``tags.has('tag')``.
General configuration
@@ -113,38 +114,6 @@ General configuration
.. versionadded:: 1.0
-.. confval:: unused_docs
-
- A list of document names that are present, but not currently included in the
- toctree. Use this setting to suppress the warning that is normally emitted
- in that case.
-
- .. deprecated:: 1.0
- Use :confval:`exclude_patterns` instead.
-
-.. confval:: exclude_trees
-
- A list of directory paths, relative to the source directory, that are to be
- recursively excluded from the search for source files, that is, their
- subdirectories won't be searched too. The default is ``[]``.
-
- .. versionadded:: 0.4
-
- .. deprecated:: 1.0
- Use :confval:`exclude_patterns` instead.
-
-.. confval:: exclude_dirnames
-
- A list of directory names that are to be excluded from any recursive
- operation Sphinx performs (e.g. searching for source files or copying static
- files). This is useful, for example, to exclude version-control-specific
- directories like ``'CVS'``. The default is ``[]``.
-
- .. versionadded:: 0.5
-
- .. deprecated:: 1.0
- Use :confval:`exclude_patterns` instead.
-
.. confval:: templates_path
A list of paths that contain extra templates (or templates that overwrite
diff --git a/doc/domains.rst b/doc/domains.rst
index 4b5a9032..483052a9 100644
--- a/doc/domains.rst
+++ b/doc/domains.rst
@@ -157,17 +157,6 @@ declarations:
The following directives are provided for module and class contents:
-.. rst:directive:: .. py:data:: name
-
- Describes global data in a module, including both variables and values used
- as "defined constants." Class and object attributes are not documented
- using this environment.
-
-.. rst:directive:: .. py:exception:: name
-
- Describes an exception class. The signature can, but need not include
- parentheses with constructor arguments.
-
.. rst:directive:: .. py:function:: name(parameters)
Describes a module-level function. The signature should include the
@@ -178,11 +167,23 @@ The following directives are provided for module and class contents:
For methods you should use :rst:dir:`py:method`.
- The description should include information about the parameters required and
- how they are used (especially whether mutable objects passed as parameters
- are modified), side effects, and possible exceptions. This information can
- optionally be given in a structured form, see :ref:`info-field-lists`. A
- small example may be provided.
+ The description normally includes information about the parameters required
+ and how they are used (especially whether mutable objects passed as
+ parameters are modified), side effects, and possible exceptions.
+
+ This information can (in any ``py`` directive) optionally be given in a
+ structured form, see :ref:`info-field-lists`.
+
+.. rst:directive:: .. py:data:: name
+
+ Describes global data in a module, including both variables and values used
+ as "defined constants." Class and object attributes are not documented
+ using this environment.
+
+.. rst:directive:: .. py:exception:: name
+
+ Describes an exception class. The signature can, but need not include
+ parentheses with constructor arguments.
.. rst:directive:: .. py:class:: name
.. py:class:: name(parameters)
diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst
index c92fe0c4..38d7700e 100644
--- a/doc/ext/autodoc.rst
+++ b/doc/ext/autodoc.rst
@@ -26,6 +26,16 @@ hand-written documentation, this technique eases the pain of having to maintain
two locations for documentation, while at the same time avoiding
auto-generated-looking pure API documentation.
+If you prefer `NumPy`_ or `Google`_ style docstrings over reStructuredText,
+you can also enable the :mod:`napoleon <sphinx.ext.napoleon>` extension.
+:mod:`napoleon <sphinx.ext.napoleon>` is a preprocessor that converts your
+docstrings to correct reStructuredText before :mod:`autodoc` processes them.
+
+.. _Google:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments
+.. _NumPy:
+ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
:mod:`autodoc` provides several directives that are versions of the usual
: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,
@@ -195,6 +205,12 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
.. versionadded:: 1.2
+ * Add a list of modules in the :confval:`autodoc_mock_imports` to prevent
+ import errors to halt the building process when some external dependencies
+ are not importable at build time.
+
+ .. versionadded:: 1.3
+
.. rst:directive:: autofunction
autodata
@@ -335,6 +351,14 @@ There are also new config values that you can set:
.. versionadded:: 1.1
+.. confval:: autodoc_mock_imports
+
+ This value contains a list of modules to be mocked up. This is useful when
+ some external dependencies are not met at build time and break the building
+ process.
+
+ .. versionadded:: 1.3
+
Docstring preprocessing
-----------------------
diff --git a/doc/ext/example_google.py b/doc/ext/example_google.py
new file mode 100644
index 00000000..c94dcdf1
--- /dev/null
+++ b/doc/ext/example_google.py
@@ -0,0 +1,223 @@
+# -*- coding: utf-8 -*-
+"""Example Google style docstrings.
+
+This module demonstrates documentation as specified by the `Google Python
+Style Guide`_. Docstrings may extend over multiple lines. Sections are created
+with a section header and a colon followed by a block of indented text.
+
+Example:
+ Examples can be given using either the ``Example`` or ``Examples``
+ sections. Sections support any reStructuredText formatting, including
+ literal blocks::
+
+ $ python example_google.py
+
+Section breaks are created by simply resuming unindented text. Section breaks
+are also implicitly created anytime a new section starts.
+
+Attributes:
+ module_level_variable (int): Module level variables may be documented in
+ either the ``Attributes`` section of the module docstring, or in an
+ inline docstring immediately following the variable.
+
+ Either form is acceptable, but the two should not be mixed. Choose
+ one convention to document module level variables and be consistent
+ with it.
+
+.. _Google Python Style Guide:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
+
+"""
+
+module_level_variable = 12345
+
+
+def module_level_function(param1, param2=None, *args, **kwargs):
+ """This is an example of a module level function.
+
+ Function parameters should be documented in the ``Args`` section. The name
+ of each parameter is required. The type and description of each parameter
+ is optional, but should be included if not obvious.
+
+ If the parameter itself is optional, it should be noted by adding
+ ", optional" to the type. If \*args or \*\*kwargs are accepted, they
+ should be listed as \*args and \*\*kwargs.
+
+ The format for a parameter is::
+
+ name (type): description
+ The description may span multiple lines. Following
+ lines should be indented.
+
+ Multiple paragraphs are supported in parameter
+ descriptions.
+
+ Args:
+ param1 (int): The first parameter.
+ param2 (str, optional): The second parameter. Defaults to None.
+ Second line of description should be indented.
+ *args: Variable length argument list.
+ **kwargs: Arbitrary keyword arguments.
+
+ Returns:
+ bool: True if successful, False otherwise.
+
+ The return type is optional and may be specified at the beginning of
+ the ``Returns`` section followed by a colon.
+
+ The ``Returns`` section may span multiple lines and paragraphs.
+ Following lines should be indented to match the first line.
+
+ The ``Returns`` section supports any reStructuredText formatting,
+ including literal blocks::
+
+ {
+ 'param1': param1,
+ 'param2': param2
+ }
+
+ Raises:
+ AttributeError: The ``Raises`` section is a list of all exceptions
+ that are relevant to the interface.
+ ValueError: If `param2` is equal to `param1`.
+
+ """
+ if param1 == param2:
+ raise ValueError('param1 may not be equal to param2')
+ return True
+
+
+def example_generator(n):
+ """Generators have a ``Yields`` section instead of a ``Returns`` section.
+
+ Args:
+ n (int): The upper limit of the range to generate, from 0 to `n` - 1
+
+ Yields:
+ int: The next number in the range of 0 to `n` - 1
+
+ Examples:
+ Examples should be written in doctest format, and should illustrate how
+ to use the function.
+
+ >>> print [i for i in example_generator(4)]
+ [0, 1, 2, 3]
+
+ """
+ for i in range(n):
+ yield i
+
+
+class ExampleError(Exception):
+ """Exceptions are documented in the same way as classes.
+
+ The __init__ method may be documented in either the class level
+ docstring, or as a docstring on the __init__ method itself.
+
+ Either form is acceptable, but the two should not be mixed. Choose one
+ convention to document the __init__ method and be consistent with it.
+
+ Note:
+ Do not include the `self` parameter in the ``Args`` section.
+
+ Args:
+ msg (str): Human readable string describing the exception.
+ code (int, optional): Error code, defaults to 2.
+
+ Attributes:
+ msg (str): Human readable string describing the exception.
+ code (int): Exception error code.
+
+ """
+ def __init__(self, msg, code=2):
+ self.msg = msg
+ self.code = code
+
+
+class ExampleClass(object):
+ """The summary line for a class docstring should fit on one line.
+
+ If the class has public attributes, they should be documented here
+ in an ``Attributes`` section and follow the same formatting as a
+ function's ``Args`` section.
+
+ Attributes:
+ attr1 (str): Description of `attr1`.
+ attr2 (list of str): Description of `attr2`.
+ attr3 (int): Description of `attr3`.
+
+ """
+ def __init__(self, param1, param2, param3=0):
+ """Example of docstring on the __init__ method.
+
+ The __init__ method may be documented in either the class level
+ docstring, or as a docstring on the __init__ method itself.
+
+ Either form is acceptable, but the two should not be mixed. Choose one
+ convention to document the __init__ method and be consistent with it.
+
+ Note:
+ Do not include the `self` parameter in the ``Args`` section.
+
+ Args:
+ param1 (str): Description of `param1`.
+ param2 (list of str): Description of `param2`. Multiple
+ lines are supported.
+ param3 (int, optional): Description of `param3`, defaults to 0.
+
+ """
+ self.attr1 = param1
+ self.attr2 = param2
+ self.attr3 = param3
+
+ def example_method(self, param1, param2):
+ """Class methods are similar to regular functions.
+
+ Note:
+ Do not include the `self` parameter in the ``Args`` section.
+
+ Args:
+ param1: The first parameter.
+ param2: The second parameter.
+
+ Returns:
+ True if successful, False otherwise.
+
+ """
+ return True
+
+ def __special__(self):
+ """By default special members with docstrings are included.
+
+ Special members are any methods or attributes that start with and
+ end with a double underscore. Any special member with a docstring
+ will be included in the output.
+
+ This behavior can be disabled by changing the following setting in
+ Sphinx's conf.py::
+
+ napoleon_include_special_with_doc = False
+
+ """
+ pass
+
+ def __special_without_docstring__(self):
+ pass
+
+ def _private(self):
+ """By default private members are not included.
+
+ Private members are any methods or attributes that start with an
+ underscore and are *not* special. By default they are not included
+ in the output.
+
+ This behavior can be changed such that private members *are* included
+ by changing the following setting in Sphinx's conf.py::
+
+ napoleon_include_private_with_doc = True
+
+ """
+ pass
+
+ def _private_without_docstring(self):
+ pass
diff --git a/doc/ext/example_google.rst b/doc/ext/example_google.rst
new file mode 100644
index 00000000..06508082
--- /dev/null
+++ b/doc/ext/example_google.rst
@@ -0,0 +1,15 @@
+:orphan:
+
+.. _example_google:
+
+Example Google Style Python Docstrings
+======================================
+
+.. seealso::
+
+ :ref:`example_numpy`
+
+Download: :download:`example_google.py <example_google.py>`
+
+.. literalinclude:: example_google.py
+ :language: python
diff --git a/doc/ext/example_numpy.py b/doc/ext/example_numpy.py
new file mode 100644
index 00000000..df1d20e6
--- /dev/null
+++ b/doc/ext/example_numpy.py
@@ -0,0 +1,272 @@
+# -*- coding: utf-8 -*-
+"""Example NumPy style docstrings.
+
+This module demonstrates documentation as specified by the `NumPy
+Documentation HOWTO`_. Docstrings may extend over multiple lines. Sections
+are created with a section header followed by an underline of equal length.
+
+Example
+-------
+Examples can be given using either the ``Example`` or ``Examples``
+sections. Sections support any reStructuredText formatting, including
+literal blocks::
+
+ $ python example_numpy.py
+
+
+Section breaks are created with two blank lines. Section breaks are also
+implicitly created anytime a new section starts. Section bodies *may* be
+indented:
+
+Notes
+-----
+ This is an example of an indented section. It's like any other section,
+ but the body is indented to help it stand out from surrounding text.
+
+If a section is indented, then a section break is created simply by
+resuming unindented text.
+
+Attributes
+----------
+module_level_variable : int
+ Module level variables may be documented in either the ``Attributes``
+ section of the module docstring, or in an inline docstring immediately
+ following the variable.
+
+ Either form is acceptable, but the two should not be mixed. Choose
+ one convention to document module level variables and be consistent
+ with it.
+
+.. _NumPy Documentation HOWTO:
+ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+"""
+
+module_level_variable = 12345
+
+
+def module_level_function(param1, param2=None, *args, **kwargs):
+ """This is an example of a module level function.
+
+ Function parameters should be documented in the ``Parameters`` section.
+ The name of each parameter is required. The type and description of each
+ parameter is optional, but should be included if not obvious.
+
+ If the parameter itself is optional, it should be noted by adding
+ ", optional" to the type. If \*args or \*\*kwargs are accepted, they
+ should be listed as \*args and \*\*kwargs.
+
+ The format for a parameter is::
+
+ name : type
+ description
+
+ The description may span multiple lines. Following lines
+ should be indented to match the first line of the description.
+
+ Multiple paragraphs are supported in parameter
+ descriptions.
+
+ Parameters
+ ----------
+ param1 : int
+ The first parameter.
+ param2 : str, optional
+ The second parameter, defaults to None.
+ *args
+ Variable length argument list.
+ **kwargs
+ Arbitrary keyword arguments.
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise.
+
+ The return type is not optional. The ``Returns`` section may span
+ multiple lines and paragraphs. Following lines should be indented to
+ match the first line of the description.
+
+ The ``Returns`` section supports any reStructuredText formatting,
+ including literal blocks::
+
+ {
+ 'param1': param1,
+ 'param2': param2
+ }
+
+ Raises
+ ------
+ AttributeError
+ The ``Raises`` section is a list of all exceptions
+ that are relevant to the interface.
+ ValueError
+ If `param2` is equal to `param1`.
+
+ """
+ if param1 == param2:
+ raise ValueError('param1 may not be equal to param2')
+ return True
+
+
+def example_generator(n):
+ """Generators have a ``Yields`` section instead of a ``Returns`` section.
+
+ Parameters
+ ----------
+ n : int
+ The upper limit of the range to generate, from 0 to `n` - 1
+
+ Yields
+ ------
+ int
+ The next number in the range of 0 to `n` - 1
+
+ Examples
+ --------
+ Examples should be written in doctest format, and should illustrate how
+ to use the function.
+
+ >>> print [i for i in example_generator(4)]
+ [0, 1, 2, 3]
+
+ """
+ for i in range(n):
+ yield i
+
+
+class ExampleError(Exception):
+ """Exceptions are documented in the same way as classes.
+
+ The __init__ method may be documented in either the class level
+ docstring, or as a docstring on the __init__ method itself.
+
+ Either form is acceptable, but the two should not be mixed. Choose one
+ convention to document the __init__ method and be consistent with it.
+
+ Note
+ ----
+ Do not include the `self` parameter in the ``Parameters`` section.
+
+ Parameters
+ ----------
+ msg : str
+ Human readable string describing the exception.
+ code : int, optional
+ Error code, defaults to 2.
+
+ Attributes
+ ----------
+ msg : str
+ Human readable string describing the exception.
+ code : int
+ Exception error code.
+
+ """
+ def __init__(self, msg, code=2):
+ self.msg = msg
+ self.code = code
+
+
+class ExampleClass(object):
+ """The summary line for a class docstring should fit on one line.
+
+ If the class has public attributes, they should be documented here
+ in an ``Attributes`` section and follow the same formatting as a
+ function's ``Parameters`` section.
+
+ Attributes
+ ----------
+ attr1 : str
+ Description of `attr1`.
+ attr2 : list of str
+ Description of `attr2`.
+ attr3 : int
+ Description of `attr3`.
+
+ """
+ def __init__(self, param1, param2, param3=0):
+ """Example of docstring on the __init__ method.
+
+ The __init__ method may be documented in either the class level
+ docstring, or as a docstring on the __init__ method itself.
+
+ Either form is acceptable, but the two should not be mixed. Choose one
+ convention to document the __init__ method and be consistent with it.
+
+ Note
+ ----
+ Do not include the `self` parameter in the ``Parameters`` section.
+
+ Parameters
+ ----------
+ param1 : str
+ Description of `param1`.
+ param2 : list of str
+ Description of `param2`. Multiple
+ lines are supported.
+ param3 : int, optional
+ Description of `param3`, defaults to 0.
+
+ """
+ self.attr1 = param1
+ self.attr2 = param2
+ self.attr3 = param3
+
+ def example_method(self, param1, param2):
+ """Class methods are similar to regular functions.
+
+ Note
+ ----
+ Do not include the `self` parameter in the ``Parameters`` section.
+
+ Parameters
+ ----------
+ param1
+ The first parameter.
+ param2
+ The second parameter.
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise.
+
+ """
+ return True
+
+ def __special__(self):
+ """By default special members with docstrings are included.
+
+ Special members are any methods or attributes that start with and
+ end with a double underscore. Any special member with a docstring
+ will be included in the output.
+
+ This behavior can be disabled by changing the following setting in
+ Sphinx's conf.py::
+
+ napoleon_include_special_with_doc = False
+
+ """
+ pass
+
+ def __special_without_docstring__(self):
+ pass
+
+ def _private(self):
+ """By default private members are not included.
+
+ Private members are any methods or attributes that start with an
+ underscore and are *not* special. By default they are not included
+ in the output.
+
+ This behavior can be changed such that private members *are* included
+ by changing the following setting in Sphinx's conf.py::
+
+ napoleon_include_private_with_doc = True
+
+ """
+ pass
+
+ def _private_without_docstring(self):
+ pass
diff --git a/doc/ext/example_numpy.rst b/doc/ext/example_numpy.rst
new file mode 100644
index 00000000..a3b41613
--- /dev/null
+++ b/doc/ext/example_numpy.rst
@@ -0,0 +1,15 @@
+:orphan:
+
+.. _example_numpy:
+
+Example NumPy Style Python Docstrings
+======================================
+
+.. seealso::
+
+ :ref:`example_google`
+
+Download: :download:`example_numpy.py <example_numpy.py>`
+
+.. literalinclude:: example_numpy.py
+ :language: python
diff --git a/doc/ext/napoleon.rst b/doc/ext/napoleon.rst
new file mode 100644
index 00000000..32deecb8
--- /dev/null
+++ b/doc/ext/napoleon.rst
@@ -0,0 +1,375 @@
+:mod:`sphinx.ext.napoleon` -- Support for NumPy and Google style docstrings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. module:: sphinx.ext.napoleon
+ :synopsis: Support for NumPy and Google style docstrings
+
+.. moduleauthor:: Rob Ruana
+
+.. versionadded:: 1.3
+
+Napoleon - *Marching toward legible docstrings*
+===============================================
+
+Are you tired of writing docstrings that look like this::
+
+ :param path: The path of the file to wrap
+ :type path: str
+ :param field_storage: The :class:`FileStorage` instance to wrap
+ :type field_storage: FileStorage
+ :param temporary: Whether or not to delete the file when the File
+ instance is destructed
+ :type temporary: bool
+ :returns: A buffered writable file descriptor
+ :rtype: BufferedFileStorage
+
+`ReStructuredText`_ is great, but it creates visually dense, hard to read
+`docstrings`_. Compare the jumble above to the same thing rewritten
+according to the `Google Python Style Guide`_::
+
+ Args:
+ path (str): The path of the file to wrap
+ field_storage (FileStorage): The :class:`FileStorage` instance to wrap
+ temporary (bool): Whether or not to delete the file when the File
+ instance is destructed
+
+ Returns:
+ BufferedFileStorage: A buffered writable file descriptor
+
+Much more legible, no?
+
+Napoleon is a Sphinx extension that allows you to write readable API
+documentation in your source code. Napoleon understands both `NumPy`_ and
+`Google`_ style docstrings - the style recommended by `Khan Academy`_.
+
+.. _ReStructuredText: http://docutils.sourceforge.net/rst.html
+.. _docstrings: http://www.python.org/dev/peps/pep-0287/
+.. _Google Python Style Guide:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
+.. _Google:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments
+.. _NumPy:
+ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+.. _Khan Academy:
+ https://sites.google.com/a/khanacademy.org/forge/for-developers/styleguide/python#TOC-Docstrings
+
+Getting Started
+---------------
+
+1. After `setting up Sphinx`_ to build your docs, enable napoleon in the
+ Sphinx `conf.py` file::
+
+ # conf.py
+
+ # Add autodoc and napoleon to the extensions list
+ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
+
+2. Use `sphinx-apidoc` to build your API documentation::
+
+ $ sphinx-apidoc -f -o docs/source projectdir
+
+.. _setting up Sphinx: http://sphinx-doc.org/tutorial.html
+
+Docstrings
+----------
+
+Napoleon interprets every docstring that :mod:`autodoc <sphinx.ext.autodoc>`
+can find, including docstrings on: ``modules``, ``classes``, ``attributes``,
+``methods``, ``functions``, and ``variables``. Inside each docstring,
+specially formatted `Sections`_ are parsed and converted to
+reStructuredText.
+
+All standard reStructuredText formatting still works as expected.
+
+
+.. _Sections:
+
+Docstring Sections
+------------------
+
+All of the following section headers are supported:
+
+ * ``Args`` *(alias of Parameters)*
+ * ``Arguments`` *(alias of Parameters)*
+ * ``Attributes``
+ * ``Example``
+ * ``Examples``
+ * ``Keyword Args`` *(alias of Keyword Arguments)*
+ * ``Keyword Arguments``
+ * ``Methods``
+ * ``Note``
+ * ``Notes``
+ * ``Other Parameters``
+ * ``Parameters``
+ * ``Return`` *(alias of Returns)*
+ * ``Returns``
+ * ``Raises``
+ * ``References``
+ * ``See Also``
+ * ``Warning``
+ * ``Warnings`` *(alias of Warning)*
+ * ``Warns``
+ * ``Yields``
+
+Google vs NumPy
+---------------
+
+Napoleon supports two styles of docstrings: `Google`_ and `NumPy`_. The
+main difference between the two styles is that Google uses indention to
+separate sections, whereas NumPy uses underlines.
+
+Google style::
+
+ def func(arg1, arg2):
+ """Summary line.
+
+ Extended description of function.
+
+ Args:
+ arg1 (int): Description of arg1
+ arg2 (str): Description of arg2
+
+ Returns:
+ bool: Description of return value
+
+ """
+ return True
+
+NumPy style::
+
+ def func(arg1, arg2):
+ """Summary line.
+
+ Extended description of function.
+
+ Parameters
+ ----------
+ arg1 : int
+ Description of arg1
+ arg2 : str
+ Description of arg2
+
+ Returns
+ -------
+ bool
+ Description of return value
+
+ """
+ return True
+
+NumPy style tends to require more vertical space, whereas Google style
+tends to use more horizontal space. Google style tends to be easier to
+read for short and simple docstrings, whereas NumPy style tends be easier
+to read for long and in-depth docstrings.
+
+The `Khan Academy`_ recommends using Google style.
+
+The choice between styles is largely aesthetic, but the two styles should
+not be mixed. Choose one style for your project and be consistent with it.
+
+.. seealso::
+
+ For complete examples:
+
+ * :ref:`example_google`
+ * :ref:`example_numpy`
+
+
+Configuration
+=============
+
+Listed below are all the settings used by napoleon and their default
+values. These settings can be changed in the Sphinx `conf.py` file. Make
+sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are
+enabled in `conf.py`::
+
+ # conf.py
+
+ # Add any Sphinx extension module names here, as strings
+ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
+
+ # Napoleon settings
+ napoleon_google_docstring = True
+ napoleon_numpy_docstring = True
+ napoleon_include_private_with_doc = False
+ napoleon_include_special_with_doc = True
+ napoleon_use_admonition_for_examples = False
+ napoleon_use_admonition_for_notes = False
+ napoleon_use_admonition_for_references = False
+ napoleon_use_ivar = False
+ napoleon_use_param = False
+ napoleon_use_rtype = False
+
+.. _Google style:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
+.. _NumPy style:
+ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+
+
+.. confval:: napoleon_google_docstring
+
+ True to parse `Google style`_ docstrings. False to disable support
+ for Google style docstrings. *Defaults to True.*
+
+.. confval:: napoleon_numpy_docstring
+
+ True to parse `NumPy style`_ docstrings. False to disable support
+ for NumPy style docstrings. *Defaults to True.*
+
+.. confval:: napoleon_include_private_with_doc
+
+ True to include private members (like ``_membername``) with docstrings
+ in the documentation. False to fall back to Sphinx's default behavior.
+ *Defaults to False.*
+
+ **If True**::
+
+ def _included(self):
+ """
+ This will be included in the docs because it has a docstring
+ """
+ pass
+
+ def _skipped(self):
+ # This will NOT be included in the docs
+ pass
+
+.. confval:: napoleon_include_special_with_doc
+
+ True to include special members (like ``__membername__``) with
+ docstrings in the documentation. False to fall back to Sphinx's
+ default behavior. *Defaults to True.*
+
+ **If True**::
+
+ def __str__(self):
+ """
+ This will be included in the docs because it has a docstring
+ """
+ return unicode(self).encode('utf-8')
+
+ def __unicode__(self):
+ # This will NOT be included in the docs
+ return unicode(self.__class__.__name__)
+
+.. confval:: napoleon_use_admonition_for_examples
+
+ True to use the ``.. admonition::`` directive for the **Example** and
+ **Examples** sections. False to use the ``.. rubric::`` directive
+ instead. One may look better than the other depending on what HTML
+ theme is used. *Defaults to False.*
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Example
+ -------
+ This is just a quick example
+
+ **If True**::
+
+ .. admonition:: Example
+
+ This is just a quick example
+
+ **If False**::
+
+ .. rubric:: Example
+
+ This is just a quick example
+
+.. confval:: napoleon_use_admonition_for_notes
+
+ True to use the ``.. admonition::`` directive for **Notes** sections.
+ False to use the ``.. rubric::`` directive instead. *Defaults to False.*
+
+ .. note:: The singular **Note** section will always be converted to a
+ ``.. note::`` directive.
+
+ .. seealso::
+
+ :attr:`napoleon_use_admonition_for_examples`
+
+.. confval:: napoleon_use_admonition_for_references
+
+ True to use the ``.. admonition::`` directive for **References**
+ sections. False to use the ``.. rubric::`` directive instead.
+ *Defaults to False.*
+
+ .. seealso::
+
+ :attr:`napoleon_use_admonition_for_examples`
+
+.. confval:: napoleon_use_ivar
+
+ True to use the ``:ivar:`` role for instance variables. False to use
+ the ``.. attribute::`` directive instead. *Defaults to False.*
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Attributes
+ ----------
+ attr1 : int
+ Description of `attr1`
+
+ **If True**::
+
+ :ivar attr1: Description of `attr1`
+ :vartype attr1: int
+
+ **If False**::
+
+ .. attribute:: attr1
+ :annotation: int
+
+ Description of `attr1`
+
+.. confval:: napoleon_use_param
+
+ True to use a ``:param:`` role for each function parameter. False to
+ use a single ``:parameters:`` role for all the parameters.
+ *Defaults to False.*
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Parameters
+ ----------
+ arg1 : str
+ Description of `arg1`
+ arg2 : int, optional
+ Description of `arg2`, defaults to 0
+
+ **If True**::
+
+ :param arg1: Description of `arg1`
+ :type arg1: str
+ :param arg2: Description of `arg2`, defaults to 0
+ :type arg2: int, optional
+
+ **If False**::
+
+ :parameters: * **arg1** (*str*) --
+ Description of `arg1`
+ * **arg2** (*int, optional*) --
+ Description of `arg2`, defaults to 0
+
+.. confval:: napoleon_use_rtype
+
+ True to use the ``:rtype:`` role for the return type. False to output
+ the return type inline with the description. *Defaults to False.*
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise
+
+ **If True**::
+
+ :returns: True if successful, False otherwise
+ :rtype: bool
+
+ **If False**::
+
+ :returns: *bool* -- True if successful, False otherwise
diff --git a/doc/ext/oldcmarkup.rst b/doc/ext/oldcmarkup.rst
deleted file mode 100644
index 0fdd9fec..00000000
--- a/doc/ext/oldcmarkup.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-:mod:`sphinx.ext.oldcmarkup` -- Compatibility extension for old C markup
-========================================================================
-
-.. module:: sphinx.ext.oldcmarkup
- :synopsis: Allow further use of the pre-domain C markup
-.. moduleauthor:: Georg Brandl
-
-.. versionadded:: 1.0
-
-
-This extension is a transition helper for projects that used the old
-(pre-domain) C markup, i.e. the directives like ``cfunction`` and roles like
-``cfunc``. Since the introduction of domains, they must be called by their
-fully-qualified name (``c:function`` and ``c:func``, respectively) or, with the
-default domain set to ``c``, by their new name (``function`` and ``func``).
-(See :ref:`c-domain` for the details.)
-
-If you activate this extension, it will register the old names, and you can
-use them like before Sphinx 1.0. The directives are:
-
-- ``cfunction``
-- ``cmember``
-- ``cmacro``
-- ``ctype``
-- ``cvar``
-
-The roles are:
-
-- ``cdata``
-- ``cfunc``
-- ``cmacro``
-- ``ctype``
-
-However, it is advised to migrate to the new markup -- this extension is a
-compatibility convenience and will disappear in a future version of Sphinx.
diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst
index 24136f74..88fd4340 100644
--- a/doc/extdev/appapi.rst
+++ b/doc/extdev/appapi.rst
@@ -212,10 +212,13 @@ package.
.. index:: pair: function; directive
The reference node will be of class ``literal`` (so it will be rendered in a
- proportional font, as appropriate for code) unless you give the *ref_nodeclass*
- argument, which must be a docutils node class (most useful are
- ``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also use
- ``docutils.nodes.generated`` if you want no further text decoration).
+ proportional font, as appropriate for code) unless you give the
+ *ref_nodeclass* argument, which must be a docutils node class. Most useful
+ are ``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also
+ use ``docutils.nodes.generated`` if you want no further text decoration. If
+ the text should be treated as literal (e.g. no smart quote replacement), but
+ not have typewriter styling, use ``sphinx.addnodes.literal_emphasis`` or
+ ``sphinx.addnodes.literal_strong``.
For the role content, you have the same syntactical possibilities as for
standard Sphinx roles (see :ref:`xref-syntax`).
diff --git a/doc/extensions.rst b/doc/extensions.rst
index b2adbc1a..b0d98e38 100644
--- a/doc/extensions.rst
+++ b/doc/extensions.rst
@@ -31,7 +31,7 @@ These extensions are built in and can be activated by respective entries in the
ext/extlinks
ext/viewcode
ext/linkcode
- ext/oldcmarkup
+ ext/napoleon
Third-party extensions
diff --git a/doc/install.rst b/doc/install.rst
index bf653872..71e37e9c 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -4,7 +4,7 @@ Installing Sphinx
=================
Since Sphinx is written in the Python language, you need to install Python
-(the required version is at least 2.5) and Sphinx.
+(the required version is at least 2.6) and Sphinx.
Sphinx packages are available on the `Python Package Index
<https://pypi.python.org/pypi/Sphinx>`_.
@@ -79,8 +79,8 @@ sidebar and under "Quick Links", click "Windows Installer" to download.
.. note::
- Currently, Python offers two major versions, 2.x and 3.x. Sphinx 1.2 can run
- under Python 2.5 to 2.7 and 3.1 to 3.3, with the recommended version being
+ Currently, Python offers two major versions, 2.x and 3.x. Sphinx 1.3 can run
+ under Python 2.6, 2.7, 3.2, 3.3, with the recommended version being
2.7. This chapter assumes you have installed Python 2.7.
Follow the Windows installer for Python.
diff --git a/doc/intro.rst b/doc/intro.rst
index 66d0c58d..dd541bf1 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -54,7 +54,7 @@ See the :ref:`pertinent section in the FAQ list <usingwith>`.
Prerequisites
-------------
-Sphinx needs at least **Python 2.5** or **Python 3.1** to run, as well as the
+Sphinx needs at least **Python 2.6** or **Python 3.2** to run, as well as the
docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.7
or some (not broken) SVN trunk snapshot. If you like to have source code
highlighting support, you must also install the Pygments_ library.
diff --git a/doc/invocation.rst b/doc/invocation.rst
index 338728b6..dca02793 100644
--- a/doc/invocation.rst
+++ b/doc/invocation.rst
@@ -124,13 +124,22 @@ The :program:`sphinx-build` script has several options:
.. option:: -D setting=value
Override a configuration value set in the :file:`conf.py` file. The value
- must be a string or dictionary value. For the latter, supply the setting
- name and key like this: ``-D latex_elements.docclass=scrartcl``. For boolean
- values, use ``0`` or ``1`` as the value.
+ must be a number, string, list or dictionary value.
+
+ For lists, you can separate elements with a comma like this: ``-D
+ html_theme_path=path1,path2``.
+
+ For dictionary values, supply the setting name and key like this:
+ ``-D latex_elements.docclass=scrartcl``.
+
+ For boolean values, use ``0`` or ``1`` as the value.
.. versionchanged:: 0.6
The value can now be a dictionary value.
+ .. versionchanged:: 1.3
+ The value can now also be a list value.
+
.. option:: -A name=value
Make the *name* assigned to *value* in the HTML templates.
diff --git a/doc/markup/code.rst b/doc/markup/code.rst
index 957774f0..ab387c6d 100644
--- a/doc/markup/code.rst
+++ b/doc/markup/code.rst
@@ -87,6 +87,14 @@ on line numbers for the individual block::
Some more Ruby code.
+The first line number can be selected with the ``lineno-start`` option. If
+present, ``linenos`` is automatically activated as well.
+
+ .. code-block:: ruby
+ :lineno-start: 10
+
+ Some more Ruby code, with line numbering starting at 10.
+
Additionally, an ``emphasize-lines`` option can be given to have Pygments
emphasize particular lines::
@@ -102,6 +110,9 @@ emphasize particular lines::
.. versionchanged:: 1.1
``emphasize-lines`` has been added.
+.. versionchanged:: 1.3
+ ``lineno-start`` has been added.
+
Includes
^^^^^^^^
@@ -122,10 +133,11 @@ Includes
Tabs in the input are expanded if you give a ``tab-width`` option with the
desired tab width.
- The directive also supports the ``linenos`` flag option to switch on line
- numbers, the ``emphasize-lines`` option to emphasize particular lines, and
- a ``language`` option to select a language different from the current
- file's standard language. Example with options::
+ Like :rst:dir:`code-block`, the directive supports the ``linenos`` flag
+ option to switch on line numbers, the ``lineno-start`` option to select the
+ first line number, the ``emphasize-lines`` option to emphasize particular
+ lines, and a ``language`` option to select a language different from the
+ current file's standard language. Example with options::
.. literalinclude:: example.rb
:language: ruby
@@ -177,6 +189,25 @@ Includes
The ``prepend`` and ``append`` options, as well as ``tab-width``.
+Showing a file name
+^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 1.3
+
+A ``filename`` option can be given to show that name before the code block. For
+example::
+
+ .. code-block:: python
+ :filename: this.py
+
+ print 'Explicit is better than implicit.'
+
+
+:rst:dir:`literalinclude` also supports the ``filename`` option, with the
+additional feature that if you leave the value empty, the shown filename will be
+exactly the one given as an argument.
+
+
.. rubric:: Footnotes
.. [1] There is a standard ``.. include`` directive, but it raises errors if the
diff --git a/setup.py b/setup.py
index 876c0782..21f6709e 100644
--- a/setup.py
+++ b/setup.py
@@ -41,20 +41,20 @@ Among its features are the following:
* Setuptools integration
'''
+if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 2):
+ print('ERROR: Sphinx requires at least Python 2.6 or 3.2 to run.')
+ sys.exit(1)
+
requires = ['Pygments>=1.2', 'docutils>=0.7']
if sys.version_info[:3] >= (3, 3, 0):
requires[1] = 'docutils>=0.10'
-if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
+if (3, 0) <= sys.version_info < (3, 3):
requires.append('Jinja2>=2.3,<2.7')
-else:
+else: # 2.6, 2.7, 3.3 or later
requires.append('Jinja2>=2.3')
-if sys.version_info < (2, 5):
- print('ERROR: Sphinx requires at least Python 2.5 to run.')
- sys.exit(1)
-
# tell distribute to use 2to3 with our own fixers
extra = {}
if sys.version_info >= (3, 0):
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 21086cf8..c1e9e38d 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -15,12 +15,12 @@
import sys
from os import path
-__version__ = '1.2.1+'
-__released__ = '1.2.1' # used when Sphinx builds its own docs
+__version__ = '1.3a0'
+__released__ = '1.3a0' # used when Sphinx builds its own docs
# version info for better programmatic use
# possible values for 3rd element: 'alpha', 'beta', 'rc', 'final'
# 'final' has 0 as the last element
-version_info = (1, 2, 1, 'final', 0)
+version_info = (1, 3, 0, 'alpha', 0)
package_dir = path.abspath(path.dirname(__file__))
@@ -42,8 +42,9 @@ if '+' in __version__ or 'pre' in __version__:
def main(argv=sys.argv):
"""Sphinx build "main" command-line entry."""
- if sys.version_info[:3] < (2, 5, 0):
- sys.stderr.write('Error: Sphinx requires at least Python 2.5 to run.\n')
+ if (sys.version_info[:3] < (2, 6, 0) or
+ (3, 0, 0) <= sys.version_info[:3] < (3, 2, 0)):
+ sys.stderr.write('Error: Sphinx requires at least Python 2.6 to run.\n')
return 1
try:
from sphinx import cmdline
diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py
index d8dca2ce..e3f6d7d6 100644
--- a/sphinx/addnodes.py
+++ b/sphinx/addnodes.py
@@ -168,6 +168,11 @@ class literal_emphasis(nodes.emphasis):
applied (e.g. smartypants for HTML output).
"""
+class literal_strong(nodes.strong):
+ """Node that behaves like `strong`, but further text processors are not
+ applied (e.g. smartypants for HTML output).
+ """
+
class abbreviation(nodes.Inline, nodes.TextElement):
"""Node for abbreviations with explanations."""
diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py
index 7e95cdae..0fa5134d 100644
--- a/sphinx/apidoc.py
+++ b/sphinx/apidoc.py
@@ -14,6 +14,8 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
+
import os
import sys
import optparse
@@ -50,12 +52,12 @@ def write_file(name, text, opts):
"""Write the output file for module/package <name>."""
fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix))
if opts.dryrun:
- print 'Would create file %s.' % fname
+ print('Would create file %s.' % fname)
return
if not opts.force and path.isfile(fname):
- print 'File %s already exists, skipping.' % fname
+ print('File %s already exists, skipping.' % fname)
else:
- print 'Creating file %s.' % fname
+ print('Creating file %s.' % fname)
f = open(fname, 'w')
try:
f.write(text)
@@ -312,7 +314,7 @@ Note: By default this script will not overwrite already created files.""")
if opts.suffix.startswith('.'):
opts.suffix = opts.suffix[1:]
if not path.isdir(rootpath):
- print >>sys.stderr, '%s is not a directory.' % rootpath
+ print('%s is not a directory.' % rootpath, file=sys.stderr)
sys.exit(1)
if not path.isdir(opts.destdir):
if not opts.dryrun:
diff --git a/sphinx/application.py b/sphinx/application.py
index e598ced8..46caa326 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -10,11 +10,13 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import sys
import types
import posixpath
+import traceback
from os import path
from cStringIO import StringIO
@@ -37,6 +39,8 @@ from sphinx.util.tags import Tags
from sphinx.util.osutil import ENOENT
from sphinx.util.console import bold, lightgray, darkgray
+if hasattr(sys, 'intern'):
+ intern = sys.intern
# List of all known core events. Maps name to arguments description.
events = {
@@ -112,8 +116,6 @@ class Sphinx(object):
if self.confdir is None:
self.confdir = self.srcdir
- # 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)
@@ -122,7 +124,7 @@ class Sphinx(object):
self.config.setup(self)
# now that we know all config values, collect them from conf.py
- self.config.init_values()
+ self.config.init_values(self.warn)
# check the Sphinx version if requested
if self.config.needs_sphinx and \
@@ -175,7 +177,7 @@ class Sphinx(object):
# this can raise if the data version doesn't fit
self.env.domains[domain] = self.domains[domain](self.env)
self.info('done')
- except Exception, err:
+ except Exception as err:
if type(err) is IOError and err.errno == ENOENT:
self.info('not yet created')
else:
@@ -186,7 +188,7 @@ class Sphinx(object):
def _init_builder(self, buildername):
if buildername is None:
- print >>self._status, 'No builder selected, using default: html'
+ print('No builder selected, using default: html', file=self._status)
buildername = 'html'
if buildername not in self.builderclasses:
raise SphinxError('Builder name %s not registered' % buildername)
@@ -210,7 +212,7 @@ class Sphinx(object):
self.builder.build_specific(filenames)
else:
self.builder.build_update()
- except Exception, err:
+ except Exception as err:
# delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
if path.isfile(envfile):
@@ -323,7 +325,8 @@ class Sphinx(object):
return
try:
mod = __import__(extension, None, None, ['setup'])
- except ImportError, err:
+ except ImportError as err:
+ self.verbose('Original exception:\n' + traceback.format_exc())
raise ExtensionError('Could not import extension %s' % extension,
err)
if not hasattr(mod, 'setup'):
@@ -332,7 +335,7 @@ class Sphinx(object):
else:
try:
mod.setup(self)
- except VersionRequirementError, err:
+ except VersionRequirementError as err:
# add the extension name to the version required
raise VersionRequirementError(
'The %s extension used by this project needs at least '
@@ -349,17 +352,17 @@ class Sphinx(object):
"""Import an object from a 'module.name' string."""
try:
module, name = objname.rsplit('.', 1)
- except ValueError, err:
+ except ValueError as err:
raise ExtensionError('Invalid full object name %s' % objname +
(source and ' (needed for %s)' % source or ''),
err)
try:
return getattr(__import__(module, None, None, [name]), name)
- except ImportError, err:
+ except ImportError as err:
raise ExtensionError('Could not import %s' % module +
(source and ' (needed for %s)' % source or ''),
err)
- except AttributeError, err:
+ except AttributeError as err:
raise ExtensionError('Could not find %s' % objname +
(source and ' (needed for %s)' % source or ''),
err)
diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py
index 81d2e6ce..4595c7c2 100644
--- a/sphinx/builders/devhelp.py
+++ b/sphinx/builders/devhelp.py
@@ -94,7 +94,7 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
def istoctree(node):
return isinstance(node, addnodes.compact_paragraph) and \
- node.has_key('toctree')
+ 'toctree' in node
for node in tocdoc.traverse(istoctree):
write_toc(node, chapters)
diff --git a/sphinx/builders/epub.py b/sphinx/builders/epub.py
index 1dfcc704..ad586165 100644
--- a/sphinx/builders/epub.py
+++ b/sphinx/builders/epub.py
@@ -12,7 +12,6 @@
import os
import re
-import sys
import time
import codecs
import zipfile
@@ -219,7 +218,7 @@ 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) and doctree.has_key('refuri'):
+ if isinstance(doctree, nodes.reference) and 'refuri' in doctree:
refuri = doctree['refuri']
if refuri.startswith('http://') or refuri.startswith('https://') \
or refuri.startswith('irc:') or refuri.startswith('mailto:'):
@@ -418,7 +417,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
try:
copyfile(path.join(self.srcdir, src),
path.join(self.outdir, '_images', dest))
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn('cannot copy image file %r: %s' %
(path.join(self.srcdir, src), err))
continue
@@ -434,7 +433,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
img = img.resize((nw, nh), Image.BICUBIC)
try:
img.save(path.join(self.outdir, '_images', dest))
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn('cannot write image file %r: %s' %
(path.join(self.srcdir, src), err))
@@ -490,7 +489,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
fn = path.join(outdir, outname)
try:
os.mkdir(path.dirname(fn))
- except OSError, err:
+ except OSError as err:
if err.errno != EEXIST:
raise
f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
@@ -750,12 +749,5 @@ class EpubBuilder(StandaloneHTMLBuilder):
zipfile.ZIP_STORED)
for file in projectfiles:
fp = path.join(outdir, file)
- if sys.version_info < (2, 6):
- # When zipile.ZipFile.write call with unicode filename, ZipFile
- # encode filename to 'utf-8' (only after Python-2.6).
- if isinstance(file, unicode):
- # OEBPS Container Format (OCF) 2.0.1 specification require
- # "File Names MUST be UTF-8 encoded".
- file = file.encode('utf-8')
epub.write(fp, file, zipfile.ZIP_DEFLATED)
epub.close()
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index f648c311..f11ac293 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -184,7 +184,7 @@ class MessageCatalogBuilder(I18nBuilder):
for textdomain, catalog in self.status_iterator(
self.catalogs.iteritems(), "writing message catalogs... ",
darkgreen, len(self.catalogs),
- lambda (textdomain, _): textdomain):
+ lambda textdomain__: textdomain__[0]):
# noop if config.gettext_compact is set
ensuredir(path.join(self.outdir, path.dirname(textdomain)))
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index beb8d3ca..5b1a7594 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -16,11 +16,7 @@ import codecs
import posixpath
import cPickle as pickle
from os import path
-try:
- from hashlib import md5
-except ImportError:
- # 2.4 compatibility
- from md5 import md5
+from hashlib import md5
from docutils import nodes
from docutils.io import DocTreeInput, StringOutput
@@ -35,7 +31,7 @@ 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, b
+from sphinx.util.pycompat import b
from sphinx.errors import SphinxError
from sphinx.locale import _
from sphinx.search import js_index
@@ -535,7 +531,7 @@ class StandaloneHTMLBuilder(Builder):
try:
copyfile(path.join(self.srcdir, src),
path.join(self.outdir, '_images', dest))
- except Exception, err:
+ except Exception as err:
self.warn('cannot copy image file %r: %s' %
(path.join(self.srcdir, src), err))
@@ -550,7 +546,7 @@ class StandaloneHTMLBuilder(Builder):
try:
copyfile(path.join(self.srcdir, src),
path.join(self.outdir, '_downloads', dest))
- except Exception, err:
+ except Exception as err:
self.warn('cannot copy downloadable file %r: %s' %
(path.join(self.srcdir, src), err))
@@ -583,10 +579,7 @@ class StandaloneHTMLBuilder(Builder):
# then, copy over all user-supplied static files
staticentries = [path.join(self.confdir, spath)
for spath in self.config.html_static_path]
- matchers = compile_matchers(
- self.config.exclude_patterns +
- ['**/' + d for d in self.config.exclude_dirnames]
- )
+ matchers = compile_matchers(self.config.exclude_patterns)
for entry in staticentries:
if not path.exists(entry):
self.warn('html_static_path entry %r does not exist' % entry)
@@ -782,7 +775,7 @@ class StandaloneHTMLBuilder(Builder):
f.write(output)
finally:
f.close()
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
if self.copysource and ctx.get('sourcename'):
# copy the source file for the "show source" link
@@ -1100,8 +1093,4 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
searchindex_filename = 'searchindex.json'
def init(self):
- 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.')
SerializingHTMLBuilder.init(self)
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index e1723ba0..e7fa4bde 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -9,6 +9,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import codecs
@@ -197,7 +198,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
f = self.open_file(outdir, outname+'.stp')
try:
for word in sorted(stopwords):
- print >>f, word
+ print(word, file=f)
finally:
f.close()
@@ -217,8 +218,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
for fn in files:
if (staticdir and not fn.endswith('.js')) or \
fn.endswith('.html'):
- print >>f, path.join(root, fn)[olen:].replace(os.sep,
- '\\')
+ print(path.join(root, fn)[olen:].replace(os.sep, '\\'),
+ file=f)
finally:
f.close()
@@ -256,7 +257,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
write_toc(subnode, ullevel)
def istoctree(node):
return isinstance(node, addnodes.compact_paragraph) and \
- node.has_key('toctree')
+ 'toctree' in node
for node in tocdoc.traverse(istoctree):
write_toc(node)
f.write(contents_footer)
diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py
index 6cbe361b..88149ed0 100644
--- a/sphinx/builders/linkcheck.py
+++ b/sphinx/builders/linkcheck.py
@@ -10,7 +10,6 @@
"""
import re
-import sys
import Queue
import socket
import threading
@@ -110,7 +109,7 @@ class CheckExternalLinksBuilder(Builder):
def check_thread(self):
kwargs = {}
- if sys.version_info > (2, 5) and self.app.config.linkcheck_timeout:
+ if self.app.config.linkcheck_timeout:
kwargs['timeout'] = self.app.config.linkcheck_timeout
def check():
@@ -154,7 +153,7 @@ class CheckExternalLinksBuilder(Builder):
req = HeadRequest(req_url)
f = opener.open(req, **kwargs)
f.close()
- except HTTPError, err:
+ except HTTPError as err:
if err.code != 405:
raise
# retry with GET if that fails, some servers
@@ -163,7 +162,7 @@ class CheckExternalLinksBuilder(Builder):
f = opener.open(req, **kwargs)
f.close()
- except Exception, err:
+ except Exception as err:
self.broken[uri] = str(err)
return 'broken', str(err), 0
if f.url.rstrip('/') == req_url.rstrip('/'):
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index ce07315d..9ef480df 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -123,7 +123,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
prune_toctrees=False)
istoctree = lambda node: (
isinstance(node, addnodes.compact_paragraph)
- and node.has_key('toctree'))
+ and 'toctree' in node)
sections = []
for node in tocdoc.traverse(istoctree):
sections.extend(self.write_toc(node))
diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py
index 9510c150..40ead11a 100644
--- a/sphinx/builders/texinfo.py
+++ b/sphinx/builders/texinfo.py
@@ -223,6 +223,6 @@ class TexinfoBuilder(Builder):
mkfile.write(TEXINFO_MAKEFILE)
finally:
mkfile.close()
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (fn, err))
self.info(' done')
diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py
index f09ad654..b0704def 100644
--- a/sphinx/builders/text.py
+++ b/sphinx/builders/text.py
@@ -65,7 +65,7 @@ class TextBuilder(Builder):
f.write(self.writer.output)
finally:
f.close()
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
def finish(self):
diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py
index 19147fb1..8bc447b1 100644
--- a/sphinx/builders/xml.py
+++ b/sphinx/builders/xml.py
@@ -81,7 +81,7 @@ class XMLBuilder(Builder):
f.write(self.writer.output)
finally:
f.close()
- except (IOError, OSError), err:
+ except (IOError, OSError) as err:
self.warn("error writing file %s: %s" % (outfilename, err))
def finish(self):
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index e2c947c7..30c8c765 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import sys
@@ -28,9 +29,9 @@ from sphinx.util.pycompat import terminal_safe, bytes
def usage(argv, msg=None):
if msg:
- print >>sys.stderr, msg
- print >>sys.stderr
- print >>sys.stderr, """\
+ print(msg, file=sys.stderr)
+ print(file=sys.stderr)
+ print("""\
Sphinx v%s
Usage: %s [options] sourcedir outdir [filenames...]
@@ -75,7 +76,7 @@ Standard options
^^^^^^^^^^^^^^^^
-h, --help show this help and exit
--version show version information and exit
-""" % (__version__, argv[0])
+""" % (__version__, argv[0]), file=sys.stderr)
def main(argv):
@@ -96,33 +97,34 @@ def main(argv):
# help and version options
if '-h' in allopts or '--help' in allopts:
usage(argv)
- print >>sys.stderr
- print >>sys.stderr, 'For more information, see <http://sphinx-doc.org/>.'
+ print(file=sys.stderr)
+ print('For more information, see <http://sphinx-doc.org/>.',
+ file=sys.stderr)
return 0
if '--version' in allopts:
- print 'Sphinx (sphinx-build) %s' % __version__
+ print('Sphinx (sphinx-build) %s' % __version__)
return 0
# get paths (first and second positional argument)
try:
srcdir = confdir = abspath(args[0])
if not path.isdir(srcdir):
- print >>sys.stderr, 'Error: Cannot find source directory `%s\'.' % (
- srcdir,)
+ print('Error: Cannot find source directory `%s\'.' % srcdir,
+ file=sys.stderr)
return 1
if not path.isfile(path.join(srcdir, 'conf.py')) and \
'-c' not in allopts and '-C' not in allopts:
- print >>sys.stderr, ('Error: Source directory doesn\'t '
- 'contain a conf.py file.')
+ print('Error: Source directory doesn\'t contain a conf.py file.',
+ file=sys.stderr)
return 1
outdir = abspath(args[1])
except IndexError:
usage(argv, 'Error: Insufficient arguments.')
return 1
except UnicodeError:
- print >>sys.stderr, (
+ print(
'Error: Multibyte filename not supported on this filesystem '
- 'encoding (%r).' % fs_encoding)
+ 'encoding (%r).' % fs_encoding, file=sys.stderr)
return 1
# handle remaining filename arguments
@@ -130,7 +132,7 @@ def main(argv):
err = 0
for filename in filenames:
if not path.isfile(filename):
- print >>sys.stderr, 'Error: Cannot find file %r.' % filename
+ print('Error: Cannot find file %r.' % filename, file=sys.stderr)
err = 1
if err:
return 1
@@ -169,8 +171,8 @@ def main(argv):
elif opt == '-c':
confdir = abspath(val)
if not path.isfile(path.join(confdir, 'conf.py')):
- print >>sys.stderr, ('Error: Configuration directory '
- 'doesn\'t contain conf.py file.')
+ print('Error: Configuration directory doesn\'t contain conf.py file.',
+ file=sys.stderr)
return 1
elif opt == '-C':
confdir = None
@@ -178,24 +180,21 @@ def main(argv):
try:
key, val = val.split('=')
except ValueError:
- print >>sys.stderr, ('Error: -D option argument must be '
- 'in the form name=value.')
+ print('Error: -D option argument must be in the form name=value.',
+ file=sys.stderr)
return 1
- try:
- val = int(val)
- except ValueError:
- if likely_encoding and isinstance(val, bytes):
- try:
- val = val.decode(likely_encoding)
- except UnicodeError:
- pass
+ if likely_encoding and isinstance(val, bytes):
+ try:
+ val = val.decode(likely_encoding)
+ except UnicodeError:
+ pass
confoverrides[key] = val
elif opt == '-A':
try:
key, val = val.split('=')
except ValueError:
- print >>sys.stderr, ('Error: -A option argument must be '
- 'in the form name=value.')
+ print('Error: -A option argument must be in the form name=value.',
+ file=sys.stderr)
return 1
try:
val = int(val)
@@ -232,8 +231,8 @@ def main(argv):
try:
parallel = int(val)
except ValueError:
- print >>sys.stderr, ('Error: -j option argument must be an '
- 'integer.')
+ print('Error: -j option argument must be an integer.',
+ file=sys.stderr)
return 1
if warning and warnfile:
@@ -243,7 +242,7 @@ def main(argv):
if not path.isdir(outdir):
if status:
- print >>status, 'Making output directory...'
+ print('Making output directory...', file=status)
os.makedirs(outdir)
app = None
@@ -253,44 +252,44 @@ def main(argv):
warningiserror, tags, verbosity, parallel)
app.build(force_all, filenames)
return app.statuscode
- except (Exception, KeyboardInterrupt), err:
+ except (Exception, KeyboardInterrupt) as err:
if use_pdb:
import pdb
- print >>error, red('Exception occurred while building, '
- 'starting debugger:')
+ print(red('Exception occurred while building, starting debugger:'),
+ file=error)
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])
else:
- print >>error
+ print(file=error)
if show_traceback:
traceback.print_exc(None, error)
- print >>error
+ print(file=error)
if isinstance(err, KeyboardInterrupt):
- print >>error, 'interrupted!'
+ print('interrupted!', file=error)
elif isinstance(err, SystemMessage):
- print >>error, red('reST markup error:')
- print >>error, terminal_safe(err.args[0])
+ print(red('reST markup error:'), file=error)
+ print(terminal_safe(err.args[0]), file=error)
elif isinstance(err, SphinxError):
- print >>error, red('%s:' % err.category)
- print >>error, terminal_safe(unicode(err))
+ print(red('%s:' % err.category), file=error)
+ print(terminal_safe(unicode(err)), file=error)
elif isinstance(err, UnicodeError):
- print >>error, red('Encoding error:')
- print >>error, terminal_safe(unicode(err))
+ print(red('Encoding error:'), file=error)
+ print(terminal_safe(unicode(err)), file=error)
tbpath = save_traceback(app)
- print >>error, red('The full traceback has been saved '
- 'in %s, if you want to report the '
- 'issue to the developers.' % tbpath)
+ print(red('The full traceback has been saved in %s, if you want '
+ 'to report the issue to the developers.' % tbpath),
+ file=error)
else:
- print >>error, red('Exception occurred:')
- print >>error, format_exception_cut_frames().rstrip()
+ print(red('Exception occurred:'), file=error)
+ print(format_exception_cut_frames().rstrip(), file=error)
tbpath = save_traceback(app)
- print >>error, red('The full traceback has been saved '
- 'in %s, if you want to report the '
- 'issue to the developers.' % tbpath)
- print >>error, ('Please also report this if it was a user '
- 'error, so that a better error message '
- 'can be provided next time.')
- print >>error, (
- 'A bug report can be filed in the tracker at '
- '<https://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!')
+ print(red('The full traceback has been saved in %s, if you '
+ 'want to report the issue to the developers.' % tbpath),
+ file=error)
+ print('Please also report this if it was a user error, so '
+ 'that a better error message can be provided next time.',
+ file=error)
+ print('A bug report can be filed in the tracker at '
+ '<https://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!',
+ file=error)
return 1
diff --git a/sphinx/config.py b/sphinx/config.py
index 8b15bdf3..127425ae 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -51,10 +51,6 @@ class Config(object):
source_suffix = ('.rst', 'env'),
source_encoding = ('utf-8-sig', 'env'),
exclude_patterns = ([], 'env'),
- # the next three are all deprecated now
- unused_docs = ([], 'env'),
- exclude_trees = ([], 'env'),
- exclude_dirnames = ([], 'env'),
default_role = (None, 'env'),
add_function_parentheses = (True, 'env'),
add_module_names = (True, 'env'),
@@ -214,8 +210,11 @@ class Config(object):
self.overrides = overrides
self.values = Config.config_values.copy()
config = {}
- if "extensions" in overrides:
- config["extensions"] = overrides["extensions"]
+ if 'extensions' in overrides:
+ if isinstance(overrides['extensions'], (str, unicode)):
+ config['extensions'] = overrides.pop('extensions').split(',')
+ else:
+ config['extensions'] = overrides.pop('extensions')
if dirname is not None:
config_file = path.join(dirname, filename)
config['__file__'] = config_file
@@ -227,7 +226,7 @@ class Config(object):
os.chdir(dirname)
try:
execfile_(filename, config)
- except SyntaxError, err:
+ except SyntaxError as err:
raise ConfigError(CONFIG_SYNTAX_ERROR % err)
finally:
os.chdir(olddir)
@@ -248,12 +247,36 @@ class Config(object):
'Please use Unicode strings, e.g. %r.' % (name, u'Content')
)
- def init_values(self):
+ def init_values(self, warn):
config = self._raw_config
for valname, value in self.overrides.iteritems():
if '.' in valname:
realvalname, key = valname.split('.', 1)
config.setdefault(realvalname, {})[key] = value
+ continue
+ elif valname not in self.values:
+ warn('unknown config value %r in override, ignoring' % valname)
+ continue
+ defvalue = self.values[valname][0]
+ if isinstance(value, (str, unicode)):
+ if isinstance(defvalue, dict):
+ warn('cannot override dictionary config setting %r, '
+ 'ignoring (use %r to set individual elements)' %
+ (valname, valname + '.key=value'))
+ continue
+ elif isinstance(defvalue, list):
+ config[valname] = value.split(',')
+ elif isinstance(defvalue, (int, long)):
+ try:
+ config[valname] = int(value)
+ except ValueError:
+ warn('invalid number %r for config value %r, ignoring'
+ % (value, valname))
+ elif defvalue is not None and not isinstance(defvalue, (str, unicode)):
+ warn('cannot override config setting %r with unsupported type, '
+ 'ignoring' % valname)
+ else:
+ config[valname] = value
else:
config[valname] = value
for name in config:
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 4d43e5ff..8b3faf52 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -39,7 +39,7 @@ class Highlight(Directive):
except Exception:
linenothreshold = 10
else:
- linenothreshold = sys.maxint
+ linenothreshold = sys.maxsize
return [addnodes.highlightlang(lang=self.arguments[0].strip(),
linenothreshold=linenothreshold)]
@@ -56,7 +56,9 @@ class CodeBlock(Directive):
final_argument_whitespace = False
option_spec = {
'linenos': directives.flag,
+ 'lineno-start': int,
'emphasize-lines': directives.unchanged_required,
+ 'filename': directives.unchanged_required,
}
def run(self):
@@ -67,7 +69,7 @@ class CodeBlock(Directive):
try:
nlines = len(self.content)
hl_lines = [x+1 for x in parselinenos(linespec, nlines)]
- except ValueError, err:
+ except ValueError as err:
document = self.state.document
return [document.reporter.warning(str(err), line=self.lineno)]
else:
@@ -75,9 +77,16 @@ class CodeBlock(Directive):
literal = nodes.literal_block(code, code)
literal['language'] = self.arguments[0]
- literal['linenos'] = 'linenos' in self.options
+ filename = self.options.get('filename')
+ if filename:
+ literal['filename'] = filename
+ literal['linenos'] = 'linenos' in self.options or \
+ 'lineno-start' in self.options
+ extra_args = literal['highlight_args'] = {}
if hl_lines is not None:
- literal['highlight_args'] = {'hl_lines': hl_lines}
+ extra_args['hl_lines'] = hl_lines
+ if 'lineno-start' in self.options:
+ extra_args['linenostart'] = self.options['lineno-start']
set_source_info(self, literal)
return [literal]
@@ -95,6 +104,7 @@ class LiteralInclude(Directive):
final_argument_whitespace = True
option_spec = {
'linenos': directives.flag,
+ 'lineno-start': int,
'tab-width': int,
'language': directives.unchanged_required,
'encoding': directives.encoding,
@@ -105,6 +115,7 @@ class LiteralInclude(Directive):
'prepend': directives.unchanged_required,
'append': directives.unchanged_required,
'emphasize-lines': directives.unchanged_required,
+ 'filename': directives.unchanged,
}
def run(self):
@@ -156,7 +167,7 @@ class LiteralInclude(Directive):
if linespec is not None:
try:
linelist = parselinenos(linespec, len(lines))
- except ValueError, err:
+ except ValueError as err:
return [document.reporter.warning(str(err), line=self.lineno)]
# just ignore nonexisting lines
nlines = len(lines)
@@ -170,7 +181,7 @@ class LiteralInclude(Directive):
if linespec:
try:
hl_lines = [x+1 for x in parselinenos(linespec, len(lines))]
- except ValueError, err:
+ except ValueError as err:
return [document.reporter.warning(str(err), line=self.lineno)]
else:
hl_lines = None
@@ -204,10 +215,18 @@ class LiteralInclude(Directive):
set_source_info(self, retnode)
if self.options.get('language', ''):
retnode['language'] = self.options['language']
- if 'linenos' in self.options:
- retnode['linenos'] = True
+ retnode['linenos'] = 'linenos' in self.options or \
+ 'lineno-start' in self.options
+ filename = self.options.get('filename')
+ if filename is not None:
+ if not filename:
+ filename = self.arguments[0]
+ retnode['filename'] = filename
+ extra_args = retnode['highlight_args'] = {}
if hl_lines is not None:
- retnode['highlight_args'] = {'hl_lines': hl_lines}
+ extra_args['hl_lines'] = hl_lines
+ if 'lineno-start' in self.options:
+ extra_args['linenostart'] = self.options['lineno-start']
env.note_dependency(rel_filename)
return [retnode]
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 26e3c984..568dfad4 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -68,7 +68,7 @@ class CObject(ObjectDescription):
def _parse_type(self, node, ctype):
# add cross-ref nodes for all words
- for part in filter(None, wsplit_re.split(ctype)):
+ for part in [_f for _f in wsplit_re.split(ctype) if _f]:
tnode = nodes.Text(part, part)
if part[0] in string.ascii_letters+'_' and \
part not in self.stopwords:
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index d44c9cd7..ef2460c1 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -1065,7 +1065,7 @@ class CPPObject(ObjectDescription):
try:
rv = self.parse_definition(parser)
parser.assert_end()
- except DefinitionError, e:
+ except DefinitionError as e:
self.state_machine.reporter.warning(e.description, line=self.lineno)
raise ValueError
self.describe_signature(signode, rv)
@@ -1219,7 +1219,7 @@ class CPPCurrentNamespace(Directive):
try:
prefix = parser.parse_type()
parser.assert_end()
- except DefinitionError, e:
+ except DefinitionError as e:
self.state_machine.reporter.warning(e.description,
line=self.lineno)
else:
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index a7ed7557..6714e838 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -81,6 +81,23 @@ def _pseudo_parse_arglist(signode, arglist):
signode += paramlist
+# This override allows our inline type specifiers to behave like :class: link
+# when it comes to handling "." and "~" prefixes.
+class PyTypedField(TypedField):
+ def make_xref(self, rolename, domain, target, innernode=nodes.emphasis):
+ result = super(PyTypedField, self).make_xref(rolename, domain, target,
+ innernode)
+ if target.startswith('.'):
+ result['reftarget'] = target[1:]
+ result['refspecific'] = True
+ result[0][0] = nodes.Text(target[1:])
+ if target.startswith('~'):
+ result['reftarget'] = target[1:]
+ title = target.split('.')[-1]
+ result[0][0] = nodes.Text(title)
+ return result
+
+
class PyObject(ObjectDescription):
"""
Description of a general Python object.
@@ -92,7 +109,7 @@ class PyObject(ObjectDescription):
}
doc_field_types = [
- TypedField('parameter', label=l_('Parameters'),
+ PyTypedField('parameter', label=l_('Parameters'),
names=('param', 'parameter', 'arg', 'argument',
'keyword', 'kwarg', 'kwparam'),
typerolename='obj', typenames=('paramtype', 'type'),
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 50c7553e..423fcb95 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -530,7 +530,7 @@ class StandardDomain(Domain):
if labelid is None:
continue
node = document.ids[labelid]
- if name.isdigit() or node.has_key('refuri') or \
+ if name.isdigit() or 'refuri' in node or \
node.tagname.startswith('desc_'):
# ignore footnote labels, labels automatically generated from a
# link and object descriptions
diff --git a/sphinx/environment.py b/sphinx/environment.py
index e3e1cd0a..c13a4af9 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -340,9 +340,6 @@ class BuildEnvironment:
matchers = compile_matchers(
config.exclude_patterns[:] +
config.html_extra_path +
- config.exclude_trees +
- [d + config.source_suffix for d in config.unused_docs] +
- ['**/' + d for d in config.exclude_dirnames] +
['**/_sources', '.#*']
)
self.found_docs = set(get_matching_docs(
@@ -812,7 +809,7 @@ class BuildEnvironment:
imgtype = imghdr.what(f)
finally:
f.close()
- except (OSError, IOError), err:
+ except (OSError, IOError) as err:
self.warn_node('image file %s not readable: %s' %
(filename, err), node)
if imgtype:
@@ -923,7 +920,7 @@ class BuildEnvironment:
longtitlenode = titlenode
# explicit title set with title directive; use this only for
# the <title> tag in HTML output
- if document.has_key('title'):
+ if 'title' in document:
longtitlenode = nodes.title()
longtitlenode += nodes.Text(document['title'])
# look for first section title and use that as the title
@@ -1427,7 +1424,7 @@ class BuildEnvironment:
for node in doctree.traverse(addnodes.only):
try:
ret = builder.tags.eval_condition(node['expr'])
- except Exception, err:
+ except Exception as err:
self.warn_node('exception while evaluating only '
'directive expression: %s' % err, node)
node.replace_self(node.children or nodes.comment())
@@ -1553,7 +1550,7 @@ class BuildEnvironment:
add_entry(first, _('see also %s') % second, link=False)
else:
self.warn(fn, 'unknown index entry type %r' % type)
- except ValueError, err:
+ except ValueError as err:
self.warn(fn, str(err))
# sort the index entries; put all symbols at the front, even those
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index d07014fa..533993c5 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -29,7 +29,7 @@ from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.compat import Directive
from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \
safe_getattr, safe_repr, is_builtin_class_method
-from sphinx.util.pycompat import base_exception, class_types
+from sphinx.util.pycompat import class_types
from sphinx.util.docstrings import prepare_docstring
@@ -70,6 +70,35 @@ class Options(dict):
return None
+class _MockModule(object):
+ """Used by autodoc_mock_imports."""
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def __call__(self, *args, **kwargs):
+ return _MockModule()
+
+ @classmethod
+ def __getattr__(cls, name):
+ if name in ('__file__', '__path__'):
+ return '/dev/null'
+ elif name[0] == name[0].upper():
+ # Not very good, we assume Uppercase names are classes...
+ mocktype = type(name, (), {})
+ mocktype.__module__ = __name__
+ return mocktype
+ else:
+ return _MockModule()
+
+def mock_import(modname):
+ if '.' in modname:
+ pkg, _n, mods = modname.rpartition('.')
+ mock_import(pkg)
+ mod = _MockModule()
+ sys.modules[modname] = mod
+ return mod
+
+
ALL = object()
INSTANCEATTR = object()
@@ -332,6 +361,9 @@ class Documenter(object):
self.modname, '.'.join(self.objpath))
try:
dbg('[autodoc] import %s', self.modname)
+ for modname in self.env.config.autodoc_mock_imports:
+ dbg('[autodoc] adding a mock module %s!', self.modname)
+ mock_import(modname)
__import__(self.modname)
parent = None
obj = self.module = sys.modules[self.modname]
@@ -411,7 +443,7 @@ class Documenter(object):
# try to introspect the signature
try:
args = self.format_args()
- except Exception, err:
+ except Exception as err:
self.directive.warn('error while formatting arguments for '
'%s: %s' % (self.fullname, err))
args = None
@@ -731,7 +763,7 @@ class Documenter(object):
# parse right now, to get PycodeErrors on parsing (results will
# be cached anyway)
self.analyzer.find_attr_docs()
- except PycodeError, err:
+ except PycodeError as err:
self.env.app.debug('[autodoc] module analyzer failed: %s', err)
# no source file -- e.g. for builtin and C modules
self.analyzer = None
@@ -1131,7 +1163,7 @@ class ExceptionDocumenter(ClassDocumenter):
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, class_types) and \
- issubclass(member, base_exception)
+ issubclass(member, BaseException)
class DataDocumenter(ModuleLevelDocumenter):
@@ -1198,7 +1230,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
ret = ClassLevelDocumenter.import_object(self)
if isinstance(self.object, classmethod) or \
(isinstance(self.object, MethodType) and
- self.object.im_self is not None):
+ self.object.__self__ is not None):
self.directivetype = 'classmethod'
# document class and static members before ordinary ones
self.member_order = self.member_order - 1
@@ -1390,7 +1422,7 @@ class AutoDirective(Directive):
try:
self.genopt = Options(assemble_option_dict(
self.options.items(), doc_class.option_spec))
- except (KeyError, ValueError, TypeError), err:
+ except (KeyError, ValueError, TypeError) as err:
# an option is either unknown or has a wrong type
msg = self.reporter.error('An option to %s is either unknown or '
'has an invalid value: %s' % (self.name, err),
@@ -1454,6 +1486,7 @@ def setup(app):
app.add_config_value('autodoc_member_order', 'alphabetic', True)
app.add_config_value('autodoc_default_flags', [], True)
app.add_config_value('autodoc_docstring_signature', True, True)
+ app.add_config_value('autodoc_mock_imports', [], True)
app.add_event('autodoc-process-docstring')
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index af0fa65c..27cd21c4 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -465,7 +465,7 @@ def _import_by_name(name):
return obj, parent
else:
return sys.modules[modname], None
- except (ValueError, ImportError, AttributeError, KeyError), e:
+ except (ValueError, ImportError, AttributeError, KeyError) as e:
raise ImportError(*e.args)
diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py
index f45aa085..605521c2 100644
--- a/sphinx/ext/autosummary/generate.py
+++ b/sphinx/ext/autosummary/generate.py
@@ -17,6 +17,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import re
@@ -70,10 +71,10 @@ def main(argv=sys.argv):
template_dir=options.templates)
def _simple_info(msg):
- print msg
+ print(msg)
def _simple_warn(msg):
- print >> sys.stderr, 'WARNING: ' + msg
+ print('WARNING: ' + msg, file=sys.stderr)
# -- Generating output ---------------------------------------------------------
@@ -127,7 +128,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
try:
name, obj, parent = import_by_name(name)
- except ImportError, e:
+ except ImportError as e:
warn('[autosummary] failed to import %r: %s' % (name, e))
continue
@@ -240,8 +241,8 @@ def find_autosummary_in_docstring(name, module=None, filename=None):
return find_autosummary_in_lines(lines, module=name, filename=filename)
except AttributeError:
pass
- except ImportError, e:
- print "Failed to import '%s': %s" % (name, e)
+ except ImportError as e:
+ print("Failed to import '%s': %s" % (name, e))
return []
def find_autosummary_in_lines(lines, module=None, filename=None):
diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py
index 0e8bc4b2..53f4a483 100644
--- a/sphinx/ext/coverage.py
+++ b/sphinx/ext/coverage.py
@@ -134,7 +134,7 @@ class CoverageBuilder(Builder):
try:
mod = __import__(mod_name, fromlist=['foo'])
- except ImportError, err:
+ except ImportError as err:
self.warn('module %s could not be imported: %s' %
(mod_name, err))
self.py_undoc[mod_name] = {'error': err}
diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py
index cd6cbf22..b21e8405 100644
--- a/sphinx/ext/doctest.py
+++ b/sphinx/ext/doctest.py
@@ -289,14 +289,14 @@ Doctest summary
if self.config.doctest_test_doctest_blocks:
def condition(node):
return (isinstance(node, (nodes.literal_block, nodes.comment))
- and node.has_key('testnodetype')) or \
+ and 'testnodetype' in node) or \
isinstance(node, nodes.doctest_block)
else:
def condition(node):
return isinstance(node, (nodes.literal_block, nodes.comment)) \
- and node.has_key('testnodetype')
+ and 'testnodetype' in node
for node in doctree.traverse(condition):
- source = node.has_key('test') and node['test'] or node.astext()
+ source = 'test' in node and node['test'] or node.astext()
if not source:
self.warn('no code/output in %s block at %s:%s' %
(node.get('testnodetype', 'doctest'),
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 32bb96d3..c3096e3a 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -156,7 +156,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
dot_args.extend(['-Tcmapx', '-o%s.map' % outfn])
try:
p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE)
- except OSError, err:
+ except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
self.builder.warn('dot command %r cannot be run (needed for graphviz '
@@ -168,7 +168,7 @@ def render_dot(self, code, options, format, prefix='graphviz'):
# Graphviz may close standard input when an error occurs,
# resulting in a broken pipe on communicate()
stdout, stderr = p.communicate(code)
- except (OSError, IOError), err:
+ except (OSError, IOError) as err:
if err.errno not in (EPIPE, EINVAL):
raise
# in this case, read the standard output and standard error streams
@@ -192,7 +192,7 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
raise GraphvizError("graphviz_output_format must be one of 'png', "
"'svg', but is %r" % format)
fname, outfn = render_dot(self, code, options, format, prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
@@ -243,7 +243,7 @@ def html_visit_graphviz(self, node):
def render_dot_latex(self, node, code, options, prefix='graphviz'):
try:
fname, outfn = render_dot(self, code, options, 'pdf', prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
@@ -276,7 +276,7 @@ def latex_visit_graphviz(self, node):
def render_dot_texinfo(self, node, code, options, prefix='graphviz'):
try:
fname, outfn = render_dot(self, code, options, 'png', prefix)
- except GraphvizError, exc:
+ except GraphvizError as exc:
self.builder.warn('dot code %r: ' % code + str(exc))
raise nodes.SkipNode
if fname is not None:
diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py
index 2e219614..dadecf9e 100644
--- a/sphinx/ext/ifconfig.py
+++ b/sphinx/ext/ifconfig.py
@@ -53,7 +53,7 @@ def process_ifconfig_nodes(app, doctree, docname):
for node in doctree.traverse(ifconfig):
try:
res = eval(node['expr'], ns)
- except Exception, err:
+ except Exception as err:
# handle exceptions in a clean fashion
from traceback import format_exception_only
msg = ''.join(format_exception_only(err.__class__, err))
diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index fd973544..3c194a0b 100644
--- a/sphinx/ext/inheritance_diagram.py
+++ b/sphinx/ext/inheritance_diagram.py
@@ -306,7 +306,7 @@ class InheritanceDiagram(Directive):
class_names, env.temp_data.get('py:module'),
parts=node['parts'],
private_bases='private-bases' in self.options)
- except InheritanceException, err:
+ except InheritanceException as err:
return [node.document.reporter.warning(err.args[0],
line=self.lineno)]
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index 193562b2..a83258de 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -132,7 +132,7 @@ def fetch_inventory(app, uri, inv):
f = urllib2.urlopen(inv)
else:
f = open(path.join(app.srcdir, inv), 'rb')
- except Exception, err:
+ except Exception as err:
app.warn('intersphinx inventory %r not fetchable due to '
'%s: %s' % (inv, err.__class__, err))
return
@@ -149,7 +149,7 @@ def fetch_inventory(app, uri, inv):
except ValueError:
f.close()
raise ValueError('unknown or unsupported inventory version')
- except Exception, err:
+ except Exception as err:
app.warn('intersphinx inventory %r not readable due to '
'%s: %s' % (inv, err.__class__.__name__, err))
else:
diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py
new file mode 100644
index 00000000..d3b6f754
--- /dev/null
+++ b/sphinx/ext/napoleon/__init__.py
@@ -0,0 +1,375 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.napoleon
+ ~~~~~~~~~~~~~~~~~~~
+
+ Support for NumPy and Google style docstrings.
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import sys
+from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
+
+
+class Config(object):
+ """Sphinx napoleon extension settings in `conf.py`.
+
+ Listed below are all the settings used by napoleon and their default
+ values. These settings can be changed in the Sphinx `conf.py` file. Make
+ sure that both "sphinx.ext.autodoc" and "sphinx.ext.napoleon" are
+ enabled in `conf.py`::
+
+ # conf.py
+
+ # Add any Sphinx extension module names here, as strings
+ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
+
+ # Napoleon settings
+ napoleon_google_docstring = True
+ napoleon_numpy_docstring = True
+ napoleon_include_private_with_doc = False
+ napoleon_include_special_with_doc = True
+ napoleon_use_admonition_for_examples = False
+ napoleon_use_admonition_for_notes = False
+ napoleon_use_admonition_for_references = False
+ napoleon_use_ivar = False
+ napoleon_use_param = False
+ napoleon_use_rtype = False
+
+ .. _Google style:
+ http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
+ .. _NumPy style:
+ https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+ Attributes
+ ----------
+ napoleon_google_docstring : bool, defaults to True
+ True to parse `Google style`_ docstrings. False to disable support
+ for Google style docstrings.
+ napoleon_numpy_docstring : bool, defaults to True
+ True to parse `NumPy style`_ docstrings. False to disable support
+ for NumPy style docstrings.
+ napoleon_include_private_with_doc : bool, defaults to False
+ True to include private members (like ``_membername``) with docstrings
+ in the documentation. False to fall back to Sphinx's default behavior.
+
+ **If True**::
+
+ def _included(self):
+ \"\"\"
+ This will be included in the docs because it has a docstring
+ \"\"\"
+ pass
+
+ def _skipped(self):
+ # This will NOT be included in the docs
+ pass
+
+ napoleon_include_special_with_doc : bool, defaults to True
+ True to include special members (like ``__membername__``) with
+ docstrings in the documentation. False to fall back to Sphinx's
+ default behavior.
+
+ **If True**::
+
+ def __str__(self):
+ \"\"\"
+ This will be included in the docs because it has a docstring
+ \"\"\"
+ return unicode(self).encode('utf-8')
+
+ def __unicode__(self):
+ # This will NOT be included in the docs
+ return unicode(self.__class__.__name__)
+
+ napoleon_use_admonition_for_examples : bool, defaults to False
+ True to use the ``.. admonition::`` directive for the **Example** and
+ **Examples** sections. False to use the ``.. rubric::`` directive
+ instead. One may look better than the other depending on what HTML
+ theme is used.
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Example
+ -------
+ This is just a quick example
+
+ **If True**::
+
+ .. admonition:: Example
+
+ This is just a quick example
+
+ **If False**::
+
+ .. rubric:: Example
+
+ This is just a quick example
+
+ napoleon_use_admonition_for_notes : bool, defaults to False
+ True to use the ``.. admonition::`` directive for **Notes** sections.
+ False to use the ``.. rubric::`` directive instead.
+
+ Note
+ ----
+ The singular **Note** section will always be converted to a
+ ``.. note::`` directive.
+
+ See Also
+ --------
+ :attr:`napoleon_use_admonition_for_examples`
+
+ napoleon_use_admonition_for_references : bool, defaults to False
+ True to use the ``.. admonition::`` directive for **References**
+ sections. False to use the ``.. rubric::`` directive instead.
+
+ See Also
+ --------
+ :attr:`napoleon_use_admonition_for_examples`
+
+ napoleon_use_ivar : bool, defaults to False
+ True to use the ``:ivar:`` role for instance variables. False to use
+ the ``.. attribute::`` directive instead.
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Attributes
+ ----------
+ attr1 : int
+ Description of `attr1`
+
+ **If True**::
+
+ :ivar attr1: Description of `attr1`
+ :vartype attr1: int
+
+ **If False**::
+
+ .. attribute:: attr1
+ :annotation: int
+
+ Description of `attr1`
+
+ napoleon_use_param : bool, defaults to False
+ True to use a ``:param:`` role for each function parameter. False to
+ use a single ``:parameters:`` role for all the parameters.
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Parameters
+ ----------
+ arg1 : str
+ Description of `arg1`
+ arg2 : int, optional
+ Description of `arg2`, defaults to 0
+
+ **If True**::
+
+ :param arg1: Description of `arg1`
+ :type arg1: str
+ :param arg2: Description of `arg2`, defaults to 0
+ :type arg2: int, optional
+
+ **If False**::
+
+ :parameters: * **arg1** (*str*) --
+ Description of `arg1`
+ * **arg2** (*int, optional*) --
+ Description of `arg2`, defaults to 0
+
+ napoleon_use_rtype : bool, defaults to False
+ True to use the ``:rtype:`` role for the return type. False to output
+ the return type inline with the description.
+
+ This `NumPy style`_ snippet will be converted as follows::
+
+ Returns
+ -------
+ bool
+ True if successful, False otherwise
+
+ **If True**::
+
+ :returns: True if successful, False otherwise
+ :rtype: bool
+
+ **If False**::
+
+ :returns: *bool* -- True if successful, False otherwise
+
+ """
+ _config_values = {
+ 'napoleon_google_docstring': (True, 'env'),
+ 'napoleon_numpy_docstring': (True, 'env'),
+ 'napoleon_include_private_with_doc': (False, 'env'),
+ 'napoleon_include_special_with_doc': (True, 'env'),
+ 'napoleon_use_admonition_for_examples': (False, 'env'),
+ 'napoleon_use_admonition_for_notes': (False, 'env'),
+ 'napoleon_use_admonition_for_references': (False, 'env'),
+ 'napoleon_use_ivar': (False, 'env'),
+ 'napoleon_use_param': (False, 'env'),
+ 'napoleon_use_rtype': (False, 'env'),
+ }
+
+ def __init__(self, **settings):
+ for name, (default, rebuild) in self._config_values.iteritems():
+ setattr(self, name, default)
+ for name, value in settings.iteritems():
+ setattr(self, name, value)
+
+
+def setup(app):
+ """Sphinx extension setup function.
+
+ When the extension is loaded, Sphinx imports this module and executes
+ the ``setup()`` function, which in turn notifies Sphinx of everything
+ the extension offers.
+
+ Parameters
+ ----------
+ app : sphinx.application.Sphinx
+ Application object representing the Sphinx process
+
+ See Also
+ --------
+ The Sphinx documentation on `Extensions`_, the `Extension Tutorial`_, and
+ the `Extension API`_.
+
+ .. _Extensions: http://sphinx-doc.org/extensions.html
+ .. _Extension Tutorial: http://sphinx-doc.org/ext/tutorial.html
+ .. _Extension API: http://sphinx-doc.org/ext/appapi.html
+
+ """
+ from sphinx.application import Sphinx
+ if not isinstance(app, Sphinx):
+ return # probably called by tests
+
+ app.connect('autodoc-process-docstring', _process_docstring)
+ app.connect('autodoc-skip-member', _skip_member)
+
+ for name, (default, rebuild) in Config._config_values.iteritems():
+ app.add_config_value(name, default, rebuild)
+
+
+def _process_docstring(app, what, name, obj, options, lines):
+ """Process the docstring for a given python object.
+
+ Called when autodoc has read and processed a docstring. `lines` is a list
+ of docstring lines that `_process_docstring` modifies in place to change
+ what Sphinx outputs.
+
+ The following settings in conf.py control what styles of docstrings will
+ be parsed:
+
+ * ``napoleon_google_docstring`` -- parse Google style docstrings
+ * ``napoleon_numpy_docstring`` -- parse NumPy style docstrings
+
+ Parameters
+ ----------
+ app : sphinx.application.Sphinx
+ Application object representing the Sphinx process.
+ what : str
+ A string specifying the type of the object to which the docstring
+ belongs. Valid values: "module", "class", "exception", "function",
+ "method", "attribute".
+ name : str
+ The fully qualified name of the object.
+ obj : module, class, exception, function, method, or attribute
+ The object to which the docstring belongs.
+ options : sphinx.ext.autodoc.Options
+ The options given to the directive: an object with attributes
+ inherited_members, undoc_members, show_inheritance and noindex that
+ are True if the flag option of same name was given to the auto
+ directive.
+ lines : list of str
+ The lines of the docstring, see above.
+
+ .. note:: `lines` is modified *in place*
+
+ """
+ result_lines = lines
+ if app.config.napoleon_numpy_docstring:
+ docstring = NumpyDocstring(result_lines, app.config, app, what, name,
+ obj, options)
+ result_lines = docstring.lines()
+ if app.config.napoleon_google_docstring:
+ docstring = GoogleDocstring(result_lines, app.config, app, what, name,
+ obj, options)
+ result_lines = docstring.lines()
+ lines[:] = result_lines[:]
+
+
+def _skip_member(app, what, name, obj, skip, options):
+ """Determine if private and special class members are included in docs.
+
+ The following settings in conf.py determine if private and special class
+ members are included in the generated documentation:
+
+ * ``napoleon_include_private_with_doc`` --
+ include private members if they have docstrings
+ * ``napoleon_include_special_with_doc`` --
+ include special members if they have docstrings
+
+ Parameters
+ ----------
+ app : sphinx.application.Sphinx
+ Application object representing the Sphinx process
+ what : str
+ A string specifying the type of the object to which the member
+ belongs. Valid values: "module", "class", "exception", "function",
+ "method", "attribute".
+ name : str
+ The name of the member.
+ obj : module, class, exception, function, method, or attribute.
+ For example, if the member is the __init__ method of class A, then
+ `obj` will be `A.__init__`.
+ skip : bool
+ A boolean indicating if autodoc will skip this member if `_skip_member`
+ does not override the decision
+ options : sphinx.ext.autodoc.Options
+ The options given to the directive: an object with attributes
+ inherited_members, undoc_members, show_inheritance and noindex that
+ are True if the flag option of same name was given to the auto
+ directive.
+
+ Returns
+ -------
+ bool
+ True if the member should be skipped during creation of the docs,
+ False if it should be included in the docs.
+
+ """
+ has_doc = getattr(obj, '__doc__', False)
+ is_member = (what == 'class' or what == 'exception' or what == 'module')
+ if name != '__weakref__' and name != '__init__' and has_doc and is_member:
+ if what == 'class' or what == 'exception':
+ if sys.version_info[0] < 3:
+ cls = getattr(obj, 'im_class', getattr(obj, '__objclass__',
+ None))
+ cls_is_owner = (cls and hasattr(cls, name) and
+ name in cls.__dict__)
+ elif sys.version_info[1] >= 3 and hasattr(obj, '__qualname__'):
+ cls_path, _, _ = obj.__qualname__.rpartition('.')
+ if cls_path:
+ import importlib
+ import functools
+
+ mod = importlib.import_module(obj.__module__)
+ cls = functools.reduce(getattr, cls_path.split('.'), mod)
+ cls_is_owner = (cls and hasattr(cls, name) and
+ name in cls.__dict__)
+ else:
+ cls_is_owner = False
+ else:
+ cls_is_owner = True
+
+ if what == 'module' or cls_is_owner:
+ is_special = name.startswith('__') and name.endswith('__')
+ is_private = not is_special and name.startswith('_')
+ inc_special = app.config.napoleon_include_special_with_doc
+ inc_private = app.config.napoleon_include_private_with_doc
+ if (is_special and inc_special) or (is_private and inc_private):
+ return False
+ return skip
diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
new file mode 100644
index 00000000..d6c73db8
--- /dev/null
+++ b/sphinx/ext/napoleon/docstring.py
@@ -0,0 +1,714 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.napoleon.docstring
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+ Classes for docstring parsing and formatting.
+
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+import sys
+from sphinx.ext.napoleon.iterators import modify_iter
+
+
+if sys.version_info[0] >= 3:
+ basestring = str
+ xrange = range
+
+
+_directive_regex = re.compile(r'\.\. \S+::')
+_field_parens_regex = re.compile(r'\s*(\w+)\s*\(\s*(.+?)\s*\)')
+
+
+class GoogleDocstring(object):
+ """Parse Google style docstrings.
+
+ Convert Google style docstrings to reStructuredText.
+
+ Parameters
+ ----------
+ docstring : str or list of str
+ The docstring to parse, given either as a string or split into
+ individual lines.
+ config : sphinx.ext.napoleon.Config or sphinx.config.Config, optional
+ The configuration settings to use. If not given, defaults to the
+ config object on `app`; or if `app` is not given defaults to the
+ a new `sphinx.ext.napoleon.Config` object.
+
+ See Also
+ --------
+ :class:`sphinx.ext.napoleon.Config`
+
+ Other Parameters
+ ----------------
+ app : sphinx.application.Sphinx, optional
+ Application object representing the Sphinx process.
+ what : str, optional
+ A string specifying the type of the object to which the docstring
+ belongs. Valid values: "module", "class", "exception", "function",
+ "method", "attribute".
+ name : str, optional
+ The fully qualified name of the object.
+ obj : module, class, exception, function, method, or attribute
+ The object to which the docstring belongs.
+ options : sphinx.ext.autodoc.Options, optional
+ The options given to the directive: an object with attributes
+ inherited_members, undoc_members, show_inheritance and noindex that
+ are True if the flag option of same name was given to the auto
+ directive.
+
+ Example
+ -------
+ >>> from sphinx.ext.napoleon import Config
+ >>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
+ >>> docstring = '''One line summary.
+ ...
+ ... Extended description.
+ ...
+ ... Args:
+ ... arg1(int): Description of `arg1`
+ ... arg2(str): Description of `arg2`
+ ... Returns:
+ ... str: Description of return value.
+ ... '''
+ >>> print(GoogleDocstring(docstring, config))
+ One line summary.
+ <BLANKLINE>
+ Extended description.
+ <BLANKLINE>
+ :param arg1: Description of `arg1`
+ :type arg1: int
+ :param arg2: Description of `arg2`
+ :type arg2: str
+ <BLANKLINE>
+ :returns: Description of return value.
+ :rtype: str
+
+ """
+ def __init__(self, docstring, config=None, app=None, what='', name='',
+ obj=None, options=None):
+ self._config = config
+ self._app = app
+ if not self._config:
+ from sphinx.ext.napoleon import Config
+ self._config = self._app and self._app.config or Config()
+ self._what = what
+ self._name = name
+ self._obj = obj
+ self._opt = options
+ if isinstance(docstring, basestring):
+ docstring = docstring.splitlines()
+ self._lines = docstring
+ self._line_iter = modify_iter(docstring, modifier=lambda s: s.rstrip())
+ self._parsed_lines = []
+ self._is_in_section = False
+ self._section_indent = 0
+ if not hasattr(self, '_directive_sections'):
+ self._directive_sections = []
+ if not hasattr(self, '_sections'):
+ self._sections = {
+ 'args': self._parse_parameters_section,
+ 'arguments': self._parse_parameters_section,
+ 'attributes': self._parse_attributes_section,
+ 'example': self._parse_examples_section,
+ 'examples': self._parse_examples_section,
+ 'keyword args': self._parse_keyword_arguments_section,
+ 'keyword arguments': self._parse_keyword_arguments_section,
+ 'methods': self._parse_methods_section,
+ 'note': self._parse_note_section,
+ 'notes': self._parse_notes_section,
+ 'other parameters': self._parse_other_parameters_section,
+ 'parameters': self._parse_parameters_section,
+ 'return': self._parse_returns_section,
+ 'returns': self._parse_returns_section,
+ 'raises': self._parse_raises_section,
+ 'references': self._parse_references_section,
+ 'see also': self._parse_see_also_section,
+ 'warning': self._parse_warning_section,
+ 'warnings': self._parse_warning_section,
+ 'warns': self._parse_warns_section,
+ 'yields': self._parse_yields_section,
+ }
+ self._parse()
+
+ def __str__(self):
+ """Return the parsed docstring in reStructuredText format.
+
+ Returns
+ -------
+ str
+ UTF-8 encoded version of the docstring.
+
+ """
+ if sys.version_info[0] >= 3:
+ return self.__unicode__()
+ else:
+ return self.__unicode__().encode('utf8')
+
+ def __unicode__(self):
+ """Return the parsed docstring in reStructuredText format.
+
+ Returns
+ -------
+ unicode
+ Unicode version of the docstring.
+
+ """
+ return u'\n'.join(self.lines())
+
+ def lines(self):
+ """Return the parsed lines of the docstring in reStructuredText format.
+
+ Returns
+ -------
+ list of str
+ The lines of the docstring in a list.
+
+ """
+ return self._parsed_lines
+
+ def _consume_indented_block(self, indent=1):
+ lines = []
+ line = self._line_iter.peek()
+ while(not self._is_section_break()
+ and (not line or self._is_indented(line, indent))):
+ lines.append(self._line_iter.next())
+ line = self._line_iter.peek()
+ return lines
+
+ def _consume_contiguous(self):
+ lines = []
+ while (self._line_iter.has_next()
+ and self._line_iter.peek()
+ and not self._is_section_header()):
+ lines.append(self._line_iter.next())
+ return lines
+
+ def _consume_empty(self):
+ lines = []
+ line = self._line_iter.peek()
+ while self._line_iter.has_next() and not line:
+ lines.append(self._line_iter.next())
+ line = self._line_iter.peek()
+ return lines
+
+ def _consume_field(self, parse_type=True, prefer_type=False):
+ line = self._line_iter.next()
+ _name, _, _desc = line.partition(':')
+ _name, _type, _desc = _name.strip(), '', _desc.strip()
+ match = _field_parens_regex.match(_name)
+ if parse_type and match:
+ _name = match.group(1)
+ _type = match.group(2)
+ if prefer_type and not _type:
+ _type, _name = _name, _type
+ indent = self._get_indent(line) + 1
+ _desc = [_desc] + self._dedent(self._consume_indented_block(indent))
+ _desc = self.__class__(_desc, self._config).lines()
+ return _name, _type, _desc
+
+ def _consume_fields(self, parse_type=True, prefer_type=False):
+ self._consume_empty()
+ fields = []
+ while not self._is_section_break():
+ _name, _type, _desc = self._consume_field(parse_type, prefer_type)
+ if _name or _type or _desc:
+ fields.append((_name, _type, _desc,))
+ return fields
+
+ def _consume_returns_section(self):
+ lines = self._dedent(self._consume_to_next_section())
+ if lines:
+ if ':' in lines[0]:
+ _type, _, _desc = lines[0].partition(':')
+ _name, _type, _desc = '', _type.strip(), _desc.strip()
+ match = _field_parens_regex.match(_type)
+ if match:
+ _name = match.group(1)
+ _type = match.group(2)
+ lines[0] = _desc
+ _desc = lines
+ else:
+ _name, _type, _desc = '', '', lines
+ _desc = self.__class__(_desc, self._config).lines()
+ return [(_name, _type, _desc,)]
+ else:
+ return []
+
+ def _consume_section_header(self):
+ section = self._line_iter.next()
+ stripped_section = section.strip(':')
+ if stripped_section.lower() in self._sections:
+ section = stripped_section
+ return section
+
+ def _consume_to_next_section(self):
+ self._consume_empty()
+ lines = []
+ while not self._is_section_break():
+ lines.append(self._line_iter.next())
+ return lines + self._consume_empty()
+
+ def _dedent(self, lines, full=False):
+ if full:
+ return [line.lstrip() for line in lines]
+ else:
+ min_indent = self._get_min_indent(lines)
+ return [line[min_indent:] for line in lines]
+
+ def _format_admonition(self, admonition, lines):
+ lines = self._strip_empty(lines)
+ if len(lines) == 1:
+ return ['.. %s:: %s' % (admonition, lines[0].strip()), '']
+ elif lines:
+ lines = self._indent(self._dedent(lines), 3)
+ return ['.. %s::' % admonition, ''] + lines + ['']
+ else:
+ return ['.. %s::' % admonition, '']
+
+ def _format_block(self, prefix, lines, padding=None):
+ if lines:
+ if padding is None:
+ padding = ' ' * len(prefix)
+ result_lines = []
+ for i, line in enumerate(lines):
+ if line:
+ if i == 0:
+ result_lines.append(prefix + line)
+ else:
+ result_lines.append(padding + line)
+ else:
+ result_lines.append('')
+ return result_lines
+ else:
+ return [prefix]
+
+ def _format_field(self, _name, _type, _desc):
+ separator = any([s for s in _desc]) and ' --' or ''
+ if _name:
+ if _type:
+ field = ['**%s** (*%s*)%s' % (_name, _type, separator)]
+ else:
+ field = ['**%s**%s' % (_name, separator)]
+ elif _type:
+ field = ['*%s*%s' % (_type, separator)]
+ else:
+ field = []
+ return field + _desc
+
+ def _format_fields(self, field_type, fields):
+ field_type = ':%s:' % field_type.strip()
+ padding = ' ' * len(field_type)
+ multi = len(fields) > 1
+ lines = []
+ for _name, _type, _desc in fields:
+ field = self._format_field(_name, _type, _desc)
+ if multi:
+ if lines:
+ lines.extend(self._format_block(padding + ' * ', field))
+ else:
+ lines.extend(self._format_block(field_type + ' * ', field))
+ else:
+ lines.extend(self._format_block(field_type + ' ', field))
+ return lines
+
+ def _get_current_indent(self, peek_ahead=0):
+ line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
+ while line != self._line_iter.sentinel:
+ if line:
+ return self._get_indent(line)
+ peek_ahead += 1
+ line = self._line_iter.peek(peek_ahead + 1)[peek_ahead]
+ return 0
+
+ def _get_indent(self, line):
+ for i, s in enumerate(line):
+ if not s.isspace():
+ return i
+ return len(line)
+
+ def _get_min_indent(self, lines):
+ min_indent = None
+ for line in lines:
+ if line:
+ indent = self._get_indent(line)
+ if min_indent is None:
+ min_indent = indent
+ elif indent < min_indent:
+ min_indent = indent
+ return min_indent or 0
+
+ def _indent(self, lines, n=4):
+ return [(' ' * n) + line for line in lines]
+
+ def _is_indented(self, line, indent=1):
+ for i, s in enumerate(line):
+ if i >= indent:
+ return True
+ elif not s.isspace():
+ return False
+ return False
+
+ def _is_section_header(self):
+ section = self._line_iter.peek().lower()
+ if section.strip(':') in self._sections:
+ header_indent = self._get_indent(section)
+ section_indent = self._get_current_indent(peek_ahead=1)
+ return section_indent > header_indent
+ elif self._directive_sections:
+ if _directive_regex.match(section):
+ for directive_section in self._directive_sections:
+ if section.startswith(directive_section):
+ return True
+ return False
+
+ def _is_section_break(self):
+ line = self._line_iter.peek()
+ return (not self._line_iter.has_next()
+ or self._is_section_header()
+ or (self._is_in_section
+ and line
+ and not self._is_indented(line, self._section_indent)))
+
+ def _parse(self):
+ self._parsed_lines = self._consume_empty()
+ while self._line_iter.has_next():
+ if self._is_section_header():
+ try:
+ section = self._consume_section_header()
+ self._is_in_section = True
+ self._section_indent = self._get_current_indent()
+ if _directive_regex.match(section):
+ lines = [section] + self._consume_to_next_section()
+ else:
+ lines = self._sections[section.lower()](section)
+ finally:
+ self._is_in_section = False
+ self._section_indent = 0
+ else:
+ if not self._parsed_lines:
+ lines = self._consume_contiguous() + self._consume_empty()
+ else:
+ lines = self._consume_to_next_section()
+ self._parsed_lines.extend(lines)
+
+ def _parse_attributes_section(self, section):
+ lines = []
+ for _name, _type, _desc in self._consume_fields():
+ if self._config.napoleon_use_ivar:
+ field = ':ivar %s: ' % _name
+ lines.extend(self._format_block(field, _desc))
+ if _type:
+ lines.append(':vartype %s: %s' % (_name, _type))
+ else:
+ lines.append('.. attribute:: ' + _name)
+ if _type:
+ lines.append(' :annotation: ' + _type)
+ if _desc:
+ lines.extend([''] + self._indent(_desc, 3))
+ lines.append('')
+ if self._config.napoleon_use_ivar:
+ lines.append('')
+ return lines
+
+ def _parse_examples_section(self, section):
+ use_admonition = self._config.napoleon_use_admonition_for_examples
+ return self._parse_generic_section(section, use_admonition)
+
+ def _parse_generic_section(self, section, use_admonition):
+ lines = self._strip_empty(self._consume_to_next_section())
+ lines = self._dedent(lines)
+ if use_admonition:
+ header = '.. admonition:: %s' % section
+ lines = self._indent(lines, 3)
+ else:
+ header = '.. rubric:: %s' % section
+ if lines:
+ return [header, ''] + lines + ['']
+ else:
+ return [header, '']
+
+ def _parse_keyword_arguments_section(self, section):
+ return self._format_fields('Keyword Arguments', self._consume_fields())
+
+ def _parse_methods_section(self, section):
+ lines = []
+ for _name, _, _desc in self._consume_fields(parse_type=False):
+ lines.append('.. method:: %s' % _name)
+ if _desc:
+ lines.extend([''] + self._indent(_desc, 3))
+ lines.append('')
+ return lines
+
+ def _parse_note_section(self, section):
+ lines = self._consume_to_next_section()
+ return self._format_admonition('note', lines)
+
+ def _parse_notes_section(self, section):
+ use_admonition = self._config.napoleon_use_admonition_for_notes
+ return self._parse_generic_section('Notes', use_admonition)
+
+ def _parse_other_parameters_section(self, section):
+ return self._format_fields('Other Parameters', self._consume_fields())
+
+ def _parse_parameters_section(self, section):
+ fields = self._consume_fields()
+ if self._config.napoleon_use_param:
+ lines = []
+ for _name, _type, _desc in fields:
+ field = ':param %s: ' % _name
+ lines.extend(self._format_block(field, _desc))
+ if _type:
+ lines.append(':type %s: %s' % (_name, _type))
+ return lines + ['']
+ else:
+ return self._format_fields('Parameters', fields)
+
+ def _parse_raises_section(self, section):
+ fields = self._consume_fields()
+ field_type = ':raises:'
+ padding = ' ' * len(field_type)
+ multi = len(fields) > 1
+ lines = []
+ for _name, _type, _desc in fields:
+ sep = _desc and ' -- ' or ''
+ if _name:
+ if ' ' in _name:
+ _name = '**%s**' % _name
+ else:
+ _name = ':exc:`%s`' % _name
+ if _type:
+ field = ['%s (*%s*)%s' % (_name, _type, sep)]
+ else:
+ field = ['%s%s' % (_name, sep)]
+ elif _type:
+ field = ['*%s*%s' % (_type, sep)]
+ else:
+ field = []
+ field = field + _desc
+ if multi:
+ if lines:
+ lines.extend(self._format_block(padding + ' * ', field))
+ else:
+ lines.extend(self._format_block(field_type + ' * ', field))
+ else:
+ lines.extend(self._format_block(field_type + ' ', field))
+ return lines
+
+ def _parse_references_section(self, section):
+ use_admonition = self._config.napoleon_use_admonition_for_references
+ return self._parse_generic_section('References', use_admonition)
+
+ def _parse_returns_section(self, section):
+ fields = self._consume_returns_section()
+ multi = len(fields) > 1
+ if multi:
+ use_rtype = False
+ else:
+ use_rtype = self._config.napoleon_use_rtype
+
+ lines = []
+ for _name, _type, _desc in fields:
+ if use_rtype:
+ field = self._format_field(_name, '', _desc)
+ else:
+ field = self._format_field(_name, _type, _desc)
+
+ if multi:
+ if lines:
+ lines.extend(self._format_block(' * ', field))
+ else:
+ lines.extend(self._format_block(':returns: * ', field))
+ else:
+ lines.extend(self._format_block(':returns: ', field))
+ if _type and use_rtype:
+ lines.append(':rtype: %s' % _type)
+ return lines
+
+ def _parse_see_also_section(self, section):
+ lines = self._consume_to_next_section()
+ return self._format_admonition('seealso', lines)
+
+ def _parse_warning_section(self, section):
+ lines = self._consume_to_next_section()
+ return self._format_admonition('warning', lines)
+
+ def _parse_warns_section(self, section):
+ return self._format_fields('Warns', self._consume_fields())
+
+ def _parse_yields_section(self, section):
+ fields = self._consume_fields(prefer_type=True)
+ return self._format_fields('Yields', fields)
+
+ def _strip_empty(self, lines):
+ if lines:
+ start = -1
+ for i, line in enumerate(lines):
+ if line:
+ start = i
+ break
+ if start == -1:
+ lines = []
+ end = -1
+ for i in reversed(xrange(len(lines))):
+ line = lines[i]
+ if line:
+ end = i
+ break
+ if start > 0 or end + 1 < len(lines):
+ lines = lines[start:end + 1]
+ return lines
+
+
+class NumpyDocstring(GoogleDocstring):
+ """Parse NumPy style docstrings.
+
+ Convert NumPy style docstrings to reStructuredText.
+
+ Parameters
+ ----------
+ docstring : str or list of str
+ The docstring to parse, given either as a string or split into
+ individual lines.
+ config : sphinx.ext.napoleon.Config or sphinx.config.Config, optional
+ The configuration settings to use. If not given, defaults to the
+ config object on `app`; or if `app` is not given defaults to the
+ a new `sphinx.ext.napoleon.Config` object.
+
+ See Also
+ --------
+ :class:`sphinx.ext.napoleon.Config`
+
+ Other Parameters
+ ----------------
+ app : sphinx.application.Sphinx, optional
+ Application object representing the Sphinx process.
+ what : str, optional
+ A string specifying the type of the object to which the docstring
+ belongs. Valid values: "module", "class", "exception", "function",
+ "method", "attribute".
+ name : str, optional
+ The fully qualified name of the object.
+ obj : module, class, exception, function, method, or attribute
+ The object to which the docstring belongs.
+ options : sphinx.ext.autodoc.Options, optional
+ The options given to the directive: an object with attributes
+ inherited_members, undoc_members, show_inheritance and noindex that
+ are True if the flag option of same name was given to the auto
+ directive.
+
+ Example
+ -------
+ >>> from sphinx.ext.napoleon import Config
+ >>> config = Config(napoleon_use_param=True, napoleon_use_rtype=True)
+ >>> docstring = '''One line summary.
+ ...
+ ... Extended description.
+ ...
+ ... Parameters
+ ... ----------
+ ... arg1 : int
+ ... Description of `arg1`
+ ... arg2 : str
+ ... Description of `arg2`
+ ... Returns
+ ... -------
+ ... str
+ ... Description of return value.
+ ... '''
+ >>> print(NumpyDocstring(docstring, config))
+ One line summary.
+ <BLANKLINE>
+ Extended description.
+ <BLANKLINE>
+ :param arg1: Description of `arg1`
+ :type arg1: int
+ :param arg2: Description of `arg2`
+ :type arg2: str
+ <BLANKLINE>
+ :returns: Description of return value.
+ :rtype: str
+
+ Methods
+ -------
+ __str__()
+ Return the parsed docstring in reStructuredText format.
+
+ Returns
+ -------
+ str
+ UTF-8 encoded version of the docstring.
+
+ __unicode__()
+ Return the parsed docstring in reStructuredText format.
+
+ Returns
+ -------
+ unicode
+ Unicode version of the docstring.
+
+ lines()
+ Return the parsed lines of the docstring in reStructuredText format.
+
+ Returns
+ -------
+ list of str
+ The lines of the docstring in a list.
+
+ """
+ def __init__(self, docstring, config=None, app=None, what='', name='',
+ obj=None, options=None):
+ self._directive_sections = ['.. index::']
+ super(NumpyDocstring, self).__init__(docstring, config, app, what,
+ name, obj, options)
+
+ def _consume_field(self, parse_type=True, prefer_type=False):
+ line = self._line_iter.next()
+ if parse_type:
+ _name, _, _type = line.partition(':')
+ else:
+ _name, _type = line, ''
+ _name, _type = _name.strip(), _type.strip()
+ if prefer_type and not _type:
+ _type, _name = _name, _type
+ indent = self._get_indent(line)
+ _desc = self._dedent(self._consume_indented_block(indent + 1))
+ _desc = self.__class__(_desc, self._config).lines()
+ return _name, _type, _desc
+
+ def _consume_returns_section(self):
+ return self._consume_fields(prefer_type=True)
+
+ def _consume_section_header(self):
+ section = self._line_iter.next()
+ if not _directive_regex.match(section):
+ # Consume the header underline
+ self._line_iter.next()
+ return section
+
+ def _is_section_break(self):
+ line1, line2 = self._line_iter.peek(2)
+ return (not self._line_iter.has_next()
+ or self._is_section_header()
+ or ['', ''] == [line1, line2]
+ or (self._is_in_section
+ and line1
+ and not self._is_indented(line1, self._section_indent)))
+
+ def _is_section_header(self):
+ section, underline = self._line_iter.peek(2)
+ section = section.lower()
+ if section in self._sections and isinstance(underline, basestring):
+ pattern = r'[=\-`:\'"~^_*+#<>]{' + str(len(section)) + r'}$'
+ return bool(re.match(pattern, underline))
+ elif self._directive_sections:
+ if _directive_regex.match(section):
+ for directive_section in self._directive_sections:
+ if section.startswith(directive_section):
+ return True
+ return False
diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py
new file mode 100644
index 00000000..2f1904da
--- /dev/null
+++ b/sphinx/ext/napoleon/iterators.py
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.ext.napoleon.iterators
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+ A collection of helpful iterators.
+
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import collections
+import sys
+
+
+if sys.version_info[0] >= 3:
+ callable = lambda o: hasattr(o, '__call__')
+
+
+class peek_iter(object):
+ """An iterator object that supports peeking ahead.
+
+ Parameters
+ ----------
+ o : iterable or callable
+ `o` is interpreted very differently depending on the presence of
+ `sentinel`.
+
+ If `sentinel` is not given, then `o` must be a collection object
+ which supports either the iteration protocol or the sequence protocol.
+
+ If `sentinel` is given, then `o` must be a callable object.
+
+ sentinel : any value, optional
+ If given, the iterator will call `o` with no arguments for each
+ call to its `next` method; if the value returned is equal to
+ `sentinel`, :exc:`StopIteration` will be raised, otherwise the
+ value will be returned.
+
+ See Also
+ --------
+ `peek_iter` can operate as a drop in replacement for the built-in
+ `iter <http://docs.python.org/2/library/functions.html#iter>`_ function.
+
+ Attributes
+ ----------
+ sentinel
+ The value used to indicate the iterator is exhausted. If `sentinel`
+ was not given when the `peek_iter` was instantiated, then it will
+ be set to a new object instance: ``object()``.
+
+ """
+ def __init__(self, *args):
+ """__init__(o, sentinel=None)"""
+ self._iterable = iter(*args)
+ self._cache = collections.deque()
+ if len(args) == 2:
+ self.sentinel = args[1]
+ else:
+ self.sentinel = object()
+
+ def __iter__(self):
+ return self
+
+ def __next__(self, n=None):
+ # note: prevent 2to3 to transform self.next() in next(self) which
+ # causes an infinite loop !
+ return getattr(self, 'next')(n)
+
+ def _fillcache(self, n):
+ """Cache `n` items. If `n` is 0 or None, then 1 item is cached."""
+ if not n:
+ n = 1
+ try:
+ while len(self._cache) < n:
+ self._cache.append(self._iterable.next())
+ except StopIteration:
+ while len(self._cache) < n:
+ self._cache.append(self.sentinel)
+
+ def has_next(self):
+ """Determine if iterator is exhausted.
+
+ Returns
+ -------
+ bool
+ True if iterator has more items, False otherwise.
+
+ Note
+ ----
+ Will never raise :exc:`StopIteration`.
+
+ """
+ return self.peek() != self.sentinel
+
+ def next(self, n=None):
+ """Get the next item or `n` items of the iterator.
+
+ Parameters
+ ----------
+ n : int or None
+ The number of items to retrieve. Defaults to None.
+
+ Returns
+ -------
+ item or list of items
+ The next item or `n` items of the iterator. If `n` is None, the
+ item itself is returned. If `n` is an int, the items will be
+ returned in a list. If `n` is 0, an empty list is returned.
+
+ Raises
+ ------
+ StopIteration
+ Raised if the iterator is exhausted, even if `n` is 0.
+
+ """
+ self._fillcache(n)
+ if not n:
+ if self._cache[0] == self.sentinel:
+ raise StopIteration
+ if n is None:
+ result = self._cache.popleft()
+ else:
+ result = []
+ else:
+ if self._cache[n - 1] == self.sentinel:
+ raise StopIteration
+ result = [self._cache.popleft() for i in range(n)]
+ return result
+
+ def peek(self, n=None):
+ """Preview the next item or `n` items of the iterator.
+
+ The iterator is not advanced when peek is called.
+
+ Returns
+ -------
+ item or list of items
+ The next item or `n` items of the iterator. If `n` is None, the
+ item itself is returned. If `n` is an int, the items will be
+ returned in a list. If `n` is 0, an empty list is returned.
+
+ If the iterator is exhausted, `peek_iter.sentinel` is returned,
+ or placed as the last item in the returned list.
+
+ Note
+ ----
+ Will never raise :exc:`StopIteration`.
+
+ """
+ self._fillcache(n)
+ if n is None:
+ result = self._cache[0]
+ else:
+ result = [self._cache[i] for i in range(n)]
+ return result
+
+
+class modify_iter(peek_iter):
+ """An iterator object that supports modifying items as they are returned.
+
+ Parameters
+ ----------
+ o : iterable or callable
+ `o` is interpreted very differently depending on the presence of
+ `sentinel`.
+
+ If `sentinel` is not given, then `o` must be a collection object
+ which supports either the iteration protocol or the sequence protocol.
+
+ If `sentinel` is given, then `o` must be a callable object.
+
+ sentinel : any value, optional
+ If given, the iterator will call `o` with no arguments for each
+ call to its `next` method; if the value returned is equal to
+ `sentinel`, :exc:`StopIteration` will be raised, otherwise the
+ value will be returned.
+
+ modifier : callable, optional
+ The function that will be used to modify each item returned by the
+ iterator. `modifier` should take a single argument and return a
+ single value. Defaults to ``lambda x: x``.
+
+ If `sentinel` is not given, `modifier` must be passed as a keyword
+ argument.
+
+ Attributes
+ ----------
+ modifier : callable
+ `modifier` is called with each item in `o` as it is iterated. The
+ return value of `modifier` is returned in lieu of the item.
+
+ Values returned by `peek` as well as `next` are affected by
+ `modifier`. However, `modify_iter.sentinel` is never passed through
+ `modifier`; it will always be returned from `peek` unmodified.
+
+ Example
+ -------
+ >>> a = [" A list ",
+ ... " of strings ",
+ ... " with ",
+ ... " extra ",
+ ... " whitespace. "]
+ >>> modifier = lambda s: s.strip().replace('with', 'without')
+ >>> for s in modify_iter(a, modifier=modifier):
+ ... print('"%s"' % s)
+ "A list"
+ "of strings"
+ "without"
+ "extra"
+ "whitespace."
+
+ """
+ def __init__(self, *args, **kwargs):
+ """__init__(o, sentinel=None, modifier=lambda x: x)"""
+ if 'modifier' in kwargs:
+ self.modifier = kwargs['modifier']
+ elif len(args) > 2:
+ self.modifier = args[2]
+ args = args[:2]
+ else:
+ self.modifier = lambda x: x
+ if not callable(self.modifier):
+ raise TypeError('modify_iter(o, modifier): '
+ 'modifier must be callable')
+ super(modify_iter, self).__init__(*args)
+
+ def _fillcache(self, n):
+ """Cache `n` modified items. If `n` is 0 or None, 1 item is cached.
+
+ Each item returned by the iterator is passed through the
+ `modify_iter.modified` function before being cached.
+
+ """
+ if not n:
+ n = 1
+ try:
+ while len(self._cache) < n:
+ self._cache.append(self.modifier(self._iterable.next()))
+ except StopIteration:
+ while len(self._cache) < n:
+ self._cache.append(self.sentinel)
diff --git a/sphinx/ext/oldcmarkup.py b/sphinx/ext/oldcmarkup.py
deleted file mode 100644
index aa10246b..00000000
--- a/sphinx/ext/oldcmarkup.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.ext.oldcmarkup
- ~~~~~~~~~~~~~~~~~~~~~
-
- Extension for compatibility with old C markup (directives and roles).
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from docutils.parsers.rst import directives
-
-from sphinx.util.compat import Directive
-
-_warned_oldcmarkup = False
-WARNING_MSG = 'using old C markup; please migrate to new-style markup ' \
- '(e.g. c:function instead of cfunction), see ' \
- 'http://sphinx-doc.org/domains.html'
-
-
-class OldCDirective(Directive):
- has_content = True
- required_arguments = 1
- optional_arguments = 0
- final_argument_whitespace = True
- option_spec = {
- 'noindex': directives.flag,
- 'module': directives.unchanged,
- }
-
- def run(self):
- env = self.state.document.settings.env
- if not env.app._oldcmarkup_warned:
- self.state_machine.reporter.warning(WARNING_MSG, line=self.lineno)
- env.app._oldcmarkup_warned = True
- newname = 'c:' + self.name[1:]
- newdir = env.lookup_domain_element('directive', newname)[0]
- return newdir(newname, self.arguments, self.options,
- self.content, self.lineno, self.content_offset,
- self.block_text, self.state, self.state_machine).run()
-
-
-def old_crole(typ, rawtext, text, lineno, inliner, options={}, content=[]):
- env = inliner.document.settings.env
- if not typ:
- typ = env.config.default_role
- if not env.app._oldcmarkup_warned:
- inliner.reporter.warning(WARNING_MSG, line=lineno)
- env.app._oldcmarkup_warned = True
- newtyp = 'c:' + typ[1:]
- newrole = env.lookup_domain_element('role', newtyp)[0]
- return newrole(newtyp, rawtext, text, lineno, inliner, options, content)
-
-
-def setup(app):
- app._oldcmarkup_warned = False
- app.add_directive('cfunction', OldCDirective)
- app.add_directive('cmember', OldCDirective)
- app.add_directive('cmacro', OldCDirective)
- app.add_directive('ctype', OldCDirective)
- app.add_directive('cvar', OldCDirective)
- app.add_role('cdata', old_crole)
- app.add_role('cfunc', old_crole)
- app.add_role('cmacro', old_crole)
- app.add_role('ctype', old_crole)
- app.add_role('cmember', old_crole)
diff --git a/sphinx/ext/pngmath.py b/sphinx/ext/pngmath.py
index e23bbd06..c87c9a9c 100644
--- a/sphinx/ext/pngmath.py
+++ b/sphinx/ext/pngmath.py
@@ -123,7 +123,7 @@ def render_math(self, math):
try:
try:
p = Popen(ltx_args, stdout=PIPE, stderr=PIPE)
- except OSError, err:
+ except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
self.builder.warn('LaTeX command %r cannot be run (needed for math '
@@ -150,7 +150,7 @@ def render_math(self, math):
dvipng_args.append(path.join(tempdir, 'math.dvi'))
try:
p = Popen(dvipng_args, stdout=PIPE, stderr=PIPE)
- except OSError, err:
+ except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
self.builder.warn('dvipng command %r cannot be run (needed for math '
@@ -190,7 +190,7 @@ def get_tooltip(self, node):
def html_visit_math(self, node):
try:
fname, depth = render_math(self, '$'+node['latex']+'$')
- except MathExtError, exc:
+ except MathExtError as exc:
msg = unicode(exc)
sm = nodes.system_message(msg, type='WARNING', level=2,
backrefs=[], source=node['latex'])
@@ -215,7 +215,7 @@ def html_visit_displaymath(self, node):
latex = wrap_displaymath(node['latex'], None)
try:
fname, depth = render_math(self, latex)
- except MathExtError, exc:
+ except MathExtError as exc:
sm = nodes.system_message(str(exc), type='WARNING', level=2,
backrefs=[], source=node['latex'])
sm.walkabout(self)
diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py
index de5d2b9f..253ae07d 100644
--- a/sphinx/ext/todo.py
+++ b/sphinx/ext/todo.py
@@ -171,4 +171,3 @@ def setup(app):
app.connect('doctree-read', process_todos)
app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos)
-
diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py
index 2c95dec0..c30c9ef3 100644
--- a/sphinx/highlighting.py
+++ b/sphinx/highlighting.py
@@ -63,12 +63,6 @@ _LATEX_STYLES = r'''
\newcommand\PYGZcb{\char`\}}
'''
-parsing_exceptions = (SyntaxError, UnicodeEncodeError)
-if sys.version_info < (2, 5):
- # Python <= 2.4 raises MemoryError when parsing an
- # invalid encoding cookie
- parsing_exceptions += MemoryError,
-
class PygmentsBridge(object):
# Set these attributes if you want to have different Pygments formatters
@@ -131,10 +125,6 @@ class PygmentsBridge(object):
# lines beginning with "..." are probably placeholders for suite
src = re.sub(r"(?m)^(\s*)" + mark + "(.)", r"\1"+ mark + r"# \2", src)
- # if we're using 2.5, use the with statement
- if sys.version_info >= (2, 5):
- src = 'from __future__ import with_statement\n' + src
-
if sys.version_info < (3, 0) and isinstance(src, unicode):
# Non-ASCII chars will only occur in string literals
# and comments. If we wanted to give them to the parser
@@ -143,18 +133,12 @@ class PygmentsBridge(object):
# just replace all non-ASCII characters.
src = src.encode('ascii', 'replace')
- if (3, 0) <= sys.version_info < (3, 2):
- # Python 3.1 can't process '\r' as linesep.
- # `parser.suite("print('hello')\r\n")` cause error.
- if '\r\n' in src:
- src = src.replace('\r\n', '\n')
-
if parser is None:
return True
try:
parser.suite(src)
- except parsing_exceptions:
+ except (SyntaxError, UnicodeEncodeError):
return False
else:
return True
diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py
index 24de6b28..6dc29c19 100644
--- a/sphinx/make_mode.py
+++ b/sphinx/make_mode.py
@@ -14,6 +14,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import sys
@@ -68,90 +69,90 @@ class Make(object):
if not path.exists(self.builddir):
return
elif not path.isdir(self.builddir):
- print "Error: %r is not a directory!" % self.builddir
+ print("Error: %r is not a directory!" % self.builddir)
return 1
- print "Removing everything under %r..." % self.builddir
+ print("Removing everything under %r..." % self.builddir)
for item in os.listdir(self.builddir):
shutil.rmtree(self.builddir_join(item))
def build_help(self):
- print bold("Sphinx v%s" % sphinx.__version__)
- print "Please use `make %s' where %s is one of" % ((blue('target'),)*2)
+ print(bold("Sphinx v%s" % sphinx.__version__))
+ print("Please use `make %s' where %s is one of" % ((blue('target'),)*2))
for osname, bname, description in BUILDERS:
if not osname or os.name == osname:
- print ' %s %s' % (blue(bname.ljust(10)), description)
+ print(' %s %s' % (blue(bname.ljust(10)), description))
def build_html(self):
if self.run_generic_build('html') > 0:
return 1
- print
- print 'Build finished. The HTML pages are in %s.' % self.builddir_join('html')
+ print()
+ print('Build finished. The HTML pages are in %s.' % self.builddir_join('html'))
def build_dirhtml(self):
if self.run_generic_build('dirhtml') > 0:
return 1
- print
- print 'Build finished. The HTML pages are in %s.' % self.builddir_join('dirhtml')
+ print()
+ print('Build finished. The HTML pages are in %s.' % self.builddir_join('dirhtml'))
def build_singlehtml(self):
if self.run_generic_build('singlehtml') > 0:
return 1
- print
- print 'Build finished. The HTML page is in %s.' % self.builddir_join('singlehtml')
+ print()
+ print('Build finished. The HTML page is in %s.' % self.builddir_join('singlehtml'))
def build_pickle(self):
if self.run_generic_build('pickle') > 0:
return 1
- print
- print 'Build finished; now you can process the pickle files.'
+ print()
+ print('Build finished; now you can process the pickle files.')
def build_json(self):
if self.run_generic_build('json') > 0:
return 1
- print
- print 'Build finished; now you can process the JSON files.'
+ print()
+ print('Build finished; now you can process the JSON files.')
def build_htmlhelp(self):
if self.run_generic_build('htmlhelp') > 0:
return 1
- print
- print ('Build finished; now you can run HTML Help Workshop with the '
- '.hhp project file in %s.') % self.builddir_join('htmlhelp')
+ print()
+ print('Build finished; now you can run HTML Help Workshop with the '
+ '.hhp project file in %s.' % self.builddir_join('htmlhelp'))
def build_qthelp(self):
if self.run_generic_build('qthelp') > 0:
return 1
- print
- print ('Build finished; now you can run "qcollectiongenerator" with the '
- '.qhcp project file in %s, like this:') % self.builddir_join('qthelp')
- print '$ qcollectiongenerator %s.qhcp' % self.builddir_join('qthelp', proj_name)
- print 'To view the help file:'
- print '$ assistant -collectionFile %s.qhc' % self.builddir_join('qthelp', proj_name)
+ print()
+ print('Build finished; now you can run "qcollectiongenerator" with the '
+ '.qhcp project file in %s, like this:' % self.builddir_join('qthelp'))
+ print('$ qcollectiongenerator %s.qhcp' % self.builddir_join('qthelp', proj_name))
+ print('To view the help file:')
+ print('$ assistant -collectionFile %s.qhc' % self.builddir_join('qthelp', proj_name))
def build_devhelp(self):
if self.run_generic_build('devhelp') > 0:
return 1
- print
- print "Build finished."
- print "To view the help file:"
- print "$ mkdir -p $HOME/.local/share/devhelp/" + proj_name
- print "$ ln -s %s $HOME/.local/share/devhelp/%s" % \
- (self.builddir_join('devhelp'), proj_name)
- print "$ devhelp"
+ print()
+ print("Build finished.")
+ print("To view the help file:")
+ print("$ mkdir -p $HOME/.local/share/devhelp/" + proj_name)
+ print("$ ln -s %s $HOME/.local/share/devhelp/%s" %
+ (self.builddir_join('devhelp'), proj_name))
+ print("$ devhelp")
def build_epub(self):
if self.run_generic_build('epub') > 0:
return 1
- print
- print 'Build finished. The ePub file is in %s.' % self.builddir_join('epub')
+ print()
+ print('Build finished. The ePub file is in %s.' % self.builddir_join('epub'))
def build_latex(self):
if self.run_generic_build('latex') > 0:
return 1
- print "Build finished; the LaTeX files are in %s." % self.builddir_join('latex')
+ print("Build finished; the LaTeX files are in %s." % self.builddir_join('latex'))
if os.name == 'posix':
- print "Run `make' in that directory to run these through (pdf)latex"
- print "(use `make latexpdf' here to do that automatically)."
+ print("Run `make' in that directory to run these through (pdf)latex")
+ print("(use `make latexpdf' here to do that automatically).")
def build_latexpdf(self):
if self.run_generic_build('latex') > 0:
@@ -166,16 +167,16 @@ class Make(object):
def build_text(self):
if self.run_generic_build('text') > 0:
return 1
- print
- print 'Build finished. The text files are in %s.' % self.builddir_join('text')
+ print()
+ print('Build finished. The text files are in %s.' % self.builddir_join('text'))
def build_texinfo(self):
if self.run_generic_build('texinfo') > 0:
return 1
- print "Build finished; the Texinfo files are in %s." % self.builddir_join('texinfo')
+ print("Build finished; the Texinfo files are in %s." % self.builddir_join('texinfo'))
if os.name == 'posix':
- print "Run `make' in that directory to run these through makeinfo"
- print "(use `make info' here to do that automatically)."
+ print("Run `make' in that directory to run these through makeinfo")
+ print("(use `make info' here to do that automatically).")
def build_info(self):
if self.run_generic_build('texinfo') > 0:
@@ -186,47 +187,47 @@ class Make(object):
dtdir = self.builddir_join('gettext', '.doctrees')
if self.run_generic_build('gettext', doctreedir=dtdir) > 0:
return 1
- print
- print 'Build finished. The message catalogs are in %s.' % self.builddir_join('gettext')
+ print()
+ print('Build finished. The message catalogs are in %s.' % self.builddir_join('gettext'))
def build_changes(self):
if self.run_generic_build('changes') > 0:
return 1
- print
- print 'Build finished. The overview file is in %s.' % self.builddir_join('changes')
+ print()
+ print('Build finished. The overview file is in %s.' % self.builddir_join('changes'))
def build_linkcheck(self):
res = self.run_generic_build('linkcheck')
- print
- print ('Link check complete; look for any errors in the above output '
- 'or in %s.') % self.builddir_join('linkcheck', 'output.txt')
+ print()
+ print('Link check complete; look for any errors in the above output '
+ 'or in %s.' % self.builddir_join('linkcheck', 'output.txt'))
return res
def build_doctest(self):
res = self.run_generic_build('doctest')
- print ("Testing of doctests in the sources finished, look at the "
- "results in %s." % self.builddir_join('doctest', 'output.txt'))
+ print("Testing of doctests in the sources finished, look at the "
+ "results in %s." % self.builddir_join('doctest', 'output.txt'))
return res
def build_coverage(self):
if self.run_generic_build('coverage') > 0:
- print "Has the coverage extension been enabled?"
+ print("Has the coverage extension been enabled?")
return 1
- print
- print ("Testing of coverage in the sources finished, look at the "
- "results in %s." % self.builddir_join('coverage'))
+ print()
+ print("Testing of coverage in the sources finished, look at the "
+ "results in %s." % self.builddir_join('coverage'))
def build_xml(self):
if self.run_generic_build('xml') > 0:
return 1
- print
- print 'Build finished. The XML files are in %s.' % self.builddir_join('xml')
+ print()
+ print('Build finished. The XML files are in %s.' % self.builddir_join('xml'))
def build_pseudoxml(self):
if self.run_generic_build('pseudoxml') > 0:
return 1
- print
- print 'Build finished. The pseudo-XML files are in %s.' % self.builddir_join('pseudoxml')
+ print()
+ print('Build finished. The pseudo-XML files are in %s.' % self.builddir_join('pseudoxml'))
def run_generic_build(self, builder, doctreedir=None):
# compatibility with old Makefile
@@ -242,8 +243,8 @@ class Make(object):
def run_make_mode(args):
if len(args) < 3:
- print >>sys.stderr, ('Error: at least 3 arguments (builder, source '
- 'dir, build dir) are required.')
+ print('Error: at least 3 arguments (builder, source '
+ 'dir, build dir) are required.', file=sys.stderr)
return 1
make = Make(args[1], args[2], args[3:])
run_method = 'build_' + args[0]
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 2c0708f9..ca5e8b09 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys
from os import path
@@ -17,7 +18,7 @@ from sphinx.errors import PycodeError
from sphinx.pycode import nodes
from sphinx.pycode.pgen2 import driver, token, tokenize, parse, literals
from sphinx.util import get_module_source, detect_encoding
-from sphinx.util.pycompat import next, StringIO, BytesIO, TextIOWrapper
+from sphinx.util.pycompat import StringIO, BytesIO, TextIOWrapper
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc
@@ -182,7 +183,7 @@ class ModuleAnalyzer(object):
return cls.cache['file', filename]
try:
fileobj = open(filename, 'rb')
- except Exception, err:
+ except Exception as err:
raise PycodeError('error opening %r' % filename, err)
obj = cls(fileobj, modname, filename)
cls.cache['file', filename] = obj
@@ -202,7 +203,7 @@ class ModuleAnalyzer(object):
obj = cls.for_string(source, modname)
else:
obj = cls.for_file(source, modname)
- except PycodeError, err:
+ except PycodeError as err:
cls.cache['module', modname] = err
raise
cls.cache['module', modname] = obj
@@ -245,7 +246,7 @@ class ModuleAnalyzer(object):
return
try:
self.tokens = list(tokenize.generate_tokens(self.source.readline))
- except tokenize.TokenError, err:
+ except tokenize.TokenError as err:
raise PycodeError('tokenizing failed', err)
self.source.close()
@@ -256,7 +257,7 @@ class ModuleAnalyzer(object):
self.tokenize()
try:
self.parsetree = pydriver.parse_tokens(self.tokens)
- except parse.ParseError, err:
+ except parse.ParseError as err:
raise PycodeError('parsing failed', err)
def find_attr_docs(self, scope=''):
@@ -344,4 +345,4 @@ if __name__ == '__main__':
pprint.pprint(ma.find_tags())
x3 = time.time()
#print nodes.nice_repr(ma.parsetree, number2name)
- print "tokenizing %.4f, parsing %.4f, finding %.4f" % (x1-x0, x2-x1, x3-x2)
+ print("tokenizing %.4f, parsing %.4f, finding %.4f" % (x1-x0, x2-x1, x3-x2))
diff --git a/sphinx/pycode/pgen2/driver.py b/sphinx/pycode/pgen2/driver.py
index 422671db..c531edb3 100644
--- a/sphinx/pycode/pgen2/driver.py
+++ b/sphinx/pycode/pgen2/driver.py
@@ -131,7 +131,7 @@ def load_grammar(gt="Grammar.txt", gp=None,
logger.info("Writing grammar tables to %s", gp)
try:
g.dump(gp)
- except IOError, e:
+ except IOError as e:
logger.info("Writing failed:"+str(e))
else:
g = grammar.Grammar()
diff --git a/sphinx/pycode/pgen2/grammar.py b/sphinx/pycode/pgen2/grammar.py
index 01d84346..91874fa2 100644
--- a/sphinx/pycode/pgen2/grammar.py
+++ b/sphinx/pycode/pgen2/grammar.py
@@ -11,6 +11,7 @@ token module; the Python tokenize module reports all operators as the
fallback token code OP, but the parser needs the actual token code.
"""
+from __future__ import print_function
# Python imports
import pickle
@@ -100,17 +101,17 @@ class Grammar(object):
def report(self):
"""Dump the grammar tables to standard output, for debugging."""
from pprint import pprint
- print "s2n"
+ print("s2n")
pprint(self.symbol2number)
- print "n2s"
+ print("n2s")
pprint(self.number2symbol)
- print "states"
+ print("states")
pprint(self.states)
- print "dfas"
+ print("dfas")
pprint(self.dfas)
- print "labels"
+ print("labels")
pprint(self.labels)
- print "start", self.start
+ print("start", self.start)
# Map from operator to number (since tokenize doesn't do this)
diff --git a/sphinx/pycode/pgen2/literals.py b/sphinx/pycode/pgen2/literals.py
index d4893702..ce4a0ebc 100644
--- a/sphinx/pycode/pgen2/literals.py
+++ b/sphinx/pycode/pgen2/literals.py
@@ -4,6 +4,7 @@
# Extended to handle raw and unicode literals by Georg Brandl.
"""Safely evaluate Python string literals without using eval()."""
+from __future__ import print_function
import re
@@ -89,7 +90,7 @@ def test():
s = repr(c)
e = evalString(s)
if e != c:
- print i, c, s, e
+ print(i, c, s, e)
if __name__ == "__main__":
diff --git a/sphinx/pycode/pgen2/parse.c b/sphinx/pycode/pgen2/parse.c
index e09f5058..96fa6c8b 100644
--- a/sphinx/pycode/pgen2/parse.c
+++ b/sphinx/pycode/pgen2/parse.c
@@ -353,95 +353,6 @@ static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[], PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args, const char* function_name); /*proto*/
-#if PY_VERSION_HEX < 0x02050000
-#ifndef PyAnySet_CheckExact
-
-#define PyAnySet_CheckExact(ob) \
- ((ob)->ob_type == &PySet_Type || \
- (ob)->ob_type == &PyFrozenSet_Type)
-
-#define PySet_New(iterable) \
- PyObject_CallFunctionObjArgs((PyObject *)&PySet_Type, (iterable), NULL)
-
-#define Pyx_PyFrozenSet_New(iterable) \
- PyObject_CallFunctionObjArgs((PyObject *)&PyFrozenSet_Type, (iterable), NULL)
-
-#define PySet_Size(anyset) \
- PyObject_Size((anyset))
-
-#define PySet_Contains(anyset, key) \
- PySequence_Contains((anyset), (key))
-
-#define PySet_Pop(set) \
- PyObject_CallMethod(set, (char *)"pop", NULL)
-
-static INLINE int PySet_Clear(PyObject *set) {
- PyObject *ret = PyObject_CallMethod(set, (char *)"clear", NULL);
- if (!ret) return -1;
- Py_DECREF(ret); return 0;
-}
-
-static INLINE int PySet_Discard(PyObject *set, PyObject *key) {
- PyObject *ret = PyObject_CallMethod(set, (char *)"discard", (char *)"O", key);
- if (!ret) return -1;
- Py_DECREF(ret); return 0;
-}
-
-static INLINE int PySet_Add(PyObject *set, PyObject *key) {
- PyObject *ret = PyObject_CallMethod(set, (char *)"add", (char *)"O", key);
- if (!ret) return -1;
- Py_DECREF(ret); return 0;
-}
-
-#endif /* PyAnySet_CheckExact (<= Py2.4) */
-
-#if PY_VERSION_HEX < 0x02040000
-#ifndef Py_SETOBJECT_H
-#define Py_SETOBJECT_H
-
-static PyTypeObject *__Pyx_PySet_Type = NULL;
-static PyTypeObject *__Pyx_PyFrozenSet_Type = NULL;
-
-#define PySet_Type (*__Pyx_PySet_Type)
-#define PyFrozenSet_Type (*__Pyx_PyFrozenSet_Type)
-
-#define PyAnySet_Check(ob) \
- (PyAnySet_CheckExact(ob) || \
- PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
- PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
-
-#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
-
-static int __Pyx_Py23SetsImport(void) {
- PyObject *sets=0, *Set=0, *ImmutableSet=0;
-
- sets = PyImport_ImportModule((char *)"sets");
- if (!sets) goto bad;
- Set = PyObject_GetAttrString(sets, (char *)"Set");
- if (!Set) goto bad;
- ImmutableSet = PyObject_GetAttrString(sets, (char *)"ImmutableSet");
- if (!ImmutableSet) goto bad;
- Py_DECREF(sets);
-
- __Pyx_PySet_Type = (PyTypeObject*) Set;
- __Pyx_PyFrozenSet_Type = (PyTypeObject*) ImmutableSet;
-
- return 0;
-
- bad:
- Py_XDECREF(sets);
- Py_XDECREF(Set);
- Py_XDECREF(ImmutableSet);
- return -1;
-}
-
-#else
-static int __Pyx_Py23SetsImport(void) { return 0; }
-#endif /* !Py_SETOBJECT_H */
-#endif /* < Py2.4 */
-#endif /* < Py2.5 */
-
-
static INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
PyObject *r;
if (!j) return NULL;
diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py
index 0a04447d..ab990cef 100644
--- a/sphinx/pycode/pgen2/pgen.py
+++ b/sphinx/pycode/pgen2/pgen.py
@@ -1,7 +1,10 @@
# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.
+from __future__ import print_function
+
# Pgen imports
+
from sphinx.pycode.pgen2 import grammar, token, tokenize
class PgenGrammar(grammar.Grammar):
@@ -203,10 +206,10 @@ class ParserGenerator(object):
return states # List of DFAState instances; first one is start
def dump_nfa(self, name, start, finish):
- print "Dump of NFA for", name
+ print("Dump of NFA for", name)
todo = [start]
for i, state in enumerate(todo):
- print " State", i, state is finish and "(final)" or ""
+ print(" State", i, state is finish and "(final)" or "")
for label, next in state.arcs:
if next in todo:
j = todo.index(next)
@@ -214,16 +217,16 @@ class ParserGenerator(object):
j = len(todo)
todo.append(next)
if label is None:
- print " -> %d" % j
+ print(" -> %d" % j)
else:
- print " %s -> %d" % (label, j)
+ print(" %s -> %d" % (label, j))
def dump_dfa(self, name, dfa):
- print "Dump of DFA for", name
+ print("Dump of DFA for", name)
for i, state in enumerate(dfa):
- print " State", i, state.isfinal and "(final)" or ""
+ print(" State", i, state.isfinal and "(final)" or "")
for label, next in state.arcs.iteritems():
- print " %s -> %d" % (label, dfa.index(next))
+ print(" %s -> %d" % (label, dfa.index(next)))
def simplify_dfa(self, dfa):
# This is not theoretically optimal, but works well enough.
diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py
index 7ad9f012..4e94fa5c 100644
--- a/sphinx/pycode/pgen2/tokenize.py
+++ b/sphinx/pycode/pgen2/tokenize.py
@@ -23,7 +23,10 @@ Older entry points
tokenize(readline, tokeneater=printtoken)
are the same, except instead of generating tokens, tokeneater is a callback
function to which the 5 fields described above are passed as 5 arguments,
-each time a new token is found."""
+each time a new token is found.
+"""
+
+from __future__ import print_function
__author__ = 'Ka-Ping Yee <ping@lfw.org>'
__credits__ = \
@@ -146,8 +149,8 @@ class StopTokenizing(Exception): pass
def printtoken(type, token, scell, ecell, line): # for testing
srow, scol = scell
erow, ecol = ecell
- print "%d,%d-%d,%d:\t%s\t%s" % \
- (srow, scol, erow, ecol, tok_name[type], repr(token))
+ print("%d,%d-%d,%d:\t%s\t%s" %
+ (srow, scol, erow, ecol, tok_name[type], repr(token)))
def tokenize(readline, tokeneater=printtoken):
"""
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
index d9449f74..a57006fd 100644
--- a/sphinx/quickstart.py
+++ b/sphinx/quickstart.py
@@ -8,9 +8,11 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys, os, time, re
from os import path
+from io import open
TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
@@ -21,7 +23,6 @@ from sphinx.util.osutil import make_filename
from sphinx.util.console import purple, bold, red, turquoise, \
nocolor, color_terminal
from sphinx.util import texescape
-from sphinx.util.pycompat import open
# function to get input from terminal -- overridden by the test suite
try:
@@ -99,7 +100,10 @@ release = '%(release_str)s'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = %(language)r
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@@ -320,7 +324,7 @@ epub_copyright = u'%(copyright_str)s'
#epub_theme = 'epub'
# The language of the text. It defaults to the language option
-# or en if the language is not set.
+# or 'en' if the language is not set.
#epub_language = ''
# The scheme of the identifier. Typical schemes are ISBN or URL.
@@ -962,9 +966,9 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
if TERM_ENCODING:
prompt = prompt.encode(TERM_ENCODING)
else:
- print turquoise('* Note: non-ASCII default value provided '
+ print(turquoise('* Note: non-ASCII default value provided '
'and terminal encoding unknown -- assuming '
- 'UTF-8 or Latin-1.')
+ 'UTF-8 or Latin-1.'))
try:
prompt = prompt.encode('utf-8')
except UnicodeEncodeError:
@@ -979,17 +983,17 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
if TERM_ENCODING:
x = x.decode(TERM_ENCODING)
else:
- print turquoise('* Note: non-ASCII characters entered '
+ print(turquoise('* Note: non-ASCII characters entered '
'and terminal encoding unknown -- assuming '
- 'UTF-8 or Latin-1.')
+ 'UTF-8 or Latin-1.'))
try:
x = x.decode('utf-8')
except UnicodeDecodeError:
x = x.decode('latin1')
try:
x = validator(x)
- except ValidationError, err:
- print red('* ' + str(err))
+ except ValidationError as err:
+ print(red('* ' + str(err)))
continue
break
d[key] = x
@@ -1018,6 +1022,7 @@ def ask_user(d):
* author: author names
* version: version of project
* release: release of project
+ * language: document language
* suffix: source file suffix
* master: master document name
* epub: use epub (bool)
@@ -1026,98 +1031,110 @@ def ask_user(d):
* batchfile: make command file
"""
- print bold('Welcome to the Sphinx %s quickstart utility.') % __version__
- print '''
+ print(bold('Welcome to the Sphinx %s quickstart utility.') % __version__)
+ print('''
Please enter values for the following settings (just press Enter to
-accept a default value, if one is given in brackets).'''
+accept a default value, if one is given in brackets).''')
if 'path' in d:
- print bold('''
-Selected root path: %s''' % d['path'])
+ print(bold('''
+Selected root path: %s''' % d['path']))
else:
- print '''
-Enter the root path for documentation.'''
+ print('''
+Enter the root path for documentation.''')
do_prompt(d, 'path', 'Root path for the documentation', '.', is_path)
while path.isfile(path.join(d['path'], 'conf.py')) or \
path.isfile(path.join(d['path'], 'source', 'conf.py')):
- print
- print bold('Error: an existing conf.py has been found in the '
- 'selected root path.')
- print 'sphinx-quickstart will not overwrite existing Sphinx projects.'
- print
+ print()
+ print(bold('Error: an existing conf.py has been found in the '
+ 'selected root path.'))
+ print('sphinx-quickstart will not overwrite existing Sphinx projects.')
+ print()
do_prompt(d, 'path', 'Please enter a new root path (or just Enter '
'to exit)', '', is_path)
if not d['path']:
sys.exit(1)
if 'sep' not in d:
- print '''
+ print('''
You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
-"source" and "build" directories within the root path.'''
+"source" and "build" directories within the root path.''')
do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n',
boolean)
if 'dot' not in d:
- print '''
+ print('''
Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
-files. You can enter another prefix (such as ".") to replace the underscore.'''
+files. You can enter another prefix (such as ".") to replace the underscore.''')
do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_', ok)
if 'project' not in d:
- print '''
-The project name will occur in several places in the built documentation.'''
+ print('''
+The project name will occur in several places in the built documentation.''')
do_prompt(d, 'project', 'Project name')
if 'author' not in d:
do_prompt(d, 'author', 'Author name(s)')
if 'version' not in d:
- print '''
+ print('''
Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1. If you don't need this dual structure,
-just set both to the same value.'''
+just set both to the same value.''')
do_prompt(d, 'version', 'Project version')
if 'release' not in d:
do_prompt(d, 'release', 'Project release', d['version'])
+ if 'language' not in d:
+ print('''
+If the documents are to be written in a language other than English,
+you can select a language here by its language code. Sphinx will then
+translate text that it generates into that language.
+
+For a list of supported codes, see
+http://sphinx-doc.org/config.html#confval-language.''')
+ do_prompt(d, 'language', 'Project language', 'en')
+ if d['language'] == 'en':
+ d['language'] = None
+
if 'suffix' not in d:
- print '''
+ print('''
The file name suffix for source files. Commonly, this is either ".txt"
-or ".rst". Only files with this suffix are considered documents.'''
+or ".rst". Only files with this suffix are considered documents.''')
do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix)
if 'master' not in d:
- print '''
+ print('''
One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
-document is a custom template, you can also set this to another filename.'''
+document is a custom template, you can also set this to another filename.''')
do_prompt(d, 'master', 'Name of your master document (without suffix)',
'index')
while path.isfile(path.join(d['path'], d['master']+d['suffix'])) or \
path.isfile(path.join(d['path'], 'source', d['master']+d['suffix'])):
- print
- print bold('Error: the master file %s has already been found in the '
- 'selected root path.' % (d['master']+d['suffix']))
- print 'sphinx-quickstart will not overwrite the existing file.'
- print
+ print()
+ print(bold('Error: the master file %s has already been found in the '
+ 'selected root path.' % (d['master']+d['suffix'])))
+ print('sphinx-quickstart will not overwrite the existing file.')
+ print()
do_prompt(d, 'master', 'Please enter a new file name, or rename the '
'existing file and press Enter', d['master'])
if 'epub' not in d:
- print '''
-Sphinx can also add configuration for epub output:'''
+ print('''
+Sphinx can also add configuration for epub output:''')
do_prompt(d, 'epub', 'Do you want to use the epub builder (y/n)',
'n', boolean)
if 'ext_autodoc' not in d:
- print '''
-Please indicate if you want to use one of the following Sphinx extensions:'''
+ print('''
+Please indicate if you want to use one of the following Sphinx extensions:''')
do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
'from modules (y/n)', 'n', boolean)
if 'ext_doctest' not in d:
@@ -1139,8 +1156,8 @@ Please indicate if you want to use one of the following Sphinx extensions:'''
do_prompt(d, 'ext_mathjax', 'mathjax: include math, rendered in the '
'browser by MathJax (y/n)', 'n', boolean)
if d['ext_pngmath'] and d['ext_mathjax']:
- print '''Note: pngmath and mathjax cannot be enabled at the same time.
-pngmath has been deselected.'''
+ print('''Note: pngmath and mathjax cannot be enabled at the same time.
+pngmath has been deselected.''')
if 'ext_ifconfig' not in d:
do_prompt(d, 'ext_ifconfig', 'ifconfig: conditional inclusion of '
'content based on config values (y/n)', 'n', boolean)
@@ -1149,15 +1166,15 @@ pngmath has been deselected.'''
'code of documented Python objects (y/n)', 'n', boolean)
if 'makefile' not in d:
- print '''
+ print('''
A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
-directly.'''
+directly.''')
do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean)
if 'batchfile' not in d:
do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)',
'y', boolean)
- print
+ print()
def generate(d, overwrite=True, silent=False):
@@ -1216,14 +1233,14 @@ def generate(d, overwrite=True, silent=False):
def write_file(fpath, content, newline=None):
if overwrite or not path.isfile(fpath):
- print 'Creating file %s.' % fpath
+ print('Creating file %s.' % fpath)
f = open(fpath, 'wt', encoding='utf-8', newline=newline)
try:
f.write(content)
finally:
f.close()
else:
- print 'File %s already exists, skipping.' % fpath
+ print('File %s already exists, skipping.' % fpath)
conf_text = QUICKSTART_CONF % d
if d['epub']:
@@ -1249,9 +1266,9 @@ def generate(d, overwrite=True, silent=False):
if silent:
return
- print
- print bold('Finished: An initial directory structure has been created.')
- print '''
+ print()
+ print(bold('Finished: An initial directory structure has been created.'))
+ print('''
You should now populate your master file %s and create other documentation
source files. ''' % masterfile + ((d['makefile'] or d['batchfile']) and '''\
Use the Makefile to build the docs, like so:
@@ -1261,7 +1278,7 @@ Use the sphinx-build command to build the docs, like so:
sphinx-build -b builder %s %s
''' % (srcdir, builddir)) + '''\
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.
-'''
+''')
def main(argv=sys.argv):
@@ -1270,14 +1287,14 @@ def main(argv=sys.argv):
d = {}
if len(argv) > 3:
- print 'Usage: sphinx-quickstart [root]'
+ print('Usage: sphinx-quickstart [root]')
sys.exit(1)
elif len(argv) == 2:
d['path'] = argv[1]
try:
ask_user(d)
except (KeyboardInterrupt, EOFError):
- print
- print '[Interrupted.]'
+ print()
+ print('[Interrupted.]')
return
generate(d)
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 6703b6b8..3b858588 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -22,15 +22,15 @@ from sphinx.util.nodes import split_explicit_title, process_index_entry, \
generic_docroles = {
- 'command' : nodes.strong,
+ 'command' : addnodes.literal_strong,
'dfn' : nodes.emphasis,
'kbd' : nodes.literal,
'mailheader' : addnodes.literal_emphasis,
- 'makevar' : nodes.strong,
+ 'makevar' : addnodes.literal_strong,
'manpage' : addnodes.literal_emphasis,
'mimetype' : addnodes.literal_emphasis,
'newsgroup' : addnodes.literal_emphasis,
- 'program' : nodes.strong, # XXX should be an x-ref
+ 'program' : addnodes.literal_strong, # XXX should be an x-ref
'regexp' : nodes.literal,
}
diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py
index f7ca7a9d..88cbc5a0 100644
--- a/sphinx/setup_command.py
+++ b/sphinx/setup_command.py
@@ -11,6 +11,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys
import os
@@ -159,12 +160,12 @@ class BuildDoc(Command):
try:
app.build(force_all=self.all_files)
- except Exception, err:
+ except Exception as err:
from docutils.utils import SystemMessage
if isinstance(err, SystemMessage):
- print >>sys.stderr, darkred('reST markup error:')
- print >>sys.stderr, err.args[0].encode('ascii',
- 'backslashreplace')
+ print(darkred('reST markup error:'), file=sys.stderr)
+ print(err.args[0].encode('ascii', 'backslashreplace'),
+ file=sys.stderr)
else:
raise
diff --git a/sphinx/texinputs/Makefile b/sphinx/texinputs/Makefile
index 6b87ad88..5e6030c0 100644
--- a/sphinx/texinputs/Makefile
+++ b/sphinx/texinputs/Makefile
@@ -9,6 +9,10 @@ ARCHIVEPRREFIX =
# Additional LaTeX options
LATEXOPTS =
+LATEX = latex
+PDFLATEX = pdflatex
+MAKEINDEX = makeindex
+
all: $(ALLPDF)
all-pdf: $(ALLPDF)
all-dvi: $(ALLDVI)
@@ -43,20 +47,20 @@ bz2: tar
# The number of LaTeX runs is quite conservative, but I don't expect it
# to get run often, so the little extra time won't hurt.
%.dvi: %.tex
- latex $(LATEXOPTS) '$<'
- latex $(LATEXOPTS) '$<'
- latex $(LATEXOPTS) '$<'
- -makeindex -s python.ist '$(basename $<).idx'
- latex $(LATEXOPTS) '$<'
- latex $(LATEXOPTS) '$<'
+ $(LATEX) $(LATEXOPTS) '$<'
+ $(LATEX) $(LATEXOPTS) '$<'
+ $(LATEX) $(LATEXOPTS) '$<'
+ -$(MAKEINDEX) -s python.ist '$(basename $<).idx'
+ $(LATEX) $(LATEXOPTS) '$<'
+ $(LATEX) $(LATEXOPTS) '$<'
%.pdf: %.tex
- pdflatex $(LATEXOPTS) '$<'
- pdflatex $(LATEXOPTS) '$<'
- pdflatex $(LATEXOPTS) '$<'
- -makeindex -s python.ist '$(basename $<).idx'
- pdflatex $(LATEXOPTS) '$<'
- pdflatex $(LATEXOPTS) '$<'
+ $(PDFLATEX) $(LATEXOPTS) '$<'
+ $(PDFLATEX) $(LATEXOPTS) '$<'
+ $(PDFLATEX) $(LATEXOPTS) '$<'
+ -$(MAKEINDEX) -s python.ist '$(basename $<).idx'
+ $(PDFLATEX) $(LATEXOPTS) '$<'
+ $(PDFLATEX) $(LATEXOPTS) '$<'
clean:
rm -f *.dvi *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla
diff --git a/sphinx/themes/agogo/layout.html b/sphinx/themes/agogo/layout.html
index fde19dbc..f2ddb217 100644
--- a/sphinx/themes/agogo/layout.html
+++ b/sphinx/themes/agogo/layout.html
@@ -11,7 +11,7 @@
{%- extends "basic/layout.html" %}
{% block header %}
- <div class="header-wrapper">
+ <div class="header-wrapper" role="banner">
<div class="header">
{%- if logo %}
<p class="logo"><a href="{{ pathto(master_doc) }}">
@@ -22,7 +22,7 @@
<div class="headertitle"><a
href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a></div>
{%- endblock %}
- <div class="rel">
+ <div class="rel" role="navigation" aria-label="related navigation">
{%- for rellink in rellinks|reverse %}
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
@@ -47,16 +47,18 @@
{{ toctree() }}
{%- endblock %}
{%- block sidebarsearch %}
- <h3 style="margin-top: 1.5em;">{{ _('Search') }}</h3>
- <form class="search" action="{{ pathto('search') }}" method="get">
- <input type="text" name="q" />
- <input type="submit" value="{{ _('Go') }}" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- <p class="searchtip" style="font-size: 90%">
- {{ _('Enter search terms or a module, class or function name.') }}
- </p>
+ <div role="search">
+ <h3 style="margin-top: 1.5em;">{{ _('Search') }}</h3>
+ <form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" />
+ <input type="submit" value="{{ _('Go') }}" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ {{ _('Enter search terms or a module, class or function name.') }}
+ </p>
+ </div>
{%- endblock %}
</div>
<div class="clearer"></div>
@@ -68,16 +70,20 @@
<div class="footer-wrapper">
<div class="footer">
<div class="left">
- {%- for rellink in rellinks|reverse %}
- <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
- {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
- {%- if not loop.last %}{{ reldelim2 }}{% endif %}
- {%- endfor %}
- {%- if show_source and has_source and sourcename %}
- <br/>
- <a href="{{ pathto('_sources/' + sourcename, true)|e }}"
- rel="nofollow">{{ _('Show Source') }}</a>
- {%- endif %}
+ <div role="navigation" aria-label="related navigaton">
+ {%- for rellink in rellinks|reverse %}
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
+ {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+ {%- if not loop.last %}{{ reldelim2 }}{% endif %}
+ {%- endfor %}
+ </div>
+ <div role="note" aria-label="source link">
+ {%- if show_source and has_source and sourcename %}
+ <br/>
+ <a href="{{ pathto('_sources/' + sourcename, true)|e }}"
+ rel="nofollow">{{ _('Show Source') }}</a>
+ {%- endif %}
+ </div>
</div>
<div class="right">
diff --git a/sphinx/themes/agogo/static/agogo.css_t b/sphinx/themes/agogo/static/agogo.css_t
index 3fb81178..8646e2dd 100644
--- a/sphinx/themes/agogo/static/agogo.css_t
+++ b/sphinx/themes/agogo/static/agogo.css_t
@@ -223,6 +223,10 @@ div.document .descname {
font-weight: bold;
}
+div.document .sig-paren {
+ font-size: larger;
+}
+
div.document .docutils.literal {
background-color: #eeeeec;
padding: 1px;
@@ -462,3 +466,10 @@ div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
+
+div.code-block-filename {
+ background-color: #ddd;
+ color: #333;
+ padding: 2px 5px;
+ font-size: small;
+}
diff --git a/sphinx/themes/basic/layout.html b/sphinx/themes/basic/layout.html
index 9e4e39a1..68a070b3 100644
--- a/sphinx/themes/basic/layout.html
+++ b/sphinx/themes/basic/layout.html
@@ -25,7 +25,7 @@
{%- endif %}
{%- macro relbar() %}
- <div class="related">
+ <div class="related" role="navigation" aria-label="related navigation">
<h3>{{ _('Navigation') }}</h3>
<ul>
{%- for rellink in rellinks %}
@@ -47,7 +47,7 @@
{%- macro sidebar() %}
{%- if render_sidebar %}
- <div class="sphinxsidebar">
+ <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
{%- block sidebarlogo %}
{%- if logo %}
@@ -152,7 +152,7 @@
{%- endblock %}
{%- block extrahead %} {% endblock %}
</head>
- <body>
+ <body role="document">
{%- block header %}{% endblock %}
{%- block relbar1 %}{{ relbar() }}{% endblock %}
@@ -166,7 +166,7 @@
{%- if render_sidebar %}
<div class="bodywrapper">
{%- endif %}
- <div class="body">
+ <div class="body" role="main">
{% block body %} {% endblock %}
</div>
{%- if render_sidebar %}
@@ -183,7 +183,7 @@
{%- block relbar2 %}{{ relbar() }}{% endblock %}
{%- block footer %}
- <div class="footer">
+ <div class="footer" role="contentinfo">
{%- if show_copyright %}
{%- if hasdoc('copyright') %}
{% trans path=pathto('copyright'), copyright=copyright|e %}&copy; <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html
index 1495701a..420e0121 100644
--- a/sphinx/themes/basic/searchbox.html
+++ b/sphinx/themes/basic/searchbox.html
@@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
#}
{%- if pagename != "search" and builder != "singlehtml" %}
-<div id="searchbox" style="display: none">
+<div id="searchbox" style="display: none" role="search">
<h3>{{ _('Quick search') }}</h3>
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" />
diff --git a/sphinx/themes/basic/sourcelink.html b/sphinx/themes/basic/sourcelink.html
index 08232efc..fbbae064 100644
--- a/sphinx/themes/basic/sourcelink.html
+++ b/sphinx/themes/basic/sourcelink.html
@@ -8,9 +8,11 @@
:license: BSD, see LICENSE for details.
#}
{%- if show_source and has_source and sourcename %}
- <h3>{{ _('This Page') }}</h3>
- <ul class="this-page-menu">
- <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
- rel="nofollow">{{ _('Show Source') }}</a></li>
- </ul>
+ <div role="note" aria-label="source link">
+ <h3>{{ _('This Page') }}</h3>
+ <ul class="this-page-menu">
+ <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
+ rel="nofollow">{{ _('Show Source') }}</a></li>
+ </ul>
+ </div>
{%- endif %}
diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t
index d54e7f4e..907ede7a 100644
--- a/sphinx/themes/basic/static/basic.css_t
+++ b/sphinx/themes/basic/static/basic.css_t
@@ -406,6 +406,10 @@ dl.glossary dt {
font-size: 1.3em;
}
+.sig-paren {
+ font-size: larger;
+}
+
.versionmodified {
font-style: italic;
}
@@ -471,6 +475,20 @@ table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
+div.code-block-filename {
+ padding: 2px 5px;
+ font-size: small;
+}
+
+div.code-block-filename tt {
+ background-color: transparent;
+}
+
+div.code-block-filename + pre,
+div.code-block-filename + div.highlight > pre {
+ margin-top: 0;
+}
+
tt.descname {
background-color: transparent;
font-weight: bold;
diff --git a/sphinx/themes/default/static/default.css_t b/sphinx/themes/default/static/default.css_t
index 5db77108..cdc1b782 100644
--- a/sphinx/themes/default/static/default.css_t
+++ b/sphinx/themes/default/static/default.css_t
@@ -308,3 +308,8 @@ div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
+
+div.code-block-filename {
+ color: #efefef;
+ background-color: #1c4e63;
+}
diff --git a/sphinx/themes/epub/static/epub.css b/sphinx/themes/epub/static/epub.css
index 6c8ff5e7..eec7a147 100644
--- a/sphinx/themes/epub/static/epub.css
+++ b/sphinx/themes/epub/static/epub.css
@@ -322,6 +322,10 @@ dl.glossary dt {
font-size: 130%;
}
+.sig-paren {
+ font-size: larger;
+}
+
.versionmodified {
font-style: italic;
}
diff --git a/sphinx/themes/haiku/layout.html b/sphinx/themes/haiku/layout.html
index 0c6b41e7..a98d89c6 100644
--- a/sphinx/themes/haiku/layout.html
+++ b/sphinx/themes/haiku/layout.html
@@ -32,7 +32,7 @@
{% endmacro %}
{% block content %}
- <div class="header">
+ <div class="header" role="banner">
{%- block haikuheader %}
{%- if theme_full_logo != "false" %}
<a href="{{ pathto('index') }}">
@@ -48,7 +48,7 @@
{%- endif %}
{%- endblock %}
</div>
- <div class="topnav">
+ <div class="topnav" role="navigation" aria-label="top navigation">
{{ nav() }}
</div>
<div class="content">
@@ -60,7 +60,7 @@
{%- endif %}#}
{% block body %}{% endblock %}
</div>
- <div class="bottomnav">
+ <div class="bottomnav" role="navigation" aria-label="bottom navigation">
{{ nav() }}
</div>
{% endblock %}
diff --git a/sphinx/themes/nature/static/nature.css_t b/sphinx/themes/nature/static/nature.css_t
index 3c492034..e4f4d2ed 100644
--- a/sphinx/themes/nature/static/nature.css_t
+++ b/sphinx/themes/nature/static/nature.css_t
@@ -243,3 +243,9 @@ div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
+
+div.code-block-filename {
+ background-color: #ddd;
+ color: #222;
+ border: 1px solid #C6C9CB;
+}
diff --git a/sphinx/themes/pyramid/layout.html b/sphinx/themes/pyramid/layout.html
index 8780ceae..318a3662 100644
--- a/sphinx/themes/pyramid/layout.html
+++ b/sphinx/themes/pyramid/layout.html
@@ -10,7 +10,7 @@
{% block header %}
{%- if logo %}
-<div class="header">
+<div class="header" role="banner">
<div class="logo">
<a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
diff --git a/sphinx/themes/pyramid/static/pyramid.css_t b/sphinx/themes/pyramid/static/pyramid.css_t
index c4e94908..c724a493 100644
--- a/sphinx/themes/pyramid/static/pyramid.css_t
+++ b/sphinx/themes/pyramid/static/pyramid.css_t
@@ -340,3 +340,8 @@ tt.xref {
font-weight: normal;
font-style: normal;
}
+
+div.code-block-filename {
+ background-color: #ddd;
+ color: #222;
+}
diff --git a/sphinx/themes/scrolls/layout.html b/sphinx/themes/scrolls/layout.html
index 48e5e4e4..0961808e 100644
--- a/sphinx/themes/scrolls/layout.html
+++ b/sphinx/themes/scrolls/layout.html
@@ -20,7 +20,7 @@
<h1 class="heading"><a href="{{ pathto('index') }}"
title="back to the documentation overview"><span>{{ title|striptags|e }}</span></a></h1>
</div>
- <div class="relnav">
+ <div class="relnav" role="navigation" aria-label="related navigation">
{%- if prev %}
<a href="{{ prev.link|e }}">&laquo; {{ prev.title }}</a> |
{%- endif %}
@@ -31,7 +31,7 @@
</div>
<div id="contentwrapper">
{%- if display_toc %}
- <div id="toc">
+ <div id="toc" role="navigation" aria-label="table of contents navigation">
<h3>{{ _('Table Of Contents') }}</h3>
{{ toc }}
</div>
diff --git a/sphinx/themes/scrolls/static/scrolls.css_t b/sphinx/themes/scrolls/static/scrolls.css_t
index c335f167..a2d3a7c2 100644
--- a/sphinx/themes/scrolls/static/scrolls.css_t
+++ b/sphinx/themes/scrolls/static/scrolls.css_t
@@ -305,6 +305,10 @@ dt .descname {
margin-right: 4px;
}
+dt .sig-paren {
+ font-size: larger;
+}
+
dt .descname, dt .descclassname {
padding: 0;
background: transparent;
diff --git a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t
index af498257..1d7c5796 100644
--- a/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t
+++ b/sphinx/themes/sphinxdoc/static/sphinxdoc.css_t
@@ -337,3 +337,9 @@ div.viewcode-block:target {
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
+
+div.code-block-filename {
+ background-color: #ddd;
+ color: #222;
+ border: 1px solid #ccc;
+}
diff --git a/sphinx/themes/traditional/static/traditional.css_t b/sphinx/themes/traditional/static/traditional.css_t
index fff411ef..10fbb2d1 100644
--- a/sphinx/themes/traditional/static/traditional.css_t
+++ b/sphinx/themes/traditional/static/traditional.css_t
@@ -659,6 +659,10 @@ h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
font-size: 1.3em;
}
+.sig-paren {
+ font-size: larger;
+}
+
.versionmodified {
font-style: italic;
}
@@ -698,3 +702,7 @@ div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
+
+div.code-block-filename {
+ background-color: #cceeff;
+}
diff --git a/sphinx/transforms.py b/sphinx/transforms.py
index 64310d7f..9b920eb9 100644
--- a/sphinx/transforms.py
+++ b/sphinx/transforms.py
@@ -23,7 +23,6 @@ from sphinx.util import split_index_msg
from sphinx.util.nodes import traverse_translatable_index, extract_messages
from sphinx.util.osutil import ustrftime, find_catalog
from sphinx.util.compat import docutils_version
-from sphinx.util.pycompat import all
from sphinx.domains.std import (
make_term_from_paragraph_node,
make_termnodes_from_paragraph_node,
@@ -70,7 +69,7 @@ class MoveModuleTargets(Transform):
for node in self.document.traverse(nodes.target):
if not node['ids']:
continue
- if (node.has_key('ismod') and
+ if ('ismod' in node and
node.parent.__class__ is nodes.section and
# index 0 is the section title node
node.parent.index(node) == 1):
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index 0fd4d49b..d0104f5d 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -208,7 +208,7 @@ def get_module_source(modname):
if modname not in sys.modules:
try:
__import__(modname)
- except Exception, err:
+ except Exception as err:
raise PycodeError('error importing %r' % modname, err)
mod = sys.modules[modname]
filename = getattr(mod, '__file__', None)
@@ -216,12 +216,12 @@ def get_module_source(modname):
if loader and getattr(loader, 'get_filename', None):
try:
filename = loader.get_filename(modname)
- except Exception, err:
+ except Exception as err:
raise PycodeError('error getting filename for %r' % filename, err)
if filename is None and loader:
try:
return 'string', loader.get_source(modname)
- except Exception, err:
+ except Exception as err:
raise PycodeError('error getting source for %r' % modname, err)
if filename is None:
raise PycodeError('no source found for module %r' % modname)
diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py
index 6fd8ba95..3050942a 100644
--- a/sphinx/util/docfields.py
+++ b/sphinx/util/docfields.py
@@ -99,7 +99,8 @@ class GroupedField(Field):
return Field.make_field(self, types, domain, items[0])
for fieldarg, content in items:
par = nodes.paragraph()
- par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
+ par += self.make_xref(self.rolename, domain, fieldarg,
+ addnodes.literal_strong)
par += nodes.Text(' -- ')
par += content
listnode += nodes.list_item('', par)
@@ -137,7 +138,8 @@ class TypedField(GroupedField):
def make_field(self, types, domain, items):
def handle_item(fieldarg, content):
par = nodes.paragraph()
- par += self.make_xref(self.rolename, domain, fieldarg, nodes.strong)
+ par += self.make_xref(self.rolename, domain, fieldarg,
+ addnodes.literal_strong)
if fieldarg in types:
par += nodes.Text(' (')
# NOTE: using .pop() here to prevent a single type node to be
@@ -238,10 +240,8 @@ class DocFieldTransformer(object):
if is_typefield:
# filter out only inline nodes; others will result in invalid
# markup being written out
- content = filter(
- lambda n: isinstance(n, nodes.Inline) or
- isinstance(n, nodes.Text),
- content)
+ content = [n for n in content if isinstance(n, nodes.Inline) or
+ isinstance(n, nodes.Text)]
if content:
types.setdefault(typename, {})[fieldarg] = content
continue
diff --git a/sphinx/util/docstrings.py b/sphinx/util/docstrings.py
index d45b938d..97303bd7 100644
--- a/sphinx/util/docstrings.py
+++ b/sphinx/util/docstrings.py
@@ -23,7 +23,7 @@ def prepare_docstring(s, ignore=1):
"""
lines = s.expandtabs().splitlines()
# Find minimum indentation of any non-blank lines after ignored lines.
- margin = sys.maxint
+ margin = sys.maxsize
for line in lines[ignore:]:
content = len(line.lstrip())
if content:
@@ -33,7 +33,7 @@ def prepare_docstring(s, ignore=1):
for i in range(ignore):
if i < len(lines):
lines[i] = lines[i].lstrip()
- if margin < sys.maxint:
+ if margin < sys.maxsize:
for i in range(ignore, len(lines)): lines[i] = lines[i][margin:]
# Remove any leading blank lines.
while lines and not lines[0]:
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index 61061a9a..d835bc41 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -55,12 +55,12 @@ if sys.version_info >= (3, 0):
raise TypeError('%r is not a Python function' % func)
return inspect.getfullargspec(func)
-elif sys.version_info >= (2, 5):
+else: # 2.6, 2.7
from functools import partial
def getargspec(func):
"""Like inspect.getargspec but supports functools.partial as well."""
if inspect.ismethod(func):
- func = func.im_func
+ func = func.__func__
parts = 0, ()
if type(func) is partial:
keywords = func.keywords
@@ -70,8 +70,8 @@ elif sys.version_info >= (2, 5):
func = func.func
if not inspect.isfunction(func):
raise TypeError('%r is not a Python function' % func)
- args, varargs, varkw = inspect.getargs(func.func_code)
- func_defaults = func.func_defaults
+ args, varargs, varkw = inspect.getargs(func.__code__)
+ func_defaults = func.__defaults__
if func_defaults is None:
func_defaults = []
else:
@@ -86,12 +86,7 @@ elif sys.version_info >= (2, 5):
del func_defaults[i]
except IndexError:
pass
- if sys.version_info >= (2, 6):
- return inspect.ArgSpec(args, varargs, varkw, func_defaults)
- else:
- return (args, varargs, varkw, func_defaults)
-else:
- getargspec = inspect.getargspec
+ return inspect.ArgSpec(args, varargs, varkw, func_defaults)
def isdescriptor(x):
diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py
index aa0ea825..de846b24 100644
--- a/sphinx/util/jsonimpl.py
+++ b/sphinx/util/jsonimpl.py
@@ -10,27 +10,15 @@
"""
import UserString
+import json
-try:
- import json
- # json-py's json module has no JSONEncoder; this will raise AttributeError
- # if json-py is imported instead of the built-in json module
- JSONEncoder = json.JSONEncoder
-except (ImportError, AttributeError):
- try:
- import simplejson as json
- JSONEncoder = json.JSONEncoder
- except ImportError:
- json = None
- JSONEncoder = object
-
-
-class SphinxJSONEncoder(JSONEncoder):
+
+class SphinxJSONEncoder(json.JSONEncoder):
"""JSONEncoder subclass that forces translation proxies."""
def default(self, obj):
if isinstance(obj, UserString.UserString):
return unicode(obj)
- return JSONEncoder.default(self, obj)
+ return json.JSONEncoder.default(self, obj)
def dump(obj, fp, *args, **kwds):
diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py
index b4c71076..61059c7c 100644
--- a/sphinx/util/matching.py
+++ b/sphinx/util/matching.py
@@ -77,4 +77,4 @@ def patfilter(names, pat):
if pat not in _pat_cache:
_pat_cache[pat] = re.compile(_translate_pattern(pat))
match = _pat_cache[pat].match
- return filter(match, names)
+ return list(filter(match, names))
diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py
index 87717771..a0b669f1 100644
--- a/sphinx/util/osutil.py
+++ b/sphinx/util/osutil.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import re
@@ -63,12 +64,15 @@ def ensuredir(path):
"""Ensure that a path exists."""
try:
os.makedirs(path)
- except OSError, err:
+ except OSError as err:
# 0 for Jython/Win32
if err.errno not in [0, EEXIST]:
raise
+# This function is same as os.walk of Python2.6, 2.7, 3.2, 3.3 except a
+# customization that check UnicodeError.
+# The customization obstacle to replace the function with the os.walk.
def walk(top, topdown=True, followlinks=False):
"""Backport of os.walk from 2.6, where the *followlinks* argument was
added.
@@ -80,9 +84,9 @@ def walk(top, topdown=True, followlinks=False):
try:
fullpath = path.join(top, name)
except UnicodeError:
- print >>sys.stderr, (
- '%s:: ERROR: non-ASCII filename not supported on this '
- 'filesystem encoding %r, skipped.' % (name, fs_encoding))
+ print('%s:: ERROR: non-ASCII filename not supported on this '
+ 'filesystem encoding %r, skipped.' % (name, fs_encoding),
+ file=sys.stderr)
continue
if path.isdir(fullpath):
dirs.append(name)
@@ -155,9 +159,8 @@ else:
def safe_relpath(path, start=None):
- from sphinx.util.pycompat import relpath
try:
- return relpath(path, start)
+ return os.path.relpath(path, start)
except ValueError:
return path
@@ -171,14 +174,13 @@ def find_catalog(docname, compaction):
def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
- from sphinx.util.pycompat import relpath
if not(lang and locale_dirs):
return []
domain = find_catalog(docname, compaction)
files = [gettext.find(domain, path.join(srcdir, dir_), [lang])
for dir_ in locale_dirs]
- files = [relpath(f, srcdir) for f in files if f]
+ files = [path.relpath(f, srcdir) for f in files if f]
return files
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index 1e5ea314..4c9ef18d 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -11,7 +11,6 @@
import sys
import codecs
-import encodings
# ------------------------------------------------------------------------------
# Python 2/3 compatibility
@@ -42,12 +41,13 @@ if sys.version_info >= (3, 0):
source = refactoring_tool._read_python_source(filepath)[0]
try:
tree = refactoring_tool.refactor_string(source, 'conf.py')
- except ParseError, err:
+ except ParseError as err:
# do not propagate lib2to3 exceptions
lineno, offset = err.context[1]
# try to match ParseError details with SyntaxError details
raise SyntaxError(err.msg, (filepath, lineno, offset, err.value))
return unicode(tree)
+ from itertools import zip_longest # Python 3 name
else:
# Python 2
@@ -69,6 +69,8 @@ else:
# error handler
import locale
sys_encoding = locale.getpreferredencoding()
+ # use Python 3 name
+ from itertools import izip_longest as zip_longest
def execfile_(filepath, _globals):
@@ -81,8 +83,8 @@ def execfile_(filepath, _globals):
finally:
f.close()
- # py25,py26,py31 accept only LF eol instead of CRLF
- if sys.version_info[:2] in ((2, 5), (2, 6), (3, 1)):
+ # py26 accept only LF eol instead of CRLF
+ if sys.version_info[:2] == (2, 6):
source = source.replace(b('\r\n'), b('\n'))
# compile to a code object, handle syntax errors
@@ -100,178 +102,7 @@ def execfile_(filepath, _globals):
exec code in _globals
-try:
- from html import escape as htmlescape
-except ImportError:
+if sys.version_info >= (3, 2):
+ from html import escape as htmlescape # >= Python 3.2
+else: # 2.6, 2.7, 3.1
from cgi import escape as htmlescape
-
-# ------------------------------------------------------------------------------
-# Missing builtins and itertools in Python < 2.6
-
-if sys.version_info >= (2, 6):
- # Python >= 2.6
- next = next
-
- from itertools import product
- try:
- from itertools import zip_longest # Python 3 name
- except ImportError:
- from itertools import izip_longest as zip_longest
-
- import os
- relpath = os.path.relpath
- del os
-
- import io
- open = io.open
-
-else:
- # Python < 2.6
- from itertools import izip, repeat, chain
-
- # this is on Python 2, where the method is called "next" (it is refactored
- # to __next__ by 2to3, but in that case never executed)
- def next(iterator):
- return iterator.next()
-
- # These replacement functions have been taken from the Python 2.6
- # itertools documentation.
- def product(*args, **kwargs):
- pools = map(tuple, args) * kwargs.get('repeat', 1)
- result = [[]]
- for pool in pools:
- result = [x + [y] for x in result for y in pool]
- for prod in result:
- yield tuple(prod)
-
- def zip_longest(*args, **kwds):
- # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
- fillvalue = kwds.get('fillvalue')
- def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
- yield counter() # yields the fillvalue, or raises IndexError
- fillers = repeat(fillvalue)
- iters = [chain(it, sentinel(), fillers) for it in args]
- try:
- for tup in izip(*iters):
- yield tup
- except IndexError:
- pass
-
- from os.path import curdir
- def relpath(path, start=curdir):
- """Return a relative version of a path"""
- from os.path import sep, abspath, commonprefix, join, pardir
-
- if not path:
- raise ValueError("no path specified")
-
- start_list = abspath(start).split(sep)
- path_list = abspath(path).split(sep)
-
- # Work out how much of the filepath is shared by start and path.
- i = len(commonprefix([start_list, path_list]))
-
- rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
- if not rel_list:
- return start
- return join(*rel_list)
- del curdir
-
- from types import MethodType
- def open(filename, mode='r', *args, **kw):
- newline = kw.pop('newline', None)
- mode = mode.replace('t', '')
- f = codecs.open(filename, mode, *args, **kw)
- if newline is not None:
- f._write = f.write
- def write(self, text):
- text = text.replace(u'\r\n', u'\n').replace(u'\n', newline)
- self._write(text)
- f.write = MethodType(write, f)
- return f
-
-
-# ------------------------------------------------------------------------------
-# Missing builtins and codecs in Python < 2.5
-
-if sys.version_info >= (2, 5):
- # Python >= 2.5
- base_exception = BaseException
- any = any
- all = all
-
-else:
- # Python 2.4
- base_exception = Exception
-
- def all(gen):
- for i in gen:
- if not i:
- return False
- return True
-
- def any(gen):
- for i in gen:
- if i:
- return True
- return False
-
- # Python 2.4 doesn't know the utf-8-sig encoding, so deliver it here
-
- def my_search_function(encoding):
- norm_encoding = encodings.normalize_encoding(encoding)
- if norm_encoding != 'utf_8_sig':
- return None
- return (encode, decode, StreamReader, StreamWriter)
-
- codecs.register(my_search_function)
-
- # begin code copied from utf_8_sig.py in Python 2.6
-
- def encode(input, errors='strict'):
- return (codecs.BOM_UTF8 +
- codecs.utf_8_encode(input, errors)[0], len(input))
-
- def decode(input, errors='strict'):
- prefix = 0
- if input[:3] == codecs.BOM_UTF8:
- input = input[3:]
- prefix = 3
- (output, consumed) = codecs.utf_8_decode(input, errors, True)
- return (output, consumed+prefix)
-
- class StreamWriter(codecs.StreamWriter):
- def reset(self):
- codecs.StreamWriter.reset(self)
- try:
- del self.encode
- except AttributeError:
- pass
-
- def encode(self, input, errors='strict'):
- self.encode = codecs.utf_8_encode
- return encode(input, errors)
-
- class StreamReader(codecs.StreamReader):
- def reset(self):
- codecs.StreamReader.reset(self)
- try:
- del self.decode
- except AttributeError:
- pass
-
- def decode(self, input, errors='strict'):
- if len(input) < 3:
- if codecs.BOM_UTF8.startswith(input):
- # not enough data to decide if this is a BOM
- # => try again on the next call
- return (u"", 0)
- elif input[:3] == codecs.BOM_UTF8:
- self.decode = codecs.utf_8_decode
- (output, consumed) = codecs.utf_8_decode(input[3:],errors)
- return (output, consumed+3)
- # (else) no BOM present
- self.decode = codecs.utf_8_decode
- return codecs.utf_8_decode(input, errors)
-
- # end code copied from utf_8_sig.py
diff --git a/sphinx/versioning.py b/sphinx/versioning.py
index a16751bb..ccab41d4 100644
--- a/sphinx/versioning.py
+++ b/sphinx/versioning.py
@@ -11,8 +11,9 @@
"""
from uuid import uuid4
from operator import itemgetter
+from itertools import product
-from sphinx.util.pycompat import product, zip_longest, all
+from sphinx.util.pycompat import zip_longest
# anything below that ratio is considered equal/changed
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index cc6da583..ecd02a73 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -70,7 +70,7 @@ class HTMLTranslator(BaseTranslator):
self.no_smarty = 0
self.builder = builder
self.highlightlang = builder.config.highlight_language
- self.highlightlinenothreshold = sys.maxint
+ self.highlightlinenothreshold = sys.maxsize
self.protect_literal_text = 0
self.permalink_text = builder.config.html_add_permalinks
# support backwards-compatible setting to a bool
@@ -130,7 +130,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append('</tt>')
def visit_desc_parameterlist(self, node):
- self.body.append('<big>(</big>')
+ self.body.append('<span class="sig-paren">(</span>')
self.first_param = 1
self.optional_param_level = 0
# How many required parameters are left.
@@ -138,7 +138,7 @@ class HTMLTranslator(BaseTranslator):
for c in node.children])
self.param_separator = node.child_text_separator
def depart_desc_parameterlist(self, node):
- self.body.append('<big>)</big>')
+ self.body.append('<span class="sig-paren">)</span>')
# If required parameters are still to come, then put the comma after
# the parameter. Otherwise, put the comma before. This ensures that
@@ -261,11 +261,11 @@ class HTMLTranslator(BaseTranslator):
linenos = node.rawsource.count('\n') >= \
self.highlightlinenothreshold - 1
highlight_args = node.get('highlight_args', {})
- if node.has_key('language'):
+ if 'language' in node:
# code-block directives
lang = node['language']
highlight_args['force'] = True
- if node.has_key('linenos'):
+ if 'linenos' in node:
linenos = node['linenos']
def warner(msg):
self.builder.warn(msg, (self.builder.current_docname, node.line))
@@ -274,6 +274,9 @@ class HTMLTranslator(BaseTranslator):
**highlight_args)
starttag = self.starttag(node, 'div', suffix='',
CLASS='highlight-%s' % lang)
+ if 'filename' in node:
+ starttag += '<div class="code-block-filename"><tt>%s</tt></div>' % (
+ node['filename'],)
self.body.append(starttag + highlighted + '</div>\n')
raise nodes.SkipNode
@@ -371,13 +374,13 @@ class HTMLTranslator(BaseTranslator):
if node['uri'].lower().endswith('svg') or \
node['uri'].lower().endswith('svgz'):
atts = {'src': node['uri']}
- if node.has_key('width'):
+ if 'width' in node:
atts['width'] = node['width']
- if node.has_key('height'):
+ if 'height' in node:
atts['height'] = node['height']
- if node.has_key('alt'):
+ if 'alt' in node:
atts['alt'] = node['alt']
- if node.has_key('align'):
+ if 'align' in node:
self.body.append('<div align="%s" class="align-%s">' %
(node['align'], node['align']))
self.context.append('</div>\n')
@@ -386,21 +389,21 @@ class HTMLTranslator(BaseTranslator):
self.body.append(self.emptytag(node, 'img', '', **atts))
return
- if node.has_key('scale'):
+ if 'scale' in node:
# Try to figure out image height and width. Docutils does that too,
# but it tries the final file name, which does not necessarily exist
# yet at the time the HTML file is written.
- if Image and not (node.has_key('width')
- and node.has_key('height')):
+ if Image and not ('width' in node
+ and 'height' in node):
try:
im = Image.open(os.path.join(self.builder.srcdir, olduri))
except (IOError, # Source image can't be found or opened
UnicodeError): # PIL doesn't like Unicode paths.
pass
else:
- if not node.has_key('width'):
+ if 'width' not in node:
node['width'] = str(im.size[0])
- if not node.has_key('height'):
+ if 'height' not in node:
node['height'] = str(im.size[1])
del im
BaseTranslator.visit_image(self, node)
@@ -515,6 +518,11 @@ class HTMLTranslator(BaseTranslator):
def depart_literal_emphasis(self, node):
return self.depart_emphasis(node)
+ def visit_literal_strong(self, node):
+ return self.visit_strong(node)
+ def depart_literal_strong(self, node):
+ return self.depart_strong(node)
+
def visit_abbreviation(self, node):
attrs = {}
if node.hasattr('explanation'):
@@ -625,6 +633,14 @@ class SmartyPantsHTMLTranslator(HTMLTranslator):
self.depart_emphasis(node)
self.no_smarty -= 1
+ def visit_literal_strong(self, node):
+ self.no_smarty += 1
+ self.visit_strong(node)
+
+ def depart_literal_strong(self, node):
+ self.depart_strong(node)
+ self.no_smarty -= 1
+
def visit_desc_signature(self, node):
self.no_smarty += 1
HTMLTranslator.visit_desc_signature(self, node)
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 3c1a50f8..1c915431 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -25,7 +25,6 @@ from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _
from sphinx.util import split_into
from sphinx.util.osutil import ustrftime
-from sphinx.util.pycompat import any
from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educate_quotes_latex
@@ -249,7 +248,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# the second item is the default for the master file and can be changed
# by .. highlight:: directive in the master file
self.hlsettingstack = 2 * [[builder.config.highlight_language,
- sys.maxint]]
+ sys.maxsize]]
self.footnotestack = []
self.curfilestack = []
self.handled_abbrs = set()
@@ -1153,7 +1152,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
else:
self.builder.warn(
'unknown index entry type %s found' % type)
- except ValueError, err:
+ except ValueError as err:
self.builder.warn(str(err))
raise nodes.SkipNode
@@ -1247,6 +1246,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_strong(self, node):
self.body.append('}')
+ def visit_literal_strong(self, node):
+ self.body.append(r'\textbf{\texttt{')
+ self.no_contractions += 1
+ def depart_literal_strong(self, node):
+ self.body.append('}}')
+ self.no_contractions -= 1
+
def visit_abbreviation(self, node):
abbr = node.astext()
self.body.append(r'\textsc{')
@@ -1331,6 +1337,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
highlight_args['force'] = True
if 'linenos' in node:
linenos = node['linenos']
+ filename = node.get('filename')
+ if filename:
+ self.body.append('\n{\\colorbox[rgb]{0.9,0.9,0.9}'
+ '{\\makebox[\\textwidth][l]'
+ '{\\small\\texttt{%s}}}}\n' % (filename,))
def warner(msg):
self.builder.warn(msg, (self.curfilestack[-1], node.line))
hlcode = self.highlighter.highlight_block(code, lang, warn=warner,
diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py
index bc4da17a..0aa0058c 100644
--- a/sphinx/writers/manpage.py
+++ b/sphinx/writers/manpage.py
@@ -304,6 +304,11 @@ class ManualPageTranslator(BaseTranslator):
def depart_literal_emphasis(self, node):
return self.depart_emphasis(node)
+ def visit_literal_strong(self, node):
+ return self.visit_strong(node)
+ def depart_literal_strong(self, node):
+ return self.depart_strong(node)
+
def visit_abbreviation(self, node):
pass
def depart_abbreviation(self, node):
diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py
index 7b70485a..e5d19127 100644
--- a/sphinx/writers/texinfo.py
+++ b/sphinx/writers/texinfo.py
@@ -655,7 +655,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
def visit_reference(self, node):
# an xref's target is displayed in Info so we ignore a few
# cases for the sake of appearance
- if isinstance(node.parent, (nodes.title, addnodes.desc_type,)):
+ if isinstance(node.parent, (nodes.title, addnodes.desc_type)):
return
if isinstance(node[0], nodes.image):
return
@@ -1207,6 +1207,11 @@ class TexinfoTranslator(nodes.NodeVisitor):
def depart_literal_emphasis(self, node):
self.body.append('}')
+ def visit_literal_strong(self, node):
+ self.body.append('@code{')
+ def depart_literal_strong(self, node):
+ self.body.append('}')
+
def visit_index(self, node):
# terminate the line but don't prevent paragraph breaks
if isinstance(node.parent, nodes.paragraph):
diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py
index 57a40b29..3efeac97 100644
--- a/sphinx/writers/text.py
+++ b/sphinx/writers/text.py
@@ -459,7 +459,7 @@ class TextTranslator(nodes.NodeVisitor):
pass
def visit_entry(self, node):
- if node.has_key('morerows') or node.has_key('morecols'):
+ if 'morerows' in node or 'morecols' in node:
raise NotImplementedError('Column or row spanning cells are '
'not implemented.')
self.new_state(0)
@@ -762,6 +762,11 @@ class TextTranslator(nodes.NodeVisitor):
def depart_strong(self, node):
self.add_text('**')
+ def visit_literal_strong(self, node):
+ self.add_text('**')
+ def depart_literal_strong(self, node):
+ self.add_text('**')
+
def visit_abbreviation(self, node):
self.add_text('')
def depart_abbreviation(self, node):
diff --git a/tests/coverage.py b/tests/coverage.py
index 95f6f844..95063b67 100755
--- a/tests/coverage.py
+++ b/tests/coverage.py
@@ -52,7 +52,9 @@ coverage.py -a [-d dir] [-o dir1,dir2,...] FILE1 FILE2 ...
e.g. python coverage.py -i -r -o c:\python23,lib\enthought\traits
Coverage data is saved in the file .coverage by default. Set the
-COVERAGE_FILE environment variable to save it somewhere else."""
+COVERAGE_FILE environment variable to save it somewhere else.
+"""
+from __future__ import print_function
__version__ = "2.85.20080914" # see detailed history at the end of this file.
@@ -64,6 +66,7 @@ import re
import string
import symbol
import sys
+import atexit
import threading
import token
import types
@@ -187,9 +190,9 @@ class StatementFindingAstVisitor(compiler.visitor.ASTVisitor):
return 0
# If this line is excluded, or suite_spots maps this line to
# another line that is exlcuded, then we're excluded.
- elif self.excluded.has_key(lineno) or \
- self.suite_spots.has_key(lineno) and \
- self.excluded.has_key(self.suite_spots[lineno][1]):
+ elif lineno in self.excluded or \
+ lineno in self.suite_spots and \
+ self.suite_spots[lineno][1] in self.excluded:
return 0
# Otherwise, this is an executable line.
else:
@@ -218,8 +221,8 @@ class StatementFindingAstVisitor(compiler.visitor.ASTVisitor):
lastprev = self.getLastLine(prevsuite)
firstelse = self.getFirstLine(suite)
for l in range(lastprev+1, firstelse):
- if self.suite_spots.has_key(l):
- self.doSuite(None, suite, exclude=self.excluded.has_key(l))
+ if l in self.suite_spots:
+ self.doSuite(None, suite, exclude=l in self.excluded)
break
else:
self.doSuite(None, suite)
@@ -328,9 +331,9 @@ class coverage:
def help(self, error=None): #pragma: no cover
if error:
- print error
- print
- print __doc__
+ print(error)
+ print()
+ print(__doc__)
sys.exit(1)
def command_line(self, argv, help_fn=None):
@@ -354,9 +357,9 @@ class coverage:
long_opts = optmap.values()
options, args = getopt.getopt(argv, short_opts, long_opts)
for o, a in options:
- if optmap.has_key(o):
+ if o in optmap:
settings[optmap[o]] = 1
- elif optmap.has_key(o + ':'):
+ elif o + ':' in optmap:
settings[optmap[o + ':']] = a
elif o[2:] in long_opts:
settings[o[2:]] = 1
@@ -398,7 +401,7 @@ class coverage:
self.start()
import __main__
sys.path[0] = os.path.dirname(sys.argv[0])
- execfile(sys.argv[0], __main__.__dict__)
+ exec(compile(open(sys.argv[0]).read(), sys.argv[0], 'exec'), __main__.__dict__)
if settings.get('collect'):
self.collect()
if not args:
@@ -493,7 +496,7 @@ class coverage:
import marshal
cexecuted = marshal.load(cache)
cache.close()
- if isinstance(cexecuted, types.DictType):
+ if isinstance(cexecuted, dict):
return cexecuted
else:
return {}
@@ -514,14 +517,14 @@ class coverage:
def merge_data(self, new_data):
for file_name, file_data in new_data.items():
- if self.cexecuted.has_key(file_name):
+ if file_name in self.cexecuted:
self.merge_file_data(self.cexecuted[file_name], file_data)
else:
self.cexecuted[file_name] = file_data
def merge_file_data(self, cache_data, new_data):
for line_number in new_data.keys():
- if not cache_data.has_key(line_number):
+ if line_number not in cache_data:
cache_data[line_number] = new_data[line_number]
def abs_file(self, filename):
@@ -554,7 +557,7 @@ class coverage:
# normalized case). See [GDR 2001-12-04b, 3.3].
def canonical_filename(self, filename):
- if not self.canonical_filename_cache.has_key(filename):
+ if filename not in self.canonical_filename_cache:
f = filename
if os.path.isabs(f) and not os.path.exists(f):
if not self.get_zip_data(f):
@@ -578,7 +581,7 @@ class coverage:
# Can't do anything useful with exec'd strings, so skip them.
continue
f = self.canonical_filename(filename)
- if not self.cexecuted.has_key(f):
+ if f not in self.cexecuted:
self.cexecuted[f] = {}
self.cexecuted[f][lineno] = 1
self.c = {}
@@ -601,7 +604,7 @@ class coverage:
# statements that cross lines.
def analyze_morf(self, morf):
- if self.analysis_cache.has_key(morf):
+ if morf in self.analysis_cache:
return self.analysis_cache[morf]
filename = self.morf_filename(morf)
ext = os.path.splitext(filename)[1]
@@ -621,7 +624,7 @@ class coverage:
lines, excluded_lines, line_map = self.find_executable_statements(
source, exclude=self.exclude_re
)
- except SyntaxError, synerr:
+ except SyntaxError as synerr:
raise CoverageException(
"Couldn't parse '%s' as Python source: '%s' at line %d" %
(filename, synerr.msg, synerr.lineno)
@@ -792,13 +795,13 @@ class coverage:
def analysis2(self, morf):
filename, statements, excluded, line_map = self.analyze_morf(morf)
self.canonicalize_filenames()
- if not self.cexecuted.has_key(filename):
+ if filename not in self.cexecuted:
self.cexecuted[filename] = {}
missing = []
for line in statements:
lines = line_map.get(line, [line, line])
for l in range(lines[0], lines[1]+1):
- if self.cexecuted[filename].has_key(l):
+ if l in self.cexecuted[filename]:
break
else:
missing.append(line)
@@ -837,7 +840,7 @@ class coverage:
def report(self, morfs, show_missing=1, ignore_errors=0, file=None,
omit_prefixes=[]):
- if not isinstance(morfs, types.ListType):
+ if not isinstance(morfs, list):
morfs = [morfs]
# On windows, the shell doesn't expand wildcards. Do it here.
globbed = []
@@ -861,8 +864,8 @@ class coverage:
fmt_coverage = fmt_coverage + " %s"
if not file:
file = sys.stdout
- print >>file, header
- print >>file, "-" * len(header)
+ print(header, file=file)
+ print("-" * len(header), file=file)
total_statements = 0
total_executed = 0
for morf in morfs:
@@ -878,7 +881,7 @@ class coverage:
args = (name, n, m, pc)
if show_missing:
args = args + (readable,)
- print >>file, fmt_coverage % args
+ print(fmt_coverage % args, file=file)
total_statements = total_statements + n
total_executed = total_executed + m
except KeyboardInterrupt: #pragma: no cover
@@ -886,9 +889,9 @@ class coverage:
except:
if not ignore_errors:
typ, msg = sys.exc_info()[:2]
- print >>file, fmt_err % (name, typ, msg)
+ print(fmt_err % (name, typ, msg), file=file)
if len(morfs) > 1:
- print >>file, "-" * len(header)
+ print("-" * len(header), file=file)
if total_statements > 0:
pc = 100.0 * total_executed / total_statements
else:
@@ -896,7 +899,7 @@ class coverage:
args = ("TOTAL", total_statements, total_executed, pc)
if show_missing:
args = args + ("",)
- print >>file, fmt_coverage % args
+ print(fmt_coverage % args, file=file)
# annotate(morfs, ignore_errors).
@@ -1006,14 +1009,7 @@ def annotate(*args, **kw):
def annotate_file(*args, **kw):
return the_coverage.annotate_file(*args, **kw)
-# Save coverage data when Python exits. (The atexit module wasn't
-# introduced until Python 2.0, so use sys.exitfunc when it's not
-# available.)
-try:
- import atexit
- atexit.register(the_coverage.save)
-except ImportError:
- sys.exitfunc = the_coverage.save
+atexit.register(the_coverage.save)
def main():
the_coverage.command_line(sys.argv[1:])
diff --git a/tests/etree13/ElementTree.py b/tests/etree13/ElementTree.py
index f459c7f8..892b08a0 100644
--- a/tests/etree13/ElementTree.py
+++ b/tests/etree13/ElementTree.py
@@ -79,6 +79,7 @@
# --------------------------------------------------------------------
from __future__ import generators
+from __future__ import absolute_import
__all__ = [
# public symbols
@@ -144,7 +145,7 @@ class _SimpleElementPath(object):
return result
try:
- import ElementPath
+ from . import ElementPath
except ImportError:
# FIXME: issue warning in this case?
ElementPath = _SimpleElementPath()
@@ -1524,7 +1525,7 @@ class XMLParser(object):
def feed(self, data):
try:
self._parser.Parse(data, 0)
- except self._error, v:
+ except self._error as v:
self._raiseerror(v)
##
@@ -1536,7 +1537,7 @@ class XMLParser(object):
def close(self):
try:
self._parser.Parse("", 1) # end of data
- except self._error, v:
+ except self._error as v:
self._raiseerror(v)
tree = self.target.close()
del self.target, self._parser # get rid of circular references
diff --git a/tests/etree13/HTMLTreeBuilder.py b/tests/etree13/HTMLTreeBuilder.py
index 4c5a24f6..3e3a7d92 100644
--- a/tests/etree13/HTMLTreeBuilder.py
+++ b/tests/etree13/HTMLTreeBuilder.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
#
# ElementTree
# $Id$
@@ -53,7 +54,7 @@ import htmlentitydefs
import re, string, sys
import mimetools, StringIO
-import ElementTree
+from . import ElementTree
AUTOCLOSE = "p", "li", "tr", "th", "td", "head", "body"
IGNOREEND = "img", "hr", "meta", "link", "br"
diff --git a/tests/path.py b/tests/path.py
index fa478557..159a8038 100755
--- a/tests/path.py
+++ b/tests/path.py
@@ -178,7 +178,7 @@ class path(unicode):
"""
return os.path.lexists(self)
- def makedirs(self, mode=0777):
+ def makedirs(self, mode=0o777):
"""
Recursively create directories.
"""
diff --git a/tests/root/autodoc.txt b/tests/root/autodoc.txt
index d4b3404c..aa0dffba 100644
--- a/tests/root/autodoc.txt
+++ b/tests/root/autodoc.txt
@@ -45,3 +45,5 @@ Just testing a few autodoc possibilities...
:members: ca1, ia1
Specific members (2 total)
+
+.. automodule:: autodoc_missing_imports
diff --git a/tests/root/autodoc_missing_imports.py b/tests/root/autodoc_missing_imports.py
new file mode 100644
index 00000000..7a717345
--- /dev/null
+++ b/tests/root/autodoc_missing_imports.py
@@ -0,0 +1,9 @@
+
+import missing_module
+from missing_module import missing_name
+import missing_package1.missing_module1
+from missing_package2 import missing_module2
+from missing_package3.missing_module3 import missing_name
+
+class TestAutodoc(object):
+ """TestAutodoc docstring."""
diff --git a/tests/root/conf.py b/tests/root/conf.py
index 8025ba33..f0d40148 100644
--- a/tests/root/conf.py
+++ b/tests/root/conf.py
@@ -8,7 +8,7 @@ sys.path.append(os.path.abspath('..'))
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath', 'sphinx.ext.todo',
'sphinx.ext.coverage', 'sphinx.ext.autosummary',
'sphinx.ext.doctest', 'sphinx.ext.extlinks',
- 'sphinx.ext.viewcode', 'sphinx.ext.oldcmarkup', 'ext']
+ 'sphinx.ext.viewcode', 'ext']
jsmath_path = 'dummy.js'
@@ -23,7 +23,6 @@ copyright = '2010, Georg Brandl & Team'
version = '0.6'
release = '0.6alpha1'
today_fmt = '%B %d, %Y'
-# unused_docs = []
exclude_patterns = ['_build', '**/excluded.*']
keep_warnings = True
pygments_style = 'sphinx'
@@ -71,6 +70,13 @@ autosummary_generate = ['autosummary']
extlinks = {'issue': ('http://bugs.python.org/issue%s', 'issue '),
'pyurl': ('http://python.org/%s', None)}
+autodoc_mock_imports = [
+ 'missing_module',
+ 'missing_package1.missing_module1',
+ 'missing_package2.missing_module2',
+ 'missing_package3.missing_module3',
+]
+
# modify tags from conf.py
tags.add('confpytag')
diff --git a/tests/root/includes.txt b/tests/root/includes.txt
index 904f0677..08917811 100644
--- a/tests/root/includes.txt
+++ b/tests/root/includes.txt
@@ -40,6 +40,7 @@ Literalinclude options
.. cssclass:: inc-lines
.. literalinclude:: literal.inc
:lines: 6-7,9
+ :lineno-start: 6
.. cssclass:: inc-startend
.. literalinclude:: literal.inc
diff --git a/tests/root/objects.txt b/tests/root/objects.txt
index 57e82212..73661d22 100644
--- a/tests/root/objects.txt
+++ b/tests/root/objects.txt
@@ -101,6 +101,7 @@ Referring to :func:`nothing <>`.
:type hour: DuplicateType
:param hour: Duplicate param. Should not lead to crashes.
:type hour: DuplicateType
+ :param .Cls extcls: A class from another module.
C items
@@ -117,14 +118,6 @@ C items
.. c:var:: sphinx_global
-Old C items (from oldcmarkup ext)
----------------------------------
-
-.. cfunction:: Sphinx_Func()
-
-Refer to :cfunc:`Sphinx_Func`.
-
-
Javascript items
================
diff --git a/tests/root/special/code.py b/tests/root/special/code.py
index 70c48d2e..b7934b23 100644
--- a/tests/root/special/code.py
+++ b/tests/root/special/code.py
@@ -1,2 +1,2 @@
-print "line 1"
-print "line 2"
+print("line 1")
+print("line 2")
diff --git a/tests/run.py b/tests/run.py
index 37a06698..7fafc7c9 100755
--- a/tests/run.py
+++ b/tests/run.py
@@ -9,6 +9,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys
from os import path, chdir, listdir, environ
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index 3a80e7fc..3d30d0dd 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -767,12 +767,8 @@ def _funky_classmethod(name, b, c, d, docstring=None):
some arguments."""
def template(cls, a, b, c, d=4, e=5, f=6):
return a, b, c, d, e, f
- if sys.version_info >= (2, 5):
- from functools import partial
- function = partial(template, b=b, c=c, d=d)
- else:
- def function(cls, a, e=5, f=6):
- return template(a, b, c, d, e, f)
+ from functools import partial
+ function = partial(template, b=b, c=c, d=d)
function.__name__ = name
function.__doc__ = docstring
return classmethod(function)
@@ -804,10 +800,9 @@ class Class(Base):
#: should be documented -- süß
attr = 'bar'
+ @property
def prop(self):
"""Property."""
- # stay 2.4 compatible (docstring!)
- prop = property(prop, doc="Property.")
docattr = 'baz'
"""should likewise be documented -- süß"""
diff --git a/tests/test_build_gettext.py b/tests/test_build_gettext.py
index ca0ff0d2..4062d982 100644
--- a/tests/test_build_gettext.py
+++ b/tests/test_build_gettext.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import gettext
import os
@@ -63,8 +64,8 @@ def test_gettext(app):
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
- print stdout
- print stderr
+ print(stdout)
+ print(stderr)
assert False, 'msginit exited with return code %s' % \
p.returncode
assert (app.outdir / 'en_US.po').isfile(), 'msginit failed'
@@ -77,8 +78,8 @@ def test_gettext(app):
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
- print stdout
- print stderr
+ print(stdout)
+ print(stderr)
assert False, 'msgfmt exited with return code %s' % \
p.returncode
assert (app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo').isfile(), \
@@ -106,7 +107,7 @@ def test_gettext_index_entries(app):
return None
pot = (app.outdir / 'index_entries.pot').text(encoding='utf-8')
- msgids = filter(None, map(msgid_getter, pot.splitlines()))
+ msgids = [_f for _f in map(msgid_getter, pot.splitlines()) if _f]
expected_msgids = [
"i18n with index entries",
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index ef8e3888..603ad546 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -44,9 +44,6 @@ reading included file u'.*?wrongenc.inc' seems to be wrong, try giving an \
%(root)s/includes.txt:4: WARNING: download file not readable: .*?nonexisting.png
%(root)s/markup.txt:\\d+: WARNING: Malformed :option: u'Python c option', does \
not contain option marker - or -- or /
-%(root)s/objects.txt:\\d*: WARNING: using old C markup; please migrate to \
-new-style markup \(e.g. c:function instead of cfunction\), see \
-http://sphinx-doc.org/domains.html
"""
HTML_WARNINGS = ENV_WARNINGS + """\
@@ -191,8 +188,6 @@ HTML_XPATH = {
(".//a[@href='#c.SPHINX_USE_PYTHON']", ''),
(".//a[@href='#c.SphinxType']", ''),
(".//a[@href='#c.sphinx_global']", ''),
- # reference from old C markup extension
- (".//a[@href='#c.Sphinx_Func']", ''),
# test global TOC created by toctree()
(".//ul[@class='current']/li[@class='toctree-l1 current']/a[@href='']",
'Testing object descriptions'),
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
index 016c7aae..636c7f60 100644
--- a/tests/test_build_latex.py
+++ b/tests/test_build_latex.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import re
@@ -90,8 +91,8 @@ def test_latex(app):
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
- print stdout
- print stderr
+ print(stdout)
+ print(stderr)
del app.cleanup_trees[:]
assert False, 'latex exited with return code %s' % p.returncode
finally:
diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py
index bf3cc49f..60c768bc 100644
--- a/tests/test_build_texinfo.py
+++ b/tests/test_build_texinfo.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import re
@@ -61,8 +62,8 @@ def test_texinfo(app):
stdout, stderr = p.communicate()
retcode = p.returncode
if retcode != 0:
- print stdout
- print stderr
+ print(stdout)
+ print(stderr)
del app.cleanup_trees[:]
assert False, 'makeinfo exited with return code %s' % retcode
finally:
diff --git a/tests/test_config.py b/tests/test_config.py
index 4d3d51b0..ea6f3ba4 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -19,7 +19,8 @@ from sphinx.util.pycompat import b
@with_app(confoverrides={'master_doc': 'master', 'nonexisting_value': 'True',
- 'latex_elements.docclass': 'scrartcl'})
+ 'latex_elements.docclass': 'scrartcl',
+ 'modindex_common_prefix': 'path1,path2'})
def test_core_config(app):
cfg = app.config
@@ -31,6 +32,7 @@ def test_core_config(app):
# overrides
assert cfg.master_doc == 'master'
assert cfg.latex_elements['docclass'] == 'scrartcl'
+ assert cfg.modindex_common_prefix == ['path1', 'path2']
# simple default values
assert 'locale_dirs' not in cfg.__dict__
@@ -92,7 +94,7 @@ def test_errors_warnings(dir):
write_file(dir / 'conf.py', u'# -*- coding: utf-8\n\n'
u'project = u"Jägermeister"\n', 'utf-8')
cfg = Config(dir, 'conf.py', {}, None)
- cfg.init_values()
+ cfg.init_values(lambda warning: 1/0)
assert cfg.project == u'Jägermeister'
# test the warning for bytestrings with non-ascii content
@@ -122,5 +124,5 @@ def test_config_eol(tmpdir):
for eol in ('\n', '\r\n'):
configfile.write_bytes(b('project = "spam"' + eol))
cfg = Config(tmpdir, 'conf.py', {}, None)
- cfg.init_values()
+ cfg.init_values(lambda warning: 1/0)
assert cfg.project == u'spam'
diff --git a/tests/test_doctest.py b/tests/test_doctest.py
index f445dab2..1b20e280 100644
--- a/tests/test_doctest.py
+++ b/tests/test_doctest.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys
import StringIO
@@ -24,7 +25,7 @@ def test_build(app):
cleanup_called = 0
app.builder.build_all()
if app.statuscode != 0:
- print >>sys.stderr, status.getvalue()
+ print(status.getvalue(), file=sys.stderr)
assert False, 'failures in doctests'
# in doctest.txt, there are two named groups and the default group,
# so the cleanup function must be called three times
diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py
index a8679e7e..8ce02cc1 100644
--- a/tests/test_intersphinx.py
+++ b/tests/test_intersphinx.py
@@ -81,7 +81,7 @@ def test_read_inventory_v2():
'/util/glossary.html#term-a-term'
-@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'})
+@with_app()
@with_tempdir
def test_missing_reference(tempdir, app):
inv_file = tempdir / 'inventory'
@@ -157,7 +157,7 @@ def test_missing_reference(tempdir, app):
assert contnode[0].astext() == 'py3k:unknown'
-@with_app(confoverrides={'extensions': 'sphinx.ext.intersphinx'})
+@with_app()
@with_tempdir
def test_load_mappings_warnings(tempdir, app):
"""
diff --git a/tests/test_intl.py b/tests/test_intl.py
index c9822089..f59e3c86 100644
--- a/tests/test_intl.py
+++ b/tests/test_intl.py
@@ -9,6 +9,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import os
import re
@@ -16,8 +17,6 @@ from StringIO import StringIO
from subprocess import Popen, PIPE
from xml.etree import ElementTree
-from sphinx.util.pycompat import relpath
-
from util import test_roots, path, with_app, SkipTest
@@ -49,7 +48,7 @@ def setup_module():
for f in [f for f in files if f.endswith('.po')]:
po = dirpath / f
mo = root / 'xx' / 'LC_MESSAGES' / (
- relpath(po[:-3], root) + '.mo')
+ os.path.relpath(po[:-3], root) + '.mo')
if not mo.parent.exists():
mo.parent.makedirs()
try:
@@ -60,8 +59,8 @@ def setup_module():
else:
stdout, stderr = p.communicate()
if p.returncode != 0:
- print stdout
- print stderr
+ print(stdout)
+ print(stderr)
assert False, \
'msgfmt exited with return code %s' % p.returncode
assert mo.isfile(), 'msgfmt failed'
@@ -75,7 +74,7 @@ def teardown_module():
def elem_gettexts(elem):
def itertext(self):
# this function copied from Python-2.7 'ElementTree.itertext'.
- # for compatibility to Python-2.5, 2.6, 3.1
+ # for compatibility to Python-2.6
tag = self.tag
if not isinstance(tag, basestring) and tag is not None:
return
@@ -86,7 +85,7 @@ def elem_gettexts(elem):
yield s
if e.tail:
yield e.tail
- return filter(None, [s.strip() for s in itertext(elem)])
+ return [_f for _f in [s.strip() for s in itertext(elem)] if _f]
def elem_getref(elem):
diff --git a/tests/test_napoleon.py b/tests/test_napoleon.py
new file mode 100644
index 00000000..d8c71960
--- /dev/null
+++ b/tests/test_napoleon.py
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+"""
+ test_napoleon
+ ~~~~~~~~~~~~~
+
+ Tests for :mod:`sphinx.ext.napoleon.__init__` module.
+
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from mock import Mock
+from sphinx.application import Sphinx
+from sphinx.ext.napoleon import (_process_docstring, _skip_member, Config,
+ setup)
+from unittest import TestCase
+
+
+def _private_doc():
+ """module._private_doc.DOCSTRING"""
+ pass
+
+
+def _private_undoc():
+ pass
+
+
+def __special_doc__():
+ """module.__special_doc__.DOCSTRING"""
+ pass
+
+
+def __special_undoc__():
+ pass
+
+
+class SampleClass(object):
+ def _private_doc(self):
+ """SampleClass._private_doc.DOCSTRING"""
+ pass
+
+ def _private_undoc(self):
+ pass
+
+ def __special_doc__(self):
+ """SampleClass.__special_doc__.DOCSTRING"""
+ pass
+
+ def __special_undoc__(self):
+ pass
+
+
+class SampleError(Exception):
+ def _private_doc(self):
+ """SampleError._private_doc.DOCSTRING"""
+ pass
+
+ def _private_undoc(self):
+ pass
+
+ def __special_doc__(self):
+ """SampleError.__special_doc__.DOCSTRING"""
+ pass
+
+ def __special_undoc__(self):
+ pass
+
+
+class ProcessDocstringTest(TestCase):
+ def test_modify_in_place(self):
+ lines = ['Summary line.',
+ '',
+ 'Args:',
+ ' arg1: arg1 description']
+ app = Mock()
+ app.config = Config()
+ _process_docstring(app, 'class', 'SampleClass', SampleClass, Mock(),
+ lines)
+
+ expected = ['Summary line.',
+ '',
+ ':Parameters: **arg1** --',
+ ' arg1 description']
+ self.assertEqual(expected, lines)
+
+
+class SetupTest(TestCase):
+ def test_unknown_app_type(self):
+ setup(object())
+
+ def test_add_config_values(self):
+ app = Mock(Sphinx)
+ setup(app)
+ for name, (default, rebuild) in Config._config_values.items():
+ has_config = False
+ for method_name, args, kwargs in app.method_calls:
+ if(method_name == 'add_config_value' and
+ args[0] == name):
+ has_config = True
+ if not has_config:
+ self.fail('Config value was not added to app %s' % name)
+
+ has_process_docstring = False
+ has_skip_member = False
+ for method_name, args, kwargs in app.method_calls:
+ if method_name == 'connect':
+ if(args[0] == 'autodoc-process-docstring' and
+ args[1] == _process_docstring):
+ has_process_docstring = True
+ elif(args[0] == 'autodoc-skip-member' and
+ args[1] == _skip_member):
+ has_skip_member = True
+ if not has_process_docstring:
+ self.fail('autodoc-process-docstring never connected')
+ if not has_skip_member:
+ self.fail('autodoc-skip-member never connected')
+
+
+class SkipMemberTest(TestCase):
+ def assertSkip(self, what, member, obj, expect_skip, config_name):
+ skip = 'default skip'
+ app = Mock()
+ app.config = Config()
+ setattr(app.config, config_name, True)
+ if expect_skip:
+ self.assertEqual(skip, _skip_member(app, what, member, obj, skip,
+ Mock()))
+ else:
+ self.assertFalse(_skip_member(app, what, member, obj, skip,
+ Mock()))
+ setattr(app.config, config_name, False)
+ self.assertEqual(skip, _skip_member(app, what, member, obj, skip,
+ Mock()))
+
+ def test_class_private_doc(self):
+ self.assertSkip('class', '_private_doc',
+ SampleClass._private_doc, False,
+ 'napoleon_include_private_with_doc')
+
+ def test_class_private_undoc(self):
+ self.assertSkip('class', '_private_undoc',
+ SampleClass._private_undoc, True,
+ 'napoleon_include_private_with_doc')
+
+ def test_class_special_doc(self):
+ self.assertSkip('class', '__special_doc__',
+ SampleClass.__special_doc__, False,
+ 'napoleon_include_special_with_doc')
+
+ def test_class_special_undoc(self):
+ self.assertSkip('class', '__special_undoc__',
+ SampleClass.__special_undoc__, True,
+ 'napoleon_include_special_with_doc')
+
+ def test_exception_private_doc(self):
+ self.assertSkip('exception', '_private_doc',
+ SampleError._private_doc, False,
+ 'napoleon_include_private_with_doc')
+
+ def test_exception_private_undoc(self):
+ self.assertSkip('exception', '_private_undoc',
+ SampleError._private_undoc, True,
+ 'napoleon_include_private_with_doc')
+
+ def test_exception_special_doc(self):
+ self.assertSkip('exception', '__special_doc__',
+ SampleError.__special_doc__, False,
+ 'napoleon_include_special_with_doc')
+
+ def test_exception_special_undoc(self):
+ self.assertSkip('exception', '__special_undoc__',
+ SampleError.__special_undoc__, True,
+ 'napoleon_include_special_with_doc')
+
+ def test_module_private_doc(self):
+ self.assertSkip('module', '_private_doc', _private_doc, False,
+ 'napoleon_include_private_with_doc')
+
+ def test_module_private_undoc(self):
+ self.assertSkip('module', '_private_undoc', _private_undoc, True,
+ 'napoleon_include_private_with_doc')
+
+ def test_module_special_doc(self):
+ self.assertSkip('module', '__special_doc__', __special_doc__, False,
+ 'napoleon_include_special_with_doc')
+
+ def test_module_special_undoc(self):
+ self.assertSkip('module', '__special_undoc__', __special_undoc__, True,
+ 'napoleon_include_special_with_doc')
diff --git a/tests/test_napoleon_docstring.py b/tests/test_napoleon_docstring.py
new file mode 100644
index 00000000..aa52aebe
--- /dev/null
+++ b/tests/test_napoleon_docstring.py
@@ -0,0 +1,259 @@
+# -*- coding: utf-8 -*-
+"""
+ test_napoleon_docstring
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ Tests for :mod:`sphinx.ext.napoleon.docstring` module.
+
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import textwrap
+from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
+from unittest import TestCase
+
+
+class BaseDocstringTest(TestCase):
+ pass
+
+
+class GoogleDocstringTest(BaseDocstringTest):
+ docstrings = [(
+ """Single line summary""",
+ """Single line summary"""
+ ), (
+ """
+ Single line summary
+
+ Extended description
+
+ """,
+ """
+ Single line summary
+
+ Extended description
+ """
+ ), (
+ """
+ Single line summary
+
+ Args:
+ arg1(str):Extended
+ description of arg1
+ """,
+ """
+ Single line summary
+
+ :Parameters: **arg1** (*str*) --
+ Extended
+ description of arg1"""
+ ), (
+ """
+ Single line summary
+
+ Args:
+ arg1(str):Extended
+ description of arg1
+ arg2 ( int ) : Extended
+ description of arg2
+
+ Keyword Args:
+ kwarg1(str):Extended
+ description of kwarg1
+ kwarg2 ( int ) : Extended
+ description of kwarg2""",
+ """
+ Single line summary
+
+ :Parameters: * **arg1** (*str*) --
+ Extended
+ description of arg1
+ * **arg2** (*int*) --
+ Extended
+ description of arg2
+
+ :Keyword Arguments: * **kwarg1** (*str*) --
+ Extended
+ description of kwarg1
+ * **kwarg2** (*int*) --
+ Extended
+ description of kwarg2"""
+ ), (
+ """
+ Single line summary
+
+ Arguments:
+ arg1(str):Extended
+ description of arg1
+ arg2 ( int ) : Extended
+ description of arg2
+
+ Keyword Arguments:
+ kwarg1(str):Extended
+ description of kwarg1
+ kwarg2 ( int ) : Extended
+ description of kwarg2""",
+ """
+ Single line summary
+
+ :Parameters: * **arg1** (*str*) --
+ Extended
+ description of arg1
+ * **arg2** (*int*) --
+ Extended
+ description of arg2
+
+ :Keyword Arguments: * **kwarg1** (*str*) --
+ Extended
+ description of kwarg1
+ * **kwarg2** (*int*) --
+ Extended
+ description of kwarg2"""
+ ), (
+ """
+ Single line summary
+
+ Return:
+ str:Extended
+ description of return value
+ """,
+ """
+ Single line summary
+
+ :returns: *str* --
+ Extended
+ description of return value"""
+ ), (
+ """
+ Single line summary
+
+ Returns:
+ str:Extended
+ description of return value
+ """,
+ """
+ Single line summary
+
+ :returns: *str* --
+ Extended
+ description of return value"""
+ )]
+
+ def test_docstrings(self):
+ for docstring, expected in self.docstrings:
+ actual = str(GoogleDocstring(textwrap.dedent(docstring)))
+ expected = textwrap.dedent(expected)
+ self.assertEqual(expected, actual)
+
+
+class NumpyDocstringTest(BaseDocstringTest):
+ docstrings = [(
+ """Single line summary""",
+ """Single line summary"""
+ ), (
+ """
+ Single line summary
+
+ Extended description
+
+ """,
+ """
+ Single line summary
+
+ Extended description
+ """
+ ), (
+ """
+ Single line summary
+
+ Parameters
+ ----------
+ arg1:str
+ Extended
+ description of arg1
+ """,
+ """
+ Single line summary
+
+ :Parameters: **arg1** (*str*) --
+ Extended
+ description of arg1"""
+ ), (
+ """
+ Single line summary
+
+ Parameters
+ ----------
+ arg1:str
+ Extended
+ description of arg1
+ arg2 : int
+ Extended
+ description of arg2
+
+ Keyword Arguments
+ -----------------
+ kwarg1:str
+ Extended
+ description of kwarg1
+ kwarg2 : int
+ Extended
+ description of kwarg2
+ """,
+ """
+ Single line summary
+
+ :Parameters: * **arg1** (*str*) --
+ Extended
+ description of arg1
+ * **arg2** (*int*) --
+ Extended
+ description of arg2
+
+ :Keyword Arguments: * **kwarg1** (*str*) --
+ Extended
+ description of kwarg1
+ * **kwarg2** (*int*) --
+ Extended
+ description of kwarg2"""
+ ), (
+ """
+ Single line summary
+
+ Return
+ ------
+ str
+ Extended
+ description of return value
+ """,
+ """
+ Single line summary
+
+ :returns: *str* --
+ Extended
+ description of return value"""
+ ), (
+ """
+ Single line summary
+
+ Returns
+ -------
+ str
+ Extended
+ description of return value
+ """,
+ """
+ Single line summary
+
+ :returns: *str* --
+ Extended
+ description of return value"""
+ )]
+
+ def test_docstrings(self):
+ for docstring, expected in self.docstrings:
+ actual = str(NumpyDocstring(textwrap.dedent(docstring)))
+ expected = textwrap.dedent(expected)
+ self.assertEqual(expected, actual)
diff --git a/tests/test_napoleon_iterators.py b/tests/test_napoleon_iterators.py
new file mode 100644
index 00000000..db0be32c
--- /dev/null
+++ b/tests/test_napoleon_iterators.py
@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+"""
+ test_napoleon_iterators
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ Tests for :mod:`sphinx.ext.napoleon.iterators` module.
+
+
+ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from sphinx.ext.napoleon.iterators import peek_iter, modify_iter
+from unittest import TestCase
+
+
+class BaseIteratorsTest(TestCase):
+ def assertEqualTwice(self, expected, func, *args):
+ self.assertEqual(expected, func(*args))
+ self.assertEqual(expected, func(*args))
+
+ def assertFalseTwice(self, func, *args):
+ self.assertFalse(func(*args))
+ self.assertFalse(func(*args))
+
+ def assertNext(self, it, expected, is_last):
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(expected, it.peek)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(expected, it.peek)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(expected, it.next())
+ if is_last:
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next)
+ else:
+ self.assertTrueTwice(it.has_next)
+
+ def assertRaisesTwice(self, exc, func, *args):
+ self.assertRaises(exc, func, *args)
+ self.assertRaises(exc, func, *args)
+
+ def assertTrueTwice(self, func, *args):
+ self.assertTrue(func(*args))
+ self.assertTrue(func(*args))
+
+
+class PeekIterTest(BaseIteratorsTest):
+ def test_init_with_sentinel(self):
+ a = iter(['1', '2', 'DONE'])
+ sentinel = 'DONE'
+ self.assertRaises(TypeError, peek_iter, a, sentinel)
+
+ def get_next():
+ return next(a)
+ it = peek_iter(get_next, sentinel)
+ self.assertEqual(it.sentinel, sentinel)
+ self.assertNext(it, '1', is_last=False)
+ self.assertNext(it, '2', is_last=True)
+
+ def test_iter(self):
+ a = ['1', '2', '3']
+ it = peek_iter(a)
+ self.assertTrue(it is it.__iter__())
+
+ a = []
+ b = [i for i in peek_iter(a)]
+ self.assertEqual([], b)
+
+ a = ['1']
+ b = [i for i in peek_iter(a)]
+ self.assertEqual(['1'], b)
+
+ a = ['1', '2']
+ b = [i for i in peek_iter(a)]
+ self.assertEqual(['1', '2'], b)
+
+ a = ['1', '2', '3']
+ b = [i for i in peek_iter(a)]
+ self.assertEqual(['1', '2', '3'], b)
+
+ def test_next_with_multi(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 2)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 2)
+ self.assertTrueTwice(it.has_next)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['1', '2'], it.next(2))
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1', '2', '3']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['1', '2'], it.next(2))
+ self.assertTrueTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 2)
+ self.assertTrueTwice(it.has_next)
+
+ a = ['1', '2', '3', '4']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['1', '2'], it.next(2))
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['3', '4'], it.next(2))
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 2)
+ self.assertFalseTwice(it.has_next)
+
+ def test_next_with_none(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertEqual('1', it.__next__())
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertNext(it, '1', is_last=True)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertNext(it, '1', is_last=False)
+ self.assertNext(it, '2', is_last=True)
+
+ a = ['1', '2', '3']
+ it = peek_iter(a)
+ self.assertNext(it, '1', is_last=False)
+ self.assertNext(it, '2', is_last=False)
+ self.assertNext(it, '3', is_last=True)
+
+ def test_next_with_one(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 1)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['1'], it.next(1))
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 1)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['1'], it.next(1))
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual(['2'], it.next(1))
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 1)
+
+ def test_next_with_zero(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertRaisesTwice(StopIteration, it.next, 0)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.next, 0)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.next, 0)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.next, 0)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.next, 0)
+
+ def test_peek_with_multi(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice([it.sentinel, it.sentinel], it.peek, 2)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', it.sentinel], it.peek, 2)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', it.sentinel, it.sentinel], it.peek, 3)
+ self.assertTrueTwice(it.has_next)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2'], it.peek, 2)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2', it.sentinel], it.peek, 3)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2', it.sentinel, it.sentinel], it.peek, 4)
+ self.assertTrueTwice(it.has_next)
+
+ a = ['1', '2', '3']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2'], it.peek, 2)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2', '3'], it.peek, 3)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1', '2', '3', it.sentinel], it.peek, 4)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqual('1', it.next())
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['2', '3'], it.peek, 2)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['2', '3', it.sentinel], it.peek, 3)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['2', '3', it.sentinel, it.sentinel], it.peek, 4)
+ self.assertTrueTwice(it.has_next)
+
+ def test_peek_with_none(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice(it.sentinel, it.peek)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice('1', it.peek)
+ self.assertEqual('1', it.next())
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice(it.sentinel, it.peek)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice('1', it.peek)
+ self.assertEqual('1', it.next())
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice('2', it.peek)
+ self.assertEqual('2', it.next())
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice(it.sentinel, it.peek)
+ self.assertFalseTwice(it.has_next)
+
+ def test_peek_with_one(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice([it.sentinel], it.peek, 1)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1'], it.peek, 1)
+ self.assertEqual('1', it.next())
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice([it.sentinel], it.peek, 1)
+ self.assertFalseTwice(it.has_next)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['1'], it.peek, 1)
+ self.assertEqual('1', it.next())
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice(['2'], it.peek, 1)
+ self.assertEqual('2', it.next())
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice([it.sentinel], it.peek, 1)
+ self.assertFalseTwice(it.has_next)
+
+ def test_peek_with_zero(self):
+ a = []
+ it = peek_iter(a)
+ self.assertFalseTwice(it.has_next)
+ self.assertEqualTwice([], it.peek, 0)
+
+ a = ['1']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.peek, 0)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.peek, 0)
+
+ a = ['1', '2']
+ it = peek_iter(a)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.peek, 0)
+ self.assertTrueTwice(it.has_next)
+ self.assertEqualTwice([], it.peek, 0)
+
+
+class ModifyIterTest(BaseIteratorsTest):
+ def test_init_with_sentinel_args(self):
+ a = iter(['1', '2', '3', 'DONE'])
+ sentinel = 'DONE'
+
+ def get_next():
+ return next(a)
+ it = modify_iter(get_next, sentinel, int)
+ expected = [1, 2, 3]
+ self.assertEqual(expected, [i for i in it])
+
+ def test_init_with_sentinel_kwargs(self):
+ a = iter([1, 2, 3, 4])
+ sentinel = 4
+
+ def get_next():
+ return next(a)
+ it = modify_iter(get_next, sentinel, modifier=str)
+ expected = ['1', '2', '3']
+ self.assertEqual(expected, [i for i in it])
+
+ def test_modifier_default(self):
+ a = ['', ' ', ' a ', 'b ', ' c', ' ', '']
+ it = modify_iter(a)
+ expected = ['', ' ', ' a ', 'b ', ' c', ' ', '']
+ self.assertEqual(expected, [i for i in it])
+
+ def test_modifier_not_callable(self):
+ self.assertRaises(TypeError, modify_iter, [1], modifier='not_callable')
+
+ def test_modifier_rstrip(self):
+ a = ['', ' ', ' a ', 'b ', ' c', ' ', '']
+ it = modify_iter(a, modifier=lambda s: s.rstrip())
+ expected = ['', '', ' a', 'b', ' c', '', '']
+ self.assertEqual(expected, [i for i in it])
+
+ def test_modifier_rstrip_unicode(self):
+ a = [u'', u' ', u' a ', u'b ', u' c', u' ', u'']
+ it = modify_iter(a, modifier=lambda s: s.rstrip())
+ expected = [u'', u'', u' a', u'b', u' c', u'', u'']
+ self.assertEqual(expected, [i for i in it])
diff --git a/tests/test_only_directive.py b/tests/test_only_directive.py
index 28e34e58..a01d7af7 100644
--- a/tests/test_only_directive.py
+++ b/tests/test_only_directive.py
@@ -53,8 +53,7 @@ def test_sectioning(app):
app.env.process_only_nodes(doctree, app.builder)
parts = [getsects(n)
- for n in filter(lambda n: isinstance(n, nodes.section),
- doctree.children)]
+ for n in [_n for _n in doctree.children if isinstance(_n, nodes.section)]]
for i, s in enumerate(parts):
testsects(str(i+1) + '.', s, 4)
assert len(parts) == 4, 'Expected 4 document level headings, got:\n%s' % \
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index 9daa7401..7323f48e 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -170,6 +170,7 @@ def test_quickstart_all_answers(tempdir):
'Author name': u'Wolfgang Schäuble & G\'Beckstein'.encode('utf-8'),
'Project version': '2.0',
'Project release': '2.0.1',
+ 'Project language': 'de',
'Source file suffix': '.txt',
'Name of your master document': 'contents',
'autodoc': 'y',
diff --git a/tests/test_versioning.py b/tests/test_versioning.py
index 6469a33c..5cff92ff 100644
--- a/tests/test_versioning.py
+++ b/tests/test_versioning.py
@@ -15,7 +15,6 @@ from docutils.parsers.rst.directives.html import MetaBody
from sphinx import addnodes
from sphinx.versioning import add_uids, merge_doctrees, get_ratio
-from sphinx.util.pycompat import all
from util import test_root, TestApp
diff --git a/tests/test_websupport.py b/tests/test_websupport.py
index 611a131a..d950a36c 100644
--- a/tests/test_websupport.py
+++ b/tests/test_websupport.py
@@ -11,12 +11,7 @@
import os
from StringIO import StringIO
-
-try:
- from functools import wraps
-except ImportError:
- # functools is new in 2.5
- wraps = lambda f: (lambda w: w)
+from functools import wraps
from sphinx.websupport import WebSupport
from sphinx.websupport.errors import DocumentNotFoundError, \
diff --git a/tests/util.py b/tests/util.py
index 4ba89030..c88d5c0a 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -13,12 +13,7 @@ import tempfile
import shutil
import re
from codecs import open
-
-try:
- from functools import wraps
-except ImportError:
- # functools is new in 2.4
- wraps = lambda f: (lambda w: w)
+from functools import wraps
from sphinx import application
from sphinx.theming import Theme
@@ -67,7 +62,7 @@ def raises_msg(exc, msg, func, *args, **kwds):
"""
try:
func(*args, **kwds)
- except exc, err:
+ except exc as err:
assert msg in str(err), "\"%s\" not in \"%s\"" % (msg, err)
else:
raise AssertionError('%s did not raise %s' %
diff --git a/tox.ini b/tox.ini
index f1675e90..ee8ce791 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,9 @@
[tox]
-envlist=py25,py26,py27,py31,py32,py33,pypy,du11,du10,du09,du08,du07
+envlist=py26,py27,py32,py33,pypy,du11,du10,du09,du08,du07
[testenv]
deps=
+ mock
nose
sqlalchemy
whoosh
@@ -12,14 +13,6 @@ commands=
{envpython} tests/run.py {posargs}
sphinx-build -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
-[testenv:py25]
-deps=
- simplejson==2.5.0
- {[testenv]deps}
-setenv=
- PIP_INSECURE = 1
- {[testenv]setenv}
-
[testenv:py33]
deps=
docutils>=0.10.0
diff --git a/utils/check_sources.py b/utils/check_sources.py
index 5512420a..30f6329d 100755
--- a/utils/check_sources.py
+++ b/utils/check_sources.py
@@ -10,6 +10,7 @@
:copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+from __future__ import print_function
import sys, os, re
import cStringIO
@@ -54,7 +55,7 @@ if sys.version_info < (3, 0):
def check_syntax(fn, lines):
try:
compile(b('').join(lines), fn, "exec")
- except SyntaxError, err:
+ except SyntaxError as err:
yield 0, "not compilable: %s" % err
@@ -77,9 +78,9 @@ def check_style_and_encoding(fn, lines):
yield lno+1, 'using == None/True/False'
try:
line.decode(encoding)
- except UnicodeDecodeError, err:
+ except UnicodeDecodeError as err:
yield lno+1, "not decodable: %s\n Line: %r" % (err, line)
- except LookupError, err:
+ except LookupError as err:
yield 0, "unknown encoding: %s" % encoding
encoding = 'latin1'
@@ -183,7 +184,7 @@ def main(argv):
elif len(args) == 1:
path = args[0]
else:
- print args
+ print(args)
parser.error('No more then one path supported')
verbose = options.verbose
@@ -214,7 +215,7 @@ def main(argv):
continue
if verbose:
- print "Checking %s..." % fn
+ print("Checking %s..." % fn)
try:
f = open(fn, 'rb')
@@ -222,8 +223,8 @@ def main(argv):
lines = list(f)
finally:
f.close()
- except (IOError, OSError), err:
- print "%s: cannot open: %s" % (fn, err)
+ except (IOError, OSError) as err:
+ print("%s: cannot open: %s" % (fn, err))
num += 1
continue
@@ -231,15 +232,15 @@ def main(argv):
if not in_check_pkg and checker.only_pkg:
continue
for lno, msg in checker(fn, lines):
- print >>out, "%s:%d: %s" % (fn, lno, msg)
+ print("%s:%d: %s" % (fn, lno, msg), file=out)
num += 1
if verbose:
- print
+ print()
if num == 0:
- print "No errors found."
+ print("No errors found.")
else:
- print out.getvalue().rstrip('\n')
- print "%d error%s found." % (num, num > 1 and "s" or "")
+ print(out.getvalue().rstrip('\n'))
+ print("%d error%s found." % (num, num > 1 and "s" or ""))
return int(num > 0)
diff --git a/utils/reindent.py b/utils/reindent.py
index 59828fd8..ef53fe8c 100755
--- a/utils/reindent.py
+++ b/utils/reindent.py
@@ -38,6 +38,7 @@ file is generated with shutil.copy(), but some corner cases regarding
user/group and permissions could leave the backup file more readable that
you'd prefer. You can always use the --nobackup option to prevent this.
"""
+from __future__ import print_function
__version__ = "1"
@@ -59,8 +60,8 @@ makebackup = True
def usage(msg=None):
if msg is not None:
- print >> sys.stderr, msg
- print >> sys.stderr, __doc__
+ print(msg, file=sys.stderr)
+ print(__doc__, file=sys.stderr)
def errprint(*args):
sep = ""
@@ -75,7 +76,7 @@ def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "drnvh",
["dryrun", "recurse", "nobackup", "verbose", "help"])
- except getopt.error, msg:
+ except getopt.error as msg:
usage(msg)
return
for o, a in opts:
@@ -101,7 +102,7 @@ def main():
def check(file):
if os.path.isdir(file) and not os.path.islink(file):
if verbose:
- print "listing directory", file
+ print("listing directory", file)
names = os.listdir(file)
for name in names:
fullname = os.path.join(file, name)
@@ -113,10 +114,10 @@ def check(file):
return
if verbose:
- print "checking", file, "...",
+ print("checking", file, "...", end=' ')
try:
f = open(file)
- except IOError, msg:
+ except IOError as msg:
errprint("%s: I/O Error: %s" % (file, str(msg)))
return
@@ -124,24 +125,24 @@ def check(file):
f.close()
if r.run():
if verbose:
- print "changed."
+ print("changed.")
if dryrun:
- print "But this is a dry run, so leaving it alone."
+ print("But this is a dry run, so leaving it alone.")
if not dryrun:
bak = file + ".bak"
if makebackup:
shutil.copyfile(file, bak)
if verbose:
- print "backed up", file, "to", bak
+ print("backed up", file, "to", bak)
f = open(file, "w")
r.write(f)
f.close()
if verbose:
- print "wrote new", file
+ print("wrote new", file)
return True
else:
if verbose:
- print "unchanged."
+ print("unchanged.")
return False
def _rstrip(line, JUNK='\n \t'):
@@ -262,7 +263,7 @@ class Reindenter:
return line
# Line-eater for tokenize.
- def tokeneater(self, type, token, (sline, scol), end, line,
+ def tokeneater(self, type, token, position, end, line,
INDENT=tokenize.INDENT,
DEDENT=tokenize.DEDENT,
NEWLINE=tokenize.NEWLINE,
@@ -285,7 +286,7 @@ class Reindenter:
elif type == COMMENT:
if self.find_stmt:
- self.stats.append((sline, -1))
+ self.stats.append((position[0], -1))
# but we're still looking for a new stmt, so leave
# find_stmt alone
@@ -298,7 +299,7 @@ class Reindenter:
# ENDMARKER.
self.find_stmt = 0
if line: # not endmarker
- self.stats.append((sline, self.level))
+ self.stats.append((position[0], self.level))
# Count number of leading blanks.
def getlspace(line):