mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge from master
This commit is contained in:
commit
d8a109976b
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
*.pyc
|
||||
*.egg
|
||||
*.so
|
||||
|
||||
.dir-locals.el
|
||||
.ropeproject/
|
||||
TAGS
|
||||
.tags
|
||||
.tox
|
||||
.DS_Store
|
||||
sphinx/pycode/Grammar*pickle
|
||||
distribute-*
|
||||
|
||||
env/
|
||||
build/
|
||||
dist/
|
||||
Sphinx.egg-info/
|
||||
doc/_build/
|
||||
tests/.coverage
|
||||
tests/build/
|
21
.hgignore
21
.hgignore
@ -1,21 +0,0 @@
|
||||
.*\.pyc
|
||||
.*\.egg
|
||||
.*\.so
|
||||
.dir-locals.el
|
||||
^\.tox
|
||||
\.DS_Store$
|
||||
^build/
|
||||
^dist/
|
||||
^tests/.coverage
|
||||
^sphinx/pycode/Grammar.*pickle
|
||||
^Sphinx.egg-info/
|
||||
^doc/_build/
|
||||
^TAGS
|
||||
^\.ropeproject/
|
||||
^env/
|
||||
\.DS_Store$
|
||||
~$
|
||||
^utils/.*3\.py$
|
||||
^distribute-
|
||||
^tests/root/_build/*
|
||||
^tests/root/generated/*
|
11
.travis.yml
11
.travis.yml
@ -1,7 +1,14 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.3"
|
||||
script: make test
|
||||
- "3.4"
|
||||
- "pypy"
|
||||
env:
|
||||
- DOCUTILS=0.11
|
||||
- DOCUTILS=0.12
|
||||
install:
|
||||
- python setup.py -q install
|
||||
- pip install docutils==$DOCUTILS
|
||||
- pip install -r test-reqs.txt
|
||||
script: make test
|
||||
|
4
AUTHORS
4
AUTHORS
@ -8,7 +8,7 @@ Other co-maintainers:
|
||||
* Takayuki Shimizukawa <shimizukawa@gmail.com>
|
||||
* Daniel Neuhäuser <@DasIch>
|
||||
* Jon Waltman <@jonwaltman>
|
||||
* Rob Ruana <@RelentlessIdiot>
|
||||
* Rob Ruana <@RobRuana>
|
||||
* Robert Lehmann <@lehmannro>
|
||||
* Roland Meister <@rolmei>
|
||||
|
||||
@ -26,6 +26,7 @@ Other contributors, listed alphabetically, are:
|
||||
* Horst Gutmann -- internationalization support
|
||||
* Martin Hans -- autodoc improvements
|
||||
* Doug Hellmann -- graphviz improvements
|
||||
* Takeshi Komiya -- numref feature
|
||||
* Dave Kuhlman -- original LaTeX writer
|
||||
* Blaise Laflamme -- pyramid theme
|
||||
* Thomas Lamb -- linkcheck builder
|
||||
@ -41,6 +42,7 @@ Other contributors, listed alphabetically, are:
|
||||
* Christopher Perkins -- autosummary integration
|
||||
* Benjamin Peterson -- unittests
|
||||
* T. Powers -- HTML output improvements
|
||||
* Jeppe Pihl -- literalinclude improvements
|
||||
* Rob Ruana -- napoleon extension
|
||||
* Stefan Seefeld -- toctree improvements
|
||||
* Shibukawa Yoshiki -- pluggable search API and Japanese search
|
||||
|
412
CHANGES
412
CHANGES
@ -1,5 +1,66 @@
|
||||
Release 1.3 (in development)
|
||||
============================
|
||||
Release 1.3b3 (in development)
|
||||
==============================
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
* Dependency requirement updates: docutils 0.11, Pygments 2.0
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* Added ``highlight_options`` configuration value.
|
||||
* The ``language`` config value is now available in the HTML templates.
|
||||
* The ``env-updated`` event can now return a value, which is interpreted
|
||||
as an iterable of additional docnames that need to be rewritten.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* LaTeX writer now generates correct markup for cells spanning multiple rows.
|
||||
* #1674: Do not crash if a module's ``__all__`` is not a list of strings.
|
||||
* #1629: Use VerbatimBorderColor to add frame to code-block in LaTeX
|
||||
* On windows, make-mode didn't work on Win32 platform if sphinx was invoked as
|
||||
``python sphinx-build.py``.
|
||||
* #1687: linkcheck now treats 401 Unauthorized responses as "working".
|
||||
* #1690: toctrees with ``glob`` option now can also contain entries for single
|
||||
documents with explicit title.
|
||||
|
||||
|
||||
Release 1.3b2 (released Dec 5, 2014)
|
||||
====================================
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
* update bundled ez_setup.py for setuptools-7.0 that requires Python 2.6 or
|
||||
later.
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #1597: Added possibility to return a new template name from
|
||||
`html-page-context`.
|
||||
* PR#314, #1150: Configuration values are now checked for their type. A
|
||||
warning is raised if the configured and the default value do not have the
|
||||
same type and do not share a common non-trivial base class.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* PR#311: sphinx-quickstart does not work on python 3.4.
|
||||
* Fix :confval:`autodoc_docstring_signature` not working with signatures
|
||||
in class docstrings.
|
||||
* Rebuilding cause crash unexpectedly when source files were added.
|
||||
* #1607: Fix a crash when building latexpdf with "howto" class
|
||||
* #1251: Fix again. Sections which depth are lower than :tocdepth: should not
|
||||
be shown on localtoc sidebar.
|
||||
* make-mode didn't work on Win32 platform if sphinx was installed by wheel
|
||||
package.
|
||||
|
||||
|
||||
Release 1.3b1 (released Oct 10, 2014)
|
||||
=====================================
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
@ -12,12 +73,21 @@ Incompatible changes
|
||||
* 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.
|
||||
* PR#269, #1476: replace `<tt>` tag by `<code>`. User customized stylesheets
|
||||
should be updated If the css contain some styles for `<tt>` tag.
|
||||
* PR#269, #1476: replace ``<tt>`` tag by ``<code>``. User customized stylesheets
|
||||
should be updated If the css contain some styles for ``tt>`` tag.
|
||||
Thanks to Takeshi Komiya.
|
||||
* #1543: :confval:`templates_path` is automatically added to
|
||||
:confval:`exclude_patterns` to avoid reading autosummary rst templates in the
|
||||
* #1543: `templates_path` is automatically added to
|
||||
`exclude_patterns` to avoid reading autosummary rst templates in the
|
||||
templates directory.
|
||||
* Custom domains should implement the new `Domain.resolve_any_xref`
|
||||
method to make the `any` role work properly.
|
||||
* gettext builder: gettext doesn't emit uuid information to generated pot files
|
||||
by default. Please set ``True`` to `gettext_uuid` to emit uuid information.
|
||||
Additionally, if the ``python-levenshtein`` 3rd-party package is installed,
|
||||
it will improve the calculation time.
|
||||
* gettext builder: disable extracting/apply 'index' node by default. Please set
|
||||
'index' to :confval:`gettext_enables` to enable extracting index entries.
|
||||
* PR#307: Add frame to code-block in LaTeX. Thanks to Takeshi Komiya.
|
||||
|
||||
Features added
|
||||
--------------
|
||||
@ -26,21 +96,35 @@ Features added
|
||||
* Add support for docutils 0.12
|
||||
* Added ``sphinx.ext.napoleon`` extension for NumPy and Google style docstring
|
||||
support.
|
||||
* Added support for parallel reading (parsing) of source files with the
|
||||
`sphinx-build -j` option. Third-party extensions will need to be checked for
|
||||
compatibility and may need to be adapted if they store information in the
|
||||
build environment object. See `env-merge-info`.
|
||||
* Added the `any` role that can be used to find a cross-reference of
|
||||
*any* type in *any* domain. Custom domains should implement the new
|
||||
`Domain.resolve_any_xref` method to make this work properly.
|
||||
* Exception logs now contain the last 10 messages emitted by Sphinx.
|
||||
* Added support for extension versions (a string returned by ``setup()``, these
|
||||
can be shown in the traceback log files). Version requirements for extensions
|
||||
can be specified in projects using the new :confval:`needs_extensions` config
|
||||
can be specified in projects using the new `needs_extensions` config
|
||||
value.
|
||||
* Changing the default role within a document with the :dudir:`default-role`
|
||||
directive is now supported.
|
||||
* PR#214: Added stemming support for 14 languages, so that the built-in document
|
||||
search can now handle these. Thanks to Shibukawa Yoshiki.
|
||||
* PR#296, PR#303, #76: numfig feature: Assign numbers to figures, tables and
|
||||
code-blocks. This feature is configured with `numfig`, `numfig_secnum_depth`
|
||||
and `numfig_format`. Also `numref` role is available. Thanks to Takeshi
|
||||
Komiya.
|
||||
* PR#202: Allow "." and "~" prefixed references in ``:param:`` doc fields
|
||||
for Python.
|
||||
* PR#184: Add :confval:`autodoc_mock_imports`, allowing to mock imports of
|
||||
* PR#184: Add `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
|
||||
* #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, PR#266: The :rst:dir:`code-block` and :rst:dir:`literalinclude`
|
||||
* PR#172, PR#266: The `code-block` and `literalinclude`
|
||||
directives now can have a ``caption`` option that shows a filename before the
|
||||
code in the output. Thanks to Nasimul Haque, Takeshi Komiya.
|
||||
* Prompt for the document language in sphinx-quickstart.
|
||||
@ -55,132 +139,56 @@ Features added
|
||||
for the ids defined on the node. Thanks to Olivier Heurtier.
|
||||
* PR#229: Allow registration of other translators. Thanks to Russell Sim.
|
||||
* Add app.set_translator() API to register or override a Docutils translator
|
||||
class like :confval:`html_translator_class`.
|
||||
class like `html_translator_class`.
|
||||
* PR#267, #1134: add 'diff' parameter to literalinclude. Thanks to Richard Wall
|
||||
and WAKAYAMA shirou.
|
||||
* PR#272: Added 'bizstyle' theme. Thanks to Shoji KUMAGAI.
|
||||
* Automatically compile ``*.mo`` files from ``*.po`` files when
|
||||
:confval:`gettext_auto_build` is True (default) and ``*.po`` is newer than
|
||||
`gettext_auto_build` is True (default) and ``*.po`` is newer than
|
||||
``*.mo`` file.
|
||||
* #623: :mod:`~sphinx.ext.viewcode` supports imported function/class aliases.
|
||||
* PR#275: :mod:`~sphinx.ext.intersphinx` supports multiple target for the
|
||||
* #623: `sphinx.ext.viewcode` supports imported function/class aliases.
|
||||
* PR#275: `sphinx.ext.intersphinx` supports multiple target for the
|
||||
inventory. Thanks to Brigitta Sipocz.
|
||||
* PR#261: Added the `env-before-read-docs` event that can be connected to modify
|
||||
the order of documents before they are read by the environment.
|
||||
* #1284: Program options documented with :rst:dir:`option` can now start with
|
||||
``+``.
|
||||
* PR#291: The caption of :rst:dir:`code-block` is recognised as a title of ref
|
||||
target. Thanks to Takeshi Komiya.
|
||||
* PR#298: Add new API: :meth:`~sphinx.application.Sphinx.add_latex_package`.
|
||||
Thanks to Takeshi Komiya.
|
||||
* #1344: add :confval:`gettext_enables` to enable extracting 'index' to gettext
|
||||
catalog output / applying translation catalog to generated documentation.
|
||||
* PR#301, #1583: Allow the line numbering of the directive `literalinclude` to
|
||||
match that of the included file, using a new ``lineno-match`` option. Thanks
|
||||
to Jeppe Pihl.
|
||||
* PR#299: add various options to sphinx-quickstart. Quiet mode option
|
||||
``--quiet`` will skips wizard mode. Thanks to WAKAYAMA shirou.
|
||||
* #1623: Return types specified with ``:rtype:`` are now turned into links if
|
||||
possible.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #1438: Updated jQuery version from 1.8.3 to 1.11.1.
|
||||
* #1568: Fix a crash when a "centered" directive contains a reference.
|
||||
* Now sphinx.ext.autodoc works with python-2.5 again.
|
||||
* #1563: :meth:`~sphinx.application.Sphinx.add_search_language` raises
|
||||
AssertionError for correct type of argument. Thanks to rikoman.
|
||||
* #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.
|
||||
* #1337: Fix autodoc with ``autoclass_content="both"`` uses useless
|
||||
``object.__init__`` docstring when class does not have ``__init__``.
|
||||
This was caused by a change for #1138.
|
||||
* #1340: Can't search alphabetical words on the HTML quick search generated
|
||||
with language='ja'.
|
||||
* #1319: Do not crash if the :confval:`html_logo` file does not exist.
|
||||
* #603: Do not use the HTML-ized title for building the search index (that
|
||||
resulted in "literal" being found on every page with a literal in the
|
||||
title).
|
||||
* #751: Allow production lists longer than a page in LaTeX by using longtable.
|
||||
* #764: Always look for stopwords lowercased in JS search.
|
||||
* #814: autodoc: Guard against strange type objects that don't have
|
||||
``__bases__``.
|
||||
* #932: autodoc: Do not crash if ``__doc__`` is not a string.
|
||||
* #933: Do not crash if an :rst:role:`option` value is malformed (contains
|
||||
spaces but no option name).
|
||||
* #908: On Python 3, handle error messages from LaTeX correctly in the pngmath
|
||||
extension.
|
||||
* #943: In autosummary, recognize "first sentences" to pull from the docstring
|
||||
if they contain uppercase letters.
|
||||
* #923: Take the entire LaTeX document into account when caching
|
||||
pngmath-generated images. This rebuilds them correctly when
|
||||
:confval:`pngmath_latex_preamble` changes.
|
||||
* #901: Emit a warning when using docutils' new "math" markup without a Sphinx
|
||||
math extension active.
|
||||
* #845: In code blocks, when the selected lexer fails, display line numbers
|
||||
nevertheless if configured.
|
||||
* #929: Support parsed-literal blocks in LaTeX output correctly.
|
||||
* #949: Update the tabulary.sty packed with Sphinx.
|
||||
* #1050: Add anonymous labels into ``objects.inv`` to be referenced via
|
||||
:mod:`~sphinx.ext.intersphinx`.
|
||||
* #1095: Fix print-media stylesheet being included always in the "scrolls"
|
||||
theme.
|
||||
* #1085: Fix current classname not getting set if class description has
|
||||
``:noindex:`` set.
|
||||
* #1181: Report option errors in autodoc directives more gracefully.
|
||||
* #1155: Fix autodocumenting C-defined methods as attributes in Python 3.
|
||||
* #1233: Allow finding both Python classes and exceptions with the "class" and
|
||||
"exc" roles in intersphinx.
|
||||
* #1198: Allow "image" for the "figwidth" option of the :rst:dir:`figure`
|
||||
directive as documented by docutils.
|
||||
* #1152: Fix pycode parsing errors of Python 3 code by including two grammar
|
||||
versions for Python 2 and 3, and loading the appropriate version for the
|
||||
running Python version.
|
||||
* #1017: Be helpful and tell the user when the argument to :rst:dir:`option`
|
||||
does not match the required format.
|
||||
* #1345: Fix two bugs with :confval:`nitpick_ignore`; now you don't have to
|
||||
remove the store environment for changes to have effect.
|
||||
* #1072: In the JS search, fix issues searching for upper-cased words by
|
||||
lowercasing words before stemming.
|
||||
* #1299: Make behavior of the :rst:dir:`math` directive more consistent and
|
||||
avoid producing empty environments in LaTeX output.
|
||||
* #1308: Strip HTML tags from the content of "raw" nodes before feeding it
|
||||
to the search indexer.
|
||||
* #1249: Fix duplicate LaTeX page numbering for manual documents.
|
||||
* #1292: In the linkchecker, retry HEAD requests when denied by HTTP 405.
|
||||
Also make the redirect code apparent and tweak the output a bit to be
|
||||
more obvious.
|
||||
* #1285: Avoid name clashes between C domain objects and section titles.
|
||||
* #848: Always take the newest code in incremental rebuilds with the
|
||||
:mod:`sphinx.ext.viewcode` extension.
|
||||
* #979, #1266: Fix exclude handling in ``sphinx-apidoc``.
|
||||
* #1302: Fix regression in :mod:`sphinx.ext.inheritance_diagram` when
|
||||
documenting classes that can't be pickled.
|
||||
* #1316: Remove hard-coded ``font-face`` resources from epub theme.
|
||||
* #1329: Fix traceback with empty translation msgstr in .po files.
|
||||
* #1300: Fix references not working in translated documents in some instances.
|
||||
* #1283: Fix a bug in the detection of changed files that would try to access
|
||||
doctrees of deleted documents.
|
||||
* #1330: Fix :confval:`exclude_patterns` behavior with subdirectories in the
|
||||
:confval:`html_static_path`.
|
||||
* #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.
|
||||
* #1374: Fix for autosummary generating overly-long summaries if first line
|
||||
doesn't end with a period.
|
||||
* #1391: Actually prevent using "pngmath" and "mathjax" extensions at the same
|
||||
time in sphinx-quickstart.
|
||||
* #1386: Fix bug preventing more than one theme being added by the entry point
|
||||
mechanism.
|
||||
* #1370: Ignore "toctree" nodes in text writer, instead of raising.
|
||||
* #1364: Fix 'make gettext' fails when the '.. todolist::' directive is present.
|
||||
* #1367: Fix a change of PR#96 that break sphinx.util.docfields.Field.make_field
|
||||
interface/behavior for `item` argument usage.
|
||||
* #1363: Fix i18n: missing python domain's cross-references with currentmodule
|
||||
directive or currentclass directive.
|
||||
* #1419: Generated i18n sphinx.js files are missing message catalog entries
|
||||
from '.js_t' and '.html'. The issue was introduced in Sphinx 1.1.
|
||||
* #636: Keep straight single quotes in literal blocks in the LaTeX build.
|
||||
`makevar`.
|
||||
* PR#235: comment db schema of websupport lacked a length of the node_id field.
|
||||
Thanks to solos.
|
||||
* #1466,PR#241: Fix failure of the cpp domain parser to parse C+11
|
||||
"variadic templates" declarations. Thanks to Victor Zverovich.
|
||||
* #1459,PR#244: Fix default mathjax js path point to `http://` that cause
|
||||
* #1459,PR#244: Fix default mathjax js path point to ``http://`` that cause
|
||||
mixed-content error on HTTPS server. Thanks to sbrandtb and robo9k.
|
||||
* PR#157: autodoc remove spurious signatures from @property decorated
|
||||
attributes. Thanks to David Ham.
|
||||
* PR#159: Add coverage targets to quickstart generated Makefile and make.bat.
|
||||
Thanks to Matthias Troffaes.
|
||||
* #1251: When specifying toctree :numbered: option and :tocdepth: metadata,
|
||||
sub section number that is larger depth than `:tocdepth:` is shrinked.
|
||||
sub section number that is larger depth than ``:tocdepth:`` is shrunk.
|
||||
* PR#260: Encode underscore in citation labels for latex export. Thanks to
|
||||
Lennart Fricke.
|
||||
* PR#264: Fix could not resolve xref for figure node with :name: option.
|
||||
@ -206,8 +214,8 @@ Bugs fixed
|
||||
* Support for scoped and unscoped enums. Enumerators in unscoped enums
|
||||
are injected into the parent scope in addition to the enum scope.
|
||||
|
||||
* PR#258, #939: Add dedent option for :rst:dir:`code-block` and
|
||||
:rst:dir:`literal-include`. Thanks to Zafar Siddiqui.
|
||||
* PR#258, #939: Add dedent option for `code-block` and
|
||||
`literalinclude`. Thanks to Zafar Siddiqui.
|
||||
* PR#268: Fix numbering section does not work at singlehtml mode. It still
|
||||
ad-hoc fix because there is a issue that section IDs are conflicted.
|
||||
Thanks to Takeshi Komiya.
|
||||
@ -215,20 +223,32 @@ Bugs fixed
|
||||
Takeshi Komiya.
|
||||
* PR#274: Set its URL as a default title value if URL appears in toctree.
|
||||
Thanks to Takeshi Komiya.
|
||||
* PR#276, #1381: :rst:role:`rfc` and :rst:role:`pep` roles support custom link
|
||||
* PR#276, #1381: `rfc` and `pep` roles support custom link
|
||||
text. Thanks to Takeshi Komiya.
|
||||
* PR#277, #1513: highlights for function pointers in argument list of
|
||||
:rst:dir:`c:function`. Thanks to Takeshi Komiya.
|
||||
`c:function`. Thanks to Takeshi Komiya.
|
||||
* PR#278: Fix section entries were shown twice if toctree has been put under
|
||||
only directive. Thanks to Takeshi Komiya.
|
||||
* #1547: pgen2 tokenizer doesn't recognize `...` literal (Ellipsis for py3).
|
||||
* #1547: pgen2 tokenizer doesn't recognize ``...`` literal (Ellipsis for py3).
|
||||
* PR#294: On LaTeX builder, wrap float environment on writing literal_block
|
||||
to avoid separation of caption and body. Thanks to Takeshi Komiya.
|
||||
* PR#295, #1520: ``make.bat latexpdf`` mechanism to ``cd`` back to the current
|
||||
directory. Thanks to Peter Suter.
|
||||
* PR#297, #1571: Add imgpath property to all builders. It make easier to
|
||||
develop builder extensions. Thanks to Takeshi Komiya.
|
||||
* #1584: Point to master doc in HTML "top" link.
|
||||
* #1585: Autosummary of modules broken in Sphinx-1.2.3.
|
||||
* #1610: Sphinx cause AttributeError when MeCab search option is enabled and
|
||||
python-mecab is not installed.
|
||||
* #1674: Do not crash if a module's ``__all__`` is not a list of strings.
|
||||
* #1673: Fix crashes with :confval:`nitpick_ignore` and ``:doc:`` references.
|
||||
* #1686: ifconfig directive doesn't care about default config values.
|
||||
* #1642: Fix only one search result appearing in Chrome.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* Add clarification about the syntax of tags. (:file:`doc/markup/misc.rst`)
|
||||
* #1325: Added a "Intersphinx" tutorial section. (:file:`doc/tutorial.rst`)
|
||||
* Extended the :ref:`documentation about building extensions <dev-extensions>`.
|
||||
|
||||
|
||||
Release 1.2.3 (released Sep 1, 2014)
|
||||
@ -237,7 +257,7 @@ Release 1.2.3 (released Sep 1, 2014)
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #1518: `sphinx-apidoc` command now have a `--version` option to show version
|
||||
* #1518: ``sphinx-apidoc`` command now has a ``--version`` option to show version
|
||||
information and exit
|
||||
* New locales: Hebrew, European Portuguese, Vietnamese.
|
||||
|
||||
@ -255,14 +275,14 @@ Bugs fixed
|
||||
Thanks to Jorge_C.
|
||||
* #1467: Exception on Python3 if nonexistent method is specified by automethod
|
||||
* #1441: autosummary can't handle nested classes correctly.
|
||||
* #1499: With non-callable `setup` in a conf.py, now sphinx-build emits
|
||||
user-friendly error message.
|
||||
* #1499: With non-callable ``setup`` in a conf.py, now sphinx-build emits
|
||||
a user-friendly error message.
|
||||
* #1502: In autodoc, fix display of parameter defaults containing backslashes.
|
||||
* #1226: autodoc, autosummary: importing setup.py by automodule will invoke
|
||||
setup process and execute `sys.exit()`. Now sphinx avoids SystemExit
|
||||
setup process and execute ``sys.exit()``. Now sphinx avoids SystemExit
|
||||
exception and emits warnings without unexpected termination.
|
||||
* #1503: py:function directive generate incorrectly signature when specifying
|
||||
a default parameter with an empty list `[]`. Thanks to Geert Jansen.
|
||||
a default parameter with an empty list ``[]``. Thanks to Geert Jansen.
|
||||
* #1508: Non-ASCII filename raise exception on make singlehtml, latex, man,
|
||||
texinfo and changes.
|
||||
* #1531: On Python3 environment, docutils.conf with 'source_link=true' in the
|
||||
@ -272,11 +292,11 @@ Bugs fixed
|
||||
* PR#281, PR#282, #1509: TODO extension not compatible with websupport. Thanks
|
||||
to Takeshi Komiya.
|
||||
* #1477: gettext does not extract nodes.line in a table or list.
|
||||
* #1544: `make text` generate wrong table when it has empty table cells.
|
||||
* #1544: ``make text`` generates wrong table when it has empty table cells.
|
||||
* #1522: Footnotes from table get displayed twice in LaTeX. This problem has
|
||||
been appeared from Sphinx-1.2.1 by #949.
|
||||
* #508: Sphinx every time exit with zero when is invoked from setup.py command.
|
||||
ex. `python setup.py build_sphinx -b doctest` return zero even if doctest
|
||||
ex. ``python setup.py build_sphinx -b doctest`` return zero even if doctest
|
||||
failed.
|
||||
|
||||
Release 1.2.2 (released Mar 2, 2014)
|
||||
@ -285,7 +305,7 @@ Release 1.2.2 (released Mar 2, 2014)
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* PR#211: When checking for existence of the :confval:`html_logo` file, check
|
||||
* PR#211: When checking for existence of the `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.
|
||||
@ -303,7 +323,7 @@ Bugs fixed
|
||||
* #1370: Ignore "toctree" nodes in text writer, instead of raising.
|
||||
* #1364: Fix 'make gettext' fails when the '.. todolist::' directive is present.
|
||||
* #1367: Fix a change of PR#96 that break sphinx.util.docfields.Field.make_field
|
||||
interface/behavior for `item` argument usage.
|
||||
interface/behavior for ``item`` argument usage.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
@ -325,7 +345,7 @@ Bugs fixed
|
||||
This was caused by a change for #1138.
|
||||
* #1340: Can't search alphabetical words on the HTML quick search generated
|
||||
with language='ja'.
|
||||
* #1319: Do not crash if the :confval:`html_logo` file does not exist.
|
||||
* #1319: Do not crash if the `html_logo` file does not exist.
|
||||
* #603: Do not use the HTML-ized title for building the search index (that
|
||||
resulted in "literal" being found on every page with a literal in the
|
||||
title).
|
||||
@ -342,7 +362,7 @@ Bugs fixed
|
||||
if they contain uppercase letters.
|
||||
* #923: Take the entire LaTeX document into account when caching
|
||||
pngmath-generated images. This rebuilds them correctly when
|
||||
:confval:`pngmath_latex_preamble` changes.
|
||||
`pngmath_latex_preamble` changes.
|
||||
* #901: Emit a warning when using docutils' new "math" markup without a Sphinx
|
||||
math extension active.
|
||||
* #845: In code blocks, when the selected lexer fails, display line numbers
|
||||
@ -359,14 +379,14 @@ Bugs fixed
|
||||
* #1155: Fix autodocumenting C-defined methods as attributes in Python 3.
|
||||
* #1233: Allow finding both Python classes and exceptions with the "class" and
|
||||
"exc" roles in intersphinx.
|
||||
* #1198: Allow "image" for the "figwidth" option of the :rst:dir:`figure`
|
||||
* #1198: Allow "image" for the "figwidth" option of the :dudir:`figure`
|
||||
directive as documented by docutils.
|
||||
* #1152: Fix pycode parsing errors of Python 3 code by including two grammar
|
||||
versions for Python 2 and 3, and loading the appropriate version for the
|
||||
running Python version.
|
||||
* #1017: Be helpful and tell the user when the argument to :rst:dir:`option`
|
||||
does not match the required format.
|
||||
* #1345: Fix two bugs with :confval:`nitpick_ignore`; now you don't have to
|
||||
* #1345: Fix two bugs with `nitpick_ignore`; now you don't have to
|
||||
remove the store environment for changes to have effect.
|
||||
* #1072: In the JS search, fix issues searching for upper-cased words by
|
||||
lowercasing words before stemming.
|
||||
@ -389,8 +409,8 @@ Bugs fixed
|
||||
* #1300: Fix references not working in translated documents in some instances.
|
||||
* #1283: Fix a bug in the detection of changed files that would try to access
|
||||
doctrees of deleted documents.
|
||||
* #1330: Fix :confval:`exclude_patterns` behavior with subdirectories in the
|
||||
:confval:`html_static_path`.
|
||||
* #1330: Fix `exclude_patterns` behavior with subdirectories in the
|
||||
`html_static_path`.
|
||||
* #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.
|
||||
@ -422,7 +442,7 @@ Bugs fixed
|
||||
* Restore ``versionmodified`` CSS class for versionadded/changed and deprecated
|
||||
directives.
|
||||
|
||||
* PR#181: Fix `html_theme_path=['.']` is a trigger of rebuild all documents
|
||||
* PR#181: Fix ``html_theme_path = ['.']`` is a trigger of rebuild all documents
|
||||
always (This change keeps the current "theme changes cause a rebuild"
|
||||
feature).
|
||||
|
||||
@ -489,7 +509,7 @@ Features added
|
||||
* Support docutils.conf 'writers' and 'html4css1 writer' section in the HTML
|
||||
writer. The latex, manpage and texinfo writers also support their respective
|
||||
'writers' sections.
|
||||
* The new :confval:`html_extra_path` config value allows to specify directories
|
||||
* The new `html_extra_path` config value allows to specify directories
|
||||
with files that should be copied directly to the HTML output directory.
|
||||
* Autodoc directives for module data and attributes now support an
|
||||
``annotation`` option, so that the default display of the data/attribute
|
||||
@ -560,10 +580,10 @@ Incompatible changes
|
||||
|
||||
* Removed ``sphinx.util.compat.directive_dwim()`` and
|
||||
``sphinx.roles.xfileref_role()`` which were deprecated since version 1.0.
|
||||
* PR#122: the files given in :confval:`latex_additional_files` now override TeX
|
||||
* PR#122: the files given in `latex_additional_files` now override TeX
|
||||
files included by Sphinx, such as ``sphinx.sty``.
|
||||
* PR#124: the node generated by :rst:dir:`versionadded`,
|
||||
:rst:dir:`versionchanged` and :rst:dir:`deprecated` directives now includes
|
||||
* PR#124: the node generated by `versionadded`,
|
||||
`versionchanged` and `deprecated` directives now includes
|
||||
all added markup (such as "New in version X") as child nodes, and no
|
||||
additional text must be generated by writers.
|
||||
* PR#99: the :rst:dir:`seealso` directive now generates admonition nodes instead
|
||||
@ -617,7 +637,7 @@ Features added
|
||||
asterisks ("*").
|
||||
- The default value for the ``paragraphindent`` has been changed from 2 to 0
|
||||
meaning that paragraphs are no longer indented by default.
|
||||
- #1110: A new configuration value :confval:`texinfo_no_detailmenu` has been
|
||||
- #1110: A new configuration value `texinfo_no_detailmenu` has been
|
||||
added for controlling whether a ``@detailmenu`` is added in the "Top"
|
||||
node's menu.
|
||||
- Detailed menus are no longer created except for the "Top" node.
|
||||
@ -626,16 +646,16 @@ Features added
|
||||
|
||||
* LaTeX builder:
|
||||
|
||||
- PR#115: Add ``'transition'`` item in :confval:`latex_elements` for
|
||||
- PR#115: Add ``'transition'`` item in `latex_elements` for
|
||||
customizing how transitions are displayed. Thanks to Jeff Klukas.
|
||||
- PR#114: The LaTeX writer now includes the "cmap" package by default. The
|
||||
``'cmappkg'`` item in :confval:`latex_elements` can be used to control this.
|
||||
``'cmappkg'`` item in `latex_elements` can be used to control this.
|
||||
Thanks to Dmitry Shachnev.
|
||||
- The ``'fontpkg'`` item in :confval:`latex_elements` now defaults to ``''``
|
||||
when the :confval:`language` uses the Cyrillic script. Suggested by Dmitry
|
||||
- The ``'fontpkg'`` item in `latex_elements` now defaults to ``''``
|
||||
when the `language` uses the Cyrillic script. Suggested by Dmitry
|
||||
Shachnev.
|
||||
- The :confval:`latex_documents`, :confval:`texinfo_documents`, and
|
||||
:confval:`man_pages` configuration values will be set to default values based
|
||||
- The `latex_documents`, `texinfo_documents`, and
|
||||
`man_pages` configuration values will be set to default values based
|
||||
on the :confval:`master_doc` if not explicitly set in :file:`conf.py`.
|
||||
Previously, if these values were not set, no output would be generated by
|
||||
their respective builders.
|
||||
@ -653,13 +673,13 @@ Features added
|
||||
- Added the Docutils-native XML and pseudo-XML builders. See
|
||||
:class:`XMLBuilder` and :class:`PseudoXMLBuilder`.
|
||||
- PR#45: The linkcheck builder now checks ``#anchor``\ s for existence.
|
||||
- PR#123, #1106: Add :confval:`epub_use_index` configuration value. If
|
||||
provided, it will be used instead of :confval:`html_use_index` for epub
|
||||
- PR#123, #1106: Add `epub_use_index` configuration value. If
|
||||
provided, it will be used instead of `html_use_index` for epub
|
||||
builder.
|
||||
- PR#126: Add :confval:`epub_tocscope` configuration value. The setting
|
||||
- PR#126: Add `epub_tocscope` configuration value. The setting
|
||||
controls the generation of the epub toc. The user can now also include
|
||||
hidden toc entries.
|
||||
- PR#112: Add :confval:`epub_show_urls` configuration value.
|
||||
- PR#112: Add `epub_show_urls` configuration value.
|
||||
|
||||
* Extensions:
|
||||
|
||||
@ -727,7 +747,7 @@ Bugs fixed
|
||||
* #1127: Fix traceback when autodoc tries to tokenize a non-Python file.
|
||||
* #1126: Fix double-hyphen to en-dash conversion in wrong places such as
|
||||
command-line option names in LaTeX.
|
||||
* #1123: Allow whitespaces in filenames given to :rst:dir:`literalinclude`.
|
||||
* #1123: Allow whitespaces in filenames given to `literalinclude`.
|
||||
* #1120: Added improvements about i18n for themes "basic", "haiku" and
|
||||
"scrolls" that Sphinx built-in. Thanks to Leonardo J. Caballero G.
|
||||
* #1118: Updated Spanish translation. Thanks to Leonardo J. Caballero G.
|
||||
@ -735,7 +755,7 @@ Bugs fixed
|
||||
* #1112: Avoid duplicate download files when referenced from documents in
|
||||
different ways (absolute/relative).
|
||||
* #1111: Fix failure to find uppercase words in search when
|
||||
:confval:`html_search_language` is 'ja'. Thanks to Tomo Saito.
|
||||
`html_search_language` is 'ja'. Thanks to Tomo Saito.
|
||||
* #1108: The text writer now correctly numbers enumerated lists with
|
||||
non-default start values (based on patch by Ewan Edwards).
|
||||
* #1102: Support multi-context "with" statements in autodoc.
|
||||
@ -800,7 +820,7 @@ Release 1.1.3 (Mar 10, 2012)
|
||||
* #860: Do not crash when encountering invalid doctest examples, just
|
||||
emit a warning.
|
||||
|
||||
* #864: Fix crash with some settings of :confval:`modindex_common_prefix`.
|
||||
* #864: Fix crash with some settings of `modindex_common_prefix`.
|
||||
|
||||
* #862: Fix handling of ``-D`` and ``-A`` options on Python 3.
|
||||
|
||||
@ -864,7 +884,7 @@ Release 1.1 (Oct 9, 2011)
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
* The :rst:dir:`py:module` directive doesn't output its ``platform`` option
|
||||
* The `py:module` directive doesn't output its ``platform`` option
|
||||
value anymore. (It was the only thing that the directive did output, and
|
||||
therefore quite inconsistent.)
|
||||
|
||||
@ -900,7 +920,7 @@ Features added
|
||||
:rst:dir:`toctree`\'s ``numbered`` option.
|
||||
- #586: Implemented improved :rst:dir:`glossary` markup which allows
|
||||
multiple terms per definition.
|
||||
- #478: Added :rst:dir:`py:decorator` directive to describe decorators.
|
||||
- #478: Added `py:decorator` directive to describe decorators.
|
||||
- C++ domain now supports array definitions.
|
||||
- C++ domain now supports doc fields (``:param x:`` inside directives).
|
||||
- Section headings in :rst:dir:`only` directives are now correctly
|
||||
@ -911,7 +931,7 @@ Features added
|
||||
* HTML builder:
|
||||
|
||||
- Added ``pyramid`` theme.
|
||||
- #559: :confval:`html_add_permalinks` is now a string giving the
|
||||
- #559: `html_add_permalinks` is now a string giving the
|
||||
text to display in permalinks.
|
||||
- #259: HTML table rows now have even/odd CSS classes to enable
|
||||
"Zebra styling".
|
||||
@ -919,26 +939,26 @@ Features added
|
||||
|
||||
* Other builders:
|
||||
|
||||
- #516: Added new value of the :confval:`latex_show_urls` option to
|
||||
- #516: Added new value of the `latex_show_urls` option to
|
||||
show the URLs in footnotes.
|
||||
- #209: Added :confval:`text_newlines` and :confval:`text_sectionchars`
|
||||
- #209: Added `text_newlines` and `text_sectionchars`
|
||||
config values.
|
||||
- Added :confval:`man_show_urls` config value.
|
||||
- Added `man_show_urls` config value.
|
||||
- #472: linkcheck builder: Check links in parallel, use HTTP HEAD
|
||||
requests and allow configuring the timeout. New config values:
|
||||
:confval:`linkcheck_timeout` and :confval:`linkcheck_workers`.
|
||||
- #521: Added :confval:`linkcheck_ignore` config value.
|
||||
`linkcheck_timeout` and `linkcheck_workers`.
|
||||
- #521: Added `linkcheck_ignore` config value.
|
||||
- #28: Support row/colspans in tables in the LaTeX builder.
|
||||
|
||||
* Configuration and extensibility:
|
||||
|
||||
- #537: Added :confval:`nitpick_ignore`.
|
||||
- #537: Added `nitpick_ignore`.
|
||||
- #306: Added :event:`env-get-outdated` event.
|
||||
- :meth:`.Application.add_stylesheet` now accepts full URIs.
|
||||
|
||||
* Autodoc:
|
||||
|
||||
- #564: Add :confval:`autodoc_docstring_signature`. When enabled (the
|
||||
- #564: Add `autodoc_docstring_signature`. When enabled (the
|
||||
default), autodoc retrieves the signature from the first line of the
|
||||
docstring, if it is found there.
|
||||
- #176: Provide ``private-members`` option for autodoc directives.
|
||||
@ -956,12 +976,12 @@ Features added
|
||||
- Added ``inline`` option to graphviz directives, and fixed the
|
||||
default (block-style) in LaTeX output.
|
||||
- #590: Added ``caption`` option to graphviz directives.
|
||||
- #553: Added :rst:dir:`testcleanup` blocks in the doctest extension.
|
||||
- #594: :confval:`trim_doctest_flags` now also removes ``<BLANKLINE>``
|
||||
- #553: Added `testcleanup` blocks in the doctest extension.
|
||||
- #594: `trim_doctest_flags` now also removes ``<BLANKLINE>``
|
||||
indicators.
|
||||
- #367: Added automatic exclusion of hidden members in inheritance
|
||||
diagrams, and an option to selectively enable it.
|
||||
- Added :confval:`pngmath_add_tooltips`.
|
||||
- Added `pngmath_add_tooltips`.
|
||||
- The math extension displaymath directives now support ``name`` in
|
||||
addition to ``label`` for giving the equation label, for compatibility
|
||||
with Docutils.
|
||||
@ -1034,7 +1054,7 @@ Release 1.0.8 (Sep 23, 2011)
|
||||
* #669: Respect the ``noindex`` flag option in py:module directives.
|
||||
|
||||
* #675: Fix IndexErrors when including nonexisting lines with
|
||||
:rst:dir:`literalinclude`.
|
||||
`literalinclude`.
|
||||
|
||||
* #676: Respect custom function/method parameter separator strings.
|
||||
|
||||
@ -1117,7 +1137,7 @@ Release 1.0.6 (Jan 04, 2011)
|
||||
* #570: Try decoding ``-D`` and ``-A`` command-line arguments with
|
||||
the locale's preferred encoding.
|
||||
|
||||
* #528: Observe :confval:`locale_dirs` when looking for the JS
|
||||
* #528: Observe `locale_dirs` when looking for the JS
|
||||
translations file.
|
||||
|
||||
* #574: Add special code for better support of Japanese documents
|
||||
@ -1290,51 +1310,51 @@ Features added
|
||||
|
||||
- Added a "nitpicky" mode that emits warnings for all missing
|
||||
references. It is activated by the :option:`-n` command-line switch
|
||||
or the :confval:`nitpicky` config value.
|
||||
or the `nitpicky` config value.
|
||||
- Added ``latexpdf`` target in quickstart Makefile.
|
||||
|
||||
* Markup:
|
||||
|
||||
- The :rst:role:`menuselection` and :rst:role:`guilabel` roles now
|
||||
- The `menuselection` and `guilabel` roles now
|
||||
support ampersand accelerators.
|
||||
- New more compact doc field syntax is now recognized: ``:param type
|
||||
name: description``.
|
||||
- Added ``tab-width`` option to :rst:dir:`literalinclude` directive.
|
||||
- Added ``tab-width`` option to `literalinclude` directive.
|
||||
- Added ``titlesonly`` option to :rst:dir:`toctree` directive.
|
||||
- Added the ``prepend`` and ``append`` options to the
|
||||
:rst:dir:`literalinclude` directive.
|
||||
`literalinclude` directive.
|
||||
- #284: All docinfo metadata is now put into the document metadata, not
|
||||
just the author.
|
||||
- The :rst:role:`ref` role can now also reference tables by caption.
|
||||
- The :rst:dir:`include` directive now supports absolute paths, which
|
||||
- The `ref` role can now also reference tables by caption.
|
||||
- The :dudir:`include` directive now supports absolute paths, which
|
||||
are interpreted as relative to the source directory.
|
||||
- In the Python domain, references like ``:func:`.name``` now look for
|
||||
matching names with any prefix if no direct match is found.
|
||||
|
||||
* Configuration:
|
||||
|
||||
- Added :confval:`rst_prolog` config value.
|
||||
- Added :confval:`html_secnumber_suffix` config value to control
|
||||
- Added `rst_prolog` config value.
|
||||
- Added `html_secnumber_suffix` config value to control
|
||||
section numbering format.
|
||||
- Added :confval:`html_compact_lists` config value to control
|
||||
- Added `html_compact_lists` config value to control
|
||||
docutils' compact lists feature.
|
||||
- The :confval:`html_sidebars` config value can now contain patterns
|
||||
- The `html_sidebars` config value can now contain patterns
|
||||
as keys, and the values can be lists that explicitly select which
|
||||
sidebar templates should be rendered. That means that the builtin
|
||||
sidebar contents can be included only selectively.
|
||||
- :confval:`html_static_path` can now contain single file entries.
|
||||
- The new universal config value :confval:`exclude_patterns` makes the
|
||||
old :confval:`unused_docs`, :confval:`exclude_trees` and
|
||||
:confval:`exclude_dirnames` obsolete.
|
||||
- Added :confval:`html_output_encoding` config value.
|
||||
- Added the :confval:`latex_docclass` config value and made the
|
||||
- `html_static_path` can now contain single file entries.
|
||||
- The new universal config value `exclude_patterns` makes the
|
||||
old ``unused_docs``, ``exclude_trees`` and
|
||||
``exclude_dirnames`` obsolete.
|
||||
- Added `html_output_encoding` config value.
|
||||
- Added the `latex_docclass` config value and made the
|
||||
"twoside" documentclass option overridable by "oneside".
|
||||
- Added the :confval:`trim_doctest_flags` config value, which is true
|
||||
- Added the `trim_doctest_flags` config value, which is true
|
||||
by default.
|
||||
- Added :confval:`html_show_copyright` config value.
|
||||
- Added :confval:`latex_show_pagerefs` and :confval:`latex_show_urls`
|
||||
- Added `html_show_copyright` config value.
|
||||
- Added `latex_show_pagerefs` and `latex_show_urls`
|
||||
config values.
|
||||
- The behavior of :confval:`html_file_suffix` changed slightly: the
|
||||
- The behavior of `html_file_suffix` changed slightly: the
|
||||
empty string now means "no suffix" instead of "default suffix", use
|
||||
``None`` for "default suffix".
|
||||
|
||||
@ -1376,7 +1396,7 @@ Features added
|
||||
* Extension API:
|
||||
|
||||
- Added :event:`html-collect-pages`.
|
||||
- Added :confval:`needs_sphinx` config value and
|
||||
- Added `needs_sphinx` config value and
|
||||
:meth:`~sphinx.application.Sphinx.require_sphinx` application API
|
||||
method.
|
||||
- #200: Added :meth:`~sphinx.application.Sphinx.add_stylesheet`
|
||||
@ -1388,7 +1408,7 @@ Features added
|
||||
- Added the :mod:`~sphinx.ext.extlinks` extension.
|
||||
- Added support for source ordering of members in autodoc, with
|
||||
``autodoc_member_order = 'bysource'``.
|
||||
- Added :confval:`autodoc_default_flags` config value, which can be
|
||||
- Added `autodoc_default_flags` config value, which can be
|
||||
used to select default flags for all autodoc directives.
|
||||
- Added a way for intersphinx to refer to named labels in other
|
||||
projects, and to specify the project you want to link to.
|
||||
@ -1398,7 +1418,7 @@ Features added
|
||||
extension, thanks to Pauli Virtanen.
|
||||
- #309: The :mod:`~sphinx.ext.graphviz` extension can now output SVG
|
||||
instead of PNG images, controlled by the
|
||||
:confval:`graphviz_output_format` config value.
|
||||
`graphviz_output_format` config value.
|
||||
- Added ``alt`` option to :rst:dir:`graphviz` extension directives.
|
||||
- Added ``exclude`` argument to :func:`.autodoc.between`.
|
||||
|
||||
@ -1423,5 +1443,5 @@ Previous versions
|
||||
=================
|
||||
|
||||
The changelog for versions before 1.0 can be found in the file ``CHANGES.old``
|
||||
in the source distribution or `at BitBucket
|
||||
<https://bitbucket.org/birkenfeld/sphinx/raw/tip/CHANGES.old>`__.
|
||||
in the source distribution or `at Github
|
||||
<https://github.com/sphinx-doc/sphinx/raw/master/CHANGES.old>`__.
|
||||
|
8
EXAMPLES
8
EXAMPLES
@ -44,6 +44,7 @@ Documentation using the default theme
|
||||
* Paste: http://pythonpaste.org/script/
|
||||
* Paver: http://paver.github.io/paver/
|
||||
* Pioneers and Prominent Men of Utah: http://pioneers.rstebbing.com/
|
||||
* PyCantonese: http://pycantonese.github.io/
|
||||
* Pyccuracy: https://github.com/heynemann/pyccuracy/wiki/
|
||||
* PyCuda: http://documen.tician.de/pycuda/
|
||||
* Pyevolve: http://pyevolve.sourceforge.net/
|
||||
@ -51,6 +52,7 @@ Documentation using the default theme
|
||||
* PyMQI: http://pythonhosted.org/pymqi/
|
||||
* PyPubSub: http://pubsub.sourceforge.net/
|
||||
* pyrticle: http://documen.tician.de/pyrticle/
|
||||
* pySPACE: http://pyspace.github.io/pyspace/
|
||||
* Python: http://docs.python.org/
|
||||
* python-apt: http://apt.alioth.debian.org/python-apt-doc/
|
||||
* PyUblas: http://documen.tician.de/pyublas/
|
||||
@ -73,6 +75,7 @@ Documentation using a customized version of the default theme
|
||||
* Chaco: http://docs.enthought.com/chaco/
|
||||
* Chef: http://docs.opscode.com/
|
||||
* Djagios: http://djagios.org/
|
||||
* EZ-Draw: http://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html
|
||||
* GetFEM++: http://home.gna.org/getfem/
|
||||
* Google or-tools:
|
||||
https://or-tools.googlecode.com/svn/trunk/documentation/user_manual/index.html
|
||||
@ -181,6 +184,8 @@ Documentation using a custom theme/integrated in a site
|
||||
* Pylons: http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/
|
||||
* PyMOTW: http://pymotw.com/2/
|
||||
* pypol: http://pypol.altervista.org/ (celery)
|
||||
* python-aspectlib: http://python-aspectlib.readthedocs.org/en/latest/
|
||||
(`sphinx-py3doc-enhanced-theme`_)
|
||||
* QGIS: http://qgis.org/en/docs/index.html
|
||||
* qooxdoo: http://manual.qooxdoo.org/current/
|
||||
* Roundup: http://www.roundup-tracker.org/
|
||||
@ -196,6 +201,8 @@ Documentation using a custom theme/integrated in a site
|
||||
* Werkzeug: http://werkzeug.pocoo.org/docs/
|
||||
* WFront: http://discorporate.us/projects/WFront/
|
||||
|
||||
.. _sphinx-py3doc-enhanced-theme: https://pypi.python.org/pypi/sphinx_py3doc_enhanced_theme
|
||||
|
||||
|
||||
Homepages and other non-documentation sites
|
||||
-------------------------------------------
|
||||
@ -235,6 +242,7 @@ Books produced using Sphinx
|
||||
http://www.oreilly.co.jp/books/9784873116488/
|
||||
* "LassoGuide":
|
||||
http://www.lassosoft.com/Lasso-Documentation
|
||||
* "Software-Dokumentation mit Sphinx": http://www.amazon.de/dp/1497448689/
|
||||
|
||||
|
||||
Thesis using Sphinx
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
License for Sphinx
|
||||
==================
|
||||
|
||||
Copyright (c) 2007-2013 by the Sphinx team (see AUTHORS file).
|
||||
Copyright (c) 2007-2015 by the Sphinx team (see AUTHORS file).
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
21
Makefile
21
Makefile
@ -7,7 +7,22 @@ DONT_CHECK = -i build -i dist -i sphinx/style/jquery.js \
|
||||
-i sphinx/pycode/pgen2 -i sphinx/util/smartypants.py \
|
||||
-i .ropeproject -i doc/_build -i tests/path.py \
|
||||
-i tests/coverage.py -i env -i utils/convert.py \
|
||||
-i sphinx/search/ja.py \
|
||||
-i sphinx/search/da.py \
|
||||
-i sphinx/search/de.py \
|
||||
-i sphinx/search/en.py \
|
||||
-i sphinx/search/es.py \
|
||||
-i sphinx/search/fi.py \
|
||||
-i sphinx/search/fr.py \
|
||||
-i sphinx/search/hu.py \
|
||||
-i sphinx/search/it.py \
|
||||
-i sphinx/search/ja.py \
|
||||
-i sphinx/search/nl.py \
|
||||
-i sphinx/search/no.py \
|
||||
-i sphinx/search/pt.py \
|
||||
-i sphinx/search/ro.py \
|
||||
-i sphinx/search/ru.py \
|
||||
-i sphinx/search/sv.py \
|
||||
-i sphinx/search/tr.py \
|
||||
-i utils/reindent3.py -i utils/check_sources3.py -i .tox
|
||||
|
||||
all: clean-pyc clean-backupfiles check test
|
||||
@ -48,10 +63,10 @@ reindent:
|
||||
@$(PYTHON) utils/reindent.py -r -n .
|
||||
endif
|
||||
|
||||
test: build
|
||||
test:
|
||||
@cd tests; $(PYTHON) run.py -d -m '^[tT]est' $(TEST)
|
||||
|
||||
covertest: build
|
||||
covertest:
|
||||
@cd tests; $(PYTHON) run.py -d -m '^[tT]est' --with-coverage \
|
||||
--cover-package=sphinx $(TEST)
|
||||
|
||||
|
21
README.rst
21
README.rst
@ -2,6 +2,9 @@
|
||||
README for Sphinx
|
||||
=================
|
||||
|
||||
This is the Sphinx documentation generator, see http://sphinx-doc.org/.
|
||||
|
||||
|
||||
Installing
|
||||
==========
|
||||
|
||||
@ -17,7 +20,7 @@ Reading the docs
|
||||
After installing::
|
||||
|
||||
cd doc
|
||||
sphinx-build . _build/html
|
||||
make html
|
||||
|
||||
Then, direct your browser to ``_build/html/index.html``.
|
||||
|
||||
@ -35,21 +38,25 @@ If you want to use a different interpreter, e.g. ``python3``, use::
|
||||
|
||||
PYTHON=python3 make test
|
||||
|
||||
Continuous testing runs on travis:
|
||||
|
||||
.. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master
|
||||
:target: https://travis-ci.org/sphinx-doc/sphinx
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a
|
||||
feature idea or a bug. There are Non Assigned issues:
|
||||
https://bitbucket.org/birkenfeld/sphinx/issues?status=new&status=open&responsible=
|
||||
feature idea or a bug.
|
||||
#. If you feel uncomfortable or uncertain about an issue or your changes, feel
|
||||
free to email sphinx-dev@googlegroups.com.
|
||||
#. Fork the repository on Bitbucket https://bitbucket.org/birkenfeld/sphinx
|
||||
to start making your changes to the **default** branch for next major
|
||||
#. Fork the repository on GitHub https://github.com/sphinx-doc/sphinx
|
||||
to start making your changes to the **master** branch for next major
|
||||
version, or **stable** branch for next minor version.
|
||||
#. Write a test which shows that the bug was fixed or that the feature works
|
||||
as expected.
|
||||
#. Send a pull request and bug the maintainer until it gets merged and
|
||||
published. Make sure to add yourself to AUTHORS
|
||||
<https://bitbucket.org/birkenfeld/sphinx/src/tip/AUTHORS> and the change to
|
||||
CHANGES <https://bitbucket.org/birkenfeld/sphinx/src/tip/CHANGES>.
|
||||
<https://github.com/sphinx-doc/sphinx/blob/master/AUTHORS> and the change to
|
||||
CHANGES <https://github.com/sphinx-doc/sphinx/blob/master/CHANGES>.
|
||||
|
5
TODO
5
TODO
@ -1,5 +0,0 @@
|
||||
Sphinx TODO
|
||||
===========
|
||||
|
||||
All todo items are now tracked as issues in the Sphinx issue tracker at
|
||||
<http://www.bitbucket.org/birkenfeld/sphinx/issues/>.
|
3
doc/_templates/index.html
vendored
3
doc/_templates/index.html
vendored
@ -34,6 +34,9 @@
|
||||
<li>{%trans path=pathto('extensions')%}<b>Extensions:</b> automatic testing of code snippets, inclusion of
|
||||
docstrings from Python modules (API docs), and
|
||||
<a href="{{ path }}#builtin-sphinx-extensions">more</a>{%endtrans%}</li>
|
||||
<li>{%trans path=pathto('develop')%}<b>Contributed extensions:</b> more than
|
||||
50 extensions <a href="{{ path }}#extensions">contributed by users</a>
|
||||
in a second repository; most of them installable from PyPI{%endtrans%}</li>
|
||||
</ul>
|
||||
<p>{%trans%}
|
||||
Sphinx uses <a href="http://docutils.sf.net/rst.html">reStructuredText</a>
|
||||
|
8
doc/_templates/indexsidebar.html
vendored
8
doc/_templates/indexsidebar.html
vendored
@ -3,18 +3,18 @@
|
||||
{%trans%}project{%endtrans%}</p>
|
||||
|
||||
<h3>Download</h3>
|
||||
{% if version.endswith('(hg)') %}
|
||||
{% if version.endswith('a0') %}
|
||||
<p>{%trans%}This documentation is for version <b>{{ version }}</b>, which is
|
||||
not released yet.{%endtrans%}</p>
|
||||
<p>{%trans%}You can use it from the
|
||||
<a href="http://bitbucket.org/birkenfeld/sphinx/">Mercurial repo</a> or look for
|
||||
<a href="https://github.com/sphinx-doc/sphinx/">Git repo</a> or look for
|
||||
released versions in the <a href="http://pypi.python.org/pypi/Sphinx">Python
|
||||
Package Index</a>.{%endtrans%}</p>
|
||||
{% else %}
|
||||
<p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p>
|
||||
<p>{%trans%}Get Sphinx from the <a href="http://pypi.python.org/pypi/Sphinx">Python Package
|
||||
Index</a>, or install it with:{%endtrans%}</p>
|
||||
<pre>easy_install -U Sphinx</pre>
|
||||
<pre>pip install -U Sphinx</pre>
|
||||
<p>{%trans%}Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
|
||||
are also available.{%endtrans%}</p>
|
||||
{% endif %}
|
||||
@ -30,4 +30,4 @@ are also available.{%endtrans%}</p>
|
||||
</form>
|
||||
<p>{%trans%}or come to the <tt>#sphinx-doc</tt> channel on FreeNode.{%endtrans%}</p>
|
||||
<p>{%trans%}You can also open an issue at the
|
||||
<a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.{%endtrans%}</p>
|
||||
<a href="https://github.com/sphinx-doc/sphinx/issues">tracker</a>.{%endtrans%}</p>
|
||||
|
2
doc/_themes/sphinx13/layout.html
vendored
2
doc/_themes/sphinx13/layout.html
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
Sphinx layout template for the sphinxdoc theme.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- extends "basic/layout.html" %}
|
||||
|
2
doc/_themes/sphinx13/static/sphinx13.css
vendored
2
doc/_themes/sphinx13/static/sphinx13.css
vendored
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Sphinx stylesheet -- sphinx13 theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
@ -1,9 +1,9 @@
|
||||
:tocdepth: 2
|
||||
|
||||
.. _authors:
|
||||
|
||||
Sphinx authors
|
||||
==============
|
||||
|
||||
.. include:: ../AUTHORS
|
||||
|
||||
:tocdepth: 2
|
||||
|
||||
.. _authors:
|
||||
|
||||
Sphinx authors
|
||||
==============
|
||||
|
||||
.. include:: ../AUTHORS
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
:tocdepth: 2
|
||||
|
||||
.. default-role:: any
|
||||
|
||||
.. _changes:
|
||||
|
||||
Changes in Sphinx
|
||||
|
@ -7,14 +7,15 @@ import sphinx
|
||||
|
||||
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||
'sphinx.ext.autosummary', 'sphinx.ext.extlinks']
|
||||
'sphinx.ext.autosummary', 'sphinx.ext.extlinks',
|
||||
'sphinx.ext.viewcode']
|
||||
|
||||
master_doc = 'contents'
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
project = 'Sphinx'
|
||||
copyright = '2007-2014, Georg Brandl and the Sphinx team'
|
||||
copyright = '2007-2015, Georg Brandl and the Sphinx team'
|
||||
version = sphinx.__released__
|
||||
release = version
|
||||
show_authors = True
|
||||
@ -83,7 +84,7 @@ texinfo_documents = [
|
||||
|
||||
# We're not using intersphinx right now, but if we did, this would be part of
|
||||
# the mapping:
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/dev', None)}
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/2/', None)}
|
||||
|
||||
# Sphinx document translation with sphinx gettext feature uses these settings:
|
||||
locale_dirs = ['locale/']
|
||||
|
@ -231,6 +231,30 @@ General configuration
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. confval:: numfig
|
||||
|
||||
If true, figures, tables and code-blocks are automatically numbered if they
|
||||
has caption. For now, it works only with the HTML builder. Default is ``False``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. confval:: numfig_format
|
||||
|
||||
A dictionary mapping ``'figure'``, ``'table'`` and ``'code-block'`` to
|
||||
strings that are used for format of figure numbers. Default is to use
|
||||
``'Fig. %s'`` for ``'figure'``, ``'Table %s'`` for ``'table'`` and
|
||||
``'Listing %s'`` for ``'code-block'``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. confval:: numfig_secnum_depth
|
||||
|
||||
The scope of figure numbers, that is, the numfig feature numbers figures
|
||||
in which scope. ``0`` means "whole document". ``1`` means "in a section".
|
||||
Sphinx numbers like x.1, x.2, x.3... ``2`` means "in a subsection". Sphinx
|
||||
numbers like x.x.1, x.x.2, x.x.3..., and so on. Default is ``1``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
Project information
|
||||
-------------------
|
||||
@ -279,10 +303,19 @@ Project information
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. confval:: highlight_options
|
||||
|
||||
A dictionary of options that modify how the lexer specified by
|
||||
:confval:`highlight_language` generates highlighted source code. These are
|
||||
lexer-specific; for the options understood by each, see the
|
||||
`Pygments documentation <http://pygments.org/docs/lexers/>`_.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. confval:: pygments_style
|
||||
|
||||
The style name to use for Pygments highlighting of source code. The default
|
||||
style is selected by the theme for HTML output, and ``'sphinx'`` otherwise.
|
||||
The style name to use for Pygments highlighting of source code. If not set,
|
||||
either the theme's default style or ``'sphinx'`` is selected for HTML output.
|
||||
|
||||
.. versionchanged:: 0.3
|
||||
If the value is a fully-qualified name of a custom Pygments style class,
|
||||
@ -424,9 +457,17 @@ documentation on :ref:`intl` for details.
|
||||
.. confval:: gettext_uuid
|
||||
|
||||
If true, Sphinx generates uuid information for version tracking in message
|
||||
catalogs.
|
||||
catalogs. It is used for:
|
||||
|
||||
The default is ``True``.
|
||||
* Add uid line for each msgids in .pot files.
|
||||
* Calculate similarity between new msgids and previously saved old msgids.
|
||||
This calculation takes a long time.
|
||||
|
||||
If you want to accelerate the calculation, you can use
|
||||
``python-levenshtein`` 3rd-party package written in C by using
|
||||
:command:`pip install python-levenshtein`.
|
||||
|
||||
The default is ``False``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
@ -447,6 +488,16 @@ documentation on :ref:`intl` for details.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. confval:: gettext_enables
|
||||
|
||||
To specify names to enable gettext extracting and translation applying for
|
||||
i18n. You can specify below names:
|
||||
|
||||
:index: index terms
|
||||
|
||||
The default is ``[]``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. _html-options:
|
||||
|
||||
@ -707,7 +758,7 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
.. confval:: html_use_opensearch
|
||||
|
||||
If nonempty, an `OpenSearch <http://opensearch.org>` description file will be
|
||||
If nonempty, an `OpenSearch <http://opensearch.org>`_ description file will be
|
||||
output, and all pages will contain a ``<link>`` tag referring to it. Since
|
||||
OpenSearch doesn't support relative URLs for its search page location, the
|
||||
value of this option must be the base URL from which these documents are
|
||||
@ -1003,9 +1054,9 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
|
||||
|
||||
This flag determines if sphinx should try to fix image formats that are not
|
||||
supported by some epub readers. At the moment palette images with a small
|
||||
color table are upgraded. You need the Python Image Library (PIL) installed
|
||||
to use this option. The default value is ``False`` because the automatic
|
||||
conversion may lose information.
|
||||
color table are upgraded. You need the Python Image Library (Pillow the
|
||||
successor of the PIL) installed to use this option. The default value is
|
||||
``False`` because the automatic conversion may lose information.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
@ -1014,7 +1065,7 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
|
||||
This option specifies the maximum width of images. If it is set to a value
|
||||
greater than zero, images with a width larger than the given value are
|
||||
scaled accordingly. If it is zero, no scaling is performed. The default
|
||||
value is ``0``. You need the Python Image Library (PIL) installed to use
|
||||
value is ``0``. You need the Python Image Library (Pillow) installed to use
|
||||
this option.
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
@ -5,10 +5,10 @@ Sphinx development
|
||||
|
||||
Sphinx is a maintained by a group of volunteers. We value every contribution!
|
||||
|
||||
* The code can be found in a Mercurial repository, at
|
||||
https://bitbucket.org/birkenfeld/sphinx/.
|
||||
* The code can be found in a Git repository, at
|
||||
https://github.com/sphinx-doc/sphinx/.
|
||||
* Issues and feature requests should be raised in the `tracker
|
||||
<https://bitbucket.org/birkenfeld/sphinx/issues/>`_.
|
||||
<https://github.com/sphinx-doc/sphinx/issues>`_.
|
||||
* The mailing list for development is at `Google Groups
|
||||
<https://groups.google.com/group/sphinx-dev/>`_.
|
||||
* There is also the #sphinx-doc IRC channel on `freenode
|
||||
@ -55,6 +55,7 @@ This is the current list of contributed extensions in that repository:
|
||||
- hyphenator: client-side hyphenation of HTML using hyphenator_
|
||||
- inlinesyntaxhighlight_: inline syntax highlighting
|
||||
- lassodomain: a domain for documenting Lasso_ source code
|
||||
- libreoffice: an extension to include any drawing supported by LibreOffice (e.g. odg, vsd...).
|
||||
- lilypond: an extension inserting music scripts from Lilypond_ in PNG format.
|
||||
- makedomain_: a domain for `GNU Make`_
|
||||
- matlabdomain: document MATLAB_ code.
|
||||
|
@ -7,10 +7,9 @@ Sphinx Developer's Guide
|
||||
system used by developers to document systems used by other developers to
|
||||
develop other systems that may also be documented using Sphinx.
|
||||
|
||||
The Sphinx source code is managed using `Mercurial`_ and is hosted on
|
||||
`BitBucket`_.
|
||||
The Sphinx source code is managed using Git and is hosted on Github.
|
||||
|
||||
hg clone https://bitbucket.org/birkenfeld/sphinx
|
||||
git clone git://github.com/sphinx-doc/sphinx
|
||||
|
||||
.. rubric:: Community
|
||||
|
||||
@ -23,15 +22,12 @@ sphinx-dev <sphinx-dev@googlegroups.com>
|
||||
#sphinx-doc on irc.freenode.net
|
||||
IRC channel for development questions and user support.
|
||||
|
||||
.. _`BitBucket`: https://bitbucket.org/
|
||||
.. _`Mercurial`: http://mercurial.selenic.com/
|
||||
|
||||
|
||||
Bug Reports and Feature Requests
|
||||
--------------------------------
|
||||
|
||||
If you have encountered a problem with Sphinx or have an idea for a new
|
||||
feature, please submit it to the `issue tracker`_ on BitBucket or discuss it
|
||||
feature, please submit it to the `issue tracker`_ on Github or discuss it
|
||||
on the sphinx-dev mailing list.
|
||||
|
||||
For bug reports, please include the output produced during the build process
|
||||
@ -43,22 +39,22 @@ Including or providing a link to the source files involved may help us fix the
|
||||
issue. If possible, try to create a minimal project that produces the error
|
||||
and post that instead.
|
||||
|
||||
.. _`issue tracker`: https://bitbucket.org/birkenfeld/sphinx/issues
|
||||
.. _`issue tracker`: https://github.com/sphinx-doc/sphinx/issues
|
||||
|
||||
|
||||
Contributing to Sphinx
|
||||
----------------------
|
||||
|
||||
The recommended way for new contributors to submit code to Sphinx is to fork
|
||||
the Mercurial repository on BitBucket and then submit a pull request after
|
||||
the repository on Github and then submit a pull request after
|
||||
committing the changes. The pull request will then need to be approved by one
|
||||
of the core developers before it is merged into the main repository.
|
||||
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a
|
||||
feature idea or a bug. There are `Non Assigned`_ issues.
|
||||
feature idea or a bug.
|
||||
#. If you feel uncomfortable or uncertain about an issue or your changes, feel
|
||||
free to email sphinx-dev@googlegroups.com.
|
||||
#. Fork `the repository`_ on Bitbucket to start making your changes to the
|
||||
#. Fork `the repository`_ on Github to start making your changes to the
|
||||
**default** branch for next major version, or **stable** branch for next
|
||||
minor version.
|
||||
#. Write a test which shows that the bug was fixed or that the feature works
|
||||
@ -67,35 +63,35 @@ of the core developers before it is merged into the main repository.
|
||||
published. Make sure to add yourself to AUTHORS_ and the change to
|
||||
CHANGES_.
|
||||
|
||||
.. _`the repository`: https://bitbucket.org/birkenfeld/sphinx
|
||||
.. _AUTHORS: https://bitbucket.org/birkenfeld/sphinx/src/tip/AUTHORS
|
||||
.. _CHANGES: https://bitbucket.org/birkenfeld/sphinx/src/tip/CHANGES
|
||||
.. _Non Assigned: https://bitbucket.org/birkenfeld/sphinx/issues?status=new&status=open&responsible=
|
||||
.. _`the repository`: https://github.com/sphinx-doc/sphinx
|
||||
.. _AUTHORS: https://github.com/sphinx-doc/sphinx/blob/master/AUTHORS
|
||||
.. _CHANGES: https://github.com/sphinx-doc/sphinx/blob/master/CHANGES
|
||||
|
||||
|
||||
Getting Started
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
These are the basic steps needed to start developing on Sphinx.
|
||||
|
||||
#. Create an account on BitBucket.
|
||||
#. Create an account on Github.
|
||||
|
||||
#. Fork the main Sphinx repository (`birkenfeld/sphinx
|
||||
<https://bitbucket.org/birkenfeld/sphinx>`_) using the BitBucket interface.
|
||||
#. Fork the main Sphinx repository (`sphinx-doc/sphinx
|
||||
<https://github.com/sphinx-doc/sphinx>`_) using the Github interface.
|
||||
|
||||
#. Clone the forked repository to your machine. ::
|
||||
|
||||
hg clone https://bitbucket.org/USERNAME/sphinx-fork
|
||||
cd sphinx-fork
|
||||
git clone https://github.com/USERNAME/sphinx
|
||||
cd sphinx
|
||||
|
||||
#. Checkout the appropriate branch.
|
||||
|
||||
For changes that should be included in the next minor release (namely bug
|
||||
fixes), use the ``stable`` branch. ::
|
||||
|
||||
hg checkout stable
|
||||
git checkout stable
|
||||
|
||||
For new features or other substantial changes that should wait until the
|
||||
next major release, use the ``default`` branch.
|
||||
next major release, use the ``master`` branch.
|
||||
|
||||
#. Optional: setup a virtual environment. ::
|
||||
|
||||
@ -103,6 +99,10 @@ These are the basic steps needed to start developing on Sphinx.
|
||||
. ~/sphinxenv/bin/activate
|
||||
pip install -e .
|
||||
|
||||
#. Create a new working branch. Choose any name you like. ::
|
||||
|
||||
git checkout -b feature-xyz
|
||||
|
||||
#. Hack, hack, hack.
|
||||
|
||||
For tips on working with the code, see the `Coding Guide`_.
|
||||
@ -130,28 +130,31 @@ These are the basic steps needed to start developing on Sphinx.
|
||||
* For bug fixes, first add a test that fails without your changes and passes
|
||||
after they are applied.
|
||||
|
||||
* Tests that need a sphinx-build run should be integrated in one of the
|
||||
existing test modules if possible. New tests that to ``@with_app`` and
|
||||
then ``build_all`` for a few assertions are not good since *the test suite
|
||||
should not take more than a minute to run*.
|
||||
|
||||
#. Please add a bullet point to :file:`CHANGES` if the fix or feature is not
|
||||
trivial (small doc updates, typo fixes). Then commit::
|
||||
|
||||
hg commit -m '#42: Add useful new feature that does this.'
|
||||
git commit -m '#42: Add useful new feature that does this.'
|
||||
|
||||
BitBucket recognizes `certain phrases`__ that can be used to automatically
|
||||
Github recognizes certain phrases that can be used to automatically
|
||||
update the issue tracker.
|
||||
|
||||
For example::
|
||||
|
||||
hg commit -m 'Closes #42: Fix invalid markup in docstring of Foo.bar.'
|
||||
git commit -m 'Closes #42: Fix invalid markup in docstring of Foo.bar.'
|
||||
|
||||
would close issue #42.
|
||||
|
||||
__ https://confluence.atlassian.com/display/BITBUCKET/Resolve+issues+automatically+when+users+push+code
|
||||
#. Push changes in the branch to your forked repository on Github. ::
|
||||
|
||||
#. Push changes to your forked repository on BitBucket. ::
|
||||
git push origin feature-xyz
|
||||
|
||||
hg push
|
||||
|
||||
#. Submit a pull request from your repository to ``birkenfeld/sphinx`` using
|
||||
the BitBucket interface.
|
||||
#. Submit a pull request from your branch to the respective branch (``master``
|
||||
or ``stable``) on ``sphinx-doc/sphinx`` using the Github interface.
|
||||
|
||||
#. Wait for a core developer to review your changes.
|
||||
|
||||
@ -179,9 +182,6 @@ The following are some general guidelines for core developers:
|
||||
* When committing code written by someone else, please attribute the original
|
||||
author in the commit message and any relevant :file:`CHANGES` entry.
|
||||
|
||||
* Using Mercurial named branches other than ``default`` and ``stable`` is not
|
||||
encouraged.
|
||||
|
||||
|
||||
Locale updates
|
||||
~~~~~~~~~~~~~~
|
||||
|
@ -310,12 +310,12 @@ are recognized and formatted nicely:
|
||||
|
||||
* ``param``, ``parameter``, ``arg``, ``argument``, ``key``, ``keyword``:
|
||||
Description of a parameter.
|
||||
* ``type``: Type of a parameter.
|
||||
* ``type``: Type of a parameter. Creates a link if possible.
|
||||
* ``raises``, ``raise``, ``except``, ``exception``: That (and when) a specific
|
||||
exception is raised.
|
||||
* ``var``, ``ivar``, ``cvar``: Description of a variable.
|
||||
* ``returns``, ``return``: Description of the return value.
|
||||
* ``rtype``: Return type.
|
||||
* ``rtype``: Return type. Creates a link if possible.
|
||||
|
||||
The field names must consist of one of these keywords and an argument (except
|
||||
for ``returns`` and ``rtype``, which do not need an argument). This is best
|
||||
@ -526,7 +526,7 @@ can start with a visibility statement (``public``, ``private`` or ``protected``)
|
||||
.. rst:directive:: .. cpp:class:: class speicifer
|
||||
|
||||
Describe a class/struct, possibly with specification of inheritance, e.g.,::
|
||||
|
||||
|
||||
.. cpp:class:: SomeName::SomeClass : public MyBase, MyOtherBase
|
||||
|
||||
.. rst:directive:: .. cpp:function:: (member-)function prototype
|
||||
|
@ -15,7 +15,7 @@ so by providing aliases to base URLs, so that you only need to give the subpage
|
||||
name when creating a link.
|
||||
|
||||
Let's assume that you want to include many links to issues at the Sphinx
|
||||
tracker, at :samp:`http://bitbucket.org/birkenfeld/sphinx/issue/{num}`. Typing
|
||||
tracker, at :samp:`http://github.com/sphinx-doc/sphinx/issues/{num}`. Typing
|
||||
this URL again and again is tedious, so you can use :mod:`~sphinx.ext.extlinks`
|
||||
to avoid repeating yourself.
|
||||
|
||||
@ -27,11 +27,11 @@ The extension adds one new config value:
|
||||
short alias names to a base URL and a *prefix*. For example, to create an
|
||||
alias for the above mentioned issues, you would add ::
|
||||
|
||||
extlinks = {'issue': ('https://bitbucket.org/birkenfeld/sphinx/issue/%s',
|
||||
extlinks = {'issue': ('https://github.com/sphinx-doc/sphinx/issues/%s',
|
||||
'issue ')}
|
||||
|
||||
Now, you can use the alias name as a new role, e.g. ``:issue:`123```. This
|
||||
then inserts a link to https://bitbucket.org/birkenfeld/sphinx/issue/123.
|
||||
then inserts a link to https://github.com/sphinx-doc/sphinx/issues/123.
|
||||
As you can see, the target given in the role is substituted in the base URL
|
||||
in the place of ``%s``.
|
||||
|
||||
|
@ -84,7 +84,7 @@ linking:
|
||||
To add links to modules and objects in the Python standard library
|
||||
documentation, use::
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.2', None)}
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.4', None)}
|
||||
|
||||
This will download the corresponding :file:`objects.inv` file from the
|
||||
Internet and generate links to the pages under the given URI. The downloaded
|
||||
@ -94,12 +94,12 @@ linking:
|
||||
A second example, showing the meaning of a non-``None`` value of the second
|
||||
tuple item::
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.2',
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.4',
|
||||
'python-inv.txt')}
|
||||
|
||||
This will read the inventory from :file:`python-inv.txt` in the source
|
||||
directory, but still generate links to the pages under
|
||||
``http://docs.python.org/3.2``. It is up to you to update the inventory file
|
||||
``http://docs.python.org/3.4``. It is up to you to update the inventory file
|
||||
as new objects are added to the Python documentation.
|
||||
|
||||
**Multiple target for the inventory**
|
||||
@ -113,7 +113,7 @@ linking:
|
||||
this to specify mirror sites for server downtime of the primary
|
||||
inventory::
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.2',
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.4',
|
||||
(None, 'python-inv.txt'))}
|
||||
|
||||
.. confval:: intersphinx_cache_limit
|
||||
|
@ -83,7 +83,7 @@ package.
|
||||
Register an event called *name*. This is needed to be able to emit it.
|
||||
|
||||
.. method:: Sphinx.set_translator(name, translator_class)
|
||||
|
||||
|
||||
Register or override a Docutils translator class. This is used to register
|
||||
a custom output translator or to replace a builtin translator.
|
||||
This allows extensions to use custom translator and define custom
|
||||
@ -288,6 +288,18 @@ package.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. method:: Sphinx.add_latex_package(packagename, options=None)
|
||||
|
||||
Add *packagename* to the list of packages that LaTeX source code will include.
|
||||
If you provide *options*, it will be taken to `\usepackage` declaration.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
app.add_latex_package('mypackage') # => \usepackage{mypackage}
|
||||
app.add_latex_package('mypackage', 'foo,bar') # => \usepackage[foo,bar]{mypackage}
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. method:: Sphinx.add_lexer(alias, lexer)
|
||||
|
||||
Use *lexer*, which must be an instance of a Pygments lexer class, to
|
||||
@ -437,6 +449,19 @@ handlers to the events. Example:
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: env-before-read-docs (app, env, docnames)
|
||||
|
||||
Emitted after the environment has determined the list of all added and
|
||||
changed files and just before it reads them. It allows extension authors to
|
||||
reorder the list of docnames (*inplace*) before processing, or add more
|
||||
docnames that Sphinx did not consider changed (but never add any docnames
|
||||
that are not in ``env.found_docs``).
|
||||
|
||||
You can also remove document names; do this with caution since it will make
|
||||
Sphinx treat changed files as unchanged.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: source-read (app, docname, source)
|
||||
|
||||
Emitted when a source file has been read. The *source* argument is a list
|
||||
@ -480,13 +505,40 @@ handlers to the events. Example:
|
||||
Here is the place to replace custom nodes that don't have visitor methods in
|
||||
the writers, so that they don't cause errors when the writers encounter them.
|
||||
|
||||
.. event:: env-merge-info (env, docnames, other)
|
||||
|
||||
This event is only emitted when parallel reading of documents is enabled. It
|
||||
is emitted once for every subprocess that has read some documents.
|
||||
|
||||
You must handle this event in an extension that stores data in the
|
||||
environment in a custom location. Otherwise the environment in the main
|
||||
process will not be aware of the information stored in the subprocess.
|
||||
|
||||
*other* is the environment object from the subprocess, *env* is the
|
||||
environment from the main process. *docnames* is a set of document names
|
||||
that have been read in the subprocess.
|
||||
|
||||
For a sample of how to deal with this event, look at the standard
|
||||
``sphinx.ext.todo`` extension. The implementation is often similar to that
|
||||
of :event:`env-purge-doc`, only that information is not removed, but added to
|
||||
the main environment from the other environment.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: env-updated (app, env)
|
||||
|
||||
Emitted when the :meth:`update` method of the build environment has
|
||||
completed, that is, the environment and all doctrees are now up-to-date.
|
||||
|
||||
You can return an iterable of docnames from the handler. These documents
|
||||
will then be considered updated, and will be (re-)written during the writing
|
||||
phase.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The handlers' return value is now used.
|
||||
|
||||
.. event:: html-collect-pages (app)
|
||||
|
||||
Emitted when the HTML builder is starting to write non-document pages. You
|
||||
@ -513,8 +565,14 @@ handlers to the events. Example:
|
||||
documents; it will be ``None`` when the page is created from an HTML template
|
||||
alone.
|
||||
|
||||
You can return a string from the handler, it will then replace
|
||||
``'page.html'`` as the HTML template for this page.
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The return value can now specify a template name.
|
||||
|
||||
.. event:: build-finished (app, exception)
|
||||
|
||||
Emitted when a build has finished, before Sphinx exits, usually used for
|
||||
|
@ -18,15 +18,32 @@ imports this module and executes its ``setup()`` function, which in turn
|
||||
notifies Sphinx of everything the extension offers -- see the extension tutorial
|
||||
for examples.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
The ``setup()`` function can return a string, this is treated by Sphinx as
|
||||
the version of the extension and used for informational purposes such as the
|
||||
traceback file when an exception occurs.
|
||||
|
||||
The configuration file itself can be treated as an extension if it contains a
|
||||
``setup()`` function. All other extensions to load must be listed in the
|
||||
:confval:`extensions` configuration value.
|
||||
|
||||
Extension metadata
|
||||
------------------
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
The ``setup()`` function can return a dictionary. This is treated by Sphinx
|
||||
as metadata of the extension. Metadata keys currently recognized are:
|
||||
|
||||
* ``'version'``: a string that identifies the extension version. It is used for
|
||||
extension version requirement checking (see :confval:`needs_extensions`) and
|
||||
informational purposes. If not given, ``"unknown version"`` is substituted.
|
||||
* ``'parallel_read_safe'``: a boolean that specifies if parallel reading of
|
||||
source files can be used when the extension is loaded. It defaults to
|
||||
``False``, i.e. you have to explicitly specify your extension to be
|
||||
parallel-read-safe after checking that it is.
|
||||
* ``'parallel_write_safe'``: a boolean that specifies if parallel writing of
|
||||
output files can be used when the extension is loaded. Since extensions
|
||||
usually don't negatively influence the process, this defaults to ``True``.
|
||||
|
||||
APIs used for writing extensions
|
||||
--------------------------------
|
||||
|
||||
.. toctree::
|
||||
|
||||
tutorial
|
||||
|
@ -162,7 +162,7 @@ new Python module called :file:`todo.py` and add the setup function::
|
||||
app.connect('doctree-resolved', process_todo_nodes)
|
||||
app.connect('env-purge-doc', purge_todos)
|
||||
|
||||
return '0.1' # identifies the version of our extension
|
||||
return {'version': '0.1'} # identifies the version of our extension
|
||||
|
||||
The calls in this function refer to classes and functions not yet written. What
|
||||
the individual calls do is the following:
|
||||
@ -247,6 +247,7 @@ todolist directive has neither content nor arguments that need to be handled.
|
||||
The ``todo`` directive function looks like this::
|
||||
|
||||
from sphinx.util.compat import make_admonition
|
||||
from sphinx.locale import _
|
||||
|
||||
class TodoDirective(Directive):
|
||||
|
||||
|
@ -41,14 +41,14 @@ You can find several extensions contributed by users in the `Sphinx Contrib`_
|
||||
repository. It is open for anyone who wants to maintain an extension
|
||||
publicly; just send a short message asking for write permissions.
|
||||
|
||||
There are also several extensions hosted elsewhere. The `Wiki at BitBucket`_
|
||||
maintains a list of those.
|
||||
There are also several extensions hosted elsewhere. The `Sphinx extension
|
||||
survey <http://sphinxext-survey.readthedocs.org/en/latest/>`__ contains a
|
||||
comprehensive list.
|
||||
|
||||
If you write an extension that you think others will find useful or you think
|
||||
should be included as a part of Sphinx, please write to the project mailing
|
||||
list (`join here <https://groups.google.com/group/sphinx-dev>`_).
|
||||
|
||||
.. _Wiki at BitBucket: https://bitbucket.org/birkenfeld/sphinx/wiki/Home
|
||||
.. _Sphinx Contrib: https://bitbucket.org/birkenfeld/sphinx-contrib
|
||||
|
||||
|
||||
|
@ -9,11 +9,11 @@ Since Sphinx is written in the Python language, you need to install Python
|
||||
Sphinx packages are available on the `Python Package Index
|
||||
<https://pypi.python.org/pypi/Sphinx>`_.
|
||||
|
||||
You can also download a snapshot from the Mercurial development repository:
|
||||
You can also download a snapshot from the Git repository:
|
||||
|
||||
* as a `.tar.bz2 <https://bitbucket.org/birkenfeld/sphinx/get/default.tar.bz2>`_
|
||||
* as a `.tar.bz2 <https://github.com/sphinx-doc/sphinx/archive/master.tar.bz2>`_
|
||||
file or
|
||||
* as a `.zip <https://bitbucket.org/birkenfeld/sphinx/get/default.zip>`_ file
|
||||
* as a `.zip <https://github.com/sphinx-doc/sphinx/archive/master.zip>`_ file
|
||||
|
||||
There are introductions for several environments:
|
||||
|
||||
@ -80,7 +80,7 @@ sidebar and under "Quick Links", click "Windows Installer" to download.
|
||||
.. note::
|
||||
|
||||
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
|
||||
under Python 2.6, 2.7, 3.3, 3.4, with the recommended version being
|
||||
2.7. This chapter assumes you have installed Python 2.7.
|
||||
|
||||
Follow the Windows installer for Python.
|
||||
@ -101,7 +101,7 @@ as ``sphinx-build`` easily from the Command Prompt.
|
||||
|
||||
- ``C:\Python27`` -- this folder contains the main Python executable
|
||||
- ``C:\Python27\Scripts`` -- this folder will contain executables added by
|
||||
Python packages installed with easy_install (see below)
|
||||
Python packages installed with pip (see below)
|
||||
|
||||
This is for Python 2.7. If you use another version of
|
||||
Python or installed to a non-default location, change the digits "27"
|
||||
@ -113,35 +113,39 @@ as ``sphinx-build`` easily from the Command Prompt.
|
||||
``>>>``. Type ``Ctrl+Z`` and Enter to quit.
|
||||
|
||||
|
||||
Install the easy_install command
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Install the pip command
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Python has a very useful :command:`easy_install` command which can download and
|
||||
install 3rd-party libraries with a single command. This is provided by the
|
||||
"setuptools" project: https://pypi.python.org/pypi/setuptools.
|
||||
Python has a very useful :command:`pip` command which can download and install
|
||||
3rd-party libraries with a single command. This is provided by the
|
||||
Python Packaging Authority(PyPA):
|
||||
https://groups.google.com/forum/#!forum/pypa-dev
|
||||
|
||||
To install setuptools, download
|
||||
https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py and
|
||||
To install pip, download https://bootstrap.pypa.io/get-pip.py and
|
||||
save it somewhere. After download, invoke the command prompt, go to the
|
||||
directory with ez_setup.py and run this command:
|
||||
directory with ``get-pip.py`` and run this command:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
C:\> python ez_setup.py
|
||||
C:\> python get-pip.py
|
||||
|
||||
Now setuptools and its :command:`easy_install` command is installed. From there
|
||||
we can go to the Sphinx install.
|
||||
Now :command:`pip` command is installed. From there we can go to the Sphinx
|
||||
install.
|
||||
|
||||
.. note::
|
||||
|
||||
``pip`` has been contained in the Python official installation after version
|
||||
of Python-3.4.0 or Python-2.7.9.
|
||||
|
||||
|
||||
Installing Sphinx with easy_install
|
||||
-----------------------------------
|
||||
Installing Sphinx with pip
|
||||
---------------------------
|
||||
|
||||
If you finished the installation of setuptools, type this line in the command
|
||||
prompt:
|
||||
If you finished the installation of pip, type this line in the command prompt:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
C:\> easy_install sphinx
|
||||
C:\> pip install sphinx
|
||||
|
||||
After installation, type :command:`sphinx-build` on the command prompt. If
|
||||
everything worked fine, you will get a Sphinx version number and a list of
|
||||
|
@ -277,7 +277,7 @@ Contributing to Sphinx reference translation
|
||||
The recommended way for new contributors to translate Sphinx reference
|
||||
is to join the translation team on Transifex.
|
||||
|
||||
There is `sphinx translation page`_ for Sphinx-1.2 documentation.
|
||||
There is `sphinx translation page`_ for Sphinx-1.3 documentation.
|
||||
|
||||
1. Login to transifex_ service.
|
||||
2. Go to `sphinx translation page`_.
|
||||
@ -297,5 +297,5 @@ There is `sphinx translation page`_ for Sphinx-1.2 documentation.
|
||||
.. _`transifex-client`: https://pypi.python.org/pypi/transifex-client
|
||||
.. _`sphinx-intl`: https://pypi.python.org/pypi/sphinx-intl
|
||||
.. _Transifex: https://www.transifex.com/
|
||||
.. _`sphinx translation page`: https://www.transifex.com/projects/p/sphinx-doc-1_2_0/
|
||||
.. _`sphinx translation page`: https://www.transifex.com/projects/p/sphinx-doc-1_3/
|
||||
.. _`Transifex Client v0.8 — Transifex documentation`: http://help.transifex.com/features/client/index.html
|
||||
|
@ -54,7 +54,7 @@ See the :ref:`pertinent section in the FAQ list <usingwith>`.
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Sphinx needs at least **Python 2.6** or **Python 3.2** to run, as well as the
|
||||
Sphinx needs at least **Python 2.6** or **Python 3.3** to run, as well as the
|
||||
docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.10
|
||||
or some (not broken) SVN trunk snapshot. If you like to have source code
|
||||
highlighting support, you must also install the Pygments_ library.
|
||||
|
@ -1,5 +1,138 @@
|
||||
.. default-role:: any
|
||||
|
||||
.. _invocation:
|
||||
|
||||
Invocation of sphinx-quickstart
|
||||
===============================
|
||||
|
||||
The :program:`sphinx-quickstart` script generates a Sphinx documentation set.
|
||||
It is called like this::
|
||||
|
||||
$ sphinx-quickstart [options] [projectdir]
|
||||
|
||||
where *projectdir* is the Sphinx documentation set directory in which you want
|
||||
to place. If you omit *projectdir*, files are generated into current directory
|
||||
by default.
|
||||
|
||||
The :program:`sphinx-quickstart` script has several options:
|
||||
|
||||
.. program:: sphinx-quickstart
|
||||
|
||||
.. option:: -q, --quiet
|
||||
|
||||
Quiet mode that will skips interactive wizard to specify options.
|
||||
This option requires `-p`, `-a` and `-v` options.
|
||||
|
||||
.. option:: -h, --help, --version
|
||||
|
||||
Display usage summary or Sphinx version.
|
||||
|
||||
|
||||
Structure options
|
||||
-----------------
|
||||
|
||||
.. option:: --sep
|
||||
|
||||
If specified, separate source and build directories.
|
||||
|
||||
.. option:: --dot=DOT
|
||||
|
||||
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.
|
||||
|
||||
Project basic options
|
||||
---------------------
|
||||
|
||||
.. option:: -p PROJECT, --project=PROJECT
|
||||
|
||||
Project name will be set. (see :confval:`project`).
|
||||
|
||||
.. option:: -a AUTHOR, --author=AUTHOR
|
||||
|
||||
Author names. (see :confval:`copyright`).
|
||||
|
||||
.. option:: -v VERSION
|
||||
|
||||
Version of project. (see :confval:`version`).
|
||||
|
||||
.. option:: -r RELEASE, --release=RELEASE
|
||||
|
||||
Release of project. (see :confval:`release`).
|
||||
|
||||
.. option:: -l LANGUAGE, --language=LANGUAGE
|
||||
|
||||
Document language. (see :confval:`language`).
|
||||
|
||||
.. option:: --suffix=SUFFIX
|
||||
|
||||
Source file suffix. (see :confval:`source_suffix`).
|
||||
|
||||
.. option:: --master=MASTER
|
||||
|
||||
Master document name. (see :confval:`master_doc`).
|
||||
|
||||
.. option:: --epub
|
||||
|
||||
Use epub.
|
||||
|
||||
Extension options
|
||||
-----------------
|
||||
|
||||
.. option:: --ext-autodoc
|
||||
|
||||
Enable `sphinx.ext.autodoc` extension.
|
||||
|
||||
.. option:: --ext-doctest
|
||||
|
||||
Enable `sphinx.ext.doctest` extension.
|
||||
|
||||
.. option:: --ext-intersphinx
|
||||
|
||||
Enable `sphinx.ext.intersphinx` extension.
|
||||
|
||||
.. option:: --ext-todo
|
||||
|
||||
Enable `sphinx.ext.todo` extension.
|
||||
|
||||
.. option:: --ext-coverage
|
||||
|
||||
Enable `sphinx.ext.coverage` extension.
|
||||
|
||||
.. option:: --ext-pngmath
|
||||
|
||||
Enable `sphinx.ext.pngmath` extension.
|
||||
|
||||
.. option:: --ext-mathjax
|
||||
|
||||
Enable `sphinx.ext.mathjax` extension.
|
||||
|
||||
.. option:: --ext-ifconfig
|
||||
|
||||
Enable `sphinx.ext.ifconfig` extension.
|
||||
|
||||
.. option:: --ext-viewcode
|
||||
|
||||
Enable `sphinx.ext.viewcode` extension.
|
||||
|
||||
|
||||
Makefile and Batchfile creation options
|
||||
---------------------------------------
|
||||
|
||||
.. option:: --makefile, --no-makefile
|
||||
|
||||
Create (or not create) makefile.
|
||||
|
||||
.. option:: --batchfile, --no-batchfile
|
||||
|
||||
Create (or not create) batchfile
|
||||
|
||||
|
||||
.. versionadded:: 1.3
|
||||
Add various options for sphinx-quickstart invocation.
|
||||
|
||||
|
||||
Invocation of sphinx-build
|
||||
==========================
|
||||
|
||||
@ -305,6 +438,11 @@ The :program:`sphinx-apidoc` script has several options:
|
||||
to default values, but you can influence the most important ones using the
|
||||
following options.
|
||||
|
||||
.. option:: -M
|
||||
|
||||
This option makes sphinx-apidoc put module documentation before submodule
|
||||
documentation.
|
||||
|
||||
.. option:: -H project
|
||||
|
||||
Sets the project name to put in generated files (see :confval:`project`).
|
||||
|
@ -36,21 +36,29 @@ installed) and handled in a smart way:
|
||||
highlighted as Python).
|
||||
|
||||
* The highlighting language can be changed using the ``highlight`` directive,
|
||||
used as follows::
|
||||
used as follows:
|
||||
|
||||
.. highlight:: c
|
||||
.. rst:directive:: .. highlight:: language
|
||||
|
||||
This language is used until the next ``highlight`` directive is encountered.
|
||||
Example::
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
This language is used until the next ``highlight`` directive is encountered.
|
||||
|
||||
* For documents that have to show snippets in different languages, there's also
|
||||
a :rst:dir:`code-block` directive that is given the highlighting language
|
||||
directly::
|
||||
directly:
|
||||
|
||||
.. code-block:: ruby
|
||||
.. rst:directive:: .. code-block:: language
|
||||
|
||||
Some Ruby code.
|
||||
Use it like this::
|
||||
|
||||
The directive's alias name :rst:dir:`sourcecode` works as well.
|
||||
.. code-block:: ruby
|
||||
|
||||
Some Ruby code.
|
||||
|
||||
The directive's alias name :rst:dir:`sourcecode` works as well.
|
||||
|
||||
* The valid values for the highlighting language are:
|
||||
|
||||
@ -176,6 +184,10 @@ Includes
|
||||
string option, only lines that precede the first lines containing that string
|
||||
are included.
|
||||
|
||||
When specifying particular parts of a file to display, it can be useful to
|
||||
display exactly which lines are being presented.
|
||||
This can be done using the ``lineno-match`` option.
|
||||
|
||||
You can prepend and/or append a line to the included code, using the
|
||||
``prepend`` and ``append`` option, respectively. This is useful e.g. for
|
||||
highlighting PHP code that doesn't include the ``<?php``/``?>`` markers.
|
||||
@ -187,8 +199,8 @@ Includes
|
||||
.. literalinclude:: example.py
|
||||
:diff: example.py.orig
|
||||
|
||||
This shows the diff between example.py and example.py.orig with unified diff format.
|
||||
|
||||
This shows the diff between example.py and example.py.orig with unified diff
|
||||
format.
|
||||
|
||||
.. versionadded:: 0.4.3
|
||||
The ``encoding`` option.
|
||||
@ -199,6 +211,7 @@ Includes
|
||||
The ``prepend`` and ``append`` options, as well as ``tab-width``.
|
||||
.. versionadded:: 1.3
|
||||
The ``diff`` option.
|
||||
The ``lineno-match`` option.
|
||||
|
||||
|
||||
Showing a file name
|
||||
|
@ -12,7 +12,9 @@ They are written as ``:rolename:`content```.
|
||||
|
||||
The default role (```content```) has no special meaning by default. You are
|
||||
free to use it for anything you like, e.g. variable names; use the
|
||||
:confval:`default_role` config value to set it to a known role.
|
||||
:confval:`default_role` config value to set it to a known role -- the
|
||||
:rst:role:`any` role to find anything or the :rst:role:`py:obj` role to find
|
||||
Python objects are very useful for this.
|
||||
|
||||
See :ref:`domains` for roles added by domains.
|
||||
|
||||
@ -38,12 +40,57 @@ more versatile:
|
||||
|
||||
* If you prefix the content with ``~``, the link text will only be the last
|
||||
component of the target. For example, ``:py:meth:`~Queue.Queue.get``` will
|
||||
refer to ``Queue.Queue.get`` but only display ``get`` as the link text.
|
||||
refer to ``Queue.Queue.get`` but only display ``get`` as the link text. This
|
||||
does not work with all cross-reference roles, but is domain specific.
|
||||
|
||||
In HTML output, the link's ``title`` attribute (that is e.g. shown as a
|
||||
tool-tip on mouse-hover) will always be the full target name.
|
||||
|
||||
|
||||
.. _any-role:
|
||||
|
||||
Cross-referencing anything
|
||||
--------------------------
|
||||
|
||||
.. rst:role:: any
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
This convenience role tries to do its best to find a valid target for its
|
||||
reference text.
|
||||
|
||||
* First, it tries standard cross-reference targets that would be referenced
|
||||
by :rst:role:`doc`, :rst:role:`ref` or :rst:role:`option`.
|
||||
|
||||
Custom objects added to the standard domain by extensions (see
|
||||
:meth:`.add_object_type`) are also searched.
|
||||
|
||||
* Then, it looks for objects (targets) in all loaded domains. It is up to
|
||||
the domains how specific a match must be. For example, in the Python
|
||||
domain a reference of ``:any:`Builder``` would match the
|
||||
``sphinx.builders.Builder`` class.
|
||||
|
||||
If none or multiple targets are found, a warning will be emitted. In the
|
||||
case of multiple targets, you can change "any" to a specific role.
|
||||
|
||||
This role is a good candidate for setting :confval:`default_role`. If you
|
||||
do, you can write cross-references without a lot of markup overhead. For
|
||||
example, in this Python function documentation ::
|
||||
|
||||
.. function:: install()
|
||||
|
||||
This function installs a `handler` for every signal known by the
|
||||
`signal` module. See the section `about-signals` for more information.
|
||||
|
||||
there could be references to a glossary term (usually ``:term:`handler```), a
|
||||
Python module (usually ``:py:mod:`signal``` or ``:mod:`signal```) and a
|
||||
section (usually ``:ref:`about-signals```).
|
||||
|
||||
The :rst:role:`any` role also works together with the
|
||||
:mod:`~sphinx.ext.intersphinx` extension: when no local cross-reference is
|
||||
found, all object types of intersphinx inventories are also searched.
|
||||
|
||||
|
||||
Cross-referencing objects
|
||||
-------------------------
|
||||
|
||||
@ -154,6 +201,24 @@ Referencing downloadable files
|
||||
suitable link generated to it.
|
||||
|
||||
|
||||
Cross-referencing figures by figure number
|
||||
------------------------------------------
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. rst:role:: numref
|
||||
|
||||
Link to the specified figures, tables and code-blocks; the standard reST
|
||||
labels are used. When you use this role, it will insert a reference to the
|
||||
figure with link text by its figure number like "Fig. 1.1".
|
||||
|
||||
If an explicit link text is given (like usual: ``:doc:`Image of Sphinx (Fig.
|
||||
#) <my-figure>```), the link caption will be the title of the reference.
|
||||
As a special character, `#` will be replaced to figure number.
|
||||
|
||||
If :confval:`numfig` is ``False``, figures are not numbered.
|
||||
so this role inserts not a reference but labels or link text.
|
||||
|
||||
Cross-referencing other items of interest
|
||||
-----------------------------------------
|
||||
|
||||
@ -182,11 +247,12 @@ objects:
|
||||
exists.
|
||||
|
||||
|
||||
The following role creates a cross-reference to the term in the glossary:
|
||||
The following role creates a cross-reference to a term in a
|
||||
:ref:`glossary <glossary-directive>`:
|
||||
|
||||
.. rst:role:: term
|
||||
|
||||
Reference to a term in the glossary. The glossary is created using the
|
||||
Reference to a term in a glossary. A glossary is created using the
|
||||
``glossary`` directive containing a definition list with terms and
|
||||
definitions. It does not have to be in the same file as the ``term`` markup,
|
||||
for example the Python docs have one global glossary in the ``glossary.rst``
|
||||
|
@ -148,6 +148,8 @@ For local tables of contents, use the standard reST :dudir:`contents directive
|
||||
<table-of-contents>`.
|
||||
|
||||
|
||||
.. _glossary-directive:
|
||||
|
||||
Glossary
|
||||
--------
|
||||
|
||||
|
@ -10,6 +10,15 @@ The green arrows designate "more info" links leading to advanced sections about
|
||||
the described task.
|
||||
|
||||
|
||||
Install Sphinx
|
||||
--------------
|
||||
|
||||
Install Sphinx, either from a distribution package or from
|
||||
`PyPI <https://pypi.python.org/pypi/Sphinx>`_ with ::
|
||||
|
||||
$ pip install Sphinx
|
||||
|
||||
|
||||
Setting up the documentation sources
|
||||
------------------------------------
|
||||
|
||||
|
@ -57,7 +57,7 @@ This will return a dictionary containing the following items:
|
||||
* **relbar**: A div containing links to related documents
|
||||
* **title**: The title of the document
|
||||
* **css**: Links to CSS files used by Sphinx
|
||||
* **js**: JavaScript containing comment options
|
||||
* **script**: JavaScript containing comment options
|
||||
|
||||
This dict can then be used as context for templates. The goal is to be easy to
|
||||
integrate with your existing templating system. An example using `Jinja2
|
||||
@ -77,9 +77,9 @@ integrate with your existing templating system. An example using `Jinja2
|
||||
<link rel="stylesheet" href="/static/websupport-custom.css" type="text/css">
|
||||
{% endblock %}
|
||||
|
||||
{%- block js %}
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
{{ document.js|safe }}
|
||||
{{ document.script|safe }}
|
||||
{%- endblock %}
|
||||
|
||||
{%- block relbar %}
|
||||
|
324
ez_setup.py
324
ez_setup.py
@ -1,14 +1,14 @@
|
||||
#!python
|
||||
#!/usr/bin/env python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
If you want to use setuptools in your package's setup.py, just include this
|
||||
file in the same directory with it, and add this to the top of your setup.py::
|
||||
To use setuptools in your package's setup.py, include this
|
||||
file in the same directory and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
If you want to require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, you can do so by supplying
|
||||
To require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, simply supply
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
@ -17,50 +17,38 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import tarfile
|
||||
import zipfile
|
||||
import optparse
|
||||
import subprocess
|
||||
import platform
|
||||
import textwrap
|
||||
import contextlib
|
||||
|
||||
from distutils import log
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
try:
|
||||
from site import USER_SITE
|
||||
except ImportError:
|
||||
USER_SITE = None
|
||||
|
||||
DEFAULT_VERSION = "1.1.6"
|
||||
DEFAULT_VERSION = "7.0"
|
||||
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
|
||||
|
||||
def _python_cmd(*args):
|
||||
"""
|
||||
Return True if the command succeeded.
|
||||
"""
|
||||
args = (sys.executable,) + args
|
||||
return subprocess.call(args) == 0
|
||||
|
||||
def _check_call_py24(cmd, *args, **kwargs):
|
||||
res = subprocess.call(cmd, *args, **kwargs)
|
||||
class CalledProcessError(Exception):
|
||||
pass
|
||||
if not res == 0:
|
||||
msg = "Command '%s' return non-zero exit status %d" % (cmd, res)
|
||||
raise CalledProcessError(msg)
|
||||
vars(subprocess).setdefault('check_call', _check_call_py24)
|
||||
|
||||
def _install(tarball, install_args=()):
|
||||
# extracting the tarball
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
log.warn('Extracting in %s', tmpdir)
|
||||
old_wd = os.getcwd()
|
||||
try:
|
||||
os.chdir(tmpdir)
|
||||
tar = tarfile.open(tarball)
|
||||
_extractall(tar)
|
||||
tar.close()
|
||||
|
||||
# going in the directory
|
||||
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||
os.chdir(subdir)
|
||||
log.warn('Now working in %s', subdir)
|
||||
|
||||
def _install(archive_filename, install_args=()):
|
||||
with archive_context(archive_filename):
|
||||
# installing
|
||||
log.warn('Installing Setuptools')
|
||||
if not _python_cmd('setup.py', 'install', *install_args):
|
||||
@ -68,47 +56,68 @@ def _install(tarball, install_args=()):
|
||||
log.warn('See the error message above.')
|
||||
# exitcode will be 2
|
||||
return 2
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def _build_egg(egg, tarball, to_dir):
|
||||
# extracting the tarball
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
log.warn('Extracting in %s', tmpdir)
|
||||
old_wd = os.getcwd()
|
||||
try:
|
||||
os.chdir(tmpdir)
|
||||
tar = tarfile.open(tarball)
|
||||
_extractall(tar)
|
||||
tar.close()
|
||||
|
||||
# going in the directory
|
||||
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||
os.chdir(subdir)
|
||||
log.warn('Now working in %s', subdir)
|
||||
|
||||
def _build_egg(egg, archive_filename, to_dir):
|
||||
with archive_context(archive_filename):
|
||||
# building an egg
|
||||
log.warn('Building a Setuptools egg in %s', to_dir)
|
||||
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
|
||||
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
# returning the result
|
||||
log.warn(egg)
|
||||
if not os.path.exists(egg):
|
||||
raise IOError('Could not build the egg.')
|
||||
|
||||
|
||||
class ContextualZipFile(zipfile.ZipFile):
|
||||
"""
|
||||
Supplement ZipFile class to support context manager for Python 2.6
|
||||
"""
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
Construct a ZipFile or ContextualZipFile as appropriate
|
||||
"""
|
||||
if hasattr(zipfile.ZipFile, '__exit__'):
|
||||
return zipfile.ZipFile(*args, **kwargs)
|
||||
return super(ContextualZipFile, cls).__new__(cls)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def archive_context(filename):
|
||||
# extracting the archive
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
log.warn('Extracting in %s', tmpdir)
|
||||
old_wd = os.getcwd()
|
||||
try:
|
||||
os.chdir(tmpdir)
|
||||
with ContextualZipFile(filename) as archive:
|
||||
archive.extractall()
|
||||
|
||||
# going in the directory
|
||||
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||
os.chdir(subdir)
|
||||
log.warn('Now working in %s', subdir)
|
||||
yield
|
||||
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def _do_download(version, download_base, to_dir, download_delay):
|
||||
egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
|
||||
% (version, sys.version_info[0], sys.version_info[1]))
|
||||
if not os.path.exists(egg):
|
||||
tarball = download_setuptools(version, download_base,
|
||||
archive = download_setuptools(version, download_base,
|
||||
to_dir, download_delay)
|
||||
_build_egg(egg, tarball, to_dir)
|
||||
_build_egg(egg, archive, to_dir)
|
||||
sys.path.insert(0, egg)
|
||||
|
||||
# Remove previously-imported pkg_resources if present (see
|
||||
@ -121,11 +130,10 @@ def _do_download(version, download_base, to_dir, download_delay):
|
||||
|
||||
|
||||
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
to_dir=os.curdir, download_delay=15):
|
||||
# making sure we use the absolute path
|
||||
to_dir=os.curdir, download_delay=15):
|
||||
to_dir = os.path.abspath(to_dir)
|
||||
was_imported = 'pkg_resources' in sys.modules or \
|
||||
'setuptools' in sys.modules
|
||||
rep_modules = 'pkg_resources', 'setuptools'
|
||||
imported = set(sys.modules).intersection(rep_modules)
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
@ -133,23 +141,36 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
try:
|
||||
pkg_resources.require("setuptools>=" + version)
|
||||
return
|
||||
except pkg_resources.VersionConflict:
|
||||
e = sys.exc_info()[1]
|
||||
if was_imported:
|
||||
sys.stderr.write(
|
||||
"The required version of setuptools (>=%s) is not available,\n"
|
||||
"and can't be installed while this script is running. Please\n"
|
||||
"install a more recent version first, using\n"
|
||||
"'easy_install -U setuptools'."
|
||||
"\n\n(Currently using %r)\n" % (version, e.args[0]))
|
||||
sys.exit(2)
|
||||
else:
|
||||
del pkg_resources, sys.modules['pkg_resources'] # reload ok
|
||||
return _do_download(version, download_base, to_dir,
|
||||
download_delay)
|
||||
except pkg_resources.DistributionNotFound:
|
||||
return _do_download(version, download_base, to_dir,
|
||||
download_delay)
|
||||
return _do_download(version, download_base, to_dir, download_delay)
|
||||
except pkg_resources.VersionConflict as VC_err:
|
||||
if imported:
|
||||
msg = textwrap.dedent("""
|
||||
The required version of setuptools (>={version}) is not available,
|
||||
and can't be installed while this script is running. Please
|
||||
install a more recent version first, using
|
||||
'easy_install -U setuptools'.
|
||||
|
||||
(Currently using {VC_err.args[0]!r})
|
||||
""").format(VC_err=VC_err, version=version)
|
||||
sys.stderr.write(msg)
|
||||
sys.exit(2)
|
||||
|
||||
# otherwise, reload ok
|
||||
del pkg_resources, sys.modules['pkg_resources']
|
||||
return _do_download(version, download_base, to_dir, download_delay)
|
||||
|
||||
def _clean_check(cmd, target):
|
||||
"""
|
||||
Run the command to download target. If the command fails, clean up before
|
||||
re-raising the error.
|
||||
"""
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
if os.access(target, os.F_OK):
|
||||
os.unlink(target)
|
||||
raise
|
||||
|
||||
def download_file_powershell(url, target):
|
||||
"""
|
||||
@ -157,61 +178,58 @@ def download_file_powershell(url, target):
|
||||
trust). Raise an exception if the command cannot complete.
|
||||
"""
|
||||
target = os.path.abspath(target)
|
||||
ps_cmd = (
|
||||
"[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
|
||||
"[System.Net.CredentialCache]::DefaultCredentials; "
|
||||
"(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
|
||||
% vars()
|
||||
)
|
||||
cmd = [
|
||||
'powershell',
|
||||
'-Command',
|
||||
"(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(),
|
||||
ps_cmd,
|
||||
]
|
||||
subprocess.check_call(cmd)
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_powershell():
|
||||
if platform.system() != 'Windows':
|
||||
return False
|
||||
cmd = ['powershell', '-Command', 'echo test']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
with open(os.path.devnull, 'wb') as devnull:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_powershell.viable = has_powershell
|
||||
|
||||
def download_file_curl(url, target):
|
||||
cmd = ['curl', url, '--silent', '--output', target]
|
||||
subprocess.check_call(cmd)
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_curl():
|
||||
cmd = ['curl', '--version']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
with open(os.path.devnull, 'wb') as devnull:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_curl.viable = has_curl
|
||||
|
||||
def download_file_wget(url, target):
|
||||
cmd = ['wget', url, '--quiet', '--output-document', target]
|
||||
subprocess.check_call(cmd)
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_wget():
|
||||
cmd = ['wget', '--version']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
with open(os.path.devnull, 'wb') as devnull:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_wget.viable = has_wget
|
||||
@ -221,45 +239,36 @@ def download_file_insecure(url, target):
|
||||
Use Python to download the file, even though it cannot authenticate the
|
||||
connection.
|
||||
"""
|
||||
src = urlopen(url)
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
src = dst = None
|
||||
try:
|
||||
src = urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
# Read all the data in one block.
|
||||
data = src.read()
|
||||
dst = open(target, "wb")
|
||||
dst.write(data)
|
||||
finally:
|
||||
if src:
|
||||
src.close()
|
||||
if dst:
|
||||
dst.close()
|
||||
src.close()
|
||||
|
||||
# Write all the data in one block to avoid creating a partial file.
|
||||
with open(target, "wb") as dst:
|
||||
dst.write(data)
|
||||
|
||||
download_file_insecure.viable = lambda: True
|
||||
|
||||
def get_best_downloader():
|
||||
downloaders = [
|
||||
downloaders = (
|
||||
download_file_powershell,
|
||||
download_file_curl,
|
||||
download_file_wget,
|
||||
download_file_insecure,
|
||||
]
|
||||
|
||||
for dl in downloaders:
|
||||
if dl.viable():
|
||||
return dl
|
||||
)
|
||||
viable_downloaders = (dl for dl in downloaders if dl.viable())
|
||||
return next(viable_downloaders, None)
|
||||
|
||||
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
to_dir=os.curdir, delay=15,
|
||||
downloader_factory=get_best_downloader):
|
||||
"""Download setuptools from a specified location and return its filename
|
||||
to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader):
|
||||
"""
|
||||
Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
as an sdist for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download
|
||||
attempt.
|
||||
@ -269,74 +278,20 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
"""
|
||||
# making sure we use the absolute path
|
||||
to_dir = os.path.abspath(to_dir)
|
||||
tgz_name = "setuptools-%s.tar.gz" % version
|
||||
url = download_base + tgz_name
|
||||
saveto = os.path.join(to_dir, tgz_name)
|
||||
zip_name = "setuptools-%s.zip" % version
|
||||
url = download_base + zip_name
|
||||
saveto = os.path.join(to_dir, zip_name)
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
log.warn("Downloading %s", url)
|
||||
downloader = downloader_factory()
|
||||
downloader(url, saveto)
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
|
||||
def _extractall(self, path=".", members=None):
|
||||
"""Extract all members from the archive to the current working
|
||||
directory and set owner, modification time and permissions on
|
||||
directories afterwards. `path' specifies a different directory
|
||||
to extract to. `members' is optional and must be a subset of the
|
||||
list returned by getmembers().
|
||||
"""
|
||||
import copy
|
||||
import operator
|
||||
from tarfile import ExtractError
|
||||
directories = []
|
||||
|
||||
if members is None:
|
||||
members = self
|
||||
|
||||
for tarinfo in members:
|
||||
if tarinfo.isdir():
|
||||
# Extract directories with a safe mode.
|
||||
directories.append(tarinfo)
|
||||
tarinfo = copy.copy(tarinfo)
|
||||
tarinfo.mode = 448 # decimal for oct 0700
|
||||
self.extract(tarinfo, path)
|
||||
|
||||
# Reverse sort directories.
|
||||
if sys.version_info < (2, 4):
|
||||
def sorter(dir1, dir2):
|
||||
return cmp(dir1.name, dir2.name)
|
||||
directories.sort(sorter)
|
||||
directories.reverse()
|
||||
else:
|
||||
directories.sort(key=operator.attrgetter('name'), reverse=True)
|
||||
|
||||
# Set correct owner, mtime and filemode on directories.
|
||||
for tarinfo in directories:
|
||||
dirpath = os.path.join(path, tarinfo.name)
|
||||
try:
|
||||
self.chown(tarinfo, dirpath)
|
||||
self.utime(tarinfo, dirpath)
|
||||
self.chmod(tarinfo, dirpath)
|
||||
except ExtractError:
|
||||
e = sys.exc_info()[1]
|
||||
if self.errorlevel > 1:
|
||||
raise
|
||||
else:
|
||||
self._dbg(1, "tarfile: %s" % e)
|
||||
|
||||
|
||||
def _build_install_args(options):
|
||||
"""
|
||||
Build the arguments to 'python setup.py install' on the setuptools package
|
||||
"""
|
||||
install_args = []
|
||||
if options.user_install:
|
||||
if sys.version_info < (2, 6):
|
||||
log.warn("--user requires Python 2.6 or later")
|
||||
raise SystemExit(1)
|
||||
install_args.append('--user')
|
||||
return install_args
|
||||
return ['--user'] if options.user_install else []
|
||||
|
||||
def _parse_args():
|
||||
"""
|
||||
@ -355,16 +310,23 @@ def _parse_args():
|
||||
const=lambda: download_file_insecure, default=get_best_downloader,
|
||||
help='Use internal, non-validating downloader'
|
||||
)
|
||||
parser.add_option(
|
||||
'--version', help="Specify which version to download",
|
||||
default=DEFAULT_VERSION,
|
||||
)
|
||||
options, args = parser.parse_args()
|
||||
# positional arguments are ignored
|
||||
return options
|
||||
|
||||
def main(version=DEFAULT_VERSION):
|
||||
def main():
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
options = _parse_args()
|
||||
tarball = download_setuptools(download_base=options.download_base,
|
||||
downloader_factory=options.downloader_factory)
|
||||
return _install(tarball, _build_install_args(options))
|
||||
archive = download_setuptools(
|
||||
version=options.version,
|
||||
download_base=options.download_base,
|
||||
downloader_factory=options.downloader_factory,
|
||||
)
|
||||
return _install(archive, _build_install_args(options))
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
@ -19,3 +19,6 @@ output_dir = sphinx/locale/
|
||||
[compile_catalog]
|
||||
domain = sphinx
|
||||
directory = sphinx/locale/
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
|
18
setup.py
18
setup.py
@ -48,12 +48,19 @@ if sys.version_info < (2, 6) or (3, 0) <= sys.version_info < (3, 3):
|
||||
requires = [
|
||||
'six>=1.4',
|
||||
'Jinja2>=2.3',
|
||||
'Pygments>=1.2',
|
||||
'docutils>=0.10',
|
||||
'Pygments>=2.0',
|
||||
'docutils>=0.11',
|
||||
'snowballstemmer>=1.1',
|
||||
'babel',
|
||||
]
|
||||
extras_require = {
|
||||
# Environment Marker works for wheel 0.24 or later
|
||||
':sys_platform=="win32"': [
|
||||
'colorama',
|
||||
],
|
||||
}
|
||||
|
||||
# for sdist installation with pip-1.5.6
|
||||
if sys.platform == 'win32':
|
||||
requires.append('colorama')
|
||||
|
||||
@ -174,12 +181,16 @@ setup(
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Framework :: Sphinx',
|
||||
'Framework :: Sphinx :: Extension',
|
||||
'Framework :: Sphinx :: Theme',
|
||||
'Topic :: Documentation',
|
||||
'Topic :: Documentation :: Sphinx',
|
||||
'Topic :: Text Processing',
|
||||
'Topic :: Utilities',
|
||||
],
|
||||
platforms='any',
|
||||
packages=find_packages(exclude=['test']),
|
||||
packages=find_packages(exclude=['tests']),
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
@ -193,5 +204,6 @@ setup(
|
||||
],
|
||||
},
|
||||
install_requires=requires,
|
||||
extras_require=extras_require,
|
||||
cmdclass=cmdclass,
|
||||
)
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Sphinx documentation toolchain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
import sys
|
||||
from os import path
|
||||
|
||||
__version__ = '1.3a0'
|
||||
__released__ = '1.3a0' # used when Sphinx builds its own docs
|
||||
__version__ = '1.3b3'
|
||||
__released__ = '1.3b3' # 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, 3, 0, 'alpha', 0)
|
||||
version_info = (1, 3, 0, 'beta', 3)
|
||||
|
||||
package_dir = path.abspath(path.dirname(__file__))
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Sphinx documentation toolchain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import sys
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Additional docutils nodes.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -25,6 +25,7 @@ class desc(nodes.Admonition, nodes.Element):
|
||||
contains one or more ``desc_signature`` and a ``desc_content``.
|
||||
"""
|
||||
|
||||
|
||||
class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for object signatures.
|
||||
|
||||
@ -39,33 +40,42 @@ class desc_addname(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
# compatibility alias
|
||||
desc_classname = desc_addname
|
||||
|
||||
|
||||
class desc_type(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for return types or object type names."""
|
||||
|
||||
|
||||
class desc_returns(desc_type):
|
||||
"""Node for a "returns" annotation (a la -> in Python)."""
|
||||
def astext(self):
|
||||
return ' -> ' + nodes.TextElement.astext(self)
|
||||
|
||||
|
||||
class desc_name(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for the main object name."""
|
||||
|
||||
|
||||
class desc_parameterlist(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for a general parameter list."""
|
||||
child_text_separator = ', '
|
||||
|
||||
|
||||
class desc_parameter(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for a single parameter."""
|
||||
|
||||
|
||||
class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for marking optional parts of the parameter list."""
|
||||
child_text_separator = ', '
|
||||
|
||||
def astext(self):
|
||||
return '[' + nodes.TextElement.astext(self) + ']'
|
||||
|
||||
|
||||
class desc_annotation(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for signature annotations (not Python 3-style annotations)."""
|
||||
|
||||
|
||||
class desc_content(nodes.General, nodes.Element):
|
||||
"""Node for object description content.
|
||||
|
||||
@ -82,15 +92,18 @@ class versionmodified(nodes.Admonition, nodes.TextElement):
|
||||
directives.
|
||||
"""
|
||||
|
||||
|
||||
class seealso(nodes.Admonition, nodes.Element):
|
||||
"""Custom "see also" admonition."""
|
||||
|
||||
|
||||
class productionlist(nodes.Admonition, nodes.Element):
|
||||
"""Node for grammar production lists.
|
||||
|
||||
Contains ``production`` nodes.
|
||||
"""
|
||||
|
||||
|
||||
class production(nodes.Part, nodes.Inline, nodes.TextElement):
|
||||
"""Node for a single grammar production rule."""
|
||||
|
||||
@ -107,26 +120,33 @@ class index(nodes.Invisible, nodes.Inline, nodes.TextElement):
|
||||
*entrytype* is one of "single", "pair", "double", "triple".
|
||||
"""
|
||||
|
||||
class centered(nodes.Part, nodes.Element):
|
||||
|
||||
class centered(nodes.Part, nodes.TextElement):
|
||||
"""Deprecated."""
|
||||
|
||||
|
||||
class acks(nodes.Element):
|
||||
"""Special node for "acks" lists."""
|
||||
|
||||
|
||||
class hlist(nodes.Element):
|
||||
"""Node for "horizontal lists", i.e. lists that should be compressed to
|
||||
take up less vertical space.
|
||||
"""
|
||||
|
||||
|
||||
class hlistcol(nodes.Element):
|
||||
"""Node for one column in a horizontal list."""
|
||||
|
||||
|
||||
class compact_paragraph(nodes.paragraph):
|
||||
"""Node for a compact paragraph (which never makes a <p> node)."""
|
||||
|
||||
|
||||
class glossary(nodes.Element):
|
||||
"""Node to insert a glossary."""
|
||||
|
||||
|
||||
class only(nodes.Element):
|
||||
"""Node for "only" directives (conditional inclusion based on tags)."""
|
||||
|
||||
@ -136,14 +156,17 @@ class only(nodes.Element):
|
||||
class start_of_file(nodes.Element):
|
||||
"""Node to mark start of a new file, used in the LaTeX builder only."""
|
||||
|
||||
|
||||
class highlightlang(nodes.Element):
|
||||
"""Inserted to set the highlight language and line number options for
|
||||
subsequent code blocks.
|
||||
"""
|
||||
|
||||
|
||||
class tabular_col_spec(nodes.Element):
|
||||
"""Node for specifying tabular columns, used for LaTeX output."""
|
||||
|
||||
|
||||
class meta(nodes.Special, nodes.PreBibliographic, nodes.Element):
|
||||
"""Node for meta directive -- same as docutils' standard meta node,
|
||||
but pickleable.
|
||||
@ -160,22 +183,31 @@ class pending_xref(nodes.Inline, nodes.Element):
|
||||
BuildEnvironment.resolve_references.
|
||||
"""
|
||||
|
||||
|
||||
class number_reference(nodes.reference):
|
||||
"""Node for number references, similar to pending_xref."""
|
||||
|
||||
|
||||
class download_reference(nodes.reference):
|
||||
"""Node for download references, similar to pending_xref."""
|
||||
|
||||
|
||||
class literal_emphasis(nodes.emphasis):
|
||||
"""Node that behaves like `emphasis`, but further text processors are not
|
||||
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."""
|
||||
|
||||
|
||||
class termsep(nodes.Structural, nodes.Element):
|
||||
"""Separates two terms within a <term> node."""
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
Copyright 2008 Société des arts technologiques (SAT),
|
||||
http://www.sat.qc.ca/
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
@ -88,7 +88,7 @@ def create_module_file(package, module, opts):
|
||||
text = format_heading(1, '%s module' % module)
|
||||
else:
|
||||
text = ''
|
||||
#text += format_heading(2, ':mod:`%s` Module' % module)
|
||||
# text += format_heading(2, ':mod:`%s` Module' % module)
|
||||
text += format_directive(module, package)
|
||||
write_file(makename(package, module), text, opts)
|
||||
|
||||
@ -173,7 +173,7 @@ def shall_skip(module, opts):
|
||||
# skip if it has a "private" name and this is selected
|
||||
filename = path.basename(module)
|
||||
if filename != '__init__.py' and filename.startswith('_') and \
|
||||
not opts.includeprivate:
|
||||
not opts.includeprivate:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -218,7 +218,7 @@ def recurse_tree(rootpath, excludes, opts):
|
||||
if is_pkg:
|
||||
# we are in a package with something to document
|
||||
if subs or len(py_files) > 1 or not \
|
||||
shall_skip(path.join(root, INITPY), opts):
|
||||
shall_skip(path.join(root, INITPY), opts):
|
||||
subpackage = root[len(rootpath):].lstrip(path.sep).\
|
||||
replace(path.sep, '.')
|
||||
create_package_file(root, root_package, subpackage,
|
||||
@ -318,7 +318,7 @@ Note: By default this script will not overwrite already created files.""")
|
||||
(opts, args) = parser.parse_args(argv[1:])
|
||||
|
||||
if opts.show_version:
|
||||
print('Sphinx (sphinx-apidoc) %s' % __version__)
|
||||
print('Sphinx (sphinx-apidoc) %s' % __version__)
|
||||
return 0
|
||||
|
||||
if not args:
|
||||
@ -367,6 +367,7 @@ Note: By default this script will not overwrite already created files.""")
|
||||
batchfile = True,
|
||||
mastertocmaxdepth = opts.maxdepth,
|
||||
mastertoctree = text,
|
||||
language = 'en',
|
||||
)
|
||||
if not opts.dryrun:
|
||||
qs.generate(d, silent=True, overwrite=opts.force)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
Gracefully adapted from the TextPress system by Armin.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
@ -18,19 +18,20 @@ import types
|
||||
import posixpath
|
||||
import traceback
|
||||
from os import path
|
||||
from collections import deque
|
||||
|
||||
from six import iteritems, itervalues
|
||||
from six import iteritems, itervalues, text_type
|
||||
from six.moves import cStringIO
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import convert_directive_function, \
|
||||
directives, roles
|
||||
directives, roles
|
||||
|
||||
import sphinx
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import SphinxError, SphinxWarning, ExtensionError, \
|
||||
VersionRequirementError, ConfigError
|
||||
VersionRequirementError, ConfigError
|
||||
from sphinx.domains import ObjType, BUILTIN_DOMAINS
|
||||
from sphinx.domains.std import GenericObject, Target, StandardDomain
|
||||
from sphinx.builders import BUILTIN_BUILDERS
|
||||
@ -38,7 +39,8 @@ from sphinx.environment import BuildEnvironment, SphinxStandaloneReader
|
||||
from sphinx.util import pycompat # imported for side-effects
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.osutil import ENOENT
|
||||
from sphinx.util.console import bold, lightgray, darkgray
|
||||
from sphinx.util.console import bold, lightgray, darkgray, darkgreen, \
|
||||
term_width_line
|
||||
|
||||
if hasattr(sys, 'intern'):
|
||||
intern = sys.intern
|
||||
@ -48,8 +50,10 @@ events = {
|
||||
'builder-inited': '',
|
||||
'env-get-outdated': 'env, added, changed, removed',
|
||||
'env-purge-doc': 'env, docname',
|
||||
'env-before-read-docs': 'env, docnames',
|
||||
'source-read': 'docname, source text',
|
||||
'doctree-read': 'the doctree before being pickled',
|
||||
'env-merge-info': 'env, read docnames, other env instance',
|
||||
'missing-reference': 'env, node, contnode',
|
||||
'doctree-resolved': 'doctree, docname',
|
||||
'env-updated': 'env',
|
||||
@ -71,7 +75,7 @@ class Sphinx(object):
|
||||
self.verbosity = verbosity
|
||||
self.next_listener_id = 0
|
||||
self._extensions = {}
|
||||
self._extension_versions = {}
|
||||
self._extension_metadata = {}
|
||||
self._listeners = {}
|
||||
self.domains = BUILTIN_DOMAINS.copy()
|
||||
self.builderclasses = BUILTIN_BUILDERS.copy()
|
||||
@ -102,17 +106,25 @@ class Sphinx(object):
|
||||
self._events = events.copy()
|
||||
self._translators = {}
|
||||
|
||||
# keep last few messages for traceback
|
||||
self.messagelog = deque(maxlen=10)
|
||||
|
||||
# say hello to the world
|
||||
self.info(bold('Running Sphinx v%s' % sphinx.__version__))
|
||||
|
||||
# status code for command-line application
|
||||
self.statuscode = 0
|
||||
|
||||
if not path.isdir(outdir):
|
||||
self.info('making output directory...')
|
||||
os.makedirs(outdir)
|
||||
|
||||
# read config
|
||||
self.tags = Tags(tags)
|
||||
self.config = Config(confdir, CONFIG_FILENAME,
|
||||
confoverrides or {}, self.tags)
|
||||
self.config.check_unicode(self.warn)
|
||||
# defer checking types until i18n has been initialized
|
||||
|
||||
# set confdir to srcdir if -C given (!= no confdir); a few pieces
|
||||
# of code expect a confdir to be set
|
||||
@ -124,7 +136,7 @@ class Sphinx(object):
|
||||
self.setup_extension(extension)
|
||||
# the config file itself can be an extension
|
||||
if self.config.setup:
|
||||
# py31 doesn't have 'callable' function for bellow check
|
||||
# py31 doesn't have 'callable' function for below check
|
||||
if hasattr(self.config.setup, '__call__'):
|
||||
self.config.setup(self)
|
||||
else:
|
||||
@ -152,7 +164,7 @@ class Sphinx(object):
|
||||
'version requirement for extension %s, but it is '
|
||||
'not loaded' % extname)
|
||||
continue
|
||||
has_ver = self._extension_versions[extname]
|
||||
has_ver = self._extension_metadata[extname]['version']
|
||||
if has_ver == 'unknown version' or needs_ver > has_ver:
|
||||
raise VersionRequirementError(
|
||||
'This project needs the extension %s at least in '
|
||||
@ -161,6 +173,8 @@ class Sphinx(object):
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
# check all configuration values for permissible types
|
||||
self.config.check_types(self.warn)
|
||||
# set up the build environment
|
||||
self._init_env(freshenv)
|
||||
# set up the builder
|
||||
@ -196,15 +210,15 @@ class Sphinx(object):
|
||||
else:
|
||||
try:
|
||||
self.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(self.config,
|
||||
path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.env = BuildEnvironment.frompickle(
|
||||
self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
self.env.domains = {}
|
||||
for domain in self.domains.keys():
|
||||
# this can raise if the data version doesn't fit
|
||||
self.env.domains[domain] = self.domains[domain](self.env)
|
||||
self.info('done')
|
||||
except Exception as err:
|
||||
if type(err) is IOError and err.errno == ENOENT:
|
||||
if isinstance(err, IOError) and err.errno == ENOENT:
|
||||
self.info('not yet created')
|
||||
else:
|
||||
self.info('failed: %s' % err)
|
||||
@ -241,6 +255,15 @@ class Sphinx(object):
|
||||
else:
|
||||
self.builder.compile_update_catalogs()
|
||||
self.builder.build_update()
|
||||
|
||||
status = (self.statuscode == 0
|
||||
and 'succeeded' or 'finished with problems')
|
||||
if self._warncount:
|
||||
self.info(bold('build %s, %s warning%s.' %
|
||||
(status, self._warncount,
|
||||
self._warncount != 1 and 's' or '')))
|
||||
else:
|
||||
self.info(bold('build %s.' % status))
|
||||
except Exception as err:
|
||||
# delete the saved env to force a fresh build next time
|
||||
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
|
||||
@ -264,6 +287,7 @@ class Sphinx(object):
|
||||
wfile.write('\n')
|
||||
if hasattr(wfile, 'flush'):
|
||||
wfile.flush()
|
||||
self.messagelog.append(message)
|
||||
|
||||
def warn(self, message, location=None, prefix='WARNING: '):
|
||||
"""Emit a warning.
|
||||
@ -286,7 +310,7 @@ class Sphinx(object):
|
||||
else:
|
||||
location = None
|
||||
warntext = location and '%s: %s%s\n' % (location, prefix, message) or \
|
||||
'%s%s\n' % (prefix, message)
|
||||
'%s%s\n' % (prefix, message)
|
||||
if self.warningiserror:
|
||||
raise SphinxWarning(warntext)
|
||||
self._warncount += 1
|
||||
@ -345,6 +369,48 @@ class Sphinx(object):
|
||||
message = message % (args or kwargs)
|
||||
self._log(lightgray(message), self._status)
|
||||
|
||||
def _display_chunk(chunk):
|
||||
if isinstance(chunk, (list, tuple)):
|
||||
if len(chunk) == 1:
|
||||
return text_type(chunk[0])
|
||||
return '%s .. %s' % (chunk[0], chunk[-1])
|
||||
return text_type(chunk)
|
||||
|
||||
def old_status_iterator(self, iterable, summary, colorfunc=darkgreen,
|
||||
stringify_func=_display_chunk):
|
||||
l = 0
|
||||
for item in iterable:
|
||||
if l == 0:
|
||||
self.info(bold(summary), nonl=1)
|
||||
l = 1
|
||||
self.info(colorfunc(stringify_func(item)) + ' ', nonl=1)
|
||||
yield item
|
||||
if l == 1:
|
||||
self.info()
|
||||
|
||||
# new version with progress info
|
||||
def status_iterator(self, iterable, summary, colorfunc=darkgreen, length=0,
|
||||
stringify_func=_display_chunk):
|
||||
if length == 0:
|
||||
for item in self.old_status_iterator(iterable, summary, colorfunc,
|
||||
stringify_func):
|
||||
yield item
|
||||
return
|
||||
l = 0
|
||||
summary = bold(summary)
|
||||
for item in iterable:
|
||||
l += 1
|
||||
s = '%s[%3d%%] %s' % (summary, 100*l/length,
|
||||
colorfunc(stringify_func(item)))
|
||||
if self.verbosity:
|
||||
s += '\n'
|
||||
else:
|
||||
s = term_width_line(s)
|
||||
self.info(s, nonl=1)
|
||||
yield item
|
||||
if l > 0:
|
||||
self.info()
|
||||
|
||||
# ---- general extensibility interface -------------------------------------
|
||||
|
||||
def setup_extension(self, extension):
|
||||
@ -361,20 +427,22 @@ class Sphinx(object):
|
||||
if not hasattr(mod, 'setup'):
|
||||
self.warn('extension %r has no setup() function; is it really '
|
||||
'a Sphinx extension module?' % extension)
|
||||
version = None
|
||||
ext_meta = None
|
||||
else:
|
||||
try:
|
||||
version = mod.setup(self)
|
||||
ext_meta = mod.setup(self)
|
||||
except VersionRequirementError as err:
|
||||
# add the extension name to the version required
|
||||
raise VersionRequirementError(
|
||||
'The %s extension used by this project needs at least '
|
||||
'Sphinx v%s; it therefore cannot be built with this '
|
||||
'version.' % (extension, err))
|
||||
if version is None:
|
||||
version = 'unknown version'
|
||||
if ext_meta is None:
|
||||
ext_meta = {}
|
||||
if not ext_meta.get('version'):
|
||||
ext_meta['version'] = 'unknown version'
|
||||
self._extensions[extension] = mod
|
||||
self._extension_versions[extension] = version
|
||||
self._extension_metadata[extension] = ext_meta
|
||||
|
||||
def require_sphinx(self, version):
|
||||
# check the Sphinx version if requested
|
||||
@ -456,7 +524,7 @@ class Sphinx(object):
|
||||
else:
|
||||
raise ExtensionError(
|
||||
'Builder %r already exists (in module %s)' % (
|
||||
builder.name, self.builderclasses[builder.name].__module__))
|
||||
builder.name, self.builderclasses[builder.name].__module__))
|
||||
self.builderclasses[builder.name] = builder
|
||||
|
||||
def add_config_value(self, name, default, rebuild):
|
||||
@ -629,6 +697,11 @@ class Sphinx(object):
|
||||
StandaloneHTMLBuilder.css_files.append(
|
||||
posixpath.join('_static', filename))
|
||||
|
||||
def add_latex_package(self, packagename, options=None):
|
||||
self.debug('[app] adding latex package: %r', packagename)
|
||||
from sphinx.builders.latex import LaTeXBuilder
|
||||
LaTeXBuilder.usepackages.append((packagename, options))
|
||||
|
||||
def add_lexer(self, alias, lexer):
|
||||
self.debug('[app] adding lexer: %r', (alias, lexer))
|
||||
from sphinx.highlighting import lexers
|
||||
@ -650,7 +723,7 @@ class Sphinx(object):
|
||||
def add_search_language(self, cls):
|
||||
self.debug('[app] adding search language: %r', cls)
|
||||
from sphinx.search import languages, SearchLanguage
|
||||
assert isinstance(cls, SearchLanguage)
|
||||
assert issubclass(cls, SearchLanguage)
|
||||
languages[cls.lang] = cls
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Builder superclass for all builders.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -22,7 +22,9 @@ from docutils import nodes
|
||||
|
||||
from sphinx.util import i18n, path_stabilize
|
||||
from sphinx.util.osutil import SEP, relative_uri, find_catalog
|
||||
from sphinx.util.console import bold, purple, darkgreen, term_width_line
|
||||
from sphinx.util.console import bold, darkgreen
|
||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
|
||||
parallel_available
|
||||
|
||||
# side effect: registers roles and directives
|
||||
from sphinx import roles
|
||||
@ -40,12 +42,14 @@ class Builder(object):
|
||||
format = ''
|
||||
# doctree versioning method
|
||||
versioning_method = 'none'
|
||||
versioning_compare = False
|
||||
# allow parallel write_doc() calls
|
||||
allow_parallel = False
|
||||
|
||||
def __init__(self, app):
|
||||
self.env = app.env
|
||||
self.env.set_versioning_method(self.versioning_method)
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.versioning_compare)
|
||||
self.srcdir = app.srcdir
|
||||
self.confdir = app.confdir
|
||||
self.outdir = app.outdir
|
||||
@ -62,9 +66,20 @@ class Builder(object):
|
||||
self.tags.add(self.name)
|
||||
self.tags.add("format_%s" % self.format)
|
||||
self.tags.add("builder_%s" % self.name)
|
||||
# compatibility aliases
|
||||
self.status_iterator = app.status_iterator
|
||||
self.old_status_iterator = app.old_status_iterator
|
||||
|
||||
# images that need to be copied over (source -> dest)
|
||||
self.images = {}
|
||||
# basename of images directory
|
||||
self.imagedir = ""
|
||||
# relative path to image directory from current docname (used at writing docs)
|
||||
self.imgpath = ""
|
||||
|
||||
# these get set later
|
||||
self.parallel_ok = False
|
||||
self.finish_tasks = None
|
||||
|
||||
# load default translator class
|
||||
self.translator_class = app._translators.get(self.name)
|
||||
@ -113,41 +128,6 @@ class Builder(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def old_status_iterator(self, iterable, summary, colorfunc=darkgreen,
|
||||
stringify_func=lambda x: x):
|
||||
l = 0
|
||||
for item in iterable:
|
||||
if l == 0:
|
||||
self.info(bold(summary), nonl=1)
|
||||
l = 1
|
||||
self.info(colorfunc(stringify_func(item)) + ' ', nonl=1)
|
||||
yield item
|
||||
if l == 1:
|
||||
self.info()
|
||||
|
||||
# new version with progress info
|
||||
def status_iterator(self, iterable, summary, colorfunc=darkgreen, length=0,
|
||||
stringify_func=lambda x: x):
|
||||
if length == 0:
|
||||
for item in self.old_status_iterator(iterable, summary, colorfunc,
|
||||
stringify_func):
|
||||
yield item
|
||||
return
|
||||
l = 0
|
||||
summary = bold(summary)
|
||||
for item in iterable:
|
||||
l += 1
|
||||
s = '%s[%3d%%] %s' % (summary, 100*l/length,
|
||||
colorfunc(stringify_func(item)))
|
||||
if self.app.verbosity:
|
||||
s += '\n'
|
||||
else:
|
||||
s = term_width_line(s)
|
||||
self.info(s, nonl=1)
|
||||
yield item
|
||||
if l > 0:
|
||||
self.info()
|
||||
|
||||
supported_image_types = []
|
||||
|
||||
def post_process_images(self, doctree):
|
||||
@ -179,9 +159,8 @@ class Builder(object):
|
||||
def compile_catalogs(self, catalogs, message):
|
||||
if not self.config.gettext_auto_build:
|
||||
return
|
||||
self.info(bold('building [mo]: '), nonl=1)
|
||||
self.info(message)
|
||||
for catalog in self.status_iterator(
|
||||
self.info(bold('building [mo]: ') + message)
|
||||
for catalog in self.app.status_iterator(
|
||||
catalogs, 'writing output... ', darkgreen, len(catalogs),
|
||||
lambda c: c.mo_path):
|
||||
catalog.write_mo(self.config.language)
|
||||
@ -263,25 +242,16 @@ class Builder(object):
|
||||
First updates the environment, and then calls :meth:`write`.
|
||||
"""
|
||||
if summary:
|
||||
self.info(bold('building [%s]: ' % self.name), nonl=1)
|
||||
self.info(summary)
|
||||
self.info(bold('building [%s]' % self.name) + ': ' + summary)
|
||||
|
||||
updated_docnames = set()
|
||||
# while reading, collect all warnings from docutils
|
||||
warnings = []
|
||||
self.env.set_warnfunc(lambda *args: warnings.append(args))
|
||||
self.info(bold('updating environment: '), nonl=1)
|
||||
msg, length, iterator = self.env.update(self.config, self.srcdir,
|
||||
self.doctreedir, self.app)
|
||||
self.info(msg)
|
||||
for docname in self.status_iterator(iterator, 'reading sources... ',
|
||||
purple, length):
|
||||
updated_docnames.add(docname)
|
||||
# nothing further to do, the environment has already
|
||||
# done the reading
|
||||
updated_docnames = set(self.env.update(self.config, self.srcdir,
|
||||
self.doctreedir, self.app))
|
||||
self.env.set_warnfunc(self.warn)
|
||||
for warning in warnings:
|
||||
self.warn(*warning)
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
doccount = len(updated_docnames)
|
||||
self.info(bold('looking for now-outdated files... '), nonl=1)
|
||||
@ -315,20 +285,33 @@ class Builder(object):
|
||||
if docnames and docnames != ['__all__']:
|
||||
docnames = set(docnames) & self.env.found_docs
|
||||
|
||||
# another indirection to support builders that don't build
|
||||
# files individually
|
||||
# determine if we can write in parallel
|
||||
self.parallel_ok = False
|
||||
if parallel_available and self.app.parallel > 1 and self.allow_parallel:
|
||||
self.parallel_ok = True
|
||||
for extname, md in self.app._extension_metadata.items():
|
||||
par_ok = md.get('parallel_write_safe', True)
|
||||
if not par_ok:
|
||||
self.app.warn('the %s extension is not safe for parallel '
|
||||
'writing, doing serial write' % extname)
|
||||
self.parallel_ok = False
|
||||
break
|
||||
|
||||
# create a task executor to use for misc. "finish-up" tasks
|
||||
# if self.parallel_ok:
|
||||
# self.finish_tasks = ParallelTasks(self.app.parallel)
|
||||
# else:
|
||||
# for now, just execute them serially
|
||||
self.finish_tasks = SerialTasks()
|
||||
|
||||
# write all "normal" documents (or everything for some builders)
|
||||
self.write(docnames, list(updated_docnames), method)
|
||||
|
||||
# finish (write static files etc.)
|
||||
self.finish()
|
||||
status = (self.app.statuscode == 0 and 'succeeded'
|
||||
or 'finished with problems')
|
||||
if self.app._warncount:
|
||||
self.info(bold('build %s, %s warning%s.' %
|
||||
(status, self.app._warncount,
|
||||
self.app._warncount != 1 and 's' or '')))
|
||||
else:
|
||||
self.info(bold('build %s.' % status))
|
||||
|
||||
# wait for all tasks
|
||||
self.finish_tasks.join()
|
||||
|
||||
def write(self, build_docnames, updated_docnames, method='update'):
|
||||
if build_docnames is None or build_docnames == ['__all__']:
|
||||
@ -354,23 +337,17 @@ class Builder(object):
|
||||
|
||||
warnings = []
|
||||
self.env.set_warnfunc(lambda *args: warnings.append(args))
|
||||
# check for prerequisites to parallel build
|
||||
# (parallel only works on POSIX, because the forking impl of
|
||||
# multiprocessing is required)
|
||||
if not (multiprocessing and
|
||||
self.app.parallel > 1 and
|
||||
self.allow_parallel and
|
||||
os.name == 'posix'):
|
||||
self._write_serial(sorted(docnames), warnings)
|
||||
else:
|
||||
if self.parallel_ok:
|
||||
# number of subprocesses is parallel-1 because the main process
|
||||
# is busy loading doctrees and doing write_doc_serialized()
|
||||
self._write_parallel(sorted(docnames), warnings,
|
||||
nproc=self.app.parallel - 1)
|
||||
else:
|
||||
self._write_serial(sorted(docnames), warnings)
|
||||
self.env.set_warnfunc(self.warn)
|
||||
|
||||
def _write_serial(self, docnames, warnings):
|
||||
for docname in self.status_iterator(
|
||||
for docname in self.app.status_iterator(
|
||||
docnames, 'writing output... ', darkgreen, len(docnames)):
|
||||
doctree = self.env.get_and_resolve_doctree(docname, self)
|
||||
self.write_doc_serialized(docname, doctree)
|
||||
@ -380,60 +357,39 @@ class Builder(object):
|
||||
|
||||
def _write_parallel(self, docnames, warnings, nproc):
|
||||
def write_process(docs):
|
||||
try:
|
||||
for docname, doctree in docs:
|
||||
self.write_doc(docname, doctree)
|
||||
except KeyboardInterrupt:
|
||||
pass # do not print a traceback on Ctrl-C
|
||||
finally:
|
||||
for warning in warnings:
|
||||
self.warn(*warning)
|
||||
local_warnings = []
|
||||
self.env.set_warnfunc(lambda *args: local_warnings.append(args))
|
||||
for docname, doctree in docs:
|
||||
self.write_doc(docname, doctree)
|
||||
return local_warnings
|
||||
|
||||
def process_thread(docs):
|
||||
p = multiprocessing.Process(target=write_process, args=(docs,))
|
||||
p.start()
|
||||
p.join()
|
||||
semaphore.release()
|
||||
|
||||
# allow only "nproc" worker processes at once
|
||||
semaphore = threading.Semaphore(nproc)
|
||||
# list of threads to join when waiting for completion
|
||||
threads = []
|
||||
def add_warnings(docs, wlist):
|
||||
warnings.extend(wlist)
|
||||
|
||||
# warm up caches/compile templates using the first document
|
||||
firstname, docnames = docnames[0], docnames[1:]
|
||||
doctree = self.env.get_and_resolve_doctree(firstname, self)
|
||||
self.write_doc_serialized(firstname, doctree)
|
||||
self.write_doc(firstname, doctree)
|
||||
# for the rest, determine how many documents to write in one go
|
||||
ndocs = len(docnames)
|
||||
chunksize = min(ndocs // nproc, 10)
|
||||
if chunksize == 0:
|
||||
chunksize = 1
|
||||
nchunks, rest = divmod(ndocs, chunksize)
|
||||
if rest:
|
||||
nchunks += 1
|
||||
# partition documents in "chunks" that will be written by one Process
|
||||
chunks = [docnames[i*chunksize:(i+1)*chunksize] for i in range(nchunks)]
|
||||
for docnames in self.status_iterator(
|
||||
chunks, 'writing output... ', darkgreen, len(chunks),
|
||||
lambda chk: '%s .. %s' % (chk[0], chk[-1])):
|
||||
docs = []
|
||||
for docname in docnames:
|
||||
|
||||
tasks = ParallelTasks(nproc)
|
||||
chunks = make_chunks(docnames, nproc)
|
||||
|
||||
for chunk in self.app.status_iterator(
|
||||
chunks, 'writing output... ', darkgreen, len(chunks)):
|
||||
arg = []
|
||||
for i, docname in enumerate(chunk):
|
||||
doctree = self.env.get_and_resolve_doctree(docname, self)
|
||||
self.write_doc_serialized(docname, doctree)
|
||||
docs.append((docname, doctree))
|
||||
# start a new thread to oversee the completion of this chunk
|
||||
semaphore.acquire()
|
||||
t = threading.Thread(target=process_thread, args=(docs,))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
arg.append((docname, doctree))
|
||||
tasks.add_task(write_process, arg, add_warnings)
|
||||
|
||||
# make sure all threads have finished
|
||||
self.info(bold('waiting for workers... '))#, nonl=True)
|
||||
for t in threads:
|
||||
t.join()
|
||||
self.info(bold('waiting for workers...'))
|
||||
tasks.join()
|
||||
|
||||
for warning in warnings:
|
||||
self.warn(*warning)
|
||||
|
||||
def prepare_writing(self, docnames):
|
||||
"""A place where you can add logic before :meth:`write_doc` is run"""
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Changelog builder.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -130,6 +130,9 @@ class ChangesBuilder(Builder):
|
||||
self.env.config.source_encoding)
|
||||
try:
|
||||
lines = f.readlines()
|
||||
except UnicodeDecodeError:
|
||||
self.warn('could not read %r for changelog creation' % docname)
|
||||
continue
|
||||
finally:
|
||||
f.close()
|
||||
targetfn = path.join(self.outdir, 'rst', os_path(docname)) + '.html'
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
.. _Devhelp: http://live.gnome.org/devhelp
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
@ -6,7 +6,7 @@
|
||||
Build epub files.
|
||||
Originally derived from qthelp.py.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -404,9 +404,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
The method tries to read and write the files with the PIL,
|
||||
converting the format and resizing the image if necessary/possible.
|
||||
"""
|
||||
ensuredir(path.join(self.outdir, '_images'))
|
||||
for src in self.status_iterator(self.images, 'copying images... ',
|
||||
brown, len(self.images)):
|
||||
ensuredir(path.join(self.outdir, self.imagedir))
|
||||
for src in self.app.status_iterator(self.images, 'copying images... ',
|
||||
brown, len(self.images)):
|
||||
dest = self.images[src]
|
||||
try:
|
||||
img = Image.open(path.join(self.srcdir, src))
|
||||
@ -416,7 +416,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
(path.join(self.srcdir, src), ))
|
||||
try:
|
||||
copyfile(path.join(self.srcdir, src),
|
||||
path.join(self.outdir, '_images', dest))
|
||||
path.join(self.outdir, self.imagedir, dest))
|
||||
except (IOError, OSError) as err:
|
||||
self.warn('cannot copy image file %r: %s' %
|
||||
(path.join(self.srcdir, src), err))
|
||||
@ -432,7 +432,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
nh = (height * nw) / width
|
||||
img = img.resize((nw, nh), Image.BICUBIC)
|
||||
try:
|
||||
img.save(path.join(self.outdir, '_images', dest))
|
||||
img.save(path.join(self.outdir, self.imagedir, dest))
|
||||
except (IOError, OSError) as err:
|
||||
self.warn('cannot write image file %r: %s' %
|
||||
(path.join(self.srcdir, src), err))
|
||||
|
@ -5,11 +5,10 @@
|
||||
|
||||
The MessageCatalogBuilder class.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from __future__ import with_statement
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from os import path, walk
|
||||
@ -85,6 +84,11 @@ class I18nBuilder(Builder):
|
||||
"""
|
||||
name = 'i18n'
|
||||
versioning_method = 'text'
|
||||
versioning_compare = None # be set by `gettext_uuid`
|
||||
|
||||
def __init__(self, app):
|
||||
self.versioning_compare = app.env.config.gettext_uuid
|
||||
super(I18nBuilder, self).__init__(app)
|
||||
|
||||
def init(self):
|
||||
Builder.init(self)
|
||||
@ -109,15 +113,16 @@ class I18nBuilder(Builder):
|
||||
for node, msg in extract_messages(doctree):
|
||||
catalog.add(msg, node)
|
||||
|
||||
# Extract translatable messages from index entries.
|
||||
for node, entries in traverse_translatable_index(doctree):
|
||||
for typ, msg, tid, main in entries:
|
||||
for m in split_index_msg(typ, msg):
|
||||
if typ == 'pair' and m in pairindextypes.values():
|
||||
# avoid built-in translated message was incorporated
|
||||
# in 'sphinx.util.nodes.process_index_entry'
|
||||
continue
|
||||
catalog.add(m, node)
|
||||
if 'index' in self.env.config.gettext_enables:
|
||||
# Extract translatable messages from index entries.
|
||||
for node, entries in traverse_translatable_index(doctree):
|
||||
for typ, msg, tid, main in entries:
|
||||
for m in split_index_msg(typ, msg):
|
||||
if typ == 'pair' and m in pairindextypes.values():
|
||||
# avoid built-in translated message was incorporated
|
||||
# in 'sphinx.util.nodes.process_index_entry'
|
||||
continue
|
||||
catalog.add(m, node)
|
||||
|
||||
|
||||
# determine tzoffset once to remain unaffected by DST change during build
|
||||
@ -170,8 +175,8 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
|
||||
extract_translations = self.templates.environment.extract_translations
|
||||
|
||||
for template in self.status_iterator(files,
|
||||
'reading templates... ', purple, len(files)):
|
||||
for template in self.app.status_iterator(
|
||||
files, 'reading templates... ', purple, len(files)):
|
||||
with open(template, 'r', encoding='utf-8') as f:
|
||||
context = f.read()
|
||||
for line, meth, msg in extract_translations(context):
|
||||
@ -191,7 +196,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
ctime = datetime.fromtimestamp(
|
||||
timestamp, ltz).strftime('%Y-%m-%d %H:%M%z'),
|
||||
)
|
||||
for textdomain, catalog in self.status_iterator(
|
||||
for textdomain, catalog in self.app.status_iterator(
|
||||
iteritems(self.catalogs), "writing message catalogs... ",
|
||||
darkgreen, len(self.catalogs),
|
||||
lambda textdomain__: textdomain__[0]):
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Several HTML builders.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -17,7 +17,7 @@ import posixpath
|
||||
from os import path
|
||||
from hashlib import md5
|
||||
|
||||
from six import iteritems, itervalues, text_type, string_types
|
||||
from six import iteritems, text_type, string_types
|
||||
from six.moves import cPickle as pickle
|
||||
from docutils import nodes
|
||||
from docutils.io import DocTreeInput, StringOutput
|
||||
@ -29,7 +29,7 @@ from docutils.readers.doctree import Reader as DoctreeReader
|
||||
from sphinx import package_dir, __version__
|
||||
from sphinx.util import jsonimpl, copy_static_entry
|
||||
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
|
||||
movefile, ustrftime, copyfile
|
||||
movefile, ustrftime, copyfile
|
||||
from sphinx.util.nodes import inline_all_toctrees
|
||||
from sphinx.util.matching import patmatch, compile_matchers
|
||||
from sphinx.locale import _
|
||||
@ -40,7 +40,7 @@ from sphinx.application import ENV_PICKLE_FILENAME
|
||||
from sphinx.highlighting import PygmentsBridge
|
||||
from sphinx.util.console import bold, darkgreen, brown
|
||||
from sphinx.writers.html import HTMLWriter, HTMLTranslator, \
|
||||
SmartyPantsHTMLTranslator
|
||||
SmartyPantsHTMLTranslator
|
||||
|
||||
#: the filename for the inventory of objects
|
||||
INVENTORY_FILENAME = 'objects.inv'
|
||||
@ -95,6 +95,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# a hash of all config values that, if changed, cause a full rebuild
|
||||
self.config_hash = ''
|
||||
self.tags_hash = ''
|
||||
# basename of images directory
|
||||
self.imagedir = '_images'
|
||||
# section numbers for headings in the currently visited document
|
||||
self.secnumbers = {}
|
||||
# currently written docname
|
||||
@ -266,7 +268,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# html_domain_indices can be False/True or a list of index names
|
||||
indices_config = self.config.html_domain_indices
|
||||
if indices_config:
|
||||
for domain in itervalues(self.env.domains):
|
||||
for domain_name in sorted(self.env.domains):
|
||||
domain = self.env.domains[domain_name]
|
||||
for indexcls in domain.indices:
|
||||
indexname = '%s-%s' % (domain.name, indexcls.name)
|
||||
if isinstance(indices_config, list):
|
||||
@ -335,6 +338,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
show_source = self.config.html_show_sourcelink,
|
||||
file_suffix = self.out_suffix,
|
||||
script_files = self.script_files,
|
||||
language = self.config.language,
|
||||
css_files = self.css_files,
|
||||
sphinx_version = __version__,
|
||||
style = stylename,
|
||||
@ -424,6 +428,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
doctree.settings = self.docsettings
|
||||
|
||||
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
|
||||
self.fignumbers = self.env.toc_fignumbers.get(docname, {})
|
||||
self.imgpath = relative_uri(self.get_target_uri(docname), '_images')
|
||||
self.dlpath = relative_uri(self.get_target_uri(docname), '_downloads')
|
||||
self.current_docname = docname
|
||||
@ -436,19 +441,26 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.handle_page(docname, ctx, event_arg=doctree)
|
||||
|
||||
def write_doc_serialized(self, docname, doctree):
|
||||
self.imgpath = relative_uri(self.get_target_uri(docname), '_images')
|
||||
self.imgpath = relative_uri(self.get_target_uri(docname), self.imagedir)
|
||||
self.post_process_images(doctree)
|
||||
title = self.env.longtitles.get(docname)
|
||||
title = title and self.render_partial(title)['title'] or ''
|
||||
self.index_page(docname, doctree, title)
|
||||
|
||||
def finish(self):
|
||||
self.info(bold('writing additional files...'), nonl=1)
|
||||
self.finish_tasks.add_task(self.gen_indices)
|
||||
self.finish_tasks.add_task(self.gen_additional_pages)
|
||||
self.finish_tasks.add_task(self.copy_image_files)
|
||||
self.finish_tasks.add_task(self.copy_download_files)
|
||||
self.finish_tasks.add_task(self.copy_static_files)
|
||||
self.finish_tasks.add_task(self.copy_extra_files)
|
||||
self.finish_tasks.add_task(self.write_buildinfo)
|
||||
|
||||
# pages from extensions
|
||||
for pagelist in self.app.emit('html-collect-pages'):
|
||||
for pagename, context, template in pagelist:
|
||||
self.handle_page(pagename, context, template)
|
||||
# dump the search index
|
||||
self.handle_finish()
|
||||
|
||||
def gen_indices(self):
|
||||
self.info(bold('generating indices...'), nonl=1)
|
||||
|
||||
# the global general index
|
||||
if self.get_builder_config('use_index', 'html'):
|
||||
@ -457,16 +469,27 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# the global domain-specific indices
|
||||
self.write_domain_indices()
|
||||
|
||||
# the search page
|
||||
if self.name != 'htmlhelp':
|
||||
self.info(' search', nonl=1)
|
||||
self.handle_page('search', {}, 'search.html')
|
||||
self.info()
|
||||
|
||||
def gen_additional_pages(self):
|
||||
# pages from extensions
|
||||
for pagelist in self.app.emit('html-collect-pages'):
|
||||
for pagename, context, template in pagelist:
|
||||
self.handle_page(pagename, context, template)
|
||||
|
||||
self.info(bold('writing additional pages...'), nonl=1)
|
||||
|
||||
# additional pages from conf.py
|
||||
for pagename, template in self.config.html_additional_pages.items():
|
||||
self.info(' '+pagename, nonl=1)
|
||||
self.handle_page(pagename, {}, template)
|
||||
|
||||
# the search page
|
||||
if self.name != 'htmlhelp':
|
||||
self.info(' search', nonl=1)
|
||||
self.handle_page('search', {}, 'search.html')
|
||||
|
||||
# the opensearch xml file
|
||||
if self.config.html_use_opensearch and self.name != 'htmlhelp':
|
||||
self.info(' opensearch', nonl=1)
|
||||
fn = path.join(self.outdir, '_static', 'opensearch.xml')
|
||||
@ -474,15 +497,6 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
self.info()
|
||||
|
||||
self.copy_image_files()
|
||||
self.copy_download_files()
|
||||
self.copy_static_files()
|
||||
self.copy_extra_files()
|
||||
self.write_buildinfo()
|
||||
|
||||
# dump the search index
|
||||
self.handle_finish()
|
||||
|
||||
def write_genindex(self):
|
||||
# the total count of lines for each index letter, used to distribute
|
||||
# the entries into two columns
|
||||
@ -525,13 +539,13 @@ class StandaloneHTMLBuilder(Builder):
|
||||
def copy_image_files(self):
|
||||
# copy image files
|
||||
if self.images:
|
||||
ensuredir(path.join(self.outdir, '_images'))
|
||||
for src in self.status_iterator(self.images, 'copying images... ',
|
||||
brown, len(self.images)):
|
||||
ensuredir(path.join(self.outdir, self.imagedir))
|
||||
for src in self.app.status_iterator(self.images, 'copying images... ',
|
||||
brown, len(self.images)):
|
||||
dest = self.images[src]
|
||||
try:
|
||||
copyfile(path.join(self.srcdir, src),
|
||||
path.join(self.outdir, '_images', dest))
|
||||
path.join(self.outdir, self.imagedir, dest))
|
||||
except Exception as err:
|
||||
self.warn('cannot copy image file %r: %s' %
|
||||
(path.join(self.srcdir, src), err))
|
||||
@ -540,9 +554,9 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# copy downloadable files
|
||||
if self.env.dlfiles:
|
||||
ensuredir(path.join(self.outdir, '_downloads'))
|
||||
for src in self.status_iterator(self.env.dlfiles,
|
||||
'copying downloadable files... ',
|
||||
brown, len(self.env.dlfiles)):
|
||||
for src in self.app.status_iterator(self.env.dlfiles,
|
||||
'copying downloadable files... ',
|
||||
brown, len(self.env.dlfiles)):
|
||||
dest = self.env.dlfiles[src][1]
|
||||
try:
|
||||
copyfile(path.join(self.srcdir, src),
|
||||
@ -755,8 +769,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.add_sidebars(pagename, ctx)
|
||||
ctx.update(addctx)
|
||||
|
||||
self.app.emit('html-page-context', pagename, templatename,
|
||||
ctx, event_arg)
|
||||
newtmpl = self.app.emit_firstresult('html-page-context', pagename,
|
||||
templatename, ctx, event_arg)
|
||||
if newtmpl:
|
||||
templatename = newtmpl
|
||||
|
||||
try:
|
||||
output = self.templates.render(templatename, ctx)
|
||||
@ -786,8 +802,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
copyfile(self.env.doc2path(pagename), source_name)
|
||||
|
||||
def handle_finish(self):
|
||||
self.dump_search_index()
|
||||
self.dump_inventory()
|
||||
self.finish_tasks.add_task(self.dump_search_index)
|
||||
self.finish_tasks.add_task(self.dump_inventory)
|
||||
|
||||
def dump_inventory(self):
|
||||
self.info(bold('dumping object inventory... '), nonl=True)
|
||||
@ -802,7 +818,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
compressor = zlib.compressobj(9)
|
||||
for domainname, domain in iteritems(self.env.domains):
|
||||
for name, dispname, type, docname, anchor, prio in \
|
||||
domain.get_objects():
|
||||
sorted(domain.get_objects()):
|
||||
if anchor.endswith(name):
|
||||
# this can shorten the inventory by as much as 25%
|
||||
anchor = anchor[:-len(name)] + '$'
|
||||
@ -1019,6 +1035,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
|
||||
def init(self):
|
||||
self.config_hash = ''
|
||||
self.tags_hash = ''
|
||||
self.imagedir = '_images'
|
||||
self.theme = None # no theme necessary
|
||||
self.templates = None # no template bridge necessary
|
||||
self.init_translator_class()
|
||||
@ -1050,8 +1067,9 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
|
||||
outfilename = path.join(self.outdir,
|
||||
os_path(pagename) + self.out_suffix)
|
||||
|
||||
self.app.emit('html-page-context', pagename, templatename,
|
||||
ctx, event_arg)
|
||||
# we're not taking the return value here, since no template is
|
||||
# actually rendered
|
||||
self.app.emit('html-page-context', pagename, templatename, ctx, event_arg)
|
||||
|
||||
ensuredir(path.dirname(outfilename))
|
||||
self.dump_context(ctx, outfilename)
|
||||
|
@ -6,7 +6,7 @@
|
||||
Build HTML help support files.
|
||||
Parts adapted from Python's Doc/tools/prechm.py.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
LaTeX builder.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -37,6 +37,7 @@ class LaTeXBuilder(Builder):
|
||||
format = 'latex'
|
||||
supported_image_types = ['application/pdf', 'image/png',
|
||||
'image/gif', 'image/jpeg']
|
||||
usepackages = []
|
||||
|
||||
def init(self):
|
||||
self.docnames = []
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The CheckExternalLinksBuilder class.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -122,7 +122,7 @@ class CheckExternalLinksBuilder(Builder):
|
||||
elif not (uri[0:5] == 'http:' or uri[0:6] == 'https:'):
|
||||
return 'local', '', 0
|
||||
elif uri in self.good:
|
||||
return 'working', '', 0
|
||||
return 'working', 'old', 0
|
||||
elif uri in self.broken:
|
||||
return 'broken', self.broken[uri], 0
|
||||
elif uri in self.redirected:
|
||||
@ -166,13 +166,20 @@ class CheckExternalLinksBuilder(Builder):
|
||||
req = Request(req_url)
|
||||
f = opener.open(req, **kwargs)
|
||||
f.close()
|
||||
|
||||
except HTTPError as err:
|
||||
if err.code == 401:
|
||||
# We'll take "Unauthorized" as working.
|
||||
self.good.add(uri)
|
||||
return 'working', ' - unauthorized', 0
|
||||
else:
|
||||
self.broken[uri] = str(err)
|
||||
return 'broken', str(err), 0
|
||||
except Exception as err:
|
||||
self.broken[uri] = str(err)
|
||||
return 'broken', str(err), 0
|
||||
if f.url.rstrip('/') == req_url.rstrip('/'):
|
||||
self.good.add(uri)
|
||||
return 'working', 'new', 0
|
||||
return 'working', '', 0
|
||||
else:
|
||||
new_url = f.url
|
||||
if hash:
|
||||
@ -192,7 +199,7 @@ class CheckExternalLinksBuilder(Builder):
|
||||
uri, docname, lineno, status, info, code = result
|
||||
if status == 'unchecked':
|
||||
return
|
||||
if status == 'working' and info != 'new':
|
||||
if status == 'working' and info == 'old':
|
||||
return
|
||||
if lineno:
|
||||
self.info('(line %4d) ' % lineno, nonl=1)
|
||||
@ -202,7 +209,7 @@ class CheckExternalLinksBuilder(Builder):
|
||||
self.info(darkgray('-local- ') + uri)
|
||||
self.write_entry('local', docname, lineno, uri)
|
||||
elif status == 'working':
|
||||
self.info(darkgreen('ok ') + uri)
|
||||
self.info(darkgreen('ok ') + uri + info)
|
||||
elif status == 'broken':
|
||||
self.info(red('broken ') + uri + red(' - ' + info))
|
||||
self.write_entry('broken', docname, lineno, uri + ': ' + info)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Manual pages builder.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Build input files for the Qt collection generator.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -157,7 +157,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
|
||||
olen = len(outdir)
|
||||
projectfiles = []
|
||||
staticdir = path.join(outdir, '_static')
|
||||
imagesdir = path.join(outdir, '_images')
|
||||
imagesdir = path.join(outdir, self.imagedir)
|
||||
for root, dirs, files in os.walk(outdir):
|
||||
resourcedir = root.startswith(staticdir) or \
|
||||
root.startswith(imagesdir)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Texinfo builder.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Plain-text Sphinx builder.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Builder for the web support package.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -27,6 +27,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
|
||||
"""
|
||||
name = 'websupport'
|
||||
versioning_method = 'commentable'
|
||||
versioning_compare = True # for commentable node's uuid stability.
|
||||
|
||||
def init(self):
|
||||
PickleHTMLBuilder.init(self)
|
||||
@ -58,7 +59,8 @@ class WebSupportBuilder(PickleHTMLBuilder):
|
||||
doctree.settings = self.docsettings
|
||||
|
||||
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
|
||||
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, '_images')
|
||||
self.fignumbers = self.env.toc_fignumbers.get(docname, {})
|
||||
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir)
|
||||
self.dlpath = '/' + posixpath.join(self.virtual_staticdir, '_downloads')
|
||||
self.current_docname = docname
|
||||
self.docwriter.write(doctree, destination)
|
||||
@ -70,7 +72,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
|
||||
self.handle_page(docname, ctx, event_arg=doctree)
|
||||
|
||||
def write_doc_serialized(self, docname, doctree):
|
||||
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, '_images')
|
||||
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir)
|
||||
self.post_process_images(doctree)
|
||||
title = self.env.longtitles.get(docname)
|
||||
title = title and self.render_partial(title)['title'] or ''
|
||||
@ -103,8 +105,10 @@ class WebSupportBuilder(PickleHTMLBuilder):
|
||||
self.add_sidebars(pagename, ctx)
|
||||
ctx.update(addctx)
|
||||
|
||||
self.app.emit('html-page-context', pagename, templatename,
|
||||
ctx, event_arg)
|
||||
newtmpl = self.app.emit_firstresult('html-page-context', pagename,
|
||||
templatename, ctx, event_arg)
|
||||
if newtmpl:
|
||||
templatename = newtmpl
|
||||
|
||||
# create a dict that will be pickled and used by webapps
|
||||
doc_ctx = {
|
||||
@ -148,7 +152,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
|
||||
PickleHTMLBuilder.handle_finish(self)
|
||||
|
||||
# move static stuff over to separate directory
|
||||
directories = ['_images', '_static']
|
||||
directories = [self.imagedir, '_static']
|
||||
for directory in directories:
|
||||
src = path.join(self.outdir, directory)
|
||||
dst = path.join(self.staticdir, directory)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Docutils-native XML and pseudo-XML builders.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,14 +5,14 @@
|
||||
|
||||
sphinx-build command-line handling.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
import optparse
|
||||
import traceback
|
||||
from os import path
|
||||
|
||||
@ -32,89 +32,121 @@ def usage(argv, msg=None):
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
print(file=sys.stderr)
|
||||
print("""\
|
||||
|
||||
USAGE = """\
|
||||
Sphinx v%s
|
||||
Usage: %s [options] sourcedir outdir [filenames...]
|
||||
Usage: %%prog [options] sourcedir outdir [filenames...]
|
||||
|
||||
General options
|
||||
^^^^^^^^^^^^^^^
|
||||
-b <builder> builder to use; default is html
|
||||
-a write all files; default is to only write new and changed files
|
||||
-E don't use a saved environment, always read all files
|
||||
-d <path> path for the cached environment and doctree files
|
||||
(default: outdir/.doctrees)
|
||||
-j <N> build in parallel with N processes where possible
|
||||
-M <builder> "make" mode -- used by Makefile, like "sphinx-build -M html"
|
||||
Filename arguments:
|
||||
without -a and without filenames, write new and changed files.
|
||||
with -a, write all files.
|
||||
with filenames, write these.
|
||||
""" % __version__
|
||||
|
||||
Build configuration options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
-c <path> path where configuration file (conf.py) is located
|
||||
(default: same as sourcedir)
|
||||
-C use no config file at all, only -D options
|
||||
-D <setting=value> override a setting in configuration file
|
||||
-t <tag> define tag: include "only" blocks with <tag>
|
||||
-A <name=value> pass a value into the templates, for HTML builder
|
||||
-n nit-picky mode, warn about all missing references
|
||||
EPILOG = """\
|
||||
For more information, visit <http://sphinx-doc.org/>.
|
||||
"""
|
||||
|
||||
Console output options
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
-v increase verbosity (can be repeated)
|
||||
-q no output on stdout, just warnings on stderr
|
||||
-Q no output at all, not even warnings
|
||||
-w <file> write warnings (and errors) to given file
|
||||
-W turn warnings into errors
|
||||
-T show full traceback on exception
|
||||
-N do not emit colored output
|
||||
-P run Pdb on exception
|
||||
|
||||
Filename arguments
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
* without -a and without filenames, write new and changed files.
|
||||
* with -a, write all files.
|
||||
* with filenames, write these.
|
||||
class MyFormatter(optparse.IndentedHelpFormatter):
|
||||
def format_usage(self, usage):
|
||||
return usage
|
||||
|
||||
Standard options
|
||||
^^^^^^^^^^^^^^^^
|
||||
-h, --help show this help and exit
|
||||
--version show version information and exit
|
||||
""" % (__version__, argv[0]), file=sys.stderr)
|
||||
def format_help(self, formatter):
|
||||
result = []
|
||||
if self.description:
|
||||
result.append(self.format_description(formatter))
|
||||
if self.option_list:
|
||||
result.append(self.format_option_help(formatter))
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
def main(argv):
|
||||
if not color_terminal():
|
||||
nocolor()
|
||||
|
||||
parser = optparse.OptionParser(USAGE, epilog=EPILOG, formatter=MyFormatter())
|
||||
parser.add_option('--version', action='store_true', dest='version',
|
||||
help='show version information and exit')
|
||||
|
||||
group = parser.add_option_group('General options')
|
||||
group.add_option('-b', metavar='BUILDER', dest='builder', default='html',
|
||||
help='builder to use; default is html')
|
||||
group.add_option('-a', action='store_true', dest='force_all',
|
||||
help='write all files; default is to only write new and '
|
||||
'changed files')
|
||||
group.add_option('-E', action='store_true', dest='freshenv',
|
||||
help='don\'t use a saved environment, always read '
|
||||
'all files')
|
||||
group.add_option('-d', metavar='PATH', default=None, dest='doctreedir',
|
||||
help='path for the cached environment and doctree files '
|
||||
'(default: outdir/.doctrees)')
|
||||
group.add_option('-j', metavar='N', default=1, type='int', dest='jobs',
|
||||
help='build in parallel with N processes where possible')
|
||||
# this option never gets through to this point (it is intercepted earlier)
|
||||
# group.add_option('-M', metavar='BUILDER', dest='make_mode',
|
||||
# help='"make" mode -- as used by Makefile, like '
|
||||
# '"sphinx-build -M html"')
|
||||
|
||||
group = parser.add_option_group('Build configuration options')
|
||||
group.add_option('-c', metavar='PATH', dest='confdir',
|
||||
help='path where configuration file (conf.py) is located '
|
||||
'(default: same as sourcedir)')
|
||||
group.add_option('-C', action='store_true', dest='noconfig',
|
||||
help='use no config file at all, only -D options')
|
||||
group.add_option('-D', metavar='setting=value', action='append',
|
||||
dest='define', default=[],
|
||||
help='override a setting in configuration file')
|
||||
group.add_option('-A', metavar='name=value', action='append',
|
||||
dest='htmldefine', default=[],
|
||||
help='pass a value into HTML templates')
|
||||
group.add_option('-t', metavar='TAG', action='append',
|
||||
dest='tags', default=[],
|
||||
help='define tag: include "only" blocks with TAG')
|
||||
group.add_option('-n', action='store_true', dest='nitpicky',
|
||||
help='nit-picky mode, warn about all missing references')
|
||||
|
||||
group = parser.add_option_group('Console output options')
|
||||
group.add_option('-v', action='count', dest='verbosity', default=0,
|
||||
help='increase verbosity (can be repeated)')
|
||||
group.add_option('-q', action='store_true', dest='quiet',
|
||||
help='no output on stdout, just warnings on stderr')
|
||||
group.add_option('-Q', action='store_true', dest='really_quiet',
|
||||
help='no output at all, not even warnings')
|
||||
group.add_option('-N', action='store_true', dest='nocolor',
|
||||
help='do not emit colored output')
|
||||
group.add_option('-w', metavar='FILE', dest='warnfile',
|
||||
help='write warnings (and errors) to given file')
|
||||
group.add_option('-W', action='store_true', dest='warningiserror',
|
||||
help='turn warnings into errors')
|
||||
group.add_option('-T', action='store_true', dest='traceback',
|
||||
help='show full traceback on exception')
|
||||
group.add_option('-P', action='store_true', dest='pdb',
|
||||
help='run Pdb on exception')
|
||||
|
||||
# parse options
|
||||
try:
|
||||
opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:nNEqQWw:PThvj:',
|
||||
['help', 'version'])
|
||||
except getopt.error as err:
|
||||
usage(argv, 'Error: %s' % err)
|
||||
return 1
|
||||
opts, args = parser.parse_args(argv[1:])
|
||||
except SystemExit as err:
|
||||
return err.code
|
||||
|
||||
# handle basic options
|
||||
allopts = set(opt[0] for opt in opts)
|
||||
# help and version options
|
||||
if '-h' in allopts or '--help' in allopts:
|
||||
usage(argv)
|
||||
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__)
|
||||
if opts.version:
|
||||
print('Sphinx (sphinx-build) %s' % __version__)
|
||||
return 0
|
||||
|
||||
# get paths (first and second positional argument)
|
||||
try:
|
||||
srcdir = confdir = abspath(args[0])
|
||||
srcdir = abspath(args[0])
|
||||
confdir = abspath(opts.confdir or srcdir)
|
||||
if opts.noconfig:
|
||||
confdir = None
|
||||
if not path.isdir(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('Error: Source directory doesn\'t contain a conf.py file.',
|
||||
if not opts.noconfig and not path.isfile(path.join(confdir, 'conf.py')):
|
||||
print('Error: Config directory doesn\'t contain a conf.py file.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
outdir = abspath(args[1])
|
||||
@ -144,116 +176,77 @@ def main(argv):
|
||||
except Exception:
|
||||
likely_encoding = None
|
||||
|
||||
buildername = None
|
||||
force_all = freshenv = warningiserror = use_pdb = False
|
||||
show_traceback = False
|
||||
verbosity = 0
|
||||
parallel = 0
|
||||
if opts.force_all and filenames:
|
||||
print('Error: Cannot combine -a option and filenames.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if opts.nocolor:
|
||||
nocolor()
|
||||
|
||||
doctreedir = abspath(opts.doctreedir or path.join(outdir, '.doctrees'))
|
||||
|
||||
status = sys.stdout
|
||||
warning = sys.stderr
|
||||
error = sys.stderr
|
||||
warnfile = None
|
||||
|
||||
if opts.quiet:
|
||||
status = None
|
||||
if opts.really_quiet:
|
||||
status = warning = None
|
||||
if warning and opts.warnfile:
|
||||
try:
|
||||
warnfp = open(opts.warnfile, 'w')
|
||||
except Exception as exc:
|
||||
print('Error: Cannot open warning file %r: %s' %
|
||||
(opts.warnfile, exc), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
warning = Tee(warning, warnfp)
|
||||
error = warning
|
||||
|
||||
confoverrides = {}
|
||||
tags = []
|
||||
doctreedir = path.join(outdir, '.doctrees')
|
||||
for opt, val in opts:
|
||||
if opt == '-b':
|
||||
buildername = val
|
||||
elif opt == '-a':
|
||||
if filenames:
|
||||
usage(argv, 'Error: Cannot combine -a option and filenames.')
|
||||
return 1
|
||||
force_all = True
|
||||
elif opt == '-t':
|
||||
tags.append(val)
|
||||
elif opt == '-d':
|
||||
doctreedir = abspath(val)
|
||||
elif opt == '-c':
|
||||
confdir = abspath(val)
|
||||
if not path.isfile(path.join(confdir, 'conf.py')):
|
||||
print('Error: Configuration directory doesn\'t contain conf.py file.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
elif opt == '-C':
|
||||
confdir = None
|
||||
elif opt == '-D':
|
||||
for val in opts.define:
|
||||
try:
|
||||
key, val = val.split('=')
|
||||
except ValueError:
|
||||
print('Error: -D option argument must be in the form name=value.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
if likely_encoding and isinstance(val, binary_type):
|
||||
try:
|
||||
key, val = val.split('=')
|
||||
except ValueError:
|
||||
print('Error: -D option argument must be in the form name=value.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
val = val.decode(likely_encoding)
|
||||
except UnicodeError:
|
||||
pass
|
||||
confoverrides[key] = val
|
||||
|
||||
for val in opts.htmldefine:
|
||||
try:
|
||||
key, val = val.split('=')
|
||||
except ValueError:
|
||||
print('Error: -A 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, binary_type):
|
||||
try:
|
||||
val = val.decode(likely_encoding)
|
||||
except UnicodeError:
|
||||
pass
|
||||
confoverrides[key] = val
|
||||
elif opt == '-A':
|
||||
try:
|
||||
key, val = val.split('=')
|
||||
except ValueError:
|
||||
print('Error: -A 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, binary_type):
|
||||
try:
|
||||
val = val.decode(likely_encoding)
|
||||
except UnicodeError:
|
||||
pass
|
||||
confoverrides['html_context.%s' % key] = val
|
||||
elif opt == '-n':
|
||||
confoverrides['nitpicky'] = True
|
||||
elif opt == '-N':
|
||||
nocolor()
|
||||
elif opt == '-E':
|
||||
freshenv = True
|
||||
elif opt == '-q':
|
||||
status = None
|
||||
elif opt == '-Q':
|
||||
status = None
|
||||
warning = None
|
||||
elif opt == '-W':
|
||||
warningiserror = True
|
||||
elif opt == '-w':
|
||||
warnfile = val
|
||||
elif opt == '-P':
|
||||
use_pdb = True
|
||||
elif opt == '-T':
|
||||
show_traceback = True
|
||||
elif opt == '-v':
|
||||
verbosity += 1
|
||||
show_traceback = True
|
||||
elif opt == '-j':
|
||||
try:
|
||||
parallel = int(val)
|
||||
except ValueError:
|
||||
print('Error: -j option argument must be an integer.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
confoverrides['html_context.%s' % key] = val
|
||||
|
||||
if warning and warnfile:
|
||||
warnfp = open(warnfile, 'w')
|
||||
warning = Tee(warning, warnfp)
|
||||
error = warning
|
||||
|
||||
if not path.isdir(outdir):
|
||||
if status:
|
||||
print('Making output directory...', file=status)
|
||||
os.makedirs(outdir)
|
||||
if opts.nitpicky:
|
||||
confoverrides['nitpicky'] = True
|
||||
|
||||
app = None
|
||||
try:
|
||||
app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername,
|
||||
confoverrides, status, warning, freshenv,
|
||||
warningiserror, tags, verbosity, parallel)
|
||||
app.build(force_all, filenames)
|
||||
app = Sphinx(srcdir, confdir, outdir, doctreedir, opts.builder,
|
||||
confoverrides, status, warning, opts.freshenv,
|
||||
opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
|
||||
app.build(opts.force_all, filenames)
|
||||
return app.statuscode
|
||||
except (Exception, KeyboardInterrupt) as err:
|
||||
if use_pdb:
|
||||
if opts.pdb:
|
||||
import pdb
|
||||
print(red('Exception occurred while building, starting debugger:'),
|
||||
file=error)
|
||||
@ -261,7 +254,7 @@ def main(argv):
|
||||
pdb.post_mortem(sys.exc_info()[2])
|
||||
else:
|
||||
print(file=error)
|
||||
if show_traceback:
|
||||
if opts.verbosity or opts.traceback:
|
||||
traceback.print_exc(None, error)
|
||||
print(file=error)
|
||||
if isinstance(err, KeyboardInterrupt):
|
||||
@ -290,6 +283,6 @@ def main(argv):
|
||||
'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!',
|
||||
'<https://github.com/sphinx-doc/sphinx/issues>. Thanks!',
|
||||
file=error)
|
||||
return 1
|
||||
|
@ -5,11 +5,10 @@
|
||||
|
||||
Build configuration file handling.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
from os import path
|
||||
|
||||
@ -17,7 +16,7 @@ from six import PY3, iteritems, string_types, binary_type, integer_types
|
||||
|
||||
from sphinx.errors import ConfigError
|
||||
from sphinx.locale import l_
|
||||
from sphinx.util.osutil import make_filename
|
||||
from sphinx.util.osutil import make_filename, cd
|
||||
from sphinx.util.pycompat import execfile_
|
||||
|
||||
nonascii_re = re.compile(br'[\x80-\xff]')
|
||||
@ -25,6 +24,9 @@ nonascii_re = re.compile(br'[\x80-\xff]')
|
||||
CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s"
|
||||
if PY3:
|
||||
CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?"
|
||||
CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \
|
||||
"called sys.exit()"
|
||||
|
||||
|
||||
class Config(object):
|
||||
"""
|
||||
@ -59,6 +61,7 @@ class Config(object):
|
||||
show_authors = (False, 'env'),
|
||||
pygments_style = (None, 'html'),
|
||||
highlight_language = ('python', 'env'),
|
||||
highlight_options = ({}, 'env'),
|
||||
templates_path = ([], 'html'),
|
||||
template_bridge = (None, 'html'),
|
||||
keep_warnings = (False, 'env'),
|
||||
@ -71,6 +74,12 @@ class Config(object):
|
||||
needs_extensions = ({}, None),
|
||||
nitpicky = (False, 'env'),
|
||||
nitpick_ignore = ([], 'html'),
|
||||
numfig = (False, 'env'),
|
||||
numfig_secnum_depth = (1, 'env'),
|
||||
numfig_format = ({'figure': l_('Fig. %s'),
|
||||
'table': l_('Table %s'),
|
||||
'code-block': l_('Listing %s')},
|
||||
'env'),
|
||||
|
||||
# HTML options
|
||||
html_theme = ('default', 'html'),
|
||||
@ -204,8 +213,9 @@ class Config(object):
|
||||
# gettext options
|
||||
gettext_compact = (True, 'gettext'),
|
||||
gettext_location = (True, 'gettext'),
|
||||
gettext_uuid = (True, 'gettext'),
|
||||
gettext_uuid = (False, 'gettext'),
|
||||
gettext_auto_build = (True, 'env'),
|
||||
gettext_enables = ([], 'env'),
|
||||
|
||||
# XML options
|
||||
xml_pretty = (True, 'env'),
|
||||
@ -215,7 +225,7 @@ class Config(object):
|
||||
self.overrides = overrides
|
||||
self.values = Config.config_values.copy()
|
||||
config = {}
|
||||
if 'extensions' in overrides:
|
||||
if 'extensions' in overrides: #XXX do we need this?
|
||||
if isinstance(overrides['extensions'], string_types):
|
||||
config['extensions'] = overrides.pop('extensions').split(',')
|
||||
else:
|
||||
@ -224,17 +234,15 @@ class Config(object):
|
||||
config_file = path.join(dirname, filename)
|
||||
config['__file__'] = config_file
|
||||
config['tags'] = tags
|
||||
olddir = os.getcwd()
|
||||
try:
|
||||
with cd(dirname):
|
||||
# we promise to have the config dir as current dir while the
|
||||
# config file is executed
|
||||
os.chdir(dirname)
|
||||
try:
|
||||
execfile_(filename, config)
|
||||
except SyntaxError as err:
|
||||
raise ConfigError(CONFIG_SYNTAX_ERROR % err)
|
||||
finally:
|
||||
os.chdir(olddir)
|
||||
except SystemExit:
|
||||
raise ConfigError(CONFIG_EXIT_ERROR)
|
||||
|
||||
self._raw_config = config
|
||||
# these two must be preinitialized because extensions can add their
|
||||
@ -242,6 +250,30 @@ class Config(object):
|
||||
self.setup = config.get('setup', None)
|
||||
self.extensions = config.get('extensions', [])
|
||||
|
||||
def check_types(self, warn):
|
||||
# check all values for deviation from the default value's type, since
|
||||
# that can result in TypeErrors all over the place
|
||||
# NB. since config values might use l_() we have to wait with calling
|
||||
# this method until i18n is initialized
|
||||
for name in self._raw_config:
|
||||
if name not in Config.config_values:
|
||||
continue # we don't know a default value
|
||||
default, dummy_rebuild = Config.config_values[name]
|
||||
if hasattr(default, '__call__'):
|
||||
default = default(self) # could invoke l_()
|
||||
if default is None:
|
||||
continue
|
||||
current = self[name]
|
||||
if type(current) is type(default):
|
||||
continue
|
||||
common_bases = (set(type(current).__bases__ + (type(current),))
|
||||
& set(type(default).__bases__))
|
||||
common_bases.discard(object)
|
||||
if common_bases:
|
||||
continue # at least we share a non-trivial base class
|
||||
warn("the config value %r has type `%s', defaults to `%s.'"
|
||||
% (name, type(current).__name__, type(default).__name__))
|
||||
|
||||
def check_unicode(self, warn):
|
||||
# check all string values for non-ASCII characters in bytestrings,
|
||||
# since that can result in UnicodeErrors all over the place
|
||||
@ -277,9 +309,11 @@ class Config(object):
|
||||
except ValueError:
|
||||
warn('invalid number %r for config value %r, ignoring'
|
||||
% (value, valname))
|
||||
elif hasattr(defvalue, '__call__'):
|
||||
config[valname] = value
|
||||
elif defvalue is not None and not isinstance(defvalue, string_types):
|
||||
warn('cannot override config setting %r with unsupported type, '
|
||||
'ignoring' % valname)
|
||||
warn('cannot override config setting %r with unsupported '
|
||||
'type, ignoring' % valname)
|
||||
else:
|
||||
config[valname] = value
|
||||
else:
|
||||
@ -287,7 +321,6 @@ class Config(object):
|
||||
for name in config:
|
||||
if name in self.values:
|
||||
self.__dict__[name] = config[name]
|
||||
del self._raw_config
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('_'):
|
||||
|
@ -5,13 +5,14 @@
|
||||
|
||||
Handlers for additional ReST directives.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives, roles
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.docfields import DocFieldTransformer
|
||||
@ -162,6 +163,34 @@ class ObjectDescription(Directive):
|
||||
DescDirective = ObjectDescription
|
||||
|
||||
|
||||
class DefaultRole(Directive):
|
||||
"""
|
||||
Set the default interpreted text role. Overridden from docutils.
|
||||
"""
|
||||
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = False
|
||||
|
||||
def run(self):
|
||||
if not self.arguments:
|
||||
if '' in roles._roles:
|
||||
# restore the "default" default role
|
||||
del roles._roles['']
|
||||
return []
|
||||
role_name = self.arguments[0]
|
||||
role, messages = roles.role(role_name, self.state_machine.language,
|
||||
self.lineno, self.state.reporter)
|
||||
if role is None:
|
||||
error = self.state.reporter.error(
|
||||
'Unknown interpreted text role "%s".' % role_name,
|
||||
nodes.literal_block(self.block_text, self.block_text),
|
||||
line=self.lineno)
|
||||
return messages + [error]
|
||||
roles._roles[''] = role
|
||||
self.state.document.settings.env.temp_data['default_role'] = role_name
|
||||
return messages
|
||||
|
||||
|
||||
class DefaultDomain(Directive):
|
||||
"""
|
||||
Directive to (re-)set the default domain for this source file.
|
||||
@ -186,6 +215,7 @@ class DefaultDomain(Directive):
|
||||
return []
|
||||
|
||||
|
||||
directives.register_directive('default-role', DefaultRole)
|
||||
directives.register_directive('default-domain', DefaultDomain)
|
||||
directives.register_directive('describe', ObjectDescription)
|
||||
# new, more consistent, name
|
||||
|
@ -3,7 +3,7 @@
|
||||
sphinx.directives.code
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -13,6 +13,7 @@ from difflib import unified_diff
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
from docutils.statemachine import ViewList
|
||||
|
||||
from six import string_types
|
||||
|
||||
@ -47,7 +48,6 @@ class Highlight(Directive):
|
||||
linenothreshold=linenothreshold)]
|
||||
|
||||
|
||||
|
||||
def dedent_lines(lines, dedent):
|
||||
if not dedent:
|
||||
return lines
|
||||
@ -62,6 +62,20 @@ def dedent_lines(lines, dedent):
|
||||
return new_lines
|
||||
|
||||
|
||||
def container_wrapper(directive, literal_node, caption):
|
||||
container_node = nodes.container('', literal_block=True)
|
||||
parsed = nodes.Element()
|
||||
directive.state.nested_parse(ViewList([caption], source=''),
|
||||
directive.content_offset, parsed)
|
||||
caption_node = nodes.caption(parsed[0].rawsource, '',
|
||||
*parsed[0].children)
|
||||
caption_node.source = parsed[0].source
|
||||
caption_node.line = parsed[0].line
|
||||
container_node += caption_node
|
||||
container_node += literal_node
|
||||
return container_node
|
||||
|
||||
|
||||
class CodeBlock(Directive):
|
||||
"""
|
||||
Directive for a code block with special highlighting or line numbering
|
||||
@ -93,7 +107,7 @@ class CodeBlock(Directive):
|
||||
return [document.reporter.warning(str(err), line=self.lineno)]
|
||||
else:
|
||||
hl_lines = None
|
||||
|
||||
|
||||
if 'dedent' in self.options:
|
||||
lines = code.split('\n')
|
||||
lines = dedent_lines(lines, self.options['dedent'])
|
||||
@ -101,9 +115,6 @@ class CodeBlock(Directive):
|
||||
|
||||
literal = nodes.literal_block(code, code)
|
||||
literal['language'] = self.arguments[0]
|
||||
caption = self.options.get('caption')
|
||||
if caption:
|
||||
literal['caption'] = caption
|
||||
literal['linenos'] = 'linenos' in self.options or \
|
||||
'lineno-start' in self.options
|
||||
extra_args = literal['highlight_args'] = {}
|
||||
@ -112,6 +123,11 @@ class CodeBlock(Directive):
|
||||
if 'lineno-start' in self.options:
|
||||
extra_args['linenostart'] = self.options['lineno-start']
|
||||
set_source_info(self, literal)
|
||||
|
||||
caption = self.options.get('caption')
|
||||
if caption:
|
||||
literal = container_wrapper(self, literal, caption)
|
||||
|
||||
return [literal]
|
||||
|
||||
|
||||
@ -130,6 +146,7 @@ class LiteralInclude(Directive):
|
||||
'dedent': int,
|
||||
'linenos': directives.flag,
|
||||
'lineno-start': int,
|
||||
'lineno-match': directives.flag,
|
||||
'tab-width': int,
|
||||
'language': directives.unchanged_required,
|
||||
'encoding': directives.encoding,
|
||||
@ -147,8 +164,8 @@ class LiteralInclude(Directive):
|
||||
def read_with_encoding(self, filename, document, codec_info, encoding):
|
||||
f = None
|
||||
try:
|
||||
f = codecs.StreamReaderWriter(open(filename, 'rb'),
|
||||
codec_info[2], codec_info[3], 'strict')
|
||||
f = codecs.StreamReaderWriter(open(filename, 'rb'), codec_info[2],
|
||||
codec_info[3], 'strict')
|
||||
lines = f.readlines()
|
||||
lines = dedent_lines(lines, self.options.get('dedent'))
|
||||
return lines
|
||||
@ -178,6 +195,17 @@ class LiteralInclude(Directive):
|
||||
'Cannot use both "pyobject" and "lines" options',
|
||||
line=self.lineno)]
|
||||
|
||||
if 'lineno-match' in self.options and 'lineno-start' in self.options:
|
||||
return [document.reporter.warning(
|
||||
'Cannot use both "lineno-match" and "lineno-start"',
|
||||
line=self.lineno)]
|
||||
|
||||
if 'lineno-match' in self.options and \
|
||||
(set(['append', 'prepend']) & set(self.options.keys())):
|
||||
return [document.reporter.warning(
|
||||
'Cannot use "lineno-match" and "append" or "prepend"',
|
||||
line=self.lineno)]
|
||||
|
||||
encoding = self.options.get('encoding', env.config.source_encoding)
|
||||
codec_info = codecs.lookup(encoding)
|
||||
|
||||
@ -191,7 +219,7 @@ class LiteralInclude(Directive):
|
||||
tmp, fulldiffsource = env.relfn2path(diffsource)
|
||||
|
||||
difflines = self.read_with_encoding(fulldiffsource, document,
|
||||
codec_info, encoding)
|
||||
codec_info, encoding)
|
||||
if not isinstance(difflines[0], string_types):
|
||||
return difflines
|
||||
diff = unified_diff(
|
||||
@ -201,6 +229,7 @@ class LiteralInclude(Directive):
|
||||
self.arguments[0])
|
||||
lines = list(diff)
|
||||
|
||||
linenostart = self.options.get('lineno-start', 1)
|
||||
objectname = self.options.get('pyobject')
|
||||
if objectname is not None:
|
||||
from sphinx.pycode import ModuleAnalyzer
|
||||
@ -211,17 +240,30 @@ class LiteralInclude(Directive):
|
||||
'Object named %r not found in include file %r' %
|
||||
(objectname, filename), line=self.lineno)]
|
||||
else:
|
||||
lines = lines[tags[objectname][1]-1 : tags[objectname][2]-1]
|
||||
lines = lines[tags[objectname][1]-1: tags[objectname][2]-1]
|
||||
if 'lineno-match' in self.options:
|
||||
linenostart = tags[objectname][1]
|
||||
|
||||
linespec = self.options.get('lines')
|
||||
if linespec is not None:
|
||||
if linespec:
|
||||
try:
|
||||
linelist = parselinenos(linespec, len(lines))
|
||||
except ValueError as err:
|
||||
return [document.reporter.warning(str(err), line=self.lineno)]
|
||||
# just ignore nonexisting lines
|
||||
nlines = len(lines)
|
||||
lines = [lines[i] for i in linelist if i < nlines]
|
||||
|
||||
if 'lineno-match' in self.options:
|
||||
# make sure the line list is not "disjoint".
|
||||
previous = linelist[0]
|
||||
for line_number in linelist[1:]:
|
||||
if line_number == previous + 1:
|
||||
previous = line_number
|
||||
continue
|
||||
return [document.reporter.warning(
|
||||
'Cannot use "lineno-match" with a disjoint set of '
|
||||
'"lines"', line=self.lineno)]
|
||||
linenostart = linelist[0] + 1
|
||||
# just ignore non-existing lines
|
||||
lines = [lines[i] for i in linelist if i < len(lines)]
|
||||
if not lines:
|
||||
return [document.reporter.warning(
|
||||
'Line spec %r: no lines pulled from include file %r' %
|
||||
@ -237,54 +279,68 @@ class LiteralInclude(Directive):
|
||||
hl_lines = None
|
||||
|
||||
startafter = self.options.get('start-after')
|
||||
endbefore = self.options.get('end-before')
|
||||
prepend = self.options.get('prepend')
|
||||
append = self.options.get('append')
|
||||
endbefore = self.options.get('end-before')
|
||||
if startafter is not None or endbefore is not None:
|
||||
use = not startafter
|
||||
res = []
|
||||
for line in lines:
|
||||
for line_number, line in enumerate(lines):
|
||||
if not use and startafter and startafter in line:
|
||||
if 'lineno-match' in self.options:
|
||||
linenostart += line_number + 1
|
||||
use = True
|
||||
elif use and endbefore and endbefore in line:
|
||||
use = False
|
||||
break
|
||||
elif use:
|
||||
res.append(line)
|
||||
lines = res
|
||||
|
||||
if 'lineno-match' in self.options:
|
||||
# handle that docutils remove preceding lines which only contains
|
||||
# line separation.
|
||||
for line in lines:
|
||||
# check if line contains anything else than line separation.
|
||||
if line and line.splitlines()[0]:
|
||||
break
|
||||
linenostart += 1
|
||||
|
||||
prepend = self.options.get('prepend')
|
||||
if prepend:
|
||||
lines.insert(0, prepend + '\n')
|
||||
lines.insert(0, prepend + '\n')
|
||||
|
||||
append = self.options.get('append')
|
||||
if append:
|
||||
lines.append(append + '\n')
|
||||
lines.append(append + '\n')
|
||||
|
||||
text = ''.join(lines)
|
||||
if self.options.get('tab-width'):
|
||||
text = text.expandtabs(self.options['tab-width'])
|
||||
retnode = nodes.literal_block(text, text, source=filename)
|
||||
set_source_info(self, retnode)
|
||||
if diffsource is not None: # if diff is set, set udiff
|
||||
if diffsource: # if diff is set, set udiff
|
||||
retnode['language'] = 'udiff'
|
||||
if self.options.get('language', ''):
|
||||
if 'language' in self.options:
|
||||
retnode['language'] = self.options['language']
|
||||
retnode['linenos'] = 'linenos' in self.options or \
|
||||
'lineno-start' in self.options
|
||||
caption = self.options.get('caption')
|
||||
if caption is not None:
|
||||
if not caption:
|
||||
caption = self.arguments[0]
|
||||
retnode['caption'] = caption
|
||||
'lineno-start' in self.options or \
|
||||
'lineno-match' in self.options
|
||||
extra_args = retnode['highlight_args'] = {}
|
||||
if hl_lines is not None:
|
||||
extra_args['hl_lines'] = hl_lines
|
||||
if 'lineno-start' in self.options:
|
||||
extra_args['linenostart'] = self.options['lineno-start']
|
||||
extra_args['linenostart'] = linenostart
|
||||
env.note_dependency(rel_filename)
|
||||
|
||||
caption = self.options.get('caption')
|
||||
if caption is not None:
|
||||
if caption:
|
||||
retnode = container_wrapper(self, retnode, caption)
|
||||
else:
|
||||
retnode = container_wrapper(self, retnode, self.arguments[0])
|
||||
|
||||
return [retnode]
|
||||
|
||||
|
||||
directives.register_directive('highlight', Highlight)
|
||||
directives.register_directive('highlightlang', Highlight) # old
|
||||
directives.register_directive('highlightlang', Highlight) # old
|
||||
directives.register_directive('code-block', CodeBlock)
|
||||
directives.register_directive('sourcecode', CodeBlock)
|
||||
directives.register_directive('literalinclude', LiteralInclude)
|
||||
|
@ -3,7 +3,7 @@
|
||||
sphinx.directives.other
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -62,7 +62,18 @@ class TocTree(Directive):
|
||||
for entry in self.content:
|
||||
if not entry:
|
||||
continue
|
||||
if not glob:
|
||||
if glob and ('*' in entry or '?' in entry or '[' in entry):
|
||||
patname = docname_join(env.docname, entry)
|
||||
docnames = sorted(patfilter(all_docnames, patname))
|
||||
for docname in docnames:
|
||||
all_docnames.remove(docname) # don't include it again
|
||||
entries.append((None, docname))
|
||||
includefiles.append(docname)
|
||||
if not docnames:
|
||||
ret.append(self.state.document.reporter.warning(
|
||||
'toctree glob pattern %r didn\'t match any documents'
|
||||
% entry, line=self.lineno))
|
||||
else:
|
||||
# look for explicit titles ("Some Title <document>")
|
||||
m = explicit_title_re.match(entry)
|
||||
if m:
|
||||
@ -85,19 +96,9 @@ class TocTree(Directive):
|
||||
'document %r' % docname, line=self.lineno))
|
||||
env.note_reread()
|
||||
else:
|
||||
all_docnames.discard(docname)
|
||||
entries.append((title, docname))
|
||||
includefiles.append(docname)
|
||||
else:
|
||||
patname = docname_join(env.docname, entry)
|
||||
docnames = sorted(patfilter(all_docnames, patname))
|
||||
for docname in docnames:
|
||||
all_docnames.remove(docname) # don't include it again
|
||||
entries.append((None, docname))
|
||||
includefiles.append(docname)
|
||||
if not docnames:
|
||||
ret.append(self.state.document.reporter.warning(
|
||||
'toctree glob pattern %r didn\'t match any documents'
|
||||
% entry, line=self.lineno))
|
||||
subnode = addnodes.toctree()
|
||||
subnode['parent'] = env.docname
|
||||
# entries contains all entries (self references, external links etc.)
|
||||
|
@ -6,7 +6,7 @@
|
||||
Support for domains, which are groupings of description directives
|
||||
and roles describing e.g. constructs of one programming language.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -155,10 +155,13 @@ class Domain(object):
|
||||
self._role_cache = {}
|
||||
self._directive_cache = {}
|
||||
self._role2type = {}
|
||||
self._type2role = {}
|
||||
for name, obj in iteritems(self.object_types):
|
||||
for rolename in obj.roles:
|
||||
self._role2type.setdefault(rolename, []).append(name)
|
||||
self._type2role[name] = obj.roles[0] if obj.roles else ''
|
||||
self.objtypes_for_role = self._role2type.get
|
||||
self.role_for_objtype = self._type2role.get
|
||||
|
||||
def role(self, name):
|
||||
"""Return a role adapter function that always gives the registered
|
||||
@ -199,6 +202,14 @@ class Domain(object):
|
||||
"""Remove traces of a document in the domain-specific inventories."""
|
||||
pass
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
"""Merge in data regarding *docnames* from a different domaindata
|
||||
inventory (coming from a subprocess in parallel builds).
|
||||
"""
|
||||
raise NotImplementedError('merge_domaindata must be implemented in %s '
|
||||
'to be able to do parallel builds!' %
|
||||
self.__class__)
|
||||
|
||||
def process_doc(self, env, docname, document):
|
||||
"""Process a document after it is read by the environment."""
|
||||
pass
|
||||
@ -220,6 +231,22 @@ class Domain(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
|
||||
"""Resolve the pending_xref *node* with the given *target*.
|
||||
|
||||
The reference comes from an "any" or similar role, which means that we
|
||||
don't know the type. Otherwise, the arguments are the same as for
|
||||
:meth:`resolve_xref`.
|
||||
|
||||
The method must return a list (potentially empty) of tuples
|
||||
``('domain:role', newnode)``, where ``'domain:role'`` is the name of a
|
||||
role that could have created the same reference, e.g. ``'py:func'``.
|
||||
``newnode`` is what :meth:`resolve_xref` would return.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_objects(self):
|
||||
"""Return an iterable of "object descriptions", which are tuples with
|
||||
five items:
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The C language domain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -130,7 +130,7 @@ class CObject(ObjectDescription):
|
||||
if m:
|
||||
name = m.group(1)
|
||||
|
||||
typename = self.env.temp_data.get('c:type')
|
||||
typename = self.env.ref_context.get('c:type')
|
||||
if self.name == 'c:member' and typename:
|
||||
fullname = typename + '.' + name
|
||||
else:
|
||||
@ -212,12 +212,12 @@ class CObject(ObjectDescription):
|
||||
self.typename_set = False
|
||||
if self.name == 'c:type':
|
||||
if self.names:
|
||||
self.env.temp_data['c:type'] = self.names[0]
|
||||
self.env.ref_context['c:type'] = self.names[0]
|
||||
self.typename_set = True
|
||||
|
||||
def after_content(self):
|
||||
if self.typename_set:
|
||||
self.env.temp_data['c:type'] = None
|
||||
self.env.ref_context.pop('c:type', None)
|
||||
|
||||
|
||||
class CXRefRole(XRefRole):
|
||||
@ -269,6 +269,12 @@ class CDomain(Domain):
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# XXX check duplicates
|
||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
self.data['objects'][fullname] = (fn, objtype)
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
# strip pointer asterisk
|
||||
@ -279,6 +285,17 @@ class CDomain(Domain):
|
||||
return make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
||||
contnode, target)
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target,
|
||||
node, contnode):
|
||||
# strip pointer asterisk
|
||||
target = target.rstrip(' *')
|
||||
if target not in self.data['objects']:
|
||||
return []
|
||||
obj = self.data['objects'][target]
|
||||
return [('c:' + self.role_for_objtype(obj[1]),
|
||||
make_refnode(builder, fromdocname, obj[0], 'c.' + target,
|
||||
contnode, target))]
|
||||
|
||||
def get_objects(self):
|
||||
for refname, (docname, type) in list(self.data['objects'].items()):
|
||||
yield (refname, refname, type, docname, 'c.' + refname, 1)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
|
||||
The JavaScript domain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -45,7 +45,7 @@ class JSObject(ObjectDescription):
|
||||
nameprefix = None
|
||||
name = prefix
|
||||
|
||||
objectname = self.env.temp_data.get('js:object')
|
||||
objectname = self.env.ref_context.get('js:object')
|
||||
if nameprefix:
|
||||
if objectname:
|
||||
# someone documenting the method of an attribute of the current
|
||||
@ -77,7 +77,7 @@ class JSObject(ObjectDescription):
|
||||
|
||||
def add_target_and_index(self, name_obj, sig, signode):
|
||||
objectname = self.options.get(
|
||||
'object', self.env.temp_data.get('js:object'))
|
||||
'object', self.env.ref_context.get('js:object'))
|
||||
fullname = name_obj[0]
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
@ -140,7 +140,7 @@ class JSConstructor(JSCallable):
|
||||
class JSXRefRole(XRefRole):
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
# basically what sphinx.domains.python.PyXRefRole does
|
||||
refnode['js:object'] = env.temp_data.get('js:object')
|
||||
refnode['js:object'] = env.ref_context.get('js:object')
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.')
|
||||
target = target.lstrip('~')
|
||||
@ -179,7 +179,7 @@ class JavaScriptDomain(Domain):
|
||||
'attr': JSXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
}
|
||||
|
||||
def clear_doc(self, docname):
|
||||
@ -187,6 +187,12 @@ class JavaScriptDomain(Domain):
|
||||
if fn == docname:
|
||||
del self.data['objects'][fullname]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# XXX check duplicates
|
||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
self.data['objects'][fullname] = (fn, objtype)
|
||||
|
||||
def find_obj(self, env, obj, name, typ, searchorder=0):
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
@ -214,6 +220,16 @@ class JavaScriptDomain(Domain):
|
||||
return make_refnode(builder, fromdocname, obj[0],
|
||||
name.replace('$', '_S_'), contnode, name)
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target, node,
|
||||
contnode):
|
||||
objectname = node.get('js:object')
|
||||
name, obj = self.find_obj(env, objectname, target, None, 1)
|
||||
if not obj:
|
||||
return []
|
||||
return [('js:' + self.role_for_objtype(obj[1]),
|
||||
make_refnode(builder, fromdocname, obj[0],
|
||||
name.replace('$', '_S_'), contnode, name))]
|
||||
|
||||
def get_objects(self):
|
||||
for refname, (docname, type) in list(self.data['objects'].items()):
|
||||
yield refname, refname, type, docname, \
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Python domain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -84,13 +84,14 @@ def _pseudo_parse_arglist(signode, arglist):
|
||||
|
||||
# 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)
|
||||
class PyXrefMixin(object):
|
||||
def make_xref(self, rolename, domain, target, innernode=nodes.emphasis,
|
||||
contnode=None):
|
||||
result = super(PyXrefMixin, self).make_xref(rolename, domain, target,
|
||||
innernode, contnode)
|
||||
result['refspecific'] = True
|
||||
if target.startswith('.'):
|
||||
result['reftarget'] = target[1:]
|
||||
result['refspecific'] = True
|
||||
result[0][0] = nodes.Text(target[1:])
|
||||
if target.startswith('~'):
|
||||
result['reftarget'] = target[1:]
|
||||
@ -99,6 +100,14 @@ class PyTypedField(TypedField):
|
||||
return result
|
||||
|
||||
|
||||
class PyField(PyXrefMixin, Field):
|
||||
pass
|
||||
|
||||
|
||||
class PyTypedField(PyXrefMixin, TypedField):
|
||||
pass
|
||||
|
||||
|
||||
class PyObject(ObjectDescription):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
@ -111,21 +120,21 @@ class PyObject(ObjectDescription):
|
||||
|
||||
doc_field_types = [
|
||||
PyTypedField('parameter', label=l_('Parameters'),
|
||||
names=('param', 'parameter', 'arg', 'argument',
|
||||
'keyword', 'kwarg', 'kwparam'),
|
||||
typerolename='obj', typenames=('paramtype', 'type'),
|
||||
can_collapse=True),
|
||||
TypedField('variable', label=l_('Variables'), rolename='obj',
|
||||
names=('var', 'ivar', 'cvar'),
|
||||
typerolename='obj', typenames=('vartype',),
|
||||
can_collapse=True),
|
||||
names=('param', 'parameter', 'arg', 'argument',
|
||||
'keyword', 'kwarg', 'kwparam'),
|
||||
typerolename='obj', typenames=('paramtype', 'type'),
|
||||
can_collapse=True),
|
||||
PyTypedField('variable', label=l_('Variables'), rolename='obj',
|
||||
names=('var', 'ivar', 'cvar'),
|
||||
typerolename='obj', typenames=('vartype',),
|
||||
can_collapse=True),
|
||||
GroupedField('exceptions', label=l_('Raises'), rolename='exc',
|
||||
names=('raises', 'raise', 'exception', 'except'),
|
||||
can_collapse=True),
|
||||
Field('returnvalue', label=l_('Returns'), has_arg=False,
|
||||
names=('returns', 'return')),
|
||||
Field('returntype', label=l_('Return type'), has_arg=False,
|
||||
names=('rtype',)),
|
||||
PyField('returntype', label=l_('Return type'), has_arg=False,
|
||||
names=('rtype',), bodyrolename='obj'),
|
||||
]
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
@ -156,8 +165,8 @@ class PyObject(ObjectDescription):
|
||||
|
||||
# determine module and class name (if applicable), as well as full name
|
||||
modname = self.options.get(
|
||||
'module', self.env.temp_data.get('py:module'))
|
||||
classname = self.env.temp_data.get('py:class')
|
||||
'module', self.env.ref_context.get('py:module'))
|
||||
classname = self.env.ref_context.get('py:class')
|
||||
if classname:
|
||||
add_module = False
|
||||
if name_prefix and name_prefix.startswith(classname):
|
||||
@ -194,7 +203,7 @@ class PyObject(ObjectDescription):
|
||||
# 'exceptions' module.
|
||||
elif add_module and self.env.config.add_module_names:
|
||||
modname = self.options.get(
|
||||
'module', self.env.temp_data.get('py:module'))
|
||||
'module', self.env.ref_context.get('py:module'))
|
||||
if modname and modname != 'exceptions':
|
||||
nodetext = modname + '.'
|
||||
signode += addnodes.desc_addname(nodetext, nodetext)
|
||||
@ -225,7 +234,7 @@ class PyObject(ObjectDescription):
|
||||
|
||||
def add_target_and_index(self, name_cls, sig, signode):
|
||||
modname = self.options.get(
|
||||
'module', self.env.temp_data.get('py:module'))
|
||||
'module', self.env.ref_context.get('py:module'))
|
||||
fullname = (modname and modname + '.' or '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
@ -254,7 +263,7 @@ class PyObject(ObjectDescription):
|
||||
|
||||
def after_content(self):
|
||||
if self.clsname_set:
|
||||
self.env.temp_data['py:class'] = None
|
||||
self.env.ref_context.pop('py:class', None)
|
||||
|
||||
|
||||
class PyModulelevel(PyObject):
|
||||
@ -299,7 +308,7 @@ class PyClasslike(PyObject):
|
||||
def before_content(self):
|
||||
PyObject.before_content(self)
|
||||
if self.names:
|
||||
self.env.temp_data['py:class'] = self.names[0][0]
|
||||
self.env.ref_context['py:class'] = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
@ -377,8 +386,8 @@ class PyClassmember(PyObject):
|
||||
def before_content(self):
|
||||
PyObject.before_content(self)
|
||||
lastname = self.names and self.names[-1][1]
|
||||
if lastname and not self.env.temp_data.get('py:class'):
|
||||
self.env.temp_data['py:class'] = lastname.strip('.')
|
||||
if lastname and not self.env.ref_context.get('py:class'):
|
||||
self.env.ref_context['py:class'] = lastname.strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
@ -434,7 +443,7 @@ class PyModule(Directive):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
env.temp_data['py:module'] = modname
|
||||
env.ref_context['py:module'] = modname
|
||||
ret = []
|
||||
if not noindex:
|
||||
env.domaindata['py']['modules'][modname] = \
|
||||
@ -472,16 +481,16 @@ class PyCurrentModule(Directive):
|
||||
env = self.state.document.settings.env
|
||||
modname = self.arguments[0].strip()
|
||||
if modname == 'None':
|
||||
env.temp_data['py:module'] = None
|
||||
env.ref_context.pop('py:module', None)
|
||||
else:
|
||||
env.temp_data['py:module'] = modname
|
||||
env.ref_context['py:module'] = modname
|
||||
return []
|
||||
|
||||
|
||||
class PyXRefRole(XRefRole):
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
refnode['py:module'] = env.temp_data.get('py:module')
|
||||
refnode['py:class'] = env.temp_data.get('py:class')
|
||||
refnode['py:module'] = env.ref_context.get('py:module')
|
||||
refnode['py:class'] = env.ref_context.get('py:class')
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.') # only has a meaning for the target
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
@ -627,6 +636,15 @@ class PythonDomain(Domain):
|
||||
if fn == docname:
|
||||
del self.data['modules'][modname]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# XXX check duplicates?
|
||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
self.data['objects'][fullname] = (fn, objtype)
|
||||
for modname, data in otherdata['modules'].items():
|
||||
if data[0] in docnames:
|
||||
self.data['modules'][modname] = data
|
||||
|
||||
def find_obj(self, env, modname, classname, name, type, searchmode=0):
|
||||
"""Find a Python object for "name", perhaps using the given module
|
||||
and/or classname. Returns a list of (name, object entry) tuples.
|
||||
@ -643,7 +661,10 @@ class PythonDomain(Domain):
|
||||
|
||||
newname = None
|
||||
if searchmode == 1:
|
||||
objtypes = self.objtypes_for_role(type)
|
||||
if type is None:
|
||||
objtypes = list(self.object_types)
|
||||
else:
|
||||
objtypes = self.objtypes_for_role(type)
|
||||
if objtypes is not None:
|
||||
if modname and classname:
|
||||
fullname = modname + '.' + classname + '.' + name
|
||||
@ -704,22 +725,44 @@ class PythonDomain(Domain):
|
||||
name, obj = matches[0]
|
||||
|
||||
if obj[1] == 'module':
|
||||
# get additional info for modules
|
||||
docname, synopsis, platform, deprecated = self.data['modules'][name]
|
||||
assert docname == obj[0]
|
||||
title = name
|
||||
if synopsis:
|
||||
title += ': ' + synopsis
|
||||
if deprecated:
|
||||
title += _(' (deprecated)')
|
||||
if platform:
|
||||
title += ' (' + platform + ')'
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
'module-' + name, contnode, title)
|
||||
return self._make_module_refnode(builder, fromdocname, name,
|
||||
contnode)
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, obj[0], name,
|
||||
contnode, name)
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target,
|
||||
node, contnode):
|
||||
modname = node.get('py:module')
|
||||
clsname = node.get('py:class')
|
||||
results = []
|
||||
|
||||
# always search in "refspecific" mode with the :any: role
|
||||
matches = self.find_obj(env, modname, clsname, target, None, 1)
|
||||
for name, obj in matches:
|
||||
if obj[1] == 'module':
|
||||
results.append(('py:mod',
|
||||
self._make_module_refnode(builder, fromdocname,
|
||||
name, contnode)))
|
||||
else:
|
||||
results.append(('py:' + self.role_for_objtype(obj[1]),
|
||||
make_refnode(builder, fromdocname, obj[0], name,
|
||||
contnode, name)))
|
||||
return results
|
||||
|
||||
def _make_module_refnode(self, builder, fromdocname, name, contnode):
|
||||
# get additional info for modules
|
||||
docname, synopsis, platform, deprecated = self.data['modules'][name]
|
||||
title = name
|
||||
if synopsis:
|
||||
title += ': ' + synopsis
|
||||
if deprecated:
|
||||
title += _(' (deprecated)')
|
||||
if platform:
|
||||
title += ' (' + platform + ')'
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
'module-' + name, contnode, title)
|
||||
|
||||
def get_objects(self):
|
||||
for modname, info in iteritems(self.data['modules']):
|
||||
yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The reStructuredText domain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -123,6 +123,12 @@ class ReSTDomain(Domain):
|
||||
if doc == docname:
|
||||
del self.data['objects'][typ, name]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# XXX check duplicates
|
||||
for (typ, name), doc in otherdata['objects'].items():
|
||||
if doc in docnames:
|
||||
self.data['objects'][typ, name] = doc
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
|
||||
contnode):
|
||||
objects = self.data['objects']
|
||||
@ -134,6 +140,19 @@ class ReSTDomain(Domain):
|
||||
objtype + '-' + target,
|
||||
contnode, target + ' ' + objtype)
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target,
|
||||
node, contnode):
|
||||
objects = self.data['objects']
|
||||
results = []
|
||||
for objtype in self.object_types:
|
||||
if (objtype, target) in self.data['objects']:
|
||||
results.append(('rst:' + self.role_for_objtype(objtype),
|
||||
make_refnode(builder, fromdocname,
|
||||
objects[objtype, target],
|
||||
objtype + '-' + target,
|
||||
contnode, target + ' ' + objtype)))
|
||||
return results
|
||||
|
||||
def get_objects(self):
|
||||
for (typ, name), docname in iteritems(self.data['objects']):
|
||||
yield name, name, typ, docname, typ + '-' + name, 1
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The standard domain.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -22,13 +22,15 @@ from sphinx.roles import XRefRole
|
||||
from sphinx.locale import l_, _
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.util import ws_re
|
||||
from sphinx.util import ws_re, get_figtype
|
||||
from sphinx.util.nodes import clean_astext, make_refnode
|
||||
from sphinx.util.compat import Directive
|
||||
|
||||
|
||||
# RE for option descriptions
|
||||
option_desc_re = re.compile(r'((?:/|-|--)?[-_a-zA-Z0-9]+)(\s*.*)')
|
||||
option_desc_re = re.compile(r'((?:/|--|-|\+)?[-?@#_a-zA-Z0-9]+)(=?\s*.*)')
|
||||
# RE for grammar tokens
|
||||
token_re = re.compile('`(\w+)`', re.U)
|
||||
|
||||
|
||||
class GenericObject(ObjectDescription):
|
||||
@ -144,8 +146,9 @@ class Cmdoption(ObjectDescription):
|
||||
self.env.warn(
|
||||
self.env.docname,
|
||||
'Malformed option description %r, should '
|
||||
'look like "opt", "-opt args", "--opt args" or '
|
||||
'"/opt args"' % potential_option, self.lineno)
|
||||
'look like "opt", "-opt args", "--opt args", '
|
||||
'"/opt args" or "+opt args"' % potential_option,
|
||||
self.lineno)
|
||||
continue
|
||||
optname, args = m.groups()
|
||||
if count:
|
||||
@ -163,7 +166,7 @@ class Cmdoption(ObjectDescription):
|
||||
return firstname
|
||||
|
||||
def add_target_and_index(self, firstname, sig, signode):
|
||||
currprogram = self.env.temp_data.get('std:program')
|
||||
currprogram = self.env.ref_context.get('std:program')
|
||||
for optname in signode.get('allnames', []):
|
||||
targetname = optname.replace('/', '-')
|
||||
if not targetname.startswith('-'):
|
||||
@ -198,36 +201,19 @@ class Program(Directive):
|
||||
env = self.state.document.settings.env
|
||||
program = ws_re.sub('-', self.arguments[0].strip())
|
||||
if program == 'None':
|
||||
env.temp_data['std:program'] = None
|
||||
env.ref_context.pop('std:program', None)
|
||||
else:
|
||||
env.temp_data['std:program'] = program
|
||||
env.ref_context['std:program'] = program
|
||||
return []
|
||||
|
||||
|
||||
class OptionXRefRole(XRefRole):
|
||||
innernodeclass = addnodes.literal_emphasis
|
||||
|
||||
def _split(self, text, refnode, env):
|
||||
try:
|
||||
program, target = re.split(' (?=-|--|/)', text, 1)
|
||||
except ValueError:
|
||||
env.warn_node('Malformed :option: %r, does not contain option '
|
||||
'marker - or -- or /' % text, refnode)
|
||||
return None, text
|
||||
else:
|
||||
program = ws_re.sub('-', program)
|
||||
return program, target
|
||||
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
program = env.temp_data.get('std:program')
|
||||
if not has_explicit_title:
|
||||
if ' ' in title and not (title.startswith('/') or
|
||||
title.startswith('-')):
|
||||
program, target = self._split(title, refnode, env)
|
||||
target = target.strip()
|
||||
elif ' ' in target:
|
||||
program, target = self._split(target, refnode, env)
|
||||
refnode['refprogram'] = program
|
||||
# validate content
|
||||
if not re.match('(.+ )?[-/+]', target):
|
||||
env.warn_node('Malformed :option: %r, does not contain option '
|
||||
'marker - or -- or / or +' % target, refnode)
|
||||
refnode['std:program'] = env.ref_context.get('std:program')
|
||||
return title, target
|
||||
|
||||
|
||||
@ -327,7 +313,7 @@ class Glossary(Directive):
|
||||
else:
|
||||
messages.append(self.state.reporter.system_message(
|
||||
2, 'glossary seems to be misformatted, check '
|
||||
'indentation', source=source, line=lineno))
|
||||
'indentation', source=source, line=lineno))
|
||||
else:
|
||||
if not in_definition:
|
||||
# first line of definition, determines indentation
|
||||
@ -338,7 +324,7 @@ class Glossary(Directive):
|
||||
else:
|
||||
messages.append(self.state.reporter.system_message(
|
||||
2, 'glossary seems to be misformatted, check '
|
||||
'indentation', source=source, line=lineno))
|
||||
'indentation', source=source, line=lineno))
|
||||
was_empty = False
|
||||
|
||||
# now, parse all the entries into a big definition list
|
||||
@ -359,7 +345,7 @@ class Glossary(Directive):
|
||||
tmp.source = source
|
||||
tmp.line = lineno
|
||||
new_id, termtext, new_termnodes = \
|
||||
make_termnodes_from_paragraph_node(env, tmp)
|
||||
make_termnodes_from_paragraph_node(env, tmp)
|
||||
ids.append(new_id)
|
||||
termtexts.append(termtext)
|
||||
termnodes.extend(new_termnodes)
|
||||
@ -386,8 +372,6 @@ class Glossary(Directive):
|
||||
return messages + [node]
|
||||
|
||||
|
||||
token_re = re.compile('`(\w+)`', re.U)
|
||||
|
||||
def token_xrefs(text):
|
||||
retnodes = []
|
||||
pos = 0
|
||||
@ -472,7 +456,7 @@ class StandardDomain(Domain):
|
||||
'productionlist': ProductionList,
|
||||
}
|
||||
roles = {
|
||||
'option': OptionXRefRole(innernodeclass=addnodes.literal_emphasis),
|
||||
'option': OptionXRefRole(),
|
||||
'envvar': EnvVarXRefRole(),
|
||||
# links to tokens in grammar productions
|
||||
'token': XRefRole(),
|
||||
@ -482,6 +466,9 @@ class StandardDomain(Domain):
|
||||
# links to headings or arbitrary labels
|
||||
'ref': XRefRole(lowercase=True, innernodeclass=nodes.emphasis,
|
||||
warn_dangling=True),
|
||||
# links to labels of numbered figures, tables and code-blocks
|
||||
'numref': XRefRole(lowercase=True,
|
||||
warn_dangling=True),
|
||||
# links to labels, without a different title
|
||||
'keyword': XRefRole(warn_dangling=True),
|
||||
}
|
||||
@ -505,6 +492,7 @@ class StandardDomain(Domain):
|
||||
'term': 'term not in glossary: %(target)s',
|
||||
'ref': 'undefined label: %(target)s (if the link has no caption '
|
||||
'the label must precede a section header)',
|
||||
'numref': 'undefined label: %(target)s',
|
||||
'keyword': 'unknown keyword: %(target)s',
|
||||
}
|
||||
|
||||
@ -522,6 +510,21 @@ class StandardDomain(Domain):
|
||||
if fn == docname:
|
||||
del self.data['anonlabels'][key]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# XXX duplicates?
|
||||
for key, data in otherdata['progoptions'].items():
|
||||
if data[0] in docnames:
|
||||
self.data['progoptions'][key] = data
|
||||
for key, data in otherdata['objects'].items():
|
||||
if data[0] in docnames:
|
||||
self.data['objects'][key] = data
|
||||
for key, data in otherdata['labels'].items():
|
||||
if data[0] in docnames:
|
||||
self.data['labels'][key] = data
|
||||
for key, data in otherdata['anonlabels'].items():
|
||||
if data[0] in docnames:
|
||||
self.data['anonlabels'][key] = data
|
||||
|
||||
def process_doc(self, env, docname, document):
|
||||
labels, anonlabels = self.data['labels'], self.data['anonlabels']
|
||||
for name, explicit in iteritems(document.nametypes):
|
||||
@ -532,7 +535,7 @@ class StandardDomain(Domain):
|
||||
continue
|
||||
node = document.ids[labelid]
|
||||
if name.isdigit() or 'refuri' in node or \
|
||||
node.tagname.startswith('desc_'):
|
||||
node.tagname.startswith('desc_'):
|
||||
# ignore footnote labels, labels automatically generated from a
|
||||
# link and object descriptions
|
||||
continue
|
||||
@ -541,7 +544,7 @@ class StandardDomain(Domain):
|
||||
'in ' + env.doc2path(labels[name][0]), node)
|
||||
anonlabels[name] = docname, labelid
|
||||
if node.tagname == 'section':
|
||||
sectname = clean_astext(node[0]) # node[0] == title node
|
||||
sectname = clean_astext(node[0]) # node[0] == title node
|
||||
elif node.tagname == 'figure':
|
||||
for n in node:
|
||||
if n.tagname == 'caption':
|
||||
@ -563,52 +566,105 @@ class StandardDomain(Domain):
|
||||
break
|
||||
else:
|
||||
continue
|
||||
elif node.tagname == 'container' and node.get('literal_block'):
|
||||
for n in node:
|
||||
if n.tagname == 'caption':
|
||||
sectname = clean_astext(n)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
# anonymous-only labels
|
||||
continue
|
||||
labels[name] = docname, labelid, sectname
|
||||
|
||||
def build_reference_node(self, fromdocname, builder,
|
||||
docname, labelid, sectname,
|
||||
**options):
|
||||
nodeclass = options.pop('nodeclass', nodes.reference)
|
||||
newnode = nodeclass('', '', internal=True, **options)
|
||||
innernode = nodes.emphasis(sectname, sectname)
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
else:
|
||||
# set more info in contnode; in case the
|
||||
# get_relative_uri call raises NoUri,
|
||||
# the builder will then have to resolve these
|
||||
contnode = addnodes.pending_xref('')
|
||||
contnode['refdocname'] = docname
|
||||
contnode['refsectname'] = sectname
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname)
|
||||
if labelid:
|
||||
newnode['refuri'] += '#' + labelid
|
||||
newnode.append(innernode)
|
||||
return newnode
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
if typ == 'ref':
|
||||
if node['refexplicit']:
|
||||
# reference to anonymous label; the reference uses
|
||||
# the supplied link caption
|
||||
docname, labelid = self.data['anonlabels'].get(target, ('',''))
|
||||
docname, labelid = self.data['anonlabels'].get(target, ('', ''))
|
||||
sectname = node.astext()
|
||||
else:
|
||||
# reference to named label; the final node will
|
||||
# contain the section name after the label
|
||||
docname, labelid, sectname = self.data['labels'].get(target,
|
||||
('','',''))
|
||||
('', '', ''))
|
||||
if not docname:
|
||||
return None
|
||||
newnode = nodes.reference('', '', internal=True)
|
||||
innernode = nodes.emphasis(sectname, sectname)
|
||||
if docname == fromdocname:
|
||||
newnode['refid'] = labelid
|
||||
|
||||
return self.build_reference_node(fromdocname, builder,
|
||||
docname, labelid, sectname)
|
||||
elif typ == 'numref':
|
||||
docname, labelid = self.data['anonlabels'].get(target, ('', ''))
|
||||
if not docname:
|
||||
return None
|
||||
|
||||
if env.config.numfig is False:
|
||||
env.warn(fromdocname, 'numfig is disabled. :numref: is ignored.')
|
||||
return contnode
|
||||
|
||||
try:
|
||||
target_node = env.get_doctree(docname).ids[labelid]
|
||||
figtype = get_figtype(target_node)
|
||||
figure_id = target_node['ids'][0]
|
||||
fignumber = env.toc_fignumbers[docname][figtype][figure_id]
|
||||
except (KeyError, IndexError):
|
||||
return None
|
||||
|
||||
title = contnode.astext()
|
||||
if target == title:
|
||||
prefix = env.config.numfig_format.get(figtype, '')
|
||||
title = prefix.replace('%s', '#')
|
||||
newtitle = prefix % '.'.join(map(str, fignumber))
|
||||
else:
|
||||
# set more info in contnode; in case the
|
||||
# get_relative_uri call raises NoUri,
|
||||
# the builder will then have to resolve these
|
||||
contnode = addnodes.pending_xref('')
|
||||
contnode['refdocname'] = docname
|
||||
contnode['refsectname'] = sectname
|
||||
newnode['refuri'] = builder.get_relative_uri(
|
||||
fromdocname, docname)
|
||||
if labelid:
|
||||
newnode['refuri'] += '#' + labelid
|
||||
newnode.append(innernode)
|
||||
return newnode
|
||||
newtitle = title.replace('#', '.'.join(map(str, fignumber)))
|
||||
|
||||
return self.build_reference_node(fromdocname, builder,
|
||||
docname, labelid, newtitle,
|
||||
nodeclass=addnodes.number_reference,
|
||||
title=title)
|
||||
elif typ == 'keyword':
|
||||
# keywords are oddballs: they are referenced by named labels
|
||||
docname, labelid, _ = self.data['labels'].get(target, ('','',''))
|
||||
docname, labelid, _ = self.data['labels'].get(target, ('', '', ''))
|
||||
if not docname:
|
||||
return None
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
elif typ == 'option':
|
||||
progname = node['refprogram']
|
||||
target = target.strip()
|
||||
# most obvious thing: we are a flag option without program
|
||||
if target.startswith(('-', '/', '+')):
|
||||
progname = node.get('std:program')
|
||||
else:
|
||||
try:
|
||||
progname, target = re.split(r' (?=-|--|/|\+)', target, 1)
|
||||
except ValueError:
|
||||
return None
|
||||
progname = ws_re.sub('-', progname.strip())
|
||||
docname, labelid = self.data['progoptions'].get((progname, target),
|
||||
('', ''))
|
||||
if not docname:
|
||||
@ -628,6 +684,28 @@ class StandardDomain(Domain):
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)
|
||||
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target,
|
||||
node, contnode):
|
||||
results = []
|
||||
ltarget = target.lower() # :ref: lowercases its target automatically
|
||||
for role in ('ref', 'option'): # do not try "keyword"
|
||||
res = self.resolve_xref(env, fromdocname, builder, role,
|
||||
ltarget if role == 'ref' else target,
|
||||
node, contnode)
|
||||
if res:
|
||||
results.append(('std:' + role, res))
|
||||
# all others
|
||||
for objtype in self.object_types:
|
||||
key = (objtype, target)
|
||||
if objtype == 'term':
|
||||
key = (objtype, ltarget)
|
||||
if key in self.data['objects']:
|
||||
docname, labelid = self.data['objects'][key]
|
||||
results.append(('std:' + self.role_for_objtype(objtype),
|
||||
make_refnode(builder, fromdocname, docname,
|
||||
labelid, contnode)))
|
||||
return results
|
||||
|
||||
def get_objects(self):
|
||||
for (prog, option), info in iteritems(self.data['progoptions']):
|
||||
yield (option, option, 'option', info[0], info[1], 1)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,13 @@
|
||||
Contains SphinxError and a few subclasses (in an extra module to avoid
|
||||
circular import problems).
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
class SphinxError(Exception):
|
||||
"""
|
||||
Base class for Sphinx errors that are shown to the user in a nicer
|
||||
@ -62,3 +65,13 @@ class PycodeError(Exception):
|
||||
if len(self.args) > 1:
|
||||
res += ' (exception was: %r)' % self.args[1]
|
||||
return res
|
||||
|
||||
|
||||
class SphinxParallelError(Exception):
|
||||
def __init__(self, orig_exc, traceback):
|
||||
self.orig_exc = orig_exc
|
||||
self.traceback = traceback
|
||||
|
||||
def __str__(self):
|
||||
return traceback.format_exception_only(
|
||||
self.orig_exc.__class__, self.orig_exc)[0].strip()
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
Contains Sphinx features not activated by default.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
@ -7,7 +7,7 @@
|
||||
the doctree, thus avoiding duplication between docstrings and documentation
|
||||
for those who like elaborate docstrings.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -30,7 +30,7 @@ from sphinx.application import ExtensionError
|
||||
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
|
||||
safe_getattr, object_description, is_builtin_class_method
|
||||
from sphinx.util.docstrings import prepare_docstring
|
||||
|
||||
|
||||
@ -50,11 +50,13 @@ class DefDict(dict):
|
||||
def __init__(self, default):
|
||||
dict.__init__(self)
|
||||
self.default = default
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
return self.default
|
||||
|
||||
def __bool__(self):
|
||||
# docutils check "if option_spec"
|
||||
return True
|
||||
@ -92,6 +94,7 @@ class _MockModule(object):
|
||||
else:
|
||||
return _MockModule()
|
||||
|
||||
|
||||
def mock_import(modname):
|
||||
if '.' in modname:
|
||||
pkg, _n, mods = modname.rpartition('.')
|
||||
@ -104,12 +107,14 @@ def mock_import(modname):
|
||||
ALL = object()
|
||||
INSTANCEATTR = object()
|
||||
|
||||
|
||||
def members_option(arg):
|
||||
"""Used to convert the :members: option to auto directives."""
|
||||
if arg is None:
|
||||
return ALL
|
||||
return [x.strip() for x in arg.split(',')]
|
||||
|
||||
|
||||
def members_set_option(arg):
|
||||
"""Used to convert the :members: option to auto directives."""
|
||||
if arg is None:
|
||||
@ -118,6 +123,7 @@ def members_set_option(arg):
|
||||
|
||||
SUPPRESS = object()
|
||||
|
||||
|
||||
def annotation_option(arg):
|
||||
if arg is None:
|
||||
# suppress showing the representation of the object
|
||||
@ -125,6 +131,7 @@ def annotation_option(arg):
|
||||
else:
|
||||
return arg
|
||||
|
||||
|
||||
def bool_option(arg):
|
||||
"""Used to convert flag options to auto directives. (Instead of
|
||||
directives.flag(), which returns None).
|
||||
@ -201,6 +208,7 @@ def cut_lines(pre, post=0, what=None):
|
||||
lines.append('')
|
||||
return process
|
||||
|
||||
|
||||
def between(marker, what=None, keepempty=False, exclude=False):
|
||||
"""Return a listener that either keeps, or if *exclude* is True excludes,
|
||||
lines between lines that match the *marker* regular expression. If no line
|
||||
@ -211,6 +219,7 @@ def between(marker, what=None, keepempty=False, exclude=False):
|
||||
be processed.
|
||||
"""
|
||||
marker_re = re.compile(marker)
|
||||
|
||||
def process(app, what_, name, obj, options, lines):
|
||||
if what and what_ not in what:
|
||||
return
|
||||
@ -234,6 +243,11 @@ def between(marker, what=None, keepempty=False, exclude=False):
|
||||
return process
|
||||
|
||||
|
||||
def formatargspec(*argspec):
|
||||
return inspect.formatargspec(*argspec,
|
||||
formatvalue=lambda x: '=' + object_description(x))
|
||||
|
||||
|
||||
class Documenter(object):
|
||||
"""
|
||||
A Documenter knows how to autodocument a single object type. When
|
||||
@ -325,7 +339,7 @@ class Documenter(object):
|
||||
# an autogenerated one
|
||||
try:
|
||||
explicit_modname, path, base, args, retann = \
|
||||
py_ext_sig_re.match(self.name).groups()
|
||||
py_ext_sig_re.match(self.name).groups()
|
||||
except AttributeError:
|
||||
self.directive.warn('invalid signature for auto%s (%r)' %
|
||||
(self.objtype, self.name))
|
||||
@ -340,7 +354,7 @@ class Documenter(object):
|
||||
parents = []
|
||||
|
||||
self.modname, self.objpath = \
|
||||
self.resolve_name(modname, parents, path, base)
|
||||
self.resolve_name(modname, parents, path, base)
|
||||
|
||||
if not self.modname:
|
||||
return False
|
||||
@ -472,14 +486,15 @@ class Documenter(object):
|
||||
domain = getattr(self, 'domain', 'py')
|
||||
directive = getattr(self, 'directivetype', self.objtype)
|
||||
name = self.format_name()
|
||||
sourcename = self.get_sourcename()
|
||||
self.add_line(u'.. %s:%s:: %s%s' % (domain, directive, name, sig),
|
||||
'<autodoc>')
|
||||
sourcename)
|
||||
if self.options.noindex:
|
||||
self.add_line(u' :noindex:', '<autodoc>')
|
||||
self.add_line(u' :noindex:', sourcename)
|
||||
if self.objpath:
|
||||
# Be explicit about the module, this is necessary since .. class::
|
||||
# etc. don't support a prepended module name
|
||||
self.add_line(u' :module: %s' % self.modname, '<autodoc>')
|
||||
self.add_line(u' :module: %s' % self.modname, sourcename)
|
||||
|
||||
def get_doc(self, encoding=None, ignore=1):
|
||||
"""Decode and return lines of the docstring(s) for the object."""
|
||||
@ -505,9 +520,7 @@ class Documenter(object):
|
||||
for line in docstringlines:
|
||||
yield line
|
||||
|
||||
def add_content(self, more_content, no_docstring=False):
|
||||
"""Add content from docstrings, attribute documentation and user."""
|
||||
# set sourcename and add content from attribute documentation
|
||||
def get_sourcename(self):
|
||||
if self.analyzer:
|
||||
# prevent encoding errors when the file name is non-ASCII
|
||||
if not isinstance(self.analyzer.srcname, text_type):
|
||||
@ -515,8 +528,14 @@ class Documenter(object):
|
||||
sys.getfilesystemencoding(), 'replace')
|
||||
else:
|
||||
filename = self.analyzer.srcname
|
||||
sourcename = u'%s:docstring of %s' % (filename, self.fullname)
|
||||
return u'%s:docstring of %s' % (filename, self.fullname)
|
||||
return u'docstring of %s' % self.fullname
|
||||
|
||||
def add_content(self, more_content, no_docstring=False):
|
||||
"""Add content from docstrings, attribute documentation and user."""
|
||||
# set sourcename and add content from attribute documentation
|
||||
sourcename = self.get_sourcename()
|
||||
if self.analyzer:
|
||||
attr_docs = self.analyzer.find_attr_docs()
|
||||
if self.objpath:
|
||||
key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
|
||||
@ -525,8 +544,6 @@ class Documenter(object):
|
||||
docstrings = [attr_docs[key]]
|
||||
for i, line in enumerate(self.process_doc(docstrings)):
|
||||
self.add_line(line, sourcename, i)
|
||||
else:
|
||||
sourcename = u'docstring of %s' % self.fullname
|
||||
|
||||
# add content from docstrings
|
||||
if not no_docstring:
|
||||
@ -637,19 +654,19 @@ class Documenter(object):
|
||||
|
||||
keep = False
|
||||
if want_all and membername.startswith('__') and \
|
||||
membername.endswith('__') and len(membername) > 4:
|
||||
membername.endswith('__') and len(membername) > 4:
|
||||
# special __methods__
|
||||
if self.options.special_members is ALL and \
|
||||
membername != '__doc__':
|
||||
keep = has_doc or self.options.undoc_members
|
||||
elif self.options.special_members and \
|
||||
self.options.special_members is not ALL and \
|
||||
self.options.special_members is not ALL and \
|
||||
membername in self.options.special_members:
|
||||
keep = has_doc or self.options.undoc_members
|
||||
elif want_all and membername.startswith('_'):
|
||||
# ignore members whose name starts with _ by default
|
||||
keep = self.options.private_members and \
|
||||
(has_doc or self.options.undoc_members)
|
||||
(has_doc or self.options.undoc_members)
|
||||
elif (namespace, membername) in attr_docs:
|
||||
# keep documented attributes
|
||||
keep = True
|
||||
@ -685,7 +702,7 @@ class Documenter(object):
|
||||
self.env.temp_data['autodoc:class'] = self.objpath[0]
|
||||
|
||||
want_all = all_members or self.options.inherited_members or \
|
||||
self.options.members is ALL
|
||||
self.options.members is ALL
|
||||
# find out which members are documentable
|
||||
members_check_module, members = self.get_object_members(want_all)
|
||||
|
||||
@ -707,11 +724,11 @@ class Documenter(object):
|
||||
# give explicitly separated module name, so that members
|
||||
# of inner classes can be documented
|
||||
full_mname = self.modname + '::' + \
|
||||
'.'.join(self.objpath + [mname])
|
||||
'.'.join(self.objpath + [mname])
|
||||
documenter = classes[-1](self.directive, full_mname, self.indent)
|
||||
memberdocumenters.append((documenter, isattr))
|
||||
member_order = self.options.member_order or \
|
||||
self.env.config.autodoc_member_order
|
||||
self.env.config.autodoc_member_order
|
||||
if member_order == 'groupwise':
|
||||
# sort by group; relies on stable sort to keep items in the
|
||||
# same group sorted alphabetically
|
||||
@ -719,6 +736,7 @@ class Documenter(object):
|
||||
elif member_order == 'bysource' and self.analyzer:
|
||||
# sort by source order, by virtue of the module analyzer
|
||||
tagorder = self.analyzer.tagorder
|
||||
|
||||
def keyfunc(entry):
|
||||
fullname = entry[0].name.split('::')[1]
|
||||
return tagorder.get(fullname, len(tagorder))
|
||||
@ -784,17 +802,19 @@ class Documenter(object):
|
||||
if not self.check_module():
|
||||
return
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
# make sure that the result starts with an empty line. This is
|
||||
# necessary for some situations where another directive preprocesses
|
||||
# reST and no starting newline is present
|
||||
self.add_line(u'', '<autodoc>')
|
||||
self.add_line(u'', sourcename)
|
||||
|
||||
# format the object's signature, if any
|
||||
sig = self.format_signature()
|
||||
|
||||
# generate the directive header and options, if applicable
|
||||
self.add_directive_header(sig)
|
||||
self.add_line(u'', '<autodoc>')
|
||||
self.add_line(u'', sourcename)
|
||||
|
||||
# e.g. the module directive doesn't have content
|
||||
self.indent += self.content_indent
|
||||
@ -844,15 +864,17 @@ class ModuleDocumenter(Documenter):
|
||||
def add_directive_header(self, sig):
|
||||
Documenter.add_directive_header(self, sig)
|
||||
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
# add some module-specific options
|
||||
if self.options.synopsis:
|
||||
self.add_line(
|
||||
u' :synopsis: ' + self.options.synopsis, '<autodoc>')
|
||||
u' :synopsis: ' + self.options.synopsis, sourcename)
|
||||
if self.options.platform:
|
||||
self.add_line(
|
||||
u' :platform: ' + self.options.platform, '<autodoc>')
|
||||
u' :platform: ' + self.options.platform, sourcename)
|
||||
if self.options.deprecated:
|
||||
self.add_line(u' :deprecated:', '<autodoc>')
|
||||
self.add_line(u' :deprecated:', sourcename)
|
||||
|
||||
def get_object_members(self, want_all):
|
||||
if want_all:
|
||||
@ -862,6 +884,15 @@ class ModuleDocumenter(Documenter):
|
||||
return True, safe_getmembers(self.object)
|
||||
else:
|
||||
memberlist = self.object.__all__
|
||||
# Sometimes __all__ is broken...
|
||||
if not isinstance(memberlist, (list, tuple)) or not \
|
||||
all(isinstance(entry, str) for entry in memberlist):
|
||||
self.directive.warn(
|
||||
'__all__ should be a list of strings, not %r '
|
||||
'(in module %s) -- ignoring __all__' %
|
||||
(memberlist, self.fullname))
|
||||
# fall back to all members
|
||||
return True, safe_getmembers(self.object)
|
||||
else:
|
||||
memberlist = self.options.members or []
|
||||
ret = []
|
||||
@ -872,7 +903,7 @@ class ModuleDocumenter(Documenter):
|
||||
self.directive.warn(
|
||||
'missing attribute mentioned in :members: or __all__: '
|
||||
'module %s, attribute %s' % (
|
||||
safe_getattr(self.object, '__name__', '???'), mname))
|
||||
safe_getattr(self.object, '__name__', '???'), mname))
|
||||
return False, ret
|
||||
|
||||
|
||||
@ -891,7 +922,7 @@ class ModuleLevelDocumenter(Documenter):
|
||||
modname = self.env.temp_data.get('autodoc:module')
|
||||
# ... or in the scope of a module directive
|
||||
if not modname:
|
||||
modname = self.env.temp_data.get('py:module')
|
||||
modname = self.env.ref_context.get('py:module')
|
||||
# ... else, it stays None, which means invalid
|
||||
return modname, parents + [base]
|
||||
|
||||
@ -913,7 +944,7 @@ class ClassLevelDocumenter(Documenter):
|
||||
mod_cls = self.env.temp_data.get('autodoc:class')
|
||||
# ... or from a class directive
|
||||
if mod_cls is None:
|
||||
mod_cls = self.env.temp_data.get('py:class')
|
||||
mod_cls = self.env.ref_context.get('py:class')
|
||||
# ... if still None, there's no way to know
|
||||
if mod_cls is None:
|
||||
return None, []
|
||||
@ -923,7 +954,7 @@ class ClassLevelDocumenter(Documenter):
|
||||
if not modname:
|
||||
modname = self.env.temp_data.get('autodoc:module')
|
||||
if not modname:
|
||||
modname = self.env.temp_data.get('py:module')
|
||||
modname = self.env.ref_context.get('py:module')
|
||||
# ... else, it stays None, which means invalid
|
||||
return modname, parents + [base]
|
||||
|
||||
@ -935,36 +966,37 @@ class DocstringSignatureMixin(object):
|
||||
"""
|
||||
|
||||
def _find_signature(self, encoding=None):
|
||||
docstrings = Documenter.get_doc(self, encoding)
|
||||
if len(docstrings) != 1:
|
||||
return
|
||||
doclines = docstrings[0]
|
||||
setattr(self, '__new_doclines', doclines)
|
||||
if not doclines:
|
||||
return
|
||||
# match first line of docstring against signature RE
|
||||
match = py_ext_sig_re.match(doclines[0])
|
||||
if not match:
|
||||
return
|
||||
exmod, path, base, args, retann = match.groups()
|
||||
# the base name must match ours
|
||||
if not self.objpath or base != self.objpath[-1]:
|
||||
return
|
||||
# re-prepare docstring to ignore indentation after signature
|
||||
docstrings = Documenter.get_doc(self, encoding, 2)
|
||||
doclines = docstrings[0]
|
||||
# ok, now jump over remaining empty lines and set the remaining
|
||||
# lines as the new doclines
|
||||
i = 1
|
||||
while i < len(doclines) and not doclines[i].strip():
|
||||
i += 1
|
||||
setattr(self, '__new_doclines', doclines[i:])
|
||||
return args, retann
|
||||
docstrings = self.get_doc(encoding)
|
||||
self._new_docstrings = docstrings[:]
|
||||
result = None
|
||||
for i, doclines in enumerate(docstrings):
|
||||
# no lines in docstring, no match
|
||||
if not doclines:
|
||||
continue
|
||||
# match first line of docstring against signature RE
|
||||
match = py_ext_sig_re.match(doclines[0])
|
||||
if not match:
|
||||
continue
|
||||
exmod, path, base, args, retann = match.groups()
|
||||
# the base name must match ours
|
||||
valid_names = [self.objpath[-1]]
|
||||
if isinstance(self, ClassDocumenter):
|
||||
valid_names.append('__init__')
|
||||
if hasattr(self.object, '__mro__'):
|
||||
valid_names.extend(cls.__name__ for cls in self.object.__mro__)
|
||||
if base not in valid_names:
|
||||
continue
|
||||
# re-prepare docstring to ignore more leading indentation
|
||||
self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[1:]))
|
||||
result = args, retann
|
||||
# don't look any further
|
||||
break
|
||||
return result
|
||||
|
||||
def get_doc(self, encoding=None, ignore=1):
|
||||
lines = getattr(self, '__new_doclines', None)
|
||||
lines = getattr(self, '_new_docstrings', None)
|
||||
if lines is not None:
|
||||
return [lines]
|
||||
return lines
|
||||
return Documenter.get_doc(self, encoding, ignore)
|
||||
|
||||
def format_signature(self):
|
||||
@ -976,6 +1008,7 @@ class DocstringSignatureMixin(object):
|
||||
self.args, self.retann = result
|
||||
return Documenter.format_signature(self)
|
||||
|
||||
|
||||
class DocstringStripSignatureMixin(DocstringSignatureMixin):
|
||||
"""
|
||||
Mixin for AttributeDocumenter to provide the
|
||||
@ -1007,7 +1040,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
|
||||
|
||||
def format_args(self):
|
||||
if inspect.isbuiltin(self.object) or \
|
||||
inspect.ismethoddescriptor(self.object):
|
||||
inspect.ismethoddescriptor(self.object):
|
||||
# cannot introspect arguments of a C function or method
|
||||
return None
|
||||
try:
|
||||
@ -1026,7 +1059,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
|
||||
argspec = getargspec(self.object.__init__)
|
||||
if argspec[0]:
|
||||
del argspec[0][0]
|
||||
args = inspect.formatargspec(*argspec)
|
||||
args = formatargspec(*argspec)
|
||||
# escape backslashes for reST
|
||||
args = args.replace('\\', '\\\\')
|
||||
return args
|
||||
@ -1035,7 +1068,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
|
||||
pass
|
||||
|
||||
|
||||
class ClassDocumenter(ModuleLevelDocumenter):
|
||||
class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for classes.
|
||||
"""
|
||||
@ -1070,8 +1103,8 @@ class ClassDocumenter(ModuleLevelDocumenter):
|
||||
# classes without __init__ method, default __init__ or
|
||||
# __init__ written in C?
|
||||
if initmeth is None or \
|
||||
is_builtin_class_method(self.object, '__init__') or \
|
||||
not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
|
||||
is_builtin_class_method(self.object, '__init__') or \
|
||||
not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
|
||||
return None
|
||||
try:
|
||||
argspec = getargspec(initmeth)
|
||||
@ -1081,24 +1114,13 @@ class ClassDocumenter(ModuleLevelDocumenter):
|
||||
return None
|
||||
if argspec[0] and argspec[0][0] in ('cls', 'self'):
|
||||
del argspec[0][0]
|
||||
return inspect.formatargspec(*argspec)
|
||||
return formatargspec(*argspec)
|
||||
|
||||
def format_signature(self):
|
||||
if self.doc_as_attr:
|
||||
return ''
|
||||
|
||||
# get __init__ method signature from __init__.__doc__
|
||||
if self.env.config.autodoc_docstring_signature:
|
||||
# only act if the feature is enabled
|
||||
init_doc = MethodDocumenter(self.directive, '__init__')
|
||||
init_doc.object = self.get_attr(self.object, '__init__', None)
|
||||
init_doc.objpath = ['__init__']
|
||||
result = init_doc._find_signature()
|
||||
if result is not None:
|
||||
# use args only for Class signature
|
||||
return '(%s)' % result[0]
|
||||
|
||||
return ModuleLevelDocumenter.format_signature(self)
|
||||
return DocstringSignatureMixin.format_signature(self)
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
if self.doc_as_attr:
|
||||
@ -1107,16 +1129,21 @@ class ClassDocumenter(ModuleLevelDocumenter):
|
||||
|
||||
# add inheritance info, if wanted
|
||||
if not self.doc_as_attr and self.options.show_inheritance:
|
||||
self.add_line(u'', '<autodoc>')
|
||||
sourcename = self.get_sourcename()
|
||||
self.add_line(u'', sourcename)
|
||||
if hasattr(self.object, '__bases__') and len(self.object.__bases__):
|
||||
bases = [b.__module__ == '__builtin__' and
|
||||
bases = [b.__module__ in ('__builtin__', 'builtins') and
|
||||
u':class:`%s`' % b.__name__ or
|
||||
u':class:`%s.%s`' % (b.__module__, b.__name__)
|
||||
for b in self.object.__bases__]
|
||||
self.add_line(_(u' Bases: %s') % ', '.join(bases),
|
||||
'<autodoc>')
|
||||
sourcename)
|
||||
|
||||
def get_doc(self, encoding=None, ignore=1):
|
||||
lines = getattr(self, '_new_docstrings', None)
|
||||
if lines is not None:
|
||||
return lines
|
||||
|
||||
content = self.env.config.autoclass_content
|
||||
|
||||
docstrings = []
|
||||
@ -1127,22 +1154,12 @@ class ClassDocumenter(ModuleLevelDocumenter):
|
||||
# for classes, what the "docstring" is can be controlled via a
|
||||
# config value; the default is only the class docstring
|
||||
if content in ('both', 'init'):
|
||||
# get __init__ method document from __init__.__doc__
|
||||
if self.env.config.autodoc_docstring_signature:
|
||||
# only act if the feature is enabled
|
||||
init_doc = MethodDocumenter(self.directive, '__init__')
|
||||
init_doc.object = self.get_attr(self.object, '__init__', None)
|
||||
init_doc.objpath = ['__init__']
|
||||
init_doc._find_signature() # this effects to get_doc() result
|
||||
initdocstring = '\n'.join(
|
||||
['\n'.join(l) for l in init_doc.get_doc(encoding)])
|
||||
else:
|
||||
initdocstring = self.get_attr(
|
||||
self.get_attr(self.object, '__init__', None), '__doc__')
|
||||
initdocstring = self.get_attr(
|
||||
self.get_attr(self.object, '__init__', None), '__doc__')
|
||||
# for new-style classes, no __init__ means default __init__
|
||||
if (initdocstring is not None and
|
||||
(initdocstring == object.__init__.__doc__ or # for pypy
|
||||
initdocstring.strip() == object.__init__.__doc__)): #for !pypy
|
||||
initdocstring.strip() == object.__init__.__doc__)): # for !pypy
|
||||
initdocstring = None
|
||||
if initdocstring:
|
||||
if content == 'init':
|
||||
@ -1186,7 +1203,7 @@ class ExceptionDocumenter(ClassDocumenter):
|
||||
@classmethod
|
||||
def can_document_member(cls, member, membername, isattr, parent):
|
||||
return isinstance(member, class_types) and \
|
||||
issubclass(member, BaseException)
|
||||
issubclass(member, BaseException)
|
||||
|
||||
|
||||
class DataDocumenter(ModuleLevelDocumenter):
|
||||
@ -1205,18 +1222,19 @@ class DataDocumenter(ModuleLevelDocumenter):
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
ModuleLevelDocumenter.add_directive_header(self, sig)
|
||||
sourcename = self.get_sourcename()
|
||||
if not self.options.annotation:
|
||||
try:
|
||||
objrepr = safe_repr(self.object)
|
||||
objrepr = object_description(self.object)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
self.add_line(u' :annotation: = ' + objrepr, '<autodoc>')
|
||||
self.add_line(u' :annotation: = ' + objrepr, sourcename)
|
||||
elif self.options.annotation is SUPPRESS:
|
||||
pass
|
||||
else:
|
||||
self.add_line(u' :annotation: %s' % self.options.annotation,
|
||||
'<autodoc>')
|
||||
sourcename)
|
||||
|
||||
def document_members(self, all_members=False):
|
||||
pass
|
||||
@ -1233,7 +1251,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
|
||||
@classmethod
|
||||
def can_document_member(cls, member, membername, isattr, parent):
|
||||
return inspect.isroutine(member) and \
|
||||
not isinstance(parent, ModuleDocumenter)
|
||||
not isinstance(parent, ModuleDocumenter)
|
||||
|
||||
def import_object(self):
|
||||
ret = ClassLevelDocumenter.import_object(self)
|
||||
@ -1257,13 +1275,13 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
|
||||
|
||||
def format_args(self):
|
||||
if inspect.isbuiltin(self.object) or \
|
||||
inspect.ismethoddescriptor(self.object):
|
||||
inspect.ismethoddescriptor(self.object):
|
||||
# can never get arguments of a C function or method
|
||||
return None
|
||||
argspec = getargspec(self.object)
|
||||
if argspec[0] and argspec[0][0] in ('cls', 'self'):
|
||||
del argspec[0][0]
|
||||
args = inspect.formatargspec(*argspec)
|
||||
args = formatargspec(*argspec)
|
||||
# escape backslashes for reST
|
||||
args = args.replace('\\', '\\\\')
|
||||
return args
|
||||
@ -1272,7 +1290,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeDocumenter(DocstringStripSignatureMixin,ClassLevelDocumenter):
|
||||
class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
||||
"""
|
||||
Specialized Documenter subclass for attributes.
|
||||
"""
|
||||
@ -1290,9 +1308,9 @@ class AttributeDocumenter(DocstringStripSignatureMixin,ClassLevelDocumenter):
|
||||
@classmethod
|
||||
def can_document_member(cls, member, membername, isattr, parent):
|
||||
isdatadesc = isdescriptor(member) and not \
|
||||
isinstance(member, cls.method_types) and not \
|
||||
type(member).__name__ in ("type", "method_descriptor",
|
||||
"instancemethod")
|
||||
isinstance(member, cls.method_types) and not \
|
||||
type(member).__name__ in ("type", "method_descriptor",
|
||||
"instancemethod")
|
||||
return isdatadesc or (not isinstance(parent, ModuleDocumenter)
|
||||
and not inspect.isroutine(member)
|
||||
and not isinstance(member, class_types))
|
||||
@ -1303,7 +1321,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin,ClassLevelDocumenter):
|
||||
def import_object(self):
|
||||
ret = ClassLevelDocumenter.import_object(self)
|
||||
if isdescriptor(self.object) and \
|
||||
not isinstance(self.object, self.method_types):
|
||||
not isinstance(self.object, self.method_types):
|
||||
self._datadescriptor = True
|
||||
else:
|
||||
# if it's not a data descriptor
|
||||
@ -1312,23 +1330,24 @@ class AttributeDocumenter(DocstringStripSignatureMixin,ClassLevelDocumenter):
|
||||
|
||||
def get_real_modname(self):
|
||||
return self.get_attr(self.parent or self.object, '__module__', None) \
|
||||
or self.modname
|
||||
or self.modname
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
ClassLevelDocumenter.add_directive_header(self, sig)
|
||||
sourcename = self.get_sourcename()
|
||||
if not self.options.annotation:
|
||||
if not self._datadescriptor:
|
||||
try:
|
||||
objrepr = safe_repr(self.object)
|
||||
objrepr = object_description(self.object)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
self.add_line(u' :annotation: = ' + objrepr, '<autodoc>')
|
||||
self.add_line(u' :annotation: = ' + objrepr, sourcename)
|
||||
elif self.options.annotation is SUPPRESS:
|
||||
pass
|
||||
else:
|
||||
self.add_line(u' :annotation: %s' % self.options.annotation,
|
||||
'<autodoc>')
|
||||
sourcename)
|
||||
|
||||
def add_content(self, more_content, no_docstring=False):
|
||||
if not self._datadescriptor:
|
||||
@ -1479,7 +1498,7 @@ def add_documenter(cls):
|
||||
raise ExtensionError('autodoc documenter %r must be a subclass '
|
||||
'of Documenter' % cls)
|
||||
# actually, it should be possible to override Documenters
|
||||
#if cls.objtype in AutoDirective._registry:
|
||||
# if cls.objtype in AutoDirective._registry:
|
||||
# raise ExtensionError('autodoc documenter for %r is already '
|
||||
# 'registered' % cls.objtype)
|
||||
AutoDirective._registry[cls.objtype] = cls
|
||||
@ -1504,7 +1523,7 @@ def setup(app):
|
||||
app.add_event('autodoc-process-signature')
|
||||
app.add_event('autodoc-skip-member')
|
||||
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
||||
|
||||
class testcls:
|
||||
|
@ -49,7 +49,7 @@
|
||||
resolved to a Python object, and otherwise it becomes simple emphasis.
|
||||
This can be used as the default role to make links 'smart'.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -58,6 +58,7 @@ import re
|
||||
import sys
|
||||
import inspect
|
||||
import posixpath
|
||||
from types import ModuleType
|
||||
|
||||
from six import text_type
|
||||
from docutils.parsers.rst import directives
|
||||
@ -68,6 +69,7 @@ import sphinx
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.compat import Directive
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.ext.autodoc import Options
|
||||
|
||||
|
||||
# -- autosummary_toc node ------------------------------------------------------
|
||||
@ -130,7 +132,7 @@ def autosummary_table_visit_html(self, node):
|
||||
|
||||
class FakeDirective:
|
||||
env = {}
|
||||
genopt = {}
|
||||
genopt = Options()
|
||||
|
||||
def get_documenter(obj, parent):
|
||||
"""Get an autodoc.Documenter class suitable for documenting the given
|
||||
@ -193,7 +195,7 @@ class Autosummary(Directive):
|
||||
|
||||
def run(self):
|
||||
self.env = env = self.state.document.settings.env
|
||||
self.genopt = {}
|
||||
self.genopt = Options()
|
||||
self.warnings = []
|
||||
self.result = ViewList()
|
||||
|
||||
@ -253,7 +255,7 @@ class Autosummary(Directive):
|
||||
|
||||
self.result = ViewList() # initialize for each documenter
|
||||
full_name = real_name
|
||||
if full_name.startswith(modname + '.'):
|
||||
if not isinstance(obj, ModuleType):
|
||||
# give explicitly separated module name, so that members
|
||||
# of inner classes can be documented
|
||||
full_name = modname + '::' + full_name[len(modname)+1:]
|
||||
@ -268,6 +270,8 @@ class Autosummary(Directive):
|
||||
self.warn('failed to import object %s' % real_name)
|
||||
items.append((display_name, '', '', real_name))
|
||||
continue
|
||||
if not documenter.check_module():
|
||||
continue
|
||||
|
||||
# try to also get a source code analyzer for attribute docs
|
||||
try:
|
||||
@ -432,11 +436,11 @@ def get_import_prefixes_from_env(env):
|
||||
"""
|
||||
prefixes = [None]
|
||||
|
||||
currmodule = env.temp_data.get('py:module')
|
||||
currmodule = env.ref_context.get('py:module')
|
||||
if currmodule:
|
||||
prefixes.insert(0, currmodule)
|
||||
|
||||
currclass = env.temp_data.get('py:class')
|
||||
currclass = env.ref_context.get('py:class')
|
||||
if currclass:
|
||||
if currmodule:
|
||||
prefixes.insert(0, currmodule + "." + currclass)
|
||||
@ -570,4 +574,4 @@ def setup(app):
|
||||
app.connect('doctree-read', process_autosummary_toc)
|
||||
app.connect('builder-inited', process_generate_options)
|
||||
app.add_config_value('autosummary_generate', [], True)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -14,7 +14,7 @@
|
||||
generate:
|
||||
sphinx-autogen -o source/generated source/*.rst
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
@ -6,7 +6,7 @@
|
||||
Check Python modules and C API for coverage. Mostly written by Josip
|
||||
Dzolonga for the Google Highly Open Participation contest.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -84,7 +84,7 @@ class CoverageBuilder(Builder):
|
||||
# Fetch all the info from the header files
|
||||
c_objects = self.env.domaindata['c']['objects']
|
||||
for filename in self.c_sourcefiles:
|
||||
undoc = []
|
||||
undoc = set()
|
||||
f = open(filename, 'r')
|
||||
try:
|
||||
for line in f:
|
||||
@ -97,7 +97,7 @@ class CoverageBuilder(Builder):
|
||||
if exp.match(name):
|
||||
break
|
||||
else:
|
||||
undoc.append((key, name))
|
||||
undoc.add((key, name))
|
||||
continue
|
||||
finally:
|
||||
f.close()
|
||||
@ -114,7 +114,7 @@ class CoverageBuilder(Builder):
|
||||
|
||||
for filename, undoc in iteritems(self.c_undoc):
|
||||
write_header(op, filename)
|
||||
for typ, name in undoc:
|
||||
for typ, name in sorted(undoc):
|
||||
op.write(' * %-50s [%9s]\n' % (name, typ))
|
||||
op.write('\n')
|
||||
finally:
|
||||
@ -265,4 +265,4 @@ def setup(app):
|
||||
app.add_config_value('coverage_ignore_c_items', {}, False)
|
||||
app.add_config_value('coverage_write_headline', True, False)
|
||||
app.add_config_value('coverage_skip_undoc_in_source', False, False)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -6,7 +6,7 @@
|
||||
Mimic doctest by automatically executing code snippets and checking
|
||||
their results.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -32,6 +32,7 @@ from sphinx.util.console import bold
|
||||
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
|
||||
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
|
||||
|
||||
|
||||
# set up the necessary directives
|
||||
|
||||
class TestDirective(Directive):
|
||||
@ -79,30 +80,35 @@ class TestDirective(Directive):
|
||||
option_strings = self.options['options'].replace(',', ' ').split()
|
||||
for option in option_strings:
|
||||
if (option[0] not in '+-' or option[1:] not in
|
||||
doctest.OPTIONFLAGS_BY_NAME):
|
||||
doctest.OPTIONFLAGS_BY_NAME):
|
||||
# XXX warn?
|
||||
continue
|
||||
flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]]
|
||||
node['options'][flag] = (option[0] == '+')
|
||||
return [node]
|
||||
|
||||
|
||||
class TestsetupDirective(TestDirective):
|
||||
option_spec = {}
|
||||
|
||||
|
||||
class TestcleanupDirective(TestDirective):
|
||||
option_spec = {}
|
||||
|
||||
|
||||
class DoctestDirective(TestDirective):
|
||||
option_spec = {
|
||||
'hide': directives.flag,
|
||||
'options': directives.unchanged,
|
||||
}
|
||||
|
||||
|
||||
class TestcodeDirective(TestDirective):
|
||||
option_spec = {
|
||||
'hide': directives.flag,
|
||||
}
|
||||
|
||||
|
||||
class TestoutputDirective(TestDirective):
|
||||
option_spec = {
|
||||
'hide': directives.flag,
|
||||
@ -112,6 +118,7 @@ class TestoutputDirective(TestDirective):
|
||||
|
||||
parser = doctest.DocTestParser()
|
||||
|
||||
|
||||
# helper classes
|
||||
|
||||
class TestGroup(object):
|
||||
@ -196,7 +203,7 @@ class DocTestBuilder(Builder):
|
||||
def init(self):
|
||||
# default options
|
||||
self.opt = doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | \
|
||||
doctest.IGNORE_EXCEPTION_DETAIL
|
||||
doctest.IGNORE_EXCEPTION_DETAIL
|
||||
|
||||
# HACK HACK HACK
|
||||
# doctest compiles its snippets with type 'single'. That is nice
|
||||
@ -247,6 +254,10 @@ Results of doctest builder run on %s
|
||||
# write executive summary
|
||||
def s(v):
|
||||
return v != 1 and 's' or ''
|
||||
repl = (self.total_tries, s(self.total_tries),
|
||||
self.total_failures, s(self.total_failures),
|
||||
self.setup_failures, s(self.setup_failures),
|
||||
self.cleanup_failures, s(self.cleanup_failures))
|
||||
self._out('''
|
||||
Doctest summary
|
||||
===============
|
||||
@ -254,10 +265,7 @@ Doctest summary
|
||||
%5d failure%s in tests
|
||||
%5d failure%s in setup code
|
||||
%5d failure%s in cleanup code
|
||||
''' % (self.total_tries, s(self.total_tries),
|
||||
self.total_failures, s(self.total_failures),
|
||||
self.setup_failures, s(self.setup_failures),
|
||||
self.cleanup_failures, s(self.cleanup_failures)))
|
||||
''' % repl)
|
||||
self.outfile.close()
|
||||
|
||||
if self.total_failures or self.setup_failures or self.cleanup_failures:
|
||||
@ -290,11 +298,11 @@ Doctest summary
|
||||
def condition(node):
|
||||
return (isinstance(node, (nodes.literal_block, nodes.comment))
|
||||
and 'testnodetype' in node) or \
|
||||
isinstance(node, nodes.doctest_block)
|
||||
isinstance(node, nodes.doctest_block)
|
||||
else:
|
||||
def condition(node):
|
||||
return isinstance(node, (nodes.literal_block, nodes.comment)) \
|
||||
and 'testnodetype' in node
|
||||
and 'testnodetype' in node
|
||||
for node in doctree.traverse(condition):
|
||||
source = 'test' in node and node['test'] or node.astext()
|
||||
if not source:
|
||||
@ -364,7 +372,7 @@ Doctest summary
|
||||
filename, 0, None)
|
||||
sim_doctest.globs = ns
|
||||
old_f = runner.failures
|
||||
self.type = 'exec' # the snippet may contain multiple statements
|
||||
self.type = 'exec' # the snippet may contain multiple statements
|
||||
runner.run(sim_doctest, out=self._warn_out, clear_globs=False)
|
||||
if runner.failures > old_f:
|
||||
return False
|
||||
@ -394,7 +402,7 @@ Doctest summary
|
||||
new_opt = code[0].options.copy()
|
||||
new_opt.update(example.options)
|
||||
example.options = new_opt
|
||||
self.type = 'single' # as for ordinary doctests
|
||||
self.type = 'single' # as for ordinary doctests
|
||||
else:
|
||||
# testcode and output separate
|
||||
output = code[1] and code[1].code or ''
|
||||
@ -413,7 +421,7 @@ Doctest summary
|
||||
options=options)
|
||||
test = doctest.DocTest([example], {}, group.name,
|
||||
filename, code[0].lineno, None)
|
||||
self.type = 'exec' # multiple statements again
|
||||
self.type = 'exec' # multiple statements again
|
||||
# DocTest.__init__ copies the globs namespace, which we don't want
|
||||
test.globs = ns
|
||||
# also don't clear the globs namespace after running the doctest
|
||||
@ -435,4 +443,4 @@ def setup(app):
|
||||
app.add_config_value('doctest_test_doctest_blocks', 'default', False)
|
||||
app.add_config_value('doctest_global_setup', '', False)
|
||||
app.add_config_value('doctest_global_cleanup', '', False)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -59,4 +59,4 @@ def setup_link_roles(app):
|
||||
def setup(app):
|
||||
app.add_config_value('extlinks', {}, 'env')
|
||||
app.connect('builder-inited', setup_link_roles)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -6,7 +6,7 @@
|
||||
Allow graphviz-formatted graphs to be included in Sphinx-generated
|
||||
documents inline.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -146,14 +146,8 @@ def render_dot(self, code, options, format, prefix='graphviz'):
|
||||
).encode('utf-8')
|
||||
|
||||
fname = '%s-%s.%s' % (prefix, sha1(hashkey).hexdigest(), format)
|
||||
if hasattr(self.builder, 'imgpath'):
|
||||
# HTML
|
||||
relfn = posixpath.join(self.builder.imgpath, fname)
|
||||
outfn = path.join(self.builder.outdir, '_images', fname)
|
||||
else:
|
||||
# LaTeX
|
||||
relfn = fname
|
||||
outfn = path.join(self.builder.outdir, fname)
|
||||
relfn = posixpath.join(self.builder.imgpath, fname)
|
||||
outfn = path.join(self.builder.outdir, self.builder.imagedir, fname)
|
||||
|
||||
if path.isfile(outfn):
|
||||
return relfn, outfn
|
||||
@ -323,4 +317,4 @@ def setup(app):
|
||||
app.add_config_value('graphviz_dot', 'dot', 'html')
|
||||
app.add_config_value('graphviz_dot_args', [], 'html')
|
||||
app.add_config_value('graphviz_output_format', 'png', 'html')
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -16,7 +16,7 @@
|
||||
namespace of the project configuration (that is, all variables from
|
||||
``conf.py`` are available.)
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -49,7 +49,8 @@ class IfConfig(Directive):
|
||||
|
||||
|
||||
def process_ifconfig_nodes(app, doctree, docname):
|
||||
ns = app.config.__dict__.copy()
|
||||
ns = {k: app.config[k] for k in app.config.values}
|
||||
ns.update(app.config.__dict__.copy())
|
||||
ns['builder'] = app.builder.name
|
||||
for node in doctree.traverse(ifconfig):
|
||||
try:
|
||||
@ -73,4 +74,4 @@ def setup(app):
|
||||
app.add_node(ifconfig)
|
||||
app.add_directive('ifconfig', IfConfig)
|
||||
app.connect('doctree-resolved', process_ifconfig_nodes)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -32,20 +32,21 @@ r"""
|
||||
The graph is inserted as a PNG+image map into HTML and a PDF in
|
||||
LaTeX.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import inspect
|
||||
import __builtin__ as __builtin__ # as __builtin__ is for lib2to3 compatibility
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
from md5 import md5
|
||||
|
||||
from six import text_type
|
||||
from six.moves import builtins
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
@ -147,10 +148,10 @@ class InheritanceGraph(object):
|
||||
displayed node names.
|
||||
"""
|
||||
all_classes = {}
|
||||
builtins = vars(__builtin__).values()
|
||||
py_builtins = vars(builtins).values()
|
||||
|
||||
def recurse(cls):
|
||||
if not show_builtins and cls in builtins:
|
||||
if not show_builtins and cls in py_builtins:
|
||||
return
|
||||
if not private_bases and cls.__name__.startswith('_'):
|
||||
return
|
||||
@ -174,7 +175,7 @@ class InheritanceGraph(object):
|
||||
baselist = []
|
||||
all_classes[cls] = (nodename, fullname, baselist, tooltip)
|
||||
for base in cls.__bases__:
|
||||
if not show_builtins and base in builtins:
|
||||
if not show_builtins and base in py_builtins:
|
||||
continue
|
||||
if not private_bases and base.__name__.startswith('_'):
|
||||
continue
|
||||
@ -185,7 +186,7 @@ class InheritanceGraph(object):
|
||||
for cls in classes:
|
||||
recurse(cls)
|
||||
|
||||
return all_classes.values()
|
||||
return list(all_classes.values())
|
||||
|
||||
def class_name(self, cls, parts=0):
|
||||
"""Given a class object, return a fully-qualified name.
|
||||
@ -194,7 +195,7 @@ class InheritanceGraph(object):
|
||||
completely general.
|
||||
"""
|
||||
module = cls.__module__
|
||||
if module == '__builtin__':
|
||||
if module in ('__builtin__', 'builtins'):
|
||||
fullname = cls.__name__
|
||||
else:
|
||||
fullname = '%s.%s' % (module, cls.__name__)
|
||||
@ -310,7 +311,7 @@ class InheritanceDiagram(Directive):
|
||||
# Create a graph starting with the list of classes
|
||||
try:
|
||||
graph = InheritanceGraph(
|
||||
class_names, env.temp_data.get('py:module'),
|
||||
class_names, env.ref_context.get('py:module'),
|
||||
parts=node['parts'],
|
||||
private_bases='private-bases' in self.options)
|
||||
except InheritanceException as err:
|
||||
@ -407,4 +408,4 @@ def setup(app):
|
||||
app.add_config_value('inheritance_graph_attrs', {}, False),
|
||||
app.add_config_value('inheritance_node_attrs', {}, False),
|
||||
app.add_config_value('inheritance_edge_attrs', {}, False),
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -20,7 +20,7 @@
|
||||
also be specified individually, e.g. if the docs should be buildable
|
||||
without Internet access.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -222,15 +222,21 @@ def load_mappings(app):
|
||||
|
||||
def missing_reference(app, env, node, contnode):
|
||||
"""Attempt to resolve a missing reference via intersphinx references."""
|
||||
domain = node.get('refdomain')
|
||||
if not domain:
|
||||
# only objects in domains are in the inventory
|
||||
return
|
||||
target = node['reftarget']
|
||||
objtypes = env.domains[domain].objtypes_for_role(node['reftype'])
|
||||
if not objtypes:
|
||||
return
|
||||
objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes]
|
||||
if node['reftype'] == 'any':
|
||||
# we search anything!
|
||||
objtypes = ['%s:%s' % (domain.name, objtype)
|
||||
for domain in env.domains.values()
|
||||
for objtype in domain.object_types]
|
||||
else:
|
||||
domain = node.get('refdomain')
|
||||
if not domain:
|
||||
# only objects in domains are in the inventory
|
||||
return
|
||||
objtypes = env.domains[domain].objtypes_for_role(node['reftype'])
|
||||
if not objtypes:
|
||||
return
|
||||
objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes]
|
||||
to_try = [(env.intersphinx_inventory, target)]
|
||||
in_set = None
|
||||
if ':' in target:
|
||||
@ -248,7 +254,7 @@ def missing_reference(app, env, node, contnode):
|
||||
# get correct path in case of subdirectories
|
||||
uri = path.join(relative_path(node['refdoc'], env.srcdir), uri)
|
||||
newnode = nodes.reference('', '', internal=False, refuri=uri,
|
||||
reftitle=_('(in %s v%s)') % (proj, version))
|
||||
reftitle=_('(in %s v%s)') % (proj, version))
|
||||
if node.get('refexplicit'):
|
||||
# use whatever title was given
|
||||
newnode.append(contnode)
|
||||
@ -276,4 +282,4 @@ def setup(app):
|
||||
app.add_config_value('intersphinx_cache_limit', 5, False)
|
||||
app.connect('missing-reference', missing_reference)
|
||||
app.connect('builder-inited', load_mappings)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -6,7 +6,7 @@
|
||||
Set up everything for use of JSMath to display math in HTML
|
||||
via JavaScript.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -57,4 +57,4 @@ def setup(app):
|
||||
mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None))
|
||||
app.add_config_value('jsmath_path', '', False)
|
||||
app.connect('builder-inited', builder_inited)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Add external links to module code in Python object descriptions.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -16,9 +16,11 @@ from sphinx import addnodes
|
||||
from sphinx.locale import _
|
||||
from sphinx.errors import SphinxError
|
||||
|
||||
|
||||
class LinkcodeError(SphinxError):
|
||||
category = "linkcode error"
|
||||
|
||||
|
||||
def doctree_read(app, doctree):
|
||||
env = app.builder.env
|
||||
|
||||
@ -68,7 +70,8 @@ def doctree_read(app, doctree):
|
||||
classes=['viewcode-link'])
|
||||
signode += onlynode
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect('doctree-read', doctree_read)
|
||||
app.add_config_value('linkcode_resolve', None, '')
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Set up math support in source files and LaTeX/text output.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
Sphinx's HTML writer -- requires the MathJax JavaScript library on your
|
||||
webserver/computer.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -64,9 +64,9 @@ def setup(app):
|
||||
# more information for mathjax secure url is here:
|
||||
# http://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
|
||||
app.add_config_value('mathjax_path',
|
||||
'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?'
|
||||
'https://cdn.mathjax.org/mathjax/latest/MathJax.js?'
|
||||
'config=TeX-AMS-MML_HTMLorMML', False)
|
||||
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
|
||||
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
|
||||
app.connect('builder-inited', builder_inited)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Support for NumPy and Google style docstrings.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -256,7 +256,7 @@ def setup(app):
|
||||
|
||||
for name, (default, rebuild) in iteritems(Config._config_values):
|
||||
app.add_config_value(name, default, rebuild)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
||||
|
||||
def _process_docstring(app, what, name, obj, options, lines):
|
||||
|
@ -7,7 +7,7 @@
|
||||
Classes for docstring parsing and formatting.
|
||||
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -23,8 +23,9 @@ from sphinx.util.pycompat import UnicodeMixin
|
||||
|
||||
|
||||
_directive_regex = re.compile(r'\.\. \S+::')
|
||||
_google_untyped_arg_regex = re.compile(r'\s*(\w+)\s*:\s*(.*)')
|
||||
_google_typed_arg_regex = re.compile(r'\s*(\w+)\s*\(\s*(.+?)\s*\)\s*:\s*(.*)')
|
||||
_google_untyped_arg_regex = re.compile(r'\s*(\*?\*?\w+)\s*:\s*(.*)')
|
||||
_google_typed_arg_regex = re.compile(r'\s*(\*?\*?\w+)\s*\(\s*(.+?)\s*\)\s*:'
|
||||
r'\s*(.*)')
|
||||
|
||||
|
||||
class GoogleDocstring(UnicodeMixin):
|
||||
@ -90,6 +91,7 @@ class GoogleDocstring(UnicodeMixin):
|
||||
<BLANKLINE>
|
||||
:returns: Description of return value.
|
||||
:rtype: str
|
||||
<BLANKLINE>
|
||||
|
||||
"""
|
||||
def __init__(self, docstring, config=None, app=None, what='', name='',
|
||||
@ -215,6 +217,11 @@ class GoogleDocstring(UnicodeMixin):
|
||||
_name = match.group(1)
|
||||
_desc = match.group(2)
|
||||
|
||||
if _name[:2] == '**':
|
||||
_name = r'\*\*'+_name[2:]
|
||||
elif _name[:1] == '*':
|
||||
_name = r'\*'+_name[1:]
|
||||
|
||||
if prefer_type and not _type:
|
||||
_type, _name = _name, _type
|
||||
indent = self._get_indent(line) + 1
|
||||
@ -254,6 +261,10 @@ class GoogleDocstring(UnicodeMixin):
|
||||
else:
|
||||
return []
|
||||
|
||||
def _consume_usage_section(self):
|
||||
lines = self._dedent(self._consume_to_next_section())
|
||||
return lines
|
||||
|
||||
def _consume_section_header(self):
|
||||
section = next(self._line_iter)
|
||||
stripped_section = section.strip(':')
|
||||
@ -291,11 +302,10 @@ class GoogleDocstring(UnicodeMixin):
|
||||
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)
|
||||
if i == 0:
|
||||
result_lines.append((prefix + line).rstrip())
|
||||
elif line:
|
||||
result_lines.append(padding + line)
|
||||
else:
|
||||
result_lines.append('')
|
||||
return result_lines
|
||||
@ -444,6 +454,13 @@ class GoogleDocstring(UnicodeMixin):
|
||||
use_admonition = self._config.napoleon_use_admonition_for_examples
|
||||
return self._parse_generic_section(section, use_admonition)
|
||||
|
||||
def _parse_usage_section(self, section):
|
||||
header = ['.. rubric:: Usage:', '']
|
||||
block = ['.. code-block:: python', '']
|
||||
lines = self._consume_usage_section()
|
||||
lines = self._indent(lines, 3)
|
||||
return header + block + lines + ['']
|
||||
|
||||
def _parse_generic_section(self, section, use_admonition):
|
||||
lines = self._strip_empty(self._consume_to_next_section())
|
||||
lines = self._dedent(lines)
|
||||
@ -664,6 +681,7 @@ class NumpyDocstring(GoogleDocstring):
|
||||
<BLANKLINE>
|
||||
:returns: Description of return value.
|
||||
:rtype: str
|
||||
<BLANKLINE>
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
@ -7,7 +7,7 @@
|
||||
A collection of helpful iterators.
|
||||
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Render math in HTML via dvipng.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -14,7 +14,7 @@ import codecs
|
||||
import shutil
|
||||
import tempfile
|
||||
import posixpath
|
||||
from os import path, getcwd, chdir
|
||||
from os import path
|
||||
from subprocess import Popen, PIPE
|
||||
from hashlib import sha1
|
||||
|
||||
@ -24,7 +24,7 @@ from docutils import nodes
|
||||
import sphinx
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.util.png import read_png_depth, write_png_depth
|
||||
from sphinx.util.osutil import ensuredir, ENOENT
|
||||
from sphinx.util.osutil import ensuredir, ENOENT, cd
|
||||
from sphinx.util.pycompat import sys_encoding
|
||||
from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath
|
||||
|
||||
@ -86,7 +86,7 @@ def render_math(self, math):
|
||||
|
||||
shasum = "%s.png" % sha1(latex.encode('utf-8')).hexdigest()
|
||||
relfn = posixpath.join(self.builder.imgpath, 'math', shasum)
|
||||
outfn = path.join(self.builder.outdir, '_images', 'math', shasum)
|
||||
outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', shasum)
|
||||
if path.isfile(outfn):
|
||||
depth = read_png_depth(outfn)
|
||||
return relfn, depth
|
||||
@ -116,10 +116,7 @@ def render_math(self, math):
|
||||
ltx_args.extend(self.builder.config.pngmath_latex_args)
|
||||
ltx_args.append('math.tex')
|
||||
|
||||
curdir = getcwd()
|
||||
chdir(tempdir)
|
||||
|
||||
try:
|
||||
with cd(tempdir):
|
||||
try:
|
||||
p = Popen(ltx_args, stdout=PIPE, stderr=PIPE)
|
||||
except OSError as err:
|
||||
@ -130,8 +127,6 @@ def render_math(self, math):
|
||||
self.builder.config.pngmath_latex)
|
||||
self.builder._mathpng_warned_latex = True
|
||||
return None, None
|
||||
finally:
|
||||
chdir(curdir)
|
||||
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
@ -246,4 +241,4 @@ def setup(app):
|
||||
app.add_config_value('pngmath_latex_preamble', '', 'html')
|
||||
app.add_config_value('pngmath_add_tooltips', True, 'html')
|
||||
app.connect('build-finished', cleanup_tempdir)
|
||||
return sphinx.__version__
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -8,7 +8,7 @@
|
||||
all todos of your project and lists them along with a backlink to the
|
||||
original location.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -150,6 +150,14 @@ def purge_todos(app, env, docname):
|
||||
if todo['docname'] != docname]
|
||||
|
||||
|
||||
def merge_info(app, env, docnames, other):
|
||||
if not hasattr(other, 'todo_all_todos'):
|
||||
return
|
||||
if not hasattr(env, 'todo_all_todos'):
|
||||
env.todo_all_todos = []
|
||||
env.todo_all_todos.extend(other.todo_all_todos)
|
||||
|
||||
|
||||
def visit_todo_node(self, node):
|
||||
self.visit_admonition(node)
|
||||
|
||||
@ -172,4 +180,5 @@ def setup(app):
|
||||
app.connect('doctree-read', process_todos)
|
||||
app.connect('doctree-resolved', process_todo_nodes)
|
||||
app.connect('env-purge-doc', purge_todos)
|
||||
return sphinx.__version__
|
||||
app.connect('env-merge-info', merge_info)
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Add links to module code in Python object descriptions.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -20,6 +20,7 @@ from sphinx.locale import _
|
||||
from sphinx.pycode import ModuleAnalyzer
|
||||
from sphinx.util import get_full_modname
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.console import blue
|
||||
|
||||
|
||||
def _get_full_modname(app, modname, attribute):
|
||||
@ -37,7 +38,7 @@ def _get_full_modname(app, modname, attribute):
|
||||
# It should be displayed only verbose mode.
|
||||
app.verbose(traceback.format_exc().rstrip())
|
||||
app.verbose('viewcode can\'t import %s, failed with error "%s"' %
|
||||
(modname, e))
|
||||
(modname, e))
|
||||
return None
|
||||
|
||||
|
||||
@ -100,6 +101,16 @@ def doctree_read(app, doctree):
|
||||
signode += onlynode
|
||||
|
||||
|
||||
def env_merge_info(app, env, docnames, other):
|
||||
if not hasattr(other, '_viewcode_modules'):
|
||||
return
|
||||
# create a _viewcode_modules dict on the main environment
|
||||
if not hasattr(env, '_viewcode_modules'):
|
||||
env._viewcode_modules = {}
|
||||
# now merge in the information from the subprocess
|
||||
env._viewcode_modules.update(other._viewcode_modules)
|
||||
|
||||
|
||||
def missing_reference(app, env, node, contnode):
|
||||
# resolve our "viewcode" reference nodes -- they need special treatment
|
||||
if node['reftype'] == 'viewcode':
|
||||
@ -116,10 +127,12 @@ def collect_pages(app):
|
||||
|
||||
modnames = set(env._viewcode_modules)
|
||||
|
||||
app.builder.info(' (%d module code pages)' %
|
||||
len(env._viewcode_modules), nonl=1)
|
||||
# app.builder.info(' (%d module code pages)' %
|
||||
# len(env._viewcode_modules), nonl=1)
|
||||
|
||||
for modname, entry in iteritems(env._viewcode_modules):
|
||||
for modname, entry in app.status_iterator(
|
||||
iteritems(env._viewcode_modules), 'highlighting module code... ',
|
||||
blue, len(env._viewcode_modules), lambda x: x[0]):
|
||||
if not entry:
|
||||
continue
|
||||
code, tags, used, refname = entry
|
||||
@ -162,15 +175,14 @@ def collect_pages(app):
|
||||
context = {
|
||||
'parents': parents,
|
||||
'title': modname,
|
||||
'body': _('<h1>Source code for %s</h1>') % modname + \
|
||||
'\n'.join(lines)
|
||||
'body': (_('<h1>Source code for %s</h1>') % modname +
|
||||
'\n'.join(lines)),
|
||||
}
|
||||
yield (pagename, context, 'page.html')
|
||||
|
||||
if not modnames:
|
||||
return
|
||||
|
||||
app.builder.info(' _modules/index', nonl=True)
|
||||
html = ['\n']
|
||||
# the stack logic is needed for using nested lists for submodules
|
||||
stack = ['']
|
||||
@ -190,8 +202,8 @@ def collect_pages(app):
|
||||
html.append('</ul>' * (len(stack) - 1))
|
||||
context = {
|
||||
'title': _('Overview: module code'),
|
||||
'body': _('<h1>All modules for which code is available</h1>') + \
|
||||
''.join(html),
|
||||
'body': (_('<h1>All modules for which code is available</h1>') +
|
||||
''.join(html)),
|
||||
}
|
||||
|
||||
yield ('_modules/index', context, 'page.html')
|
||||
@ -200,8 +212,9 @@ def collect_pages(app):
|
||||
def setup(app):
|
||||
app.add_config_value('viewcode_import', True, False)
|
||||
app.connect('doctree-read', doctree_read)
|
||||
app.connect('env-merge-info', env_merge_info)
|
||||
app.connect('html-collect-pages', collect_pages)
|
||||
app.connect('missing-reference', missing_reference)
|
||||
#app.add_config_value('viewcode_include_modules', [], 'env')
|
||||
#app.add_config_value('viewcode_exclude_modules', [], 'env')
|
||||
return sphinx.__version__
|
||||
# app.add_config_value('viewcode_include_modules', [], 'env')
|
||||
# app.add_config_value('viewcode_exclude_modules', [], 'env')
|
||||
return {'version': sphinx.__version__, 'parallel_read_safe': True}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Highlight code blocks using Pygments.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -24,46 +24,32 @@ from sphinx.util.pycompat import htmlescape
|
||||
from sphinx.util.texescape import tex_hl_escape_map_new
|
||||
from sphinx.ext import doctest
|
||||
|
||||
try:
|
||||
import pygments
|
||||
from pygments import highlight
|
||||
from pygments.lexers import PythonLexer, PythonConsoleLexer, CLexer, \
|
||||
TextLexer, RstLexer
|
||||
from pygments.lexers import get_lexer_by_name, guess_lexer
|
||||
from pygments.formatters import HtmlFormatter, LatexFormatter
|
||||
from pygments.filters import ErrorToken
|
||||
from pygments.styles import get_style_by_name
|
||||
from pygments.util import ClassNotFound
|
||||
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
||||
except ImportError:
|
||||
pygments = None
|
||||
lexers = None
|
||||
HtmlFormatter = LatexFormatter = None
|
||||
else:
|
||||
from pygments import highlight
|
||||
from pygments.lexers import PythonLexer, PythonConsoleLexer, CLexer, \
|
||||
TextLexer, RstLexer
|
||||
from pygments.lexers import get_lexer_by_name, guess_lexer
|
||||
from pygments.formatters import HtmlFormatter, LatexFormatter
|
||||
from pygments.filters import ErrorToken
|
||||
from pygments.styles import get_style_by_name
|
||||
from pygments.util import ClassNotFound
|
||||
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
||||
|
||||
lexers = dict(
|
||||
none = TextLexer(),
|
||||
python = PythonLexer(),
|
||||
pycon = PythonConsoleLexer(),
|
||||
pycon3 = PythonConsoleLexer(python3=True),
|
||||
rest = RstLexer(),
|
||||
c = CLexer(),
|
||||
)
|
||||
for _lexer in lexers.values():
|
||||
_lexer.add_filter('raiseonerror')
|
||||
lexers = dict(
|
||||
none = TextLexer(),
|
||||
python = PythonLexer(),
|
||||
pycon = PythonConsoleLexer(),
|
||||
pycon3 = PythonConsoleLexer(python3=True),
|
||||
rest = RstLexer(),
|
||||
c = CLexer(),
|
||||
)
|
||||
for _lexer in lexers.values():
|
||||
_lexer.add_filter('raiseonerror')
|
||||
|
||||
|
||||
escape_hl_chars = {ord(u'\\'): u'\\PYGZbs{}',
|
||||
ord(u'{'): u'\\PYGZob{}',
|
||||
ord(u'}'): u'\\PYGZcb{}'}
|
||||
|
||||
# used if Pygments is not available
|
||||
_LATEX_STYLES = r'''
|
||||
\newcommand\PYGZbs{\char`\\}
|
||||
\newcommand\PYGZob{\char`\{}
|
||||
\newcommand\PYGZcb{\char`\}}
|
||||
'''
|
||||
|
||||
# used if Pygments is available
|
||||
# use textcomp quote to get a true single quote
|
||||
_LATEX_ADD_STYLES = r'''
|
||||
@ -80,8 +66,6 @@ class PygmentsBridge(object):
|
||||
def __init__(self, dest='html', stylename='sphinx',
|
||||
trim_doctest_flags=False):
|
||||
self.dest = dest
|
||||
if not pygments:
|
||||
return
|
||||
if stylename is None or stylename == 'sphinx':
|
||||
style = SphinxStyle
|
||||
elif stylename == 'none':
|
||||
@ -150,11 +134,9 @@ class PygmentsBridge(object):
|
||||
else:
|
||||
return True
|
||||
|
||||
def highlight_block(self, source, lang, warn=None, force=False, **kwargs):
|
||||
def highlight_block(self, source, lang, opts=None, warn=None, force=False, **kwargs):
|
||||
if not isinstance(source, text_type):
|
||||
source = source.decode()
|
||||
if not pygments:
|
||||
return self.unhighlighted(source)
|
||||
|
||||
# find out which lexer to use
|
||||
if lang in ('py', 'python'):
|
||||
@ -182,7 +164,7 @@ class PygmentsBridge(object):
|
||||
lexer = lexers[lang]
|
||||
else:
|
||||
try:
|
||||
lexer = lexers[lang] = get_lexer_by_name(lang)
|
||||
lexer = lexers[lang] = get_lexer_by_name(lang, **opts or {})
|
||||
except ClassNotFound:
|
||||
if warn:
|
||||
warn('Pygments lexer name %r is not known' % lang)
|
||||
@ -213,11 +195,6 @@ class PygmentsBridge(object):
|
||||
return hlsource.translate(tex_hl_escape_map_new)
|
||||
|
||||
def get_stylesheet(self):
|
||||
if not pygments:
|
||||
if self.dest == 'latex':
|
||||
return _LATEX_STYLES
|
||||
# no HTML styles needed
|
||||
return ''
|
||||
formatter = self.get_formatter()
|
||||
if self.dest == 'html':
|
||||
return formatter.get_style_defs('.highlight')
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Glue code for the jinja2 templating engine.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user