Merge branch 'master' into ignore__all__

This commit is contained in:
Takeshi KOMIYA 2017-12-22 00:28:26 +09:00 committed by GitHub
commit ffa9d48d0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 844 additions and 369 deletions

View File

@ -49,7 +49,9 @@ Features added
* HTML themes can set up default sidebars through ``theme.conf`` * HTML themes can set up default sidebars through ``theme.conf``
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role * #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
* #4212: autosummary: catch all exceptions when importing modules * #4212: autosummary: catch all exceptions when importing modules
* #3991, #4080: Add :confval:`math_numfig` for equation numbering by section * #4166: Add :confval:`math_numfig` for equation numbering by section (refs:
#3991, #4080). Thanks to Oliver Jahn.
* #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, ...
* #947: autodoc now supports ignore-module-all to ignore a module's ``__all__`` * #947: autodoc now supports ignore-module-all to ignore a module's ``__all__``
@ -92,6 +94,8 @@ Bugs fixed
* #4094: C++, allow empty template argument lists. * #4094: C++, allow empty template argument lists.
* C++, also hyperlink types in the name of declarations with qualified names. * C++, also hyperlink types in the name of declarations with qualified names.
* C++, do not add index entries for declarations inside concepts. * C++, do not add index entries for declarations inside concepts.
* #4314: For PDF 'howto' documents, numbering of code-blocks differs from the
one of figures and tables
Testing Testing
-------- --------
@ -134,6 +138,8 @@ Bugs fixed
remote image remote image
* #1421: Respect the quiet flag in sphinx-quickstart * #1421: Respect the quiet flag in sphinx-quickstart
* #4281: Race conditions when creating output directory * #4281: Race conditions when creating output directory
* #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates
``\chapter`` commands
Testing Testing
-------- --------

View File

@ -141,6 +141,7 @@ Documentation using the nature theme
Documentation using another builtin theme Documentation using another builtin theme
----------------------------------------- -----------------------------------------
* Arcade: http://arcade.academy/ (sphinx_rtd_theme)
* Breathe: https://breathe.readthedocs.io/ (haiku) * Breathe: https://breathe.readthedocs.io/ (haiku)
* MPipe: https://vmlaker.github.io/mpipe/ (sphinx13) * MPipe: https://vmlaker.github.io/mpipe/ (sphinx13)
* NLTK: http://www.nltk.org/ (agogo) * NLTK: http://www.nltk.org/ (agogo)

View File

@ -341,20 +341,19 @@ General configuration
starting at ``1``. starting at ``1``.
- if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x`` - if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x``
the section number (top level sectioning; no ``x.`` if no section). the section number (top level sectioning; no ``x.`` if no section).
This naturally applies only if section numbering has been activated via This naturally applies only if section numbering has been activated via
the ``:numbered:`` option of the :rst:dir:`toctree` directive. the ``:numbered:`` option of the :rst:dir:`toctree` directive.
- ``2`` means that numbers will be ``x.y.1``, ``x.y.2``, ... if located in - ``2`` means that numbers will be ``x.y.1``, ``x.y.2``, ... if located in
a sub-section (but still ``x.1``, ``x.2``, ... if located directly under a a sub-section (but still ``x.1``, ``x.2``, ... if located directly under a
section and ``1``, ``2``, ... if not in any top level section.) section and ``1``, ``2``, ... if not in any top level section.)
- etc... - etc...
.. note::
The LaTeX builder currently ignores this configuration setting. It will
obey it at Sphinx 1.7.
.. versionadded:: 1.3 .. versionadded:: 1.3
.. versionchanged:: 1.7
The LaTeX builder obeys this setting (if :confval:`numfig` is set to
``True``).
.. confval:: tls_verify .. confval:: tls_verify
If true, Sphinx verifies server certifications. Default is ``True``. If true, Sphinx verifies server certifications. Default is ``True``.
@ -1624,10 +1623,15 @@ These options influence LaTeX output. See further :doc:`latex`.
.. confval:: latex_toplevel_sectioning .. confval:: latex_toplevel_sectioning
This value determines the topmost sectioning unit. It should be chosen from This value determines the topmost sectioning unit. It should be chosen from
``part``, ``chapter`` or ``section``. The default is ``None``; the topmost ``'part'``, ``'chapter'`` or ``'section'``. The default is ``None``;
sectioning unit is switched by documentclass. ``section`` is used if the topmost
sectioning unit is switched by documentclass: ``section`` is used if
documentclass will be ``howto``, otherwise ``chapter`` will be used. documentclass will be ``howto``, otherwise ``chapter`` will be used.
Note that if LaTeX uses ``\part`` command, then the numbering of sectioning
units one level deep gets off-sync with HTML numbering, because LaTeX
numbers continuously ``\chapter`` (or ``\section`` for ``howto``.)
.. versionadded:: 1.4 .. versionadded:: 1.4
.. confval:: latex_appendices .. confval:: latex_appendices

View File

@ -183,7 +183,7 @@
% control caption around literal-block % control caption around literal-block
\RequirePackage{capt-of} \RequirePackage{capt-of}
\RequirePackage{needspace} \RequirePackage{needspace}
\RequirePackage{remreset}% provides \@removefromreset
% to make pdf with correct encoded bookmarks in Japanese % to make pdf with correct encoded bookmarks in Japanese
% this should precede the hyperref package % this should precede the hyperref package
\ifx\kanjiskip\@undefined \ifx\kanjiskip\@undefined
@ -247,7 +247,9 @@
\fi \fi
\DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0} \DeclareStringOption[0]{maxlistdepth}% \newcommand*\spx@opt@maxlistdepth{0}
\DeclareStringOption[-1]{numfigreset}
\DeclareBoolOption[false]{nonumfigreset}
% \DeclareBoolOption[false]{usespart}% not used
% dimensions, we declare the \dimen registers here. % dimensions, we declare the \dimen registers here.
\newdimen\sphinxverbatimsep \newdimen\sphinxverbatimsep
\newdimen\sphinxverbatimborder \newdimen\sphinxverbatimborder
@ -349,6 +351,8 @@
\ProcessKeyvalOptions* \ProcessKeyvalOptions*
% don't allow use of maxlistdepth via \sphinxsetup. % don't allow use of maxlistdepth via \sphinxsetup.
\DisableKeyvalOption{sphinx}{maxlistdepth} \DisableKeyvalOption{sphinx}{maxlistdepth}
\DisableKeyvalOption{sphinx}{numfigreset}
\DisableKeyvalOption{sphinx}{nonumfigreset}
% user interface: options can be changed midway in a document! % user interface: options can be changed midway in a document!
\newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}} \newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}}
@ -657,6 +661,7 @@
{\abovecaptionskip\smallskipamount {\abovecaptionskip\smallskipamount
\belowcaptionskip\smallskipamount} \belowcaptionskip\smallskipamount}
%% FOOTNOTES %% FOOTNOTES
% %
% Support large numbered footnotes in minipage % Support large numbered footnotes in minipage
@ -665,6 +670,87 @@
\def\thempfootnote{\arabic{mpfootnote}} \def\thempfootnote{\arabic{mpfootnote}}
%% NUMBERING OF FIGURES, TABLES, AND LITERAL BLOCKS
\ltx@ifundefined{c@chapter}
{\newcounter{literalblock}}%
{\newcounter{literalblock}[chapter]%
\def\theliteralblock{\ifnum\c@chapter>\z@\arabic{chapter}.\fi
\arabic{literalblock}}%
}%
\ifspx@opt@nonumfigreset
\ltx@ifundefined{c@chapter}{}{%
\@removefromreset{figure}{chapter}%
\@removefromreset{table}{chapter}%
\@removefromreset{literalblock}{chapter}%
}%
\def\thefigure{\arabic{figure}}%
\def\thetable {\arabic{table}}%
\def\theliteralblock{\arabic{literalblock}}%
%\let\theHliteralblock\theliteralblock
\else
\let\spx@preAthefigure\@empty
\let\spx@preBthefigure\@empty
% \ifspx@opt@usespart % <-- LaTeX writer could pass such a 'usespart' boolean
% % as sphinx.sty package option
% If document uses \part, (triggered in Sphinx by latex_toplevel_sectioning)
% LaTeX core per default does not reset chapter or section
% counters at each part.
% But if we modify this, we need to redefine \thechapter, \thesection to
% include the part number and this will cause problems in table of contents
% because of too wide numbering. Simplest is to do nothing.
% \fi
\ifnum\spx@opt@numfigreset>0
\ltx@ifundefined{c@chapter}
{}
{\g@addto@macro\spx@preAthefigure{\ifnum\c@chapter>\z@\arabic{chapter}.}%
\g@addto@macro\spx@preBthefigure{\fi}}%
\fi
\ifnum\spx@opt@numfigreset>1
\@addtoreset{figure}{section}%
\@addtoreset{table}{section}%
\@addtoreset{literalblock}{section}%
\g@addto@macro\spx@preAthefigure{\ifnum\c@section>\z@\arabic{section}.}%
\g@addto@macro\spx@preBthefigure{\fi}%
\fi
\ifnum\spx@opt@numfigreset>2
\@addtoreset{figure}{subsection}%
\@addtoreset{table}{subsection}%
\@addtoreset{literalblock}{subsection}%
\g@addto@macro\spx@preAthefigure{\ifnum\c@subsection>\z@\arabic{subsection}.}%
\g@addto@macro\spx@preBthefigure{\fi}%
\fi
\ifnum\spx@opt@numfigreset>3
\@addtoreset{figure}{subsubsection}%
\@addtoreset{table}{subsubsection}%
\@addtoreset{literalblock}{subsubsection}%
\g@addto@macro\spx@preAthefigure{\ifnum\c@subsubsection>\z@\arabic{subsubsection}.}%
\g@addto@macro\spx@preBthefigure{\fi}%
\fi
\ifnum\spx@opt@numfigreset>4
\@addtoreset{figure}{paragraph}%
\@addtoreset{table}{paragraph}%
\@addtoreset{literalblock}{paragraph}%
\g@addto@macro\spx@preAthefigure{\ifnum\c@subparagraph>\z@\arabic{subparagraph}.}%
\g@addto@macro\spx@preBthefigure{\fi}%
\fi
\ifnum\spx@opt@numfigreset>5
\@addtoreset{figure}{subparagraph}%
\@addtoreset{table}{subparagraph}%
\@addtoreset{literalblock}{subparagraph}%
\g@addto@macro\spx@preAthefigure{\ifnum\c@subsubparagraph>\z@\arabic{subsubparagraph}.}%
\g@addto@macro\spx@preBthefigure{\fi}%
\fi
\expandafter\g@addto@macro
\expandafter\spx@preAthefigure\expandafter{\spx@preBthefigure}%
\let\thefigure\spx@preAthefigure
\let\thetable\spx@preAthefigure
\let\theliteralblock\spx@preAthefigure
\g@addto@macro\thefigure{\arabic{figure}}%
\g@addto@macro\thetable{\arabic{table}}%
\g@addto@macro\theliteralblock{\arabic{literalblock}}%
\fi
%% LITERAL BLOCKS %% LITERAL BLOCKS
% %
% Based on use of "fancyvrb.sty"'s Verbatim. % Based on use of "fancyvrb.sty"'s Verbatim.
@ -680,15 +766,6 @@
\let\endOriginalVerbatim\endVerbatim \let\endOriginalVerbatim\endVerbatim
% for captions of literal blocks % for captions of literal blocks
% also define `\theH...` macros for hyperref
\newcounter{literalblock}
\ltx@ifundefined{c@chapter}
{\@addtoreset{literalblock}{section}
\def\theliteralblock {\ifnum\c@section>\z@ \thesection.\fi\arabic{literalblock}}
\def\theHliteralblock {\theHsection.\arabic{literalblock}}}
{\@addtoreset{literalblock}{chapter}
\def\theliteralblock {\ifnum\c@chapter>\z@ \thechapter.\fi\arabic{literalblock}}
\def\theHliteralblock {\theHchapter.\arabic{literalblock}}}
% at start of caption title % at start of caption title
\newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock} \newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock}
% this will be overwritten in document preamble by Babel translation % this will be overwritten in document preamble by Babel translation

View File

@ -48,7 +48,8 @@ BEGIN_DOC = r'''
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:') URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
SECNUMDEPTH = 3 LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
DEFAULT_SETTINGS = { DEFAULT_SETTINGS = {
'latex_engine': 'pdflatex', 'latex_engine': 'pdflatex',
@ -501,9 +502,9 @@ def rstdim_to_latexdim(width_str):
class LaTeXTranslator(nodes.NodeVisitor): class LaTeXTranslator(nodes.NodeVisitor):
sectionnames = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
secnumdepth = 2 # legacy sphinxhowto.cls uses this, whereas article.cls
# default is originally 3. For book/report, 2 is already LaTeX default.
ignore_missing_images = False ignore_missing_images = False
# sphinx specific document classes # sphinx specific document classes
@ -532,16 +533,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.compact_list = 0 self.compact_list = 0
self.first_param = 0 self.first_param = 0
# determine top section level
if builder.config.latex_toplevel_sectioning:
self.top_sectionlevel = \
self.sectionnames.index(builder.config.latex_toplevel_sectioning)
else:
if document.settings.docclass == 'howto':
self.top_sectionlevel = 2
else:
self.top_sectionlevel = 1
# sort out some elements # sort out some elements
self.elements = DEFAULT_SETTINGS.copy() self.elements = DEFAULT_SETTINGS.copy()
self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {})) self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
@ -562,16 +553,55 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.elements.update({ self.elements.update({
'releasename': _('Release'), 'releasename': _('Release'),
}) })
# we assume LaTeX class provides \chapter command except in case
# of non-Japanese 'howto' case
self.sectionnames = LATEXSECTIONNAMES[:]
if document.settings.docclass == 'howto': if document.settings.docclass == 'howto':
docclass = builder.config.latex_docclass.get('howto', 'article') docclass = builder.config.latex_docclass.get('howto', 'article')
if docclass[0] == 'j': # Japanese class...
pass
else:
self.sectionnames.remove('chapter')
else: else:
docclass = builder.config.latex_docclass.get('manual', 'report') docclass = builder.config.latex_docclass.get('manual', 'report')
self.elements['docclass'] = docclass self.elements['docclass'] = docclass
# determine top section level
self.top_sectionlevel = 1
if builder.config.latex_toplevel_sectioning:
try:
self.top_sectionlevel = \
self.sectionnames.index(builder.config.latex_toplevel_sectioning)
except ValueError:
logger.warning('unknown %r toplevel_sectioning for class %r' %
(builder.config.latex_toplevel_sectioning, docclass))
if builder.config.today: if builder.config.today:
self.elements['date'] = builder.config.today self.elements['date'] = builder.config.today
else: else:
self.elements['date'] = format_date(builder.config.today_fmt or _('%b %d, %Y'), # type: ignore # NOQA self.elements['date'] = format_date(builder.config.today_fmt or _('%b %d, %Y'), # type: ignore # NOQA
language=builder.config.language) language=builder.config.language)
if builder.config.numfig:
self.numfig_secnum_depth = builder.config.numfig_secnum_depth
if self.numfig_secnum_depth > 0: # default is 1
# numfig_secnum_depth as passed to sphinx.sty indices same names as in
# LATEXSECTIONNAMES but with -1 for part, 0 for chapter, 1 for section...
if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \
self.top_sectionlevel > 0:
self.numfig_secnum_depth += self.top_sectionlevel
else:
self.numfig_secnum_depth += self.top_sectionlevel - 1
# this (minus one) will serve as minimum to LaTeX's secnumdepth
self.numfig_secnum_depth = min(self.numfig_secnum_depth,
len(LATEXSECTIONNAMES) - 1)
# if passed key value is < 1 LaTeX will act as if 0; see sphinx.sty
self.elements['sphinxpkgoptions'] += \
(',numfigreset=%s' % self.numfig_secnum_depth)
else:
self.elements['sphinxpkgoptions'] += ',nonumfigreset'
if builder.config.latex_logo: if builder.config.latex_logo:
# no need for \\noindent here, used in flushright # no need for \\noindent here, used in flushright
self.elements['logo'] = '\\sphinxincludegraphics{%s}\\par' % \ self.elements['logo'] = '\\sphinxincludegraphics{%s}\\par' % \
@ -628,23 +658,32 @@ class LaTeXTranslator(nodes.NodeVisitor):
return '\\usepackage{%s}' % (packagename,) return '\\usepackage{%s}' % (packagename,)
usepackages = (declare_package(*p) for p in builder.usepackages) usepackages = (declare_package(*p) for p in builder.usepackages)
self.elements['usepackages'] += "\n".join(usepackages) self.elements['usepackages'] += "\n".join(usepackages)
minsecnumdepth = self.secnumdepth # 2 from legacy sphinx manual/howto
if document.get('tocdepth'): if document.get('tocdepth'):
# redece tocdepth if `part` or `chapter` is used for top_sectionlevel # reduce tocdepth if `part` or `chapter` is used for top_sectionlevel
# tocdepth = -1: show only parts # tocdepth = -1: show only parts
# tocdepth = 0: show parts and chapters # tocdepth = 0: show parts and chapters
# tocdepth = 1: show parts, chapters and sections # tocdepth = 1: show parts, chapters and sections
# tocdepth = 2: show parts, chapters, sections and subsections # tocdepth = 2: show parts, chapters, sections and subsections
# ... # ...
tocdepth = document['tocdepth'] + self.top_sectionlevel - 2 tocdepth = document['tocdepth'] + self.top_sectionlevel - 2
maxdepth = len(self.sectionnames) - self.top_sectionlevel if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \
if tocdepth > maxdepth: self.top_sectionlevel > 0:
tocdepth += 1 # because top_sectionlevel is shifted by -1
if tocdepth > len(LATEXSECTIONNAMES) - 2: # default is 5 <-> subparagraph
logger.warning('too large :maxdepth:, ignored.') logger.warning('too large :maxdepth:, ignored.')
tocdepth = maxdepth tocdepth = len(LATEXSECTIONNAMES) - 2
self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth
if tocdepth >= SECNUMDEPTH: minsecnumdepth = max(minsecnumdepth, tocdepth)
# Increase secnumdepth if tocdepth is depther than default SECNUMDEPTH
self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' % tocdepth if builder.config.numfig and (builder.config.numfig_secnum_depth > 0):
minsecnumdepth = max(minsecnumdepth, self.numfig_secnum_depth - 1)
if minsecnumdepth > self.secnumdepth:
self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' %\
minsecnumdepth
if getattr(document.settings, 'contentsname', None): if getattr(document.settings, 'contentsname', None):
self.elements['contentsname'] = \ self.elements['contentsname'] = \

View File

@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
import enum
from six import StringIO, add_metaclass
from sphinx.ext.autodoc import add_documenter # NOQA
__all__ = ['Class']
#: documentation for the integer
integer = 1
def raises(exc, func, *args, **kwds):
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*."""
pass
class CustomEx(Exception):
"""My custom exception."""
def f(self):
"""Exception method."""
class CustomDataDescriptor(object):
"""Descriptor class docstring."""
def __init__(self, doc):
self.__doc__ = doc
def __get__(self, obj, type=None):
if obj is None:
return self
return 42
def meth(self):
"""Function."""
return "The Answer"
class CustomDataDescriptorMeta(type):
"""Descriptor metaclass docstring."""
@add_metaclass(CustomDataDescriptorMeta)
class CustomDataDescriptor2(CustomDataDescriptor):
"""Descriptor class with custom metaclass docstring."""
def _funky_classmethod(name, b, c, d, docstring=None):
"""Generates a classmethod for a class from a template by filling out
some arguments."""
def template(cls, a, b, c, d=4, e=5, f=6):
return a, b, c, d, e, f
from functools import partial
function = partial(template, b=b, c=c, d=d)
function.__name__ = name
function.__doc__ = docstring
return classmethod(function)
class Base(object):
def inheritedmeth(self):
"""Inherited function."""
class Derived(Base):
def inheritedmeth(self):
# no docstring here
pass
class Class(Base):
"""Class to document."""
descr = CustomDataDescriptor("Descriptor instance docstring.")
def meth(self):
"""Function."""
def undocmeth(self):
pass
def skipmeth(self):
"""Method that should be skipped."""
def excludemeth(self):
"""Method that should be excluded."""
# should not be documented
skipattr = 'foo'
#: should be documented -- süß
attr = 'bar'
@property
def prop(self):
"""Property."""
docattr = 'baz'
"""should likewise be documented -- süß"""
udocattr = 'quux'
u"""should be documented as well - süß"""
# initialized to any class imported from another module
mdocattr = StringIO()
"""should be documented as well - süß"""
roger = _funky_classmethod("roger", 2, 3, 4)
moore = _funky_classmethod("moore", 9, 8, 7,
docstring="moore(a, e, f) -> happiness")
def __init__(self, arg):
self.inst_attr_inline = None #: an inline documented instance attr
#: a documented instance attribute
self.inst_attr_comment = None
self.inst_attr_string = None
"""a documented instance attribute"""
self._private_inst_attr = None #: a private instance attribute
def __special1__(self):
"""documented special method"""
def __special2__(self):
# undocumented special method
pass
class CustomDict(dict):
"""Docstring."""
def function(foo, *args, **kwds):
"""
Return spam.
"""
pass
class Outer(object):
"""Foo"""
class Inner(object):
"""Foo"""
def meth(self):
"""Foo"""
# should be documented as an alias
factory = dict
class DocstringSig(object):
def meth(self):
"""meth(FOO, BAR=1) -> BAZ
First line of docstring
rest of docstring
"""
def meth2(self):
"""First line, no signature
Second line followed by indentation::
indented line
"""
@property
def prop1(self):
"""DocstringSig.prop1(self)
First line of docstring
"""
return 123
@property
def prop2(self):
"""First line of docstring
Second line of docstring
"""
return 456
class StrRepr(str):
def __repr__(self):
return self
class AttCls(object):
a1 = StrRepr('hello\nworld')
a2 = None
class InstAttCls(object):
"""Class with documented class and instance attributes."""
#: Doc comment for class attribute InstAttCls.ca1.
#: It can have multiple lines.
ca1 = 'a'
ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only.
ca3 = 'c'
"""Docstring for class attribute InstAttCls.ca3."""
def __init__(self):
#: Doc comment for instance attribute InstAttCls.ia1
self.ia1 = 'd'
self.ia2 = 'e'
"""Docstring for instance attribute InstAttCls.ia2."""
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
latex_documents = [
('indexmanual', 'SphinxManual.tex', 'Test numfig manual',
'Sphinx', 'manual'),
('indexhowto', 'SphinxHowTo.tex', 'Test numfig howto',
'Sphinx', 'howto'),
]

View File

@ -0,0 +1,9 @@
=================
test-latex-numfig
=================
.. toctree::
:numbered:
indexmanual
indexhowto

View File

@ -0,0 +1,10 @@
=======================
test-latex-numfig-howto
=======================
This is a part
==============
This is a section
-----------------

View File

@ -0,0 +1,13 @@
========================
test-latex-numfig-manual
========================
First part
==========
This is chapter
---------------
This is section
~~~~~~~~~~~~~~~

View File

@ -5,7 +5,7 @@ Just testing a few autodoc possibilities...
.. automodule:: util .. automodule:: util
.. automodule:: test_autodoc .. automodule:: autodoc_target
:members: :members:
.. autofunction:: function .. autofunction:: function
@ -34,7 +34,7 @@ Just testing a few autodoc possibilities...
.. autoclass:: MarkupError .. autoclass:: MarkupError
.. currentmodule:: test_autodoc .. currentmodule:: autodoc_target
.. autoclass:: InstAttCls .. autoclass:: InstAttCls
:members: :members:

View File

@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
import enum
from six import StringIO, add_metaclass
from sphinx.ext.autodoc import add_documenter # NOQA
__all__ = ['Class']
#: documentation for the integer
integer = 1
def raises(exc, func, *args, **kwds):
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*."""
pass
class CustomEx(Exception):
"""My custom exception."""
def f(self):
"""Exception method."""
class CustomDataDescriptor(object):
"""Descriptor class docstring."""
def __init__(self, doc):
self.__doc__ = doc
def __get__(self, obj, type=None):
if obj is None:
return self
return 42
def meth(self):
"""Function."""
return "The Answer"
class CustomDataDescriptorMeta(type):
"""Descriptor metaclass docstring."""
@add_metaclass(CustomDataDescriptorMeta)
class CustomDataDescriptor2(CustomDataDescriptor):
"""Descriptor class with custom metaclass docstring."""
def _funky_classmethod(name, b, c, d, docstring=None):
"""Generates a classmethod for a class from a template by filling out
some arguments."""
def template(cls, a, b, c, d=4, e=5, f=6):
return a, b, c, d, e, f
from functools import partial
function = partial(template, b=b, c=c, d=d)
function.__name__ = name
function.__doc__ = docstring
return classmethod(function)
class Base(object):
def inheritedmeth(self):
"""Inherited function."""
class Derived(Base):
def inheritedmeth(self):
# no docstring here
pass
class Class(Base):
"""Class to document."""
descr = CustomDataDescriptor("Descriptor instance docstring.")
def meth(self):
"""Function."""
def undocmeth(self):
pass
def skipmeth(self):
"""Method that should be skipped."""
def excludemeth(self):
"""Method that should be excluded."""
# should not be documented
skipattr = 'foo'
#: should be documented -- süß
attr = 'bar'
@property
def prop(self):
"""Property."""
docattr = 'baz'
"""should likewise be documented -- süß"""
udocattr = 'quux'
u"""should be documented as well - süß"""
# initialized to any class imported from another module
mdocattr = StringIO()
"""should be documented as well - süß"""
roger = _funky_classmethod("roger", 2, 3, 4)
moore = _funky_classmethod("moore", 9, 8, 7,
docstring="moore(a, e, f) -> happiness")
def __init__(self, arg):
self.inst_attr_inline = None #: an inline documented instance attr
#: a documented instance attribute
self.inst_attr_comment = None
self.inst_attr_string = None
"""a documented instance attribute"""
self._private_inst_attr = None #: a private instance attribute
def __special1__(self):
"""documented special method"""
def __special2__(self):
# undocumented special method
pass
class CustomDict(dict):
"""Docstring."""
def function(foo, *args, **kwds):
"""
Return spam.
"""
pass
class Outer(object):
"""Foo"""
class Inner(object):
"""Foo"""
def meth(self):
"""Foo"""
# should be documented as an alias
factory = dict
class DocstringSig(object):
def meth(self):
"""meth(FOO, BAR=1) -> BAZ
First line of docstring
rest of docstring
"""
def meth2(self):
"""First line, no signature
Second line followed by indentation::
indented line
"""
@property
def prop1(self):
"""DocstringSig.prop1(self)
First line of docstring
"""
return 123
@property
def prop2(self):
"""First line of docstring
Second line of docstring
"""
return 456
class StrRepr(str):
def __repr__(self):
return self
class AttCls(object):
a1 = StrRepr('hello\nworld')
a2 = None
class InstAttCls(object):
"""Class with documented class and instance attributes."""
#: Doc comment for class attribute InstAttCls.ca1.
#: It can have multiple lines.
ca1 = 'a'
ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only.
ca3 = 'c'
"""Docstring for class attribute InstAttCls.ca3."""
def __init__(self):
#: Doc comment for instance attribute InstAttCls.ia1
self.ia1 = 'd'
self.ia2 = 'e'
"""Docstring for instance attribute InstAttCls.ia2."""
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""

View File

@ -10,13 +10,12 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import sys
from six import PY3 from six import PY3
from sphinx.testing.util import SphinxTestApp, Struct # NOQA from sphinx.testing.util import SphinxTestApp, Struct # NOQA
import pytest import pytest
import enum
from six import StringIO, add_metaclass
from docutils.statemachine import ViewList from docutils.statemachine import ViewList
from sphinx.ext.autodoc import AutoDirective, add_documenter, \ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
@ -27,18 +26,23 @@ app = None
@pytest.fixture(scope='module', autouse=True) @pytest.fixture(scope='module', autouse=True)
def setup_module(rootdir, sphinx_test_tempdir): def setup_module(rootdir, sphinx_test_tempdir):
global app try:
srcdir = sphinx_test_tempdir / 'autodoc-root' global app
if not srcdir.exists(): srcdir = sphinx_test_tempdir / 'autodoc-root'
(rootdir/'test-root').copytree(srcdir) if not srcdir.exists():
app = SphinxTestApp(srcdir=srcdir) (rootdir / 'test-root').copytree(srcdir)
app.builder.env.app = app testroot = rootdir / 'test-ext-autodoc'
app.builder.env.temp_data['docname'] = 'dummy' sys.path.append(testroot)
app.connect('autodoc-process-docstring', process_docstring) app = SphinxTestApp(srcdir=srcdir)
app.connect('autodoc-process-signature', process_signature) app.builder.env.app = app
app.connect('autodoc-skip-member', skip_member) app.builder.env.temp_data['docname'] = 'dummy'
yield app.connect('autodoc-process-docstring', process_docstring)
app.cleanup() app.connect('autodoc-process-signature', process_signature)
app.connect('autodoc-skip-member', skip_member)
yield
finally:
app.cleanup()
sys.path.remove(testroot)
directive = options = None directive = options = None
@ -432,6 +436,8 @@ def test_get_doc():
directive.env.config.autoclass_content = 'both' directive.env.config.autoclass_content = 'both'
assert getdocl('class', I) == ['Class docstring', '', 'New docstring'] assert getdocl('class', I) == ['Class docstring', '', 'New docstring']
from target import Base, Derived
# NOTE: inspect.getdoc seems not to work with locally defined classes # NOTE: inspect.getdoc seems not to work with locally defined classes
directive.env.config.autodoc_inherit_docstrings = False directive.env.config.autodoc_inherit_docstrings = False
assert getdocl('method', Base.inheritedmeth) == ['Inherited function.'] assert getdocl('method', Base.inheritedmeth) == ['Inherited function.']
@ -509,24 +515,24 @@ def test_docstring_property_processing():
directive.env.config.autodoc_docstring_signature = False directive.env.config.autodoc_docstring_signature = False
results, docstrings = \ results, docstrings = \
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') genarate_docstring('attribute', 'target.DocstringSig.prop1')
assert '.. py:attribute:: DocstringSig.prop1' in results assert '.. py:attribute:: DocstringSig.prop1' in results
assert 'First line of docstring' in docstrings assert 'First line of docstring' in docstrings
assert 'DocstringSig.prop1(self)' in docstrings assert 'DocstringSig.prop1(self)' in docstrings
results, docstrings = \ results, docstrings = \
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') genarate_docstring('attribute', 'target.DocstringSig.prop2')
assert '.. py:attribute:: DocstringSig.prop2' in results assert '.. py:attribute:: DocstringSig.prop2' in results
assert 'First line of docstring' in docstrings assert 'First line of docstring' in docstrings
assert 'Second line of docstring' in docstrings assert 'Second line of docstring' in docstrings
directive.env.config.autodoc_docstring_signature = True directive.env.config.autodoc_docstring_signature = True
results, docstrings = \ results, docstrings = \
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1') genarate_docstring('attribute', 'target.DocstringSig.prop1')
assert '.. py:attribute:: DocstringSig.prop1' in results assert '.. py:attribute:: DocstringSig.prop1' in results
assert 'First line of docstring' in docstrings assert 'First line of docstring' in docstrings
assert 'DocstringSig.prop1(self)' not in docstrings assert 'DocstringSig.prop1(self)' not in docstrings
results, docstrings = \ results, docstrings = \
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2') genarate_docstring('attribute', 'target.DocstringSig.prop2')
assert '.. py:attribute:: DocstringSig.prop2' in results assert '.. py:attribute:: DocstringSig.prop2' in results
assert 'First line of docstring' in docstrings assert 'First line of docstring' in docstrings
assert 'Second line of docstring' in docstrings assert 'Second line of docstring' in docstrings
@ -557,11 +563,13 @@ def test_new_documenter():
del directive.result[:] del directive.result[:]
options.members = ['integer'] options.members = ['integer']
assert_result_contains('.. py:data:: integer', 'module', 'test_autodoc') assert_result_contains('.. py:data:: integer', 'module', 'target')
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
def test_attrgetter_using(): def test_attrgetter_using():
from target import Class
def assert_getter_works(objtype, name, obj, attrs=[], **kw): def assert_getter_works(objtype, name, obj, attrs=[], **kw):
getattr_spy = [] getattr_spy = []
@ -586,10 +594,10 @@ def test_attrgetter_using():
options.members = ALL options.members = ALL
options.inherited_members = False options.inherited_members = False
assert_getter_works('class', 'test_autodoc.Class', Class, ['meth']) assert_getter_works('class', 'target.Class', Class, ['meth'])
options.inherited_members = True options.inherited_members = True
assert_getter_works('class', 'test_autodoc.Class', Class, ['meth', 'inheritedmeth']) assert_getter_works('class', 'target.Class', Class, ['meth', 'inheritedmeth'])
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
@ -656,11 +664,11 @@ def test_generate():
assert_warns("failed to import function 'foobar' from module 'util'", assert_warns("failed to import function 'foobar' from module 'util'",
'function', 'util.foobar', more_content=None) 'function', 'util.foobar', more_content=None)
# method missing # method missing
assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc';", assert_warns("failed to import method 'Class.foobar' from module 'target';",
'method', 'test_autodoc.Class.foobar', more_content=None) 'method', 'target.Class.foobar', more_content=None)
# test auto and given content mixing # test auto and given content mixing
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'target'
assert_result_contains(' Function.', 'method', 'Class.meth') assert_result_contains(' Function.', 'method', 'Class.meth')
add_content = ViewList() add_content = ViewList()
add_content.append('Content.', '', 0) add_content.append('Content.', '', 0)
@ -675,63 +683,63 @@ def test_generate():
assert len(directive.result) == 0 assert len(directive.result) == 0
# assert that exceptions can be documented # assert that exceptions can be documented
assert_works('exception', 'test_autodoc.CustomEx', all_members=True) assert_works('exception', 'target.CustomEx', all_members=True)
assert_works('exception', 'test_autodoc.CustomEx') assert_works('exception', 'target.CustomEx')
# test diverse inclusion settings for members # test diverse inclusion settings for members
should = [('class', 'test_autodoc.Class')] should = [('class', 'target.Class')]
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
should.extend([('method', 'test_autodoc.Class.meth')]) should.extend([('method', 'target.Class.meth')])
options.members = ['meth'] options.members = ['meth']
options.exclude_members = set(['excludemeth']) options.exclude_members = set(['excludemeth'])
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
should.extend([('attribute', 'test_autodoc.Class.prop'), should.extend([('attribute', 'target.Class.prop'),
('attribute', 'test_autodoc.Class.descr'), ('attribute', 'target.Class.descr'),
('attribute', 'test_autodoc.Class.attr'), ('attribute', 'target.Class.attr'),
('attribute', 'test_autodoc.Class.docattr'), ('attribute', 'target.Class.docattr'),
('attribute', 'test_autodoc.Class.udocattr'), ('attribute', 'target.Class.udocattr'),
('attribute', 'test_autodoc.Class.mdocattr'), ('attribute', 'target.Class.mdocattr'),
('attribute', 'test_autodoc.Class.inst_attr_comment'), ('attribute', 'target.Class.inst_attr_comment'),
('attribute', 'test_autodoc.Class.inst_attr_inline'), ('attribute', 'target.Class.inst_attr_inline'),
('attribute', 'test_autodoc.Class.inst_attr_string'), ('attribute', 'target.Class.inst_attr_string'),
('method', 'test_autodoc.Class.moore'), ('method', 'target.Class.moore'),
]) ])
options.members = ALL options.members = ALL
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
options.undoc_members = True options.undoc_members = True
should.extend((('attribute', 'test_autodoc.Class.skipattr'), should.extend((('attribute', 'target.Class.skipattr'),
('method', 'test_autodoc.Class.undocmeth'), ('method', 'target.Class.undocmeth'),
('method', 'test_autodoc.Class.roger'))) ('method', 'target.Class.roger')))
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
options.inherited_members = True options.inherited_members = True
should.append(('method', 'test_autodoc.Class.inheritedmeth')) should.append(('method', 'target.Class.inheritedmeth'))
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
# test special members # test special members
options.special_members = ['__special1__'] options.special_members = ['__special1__']
should.append(('method', 'test_autodoc.Class.__special1__')) should.append(('method', 'target.Class.__special1__'))
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
options.special_members = ALL options.special_members = ALL
should.append(('method', 'test_autodoc.Class.__special2__')) should.append(('method', 'target.Class.__special2__'))
assert_processes(should, 'class', 'Class') assert_processes(should, 'class', 'Class')
options.special_members = False options.special_members = False
options.members = [] options.members = []
# test module flags # test module flags
assert_result_contains('.. py:module:: test_autodoc', assert_result_contains('.. py:module:: target',
'module', 'test_autodoc') 'module', 'target')
options.synopsis = 'Synopsis' options.synopsis = 'Synopsis'
assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc') assert_result_contains(' :synopsis: Synopsis', 'module', 'target')
options.deprecated = True options.deprecated = True
assert_result_contains(' :deprecated:', 'module', 'test_autodoc') assert_result_contains(' :deprecated:', 'module', 'target')
options.platform = 'Platform' options.platform = 'Platform'
assert_result_contains(' :platform: Platform', 'module', 'test_autodoc') assert_result_contains(' :platform: Platform', 'module', 'target')
# test if __all__ is respected for modules # test if __all__ is respected for modules
options.members = ALL options.members = ALL
assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc') assert_result_contains('.. py:class:: Class(arg)', 'module', 'target')
try: try:
assert_result_contains('.. py:exception:: CustomEx', assert_result_contains('.. py:exception:: CustomEx',
'module', 'test_autodoc') 'module', 'target')
except AssertionError: except AssertionError:
pass pass
else: else:
@ -746,7 +754,7 @@ def test_generate():
# test noindex flag # test noindex flag
options.members = [] options.members = []
options.noindex = True options.noindex = True
assert_result_contains(' :noindex:', 'module', 'test_autodoc') assert_result_contains(' :noindex:', 'module', 'target')
assert_result_contains(' :noindex:', 'class', 'Base') assert_result_contains(' :noindex:', 'class', 'Base')
# okay, now let's get serious about mixing Python and C signature stuff # okay, now let's get serious about mixing Python and C signature stuff
@ -754,14 +762,14 @@ def test_generate():
all_members=True) all_members=True)
# test inner class handling # test inner class handling
assert_processes([('class', 'test_autodoc.Outer'), assert_processes([('class', 'target.Outer'),
('class', 'test_autodoc.Outer.Inner'), ('class', 'target.Outer.Inner'),
('method', 'test_autodoc.Outer.Inner.meth')], ('method', 'target.Outer.Inner.meth')],
'class', 'Outer', all_members=True) 'class', 'Outer', all_members=True)
# test descriptor docstrings # test descriptor docstrings
assert_result_contains(' Descriptor instance docstring.', assert_result_contains(' Descriptor instance docstring.',
'attribute', 'test_autodoc.Class.descr') 'attribute', 'target.Class.descr')
# test generation for C modules (which have no source file) # test generation for C modules (which have no source file)
directive.env.ref_context['py:module'] = 'time' directive.env.ref_context['py:module'] = 'time'
@ -769,7 +777,7 @@ def test_generate():
assert_processes([('function', 'time.asctime')], 'function', 'asctime') assert_processes([('function', 'time.asctime')], 'function', 'asctime')
# test autodoc_member_order == 'source' # test autodoc_member_order == 'source'
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'target'
options.private_members = True options.private_members = True
if PY3: if PY3:
roger_line = ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)' roger_line = ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)'
@ -795,7 +803,7 @@ def test_generate():
del directive.env.ref_context['py:module'] del directive.env.ref_context['py:module']
# test attribute initialized to class instance from other module # test attribute initialized to class instance from other module
directive.env.temp_data['autodoc:class'] = 'test_autodoc.Class' directive.env.temp_data['autodoc:class'] = 'target.Class'
assert_result_contains(u' should be documented as well - s\xfc\xdf', assert_result_contains(u' should be documented as well - s\xfc\xdf',
'attribute', 'mdocattr') 'attribute', 'mdocattr')
del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:class']
@ -803,25 +811,25 @@ def test_generate():
# test autodoc_docstring_signature # test autodoc_docstring_signature
assert_result_contains( assert_result_contains(
'.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method', '.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method',
'test_autodoc.DocstringSig.meth') 'target.DocstringSig.meth')
assert_result_contains( assert_result_contains(
' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth') ' rest of docstring', 'method', 'target.DocstringSig.meth')
assert_result_contains( assert_result_contains(
'.. py:method:: DocstringSig.meth2()', 'method', '.. py:method:: DocstringSig.meth2()', 'method',
'test_autodoc.DocstringSig.meth2') 'target.DocstringSig.meth2')
assert_result_contains( assert_result_contains(
' indented line', 'method', ' indented line', 'method',
'test_autodoc.DocstringSig.meth2') 'target.DocstringSig.meth2')
assert_result_contains( assert_result_contains(
'.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method', '.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method',
'test_autodoc.Class.moore') 'target.Class.moore')
# test new attribute documenter behavior # test new attribute documenter behavior
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'target'
options.undoc_members = True options.undoc_members = True
assert_processes([('class', 'test_autodoc.AttCls'), assert_processes([('class', 'target.AttCls'),
('attribute', 'test_autodoc.AttCls.a1'), ('attribute', 'target.AttCls.a1'),
('attribute', 'test_autodoc.AttCls.a2'), ('attribute', 'target.AttCls.a2'),
], 'class', 'AttCls') ], 'class', 'AttCls')
assert_result_contains( assert_result_contains(
' :annotation: = hello world', 'attribute', 'AttCls.a1') ' :annotation: = hello world', 'attribute', 'AttCls.a1')
@ -831,40 +839,40 @@ def test_generate():
# test explicit members with instance attributes # test explicit members with instance attributes
del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module'] del directive.env.temp_data['autodoc:module']
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'target'
options.inherited_members = False options.inherited_members = False
options.undoc_members = False options.undoc_members = False
options.members = ALL options.members = ALL
assert_processes([ assert_processes([
('class', 'test_autodoc.InstAttCls'), ('class', 'target.InstAttCls'),
('attribute', 'test_autodoc.InstAttCls.ca1'), ('attribute', 'target.InstAttCls.ca1'),
('attribute', 'test_autodoc.InstAttCls.ca2'), ('attribute', 'target.InstAttCls.ca2'),
('attribute', 'test_autodoc.InstAttCls.ca3'), ('attribute', 'target.InstAttCls.ca3'),
('attribute', 'test_autodoc.InstAttCls.ia1'), ('attribute', 'target.InstAttCls.ia1'),
('attribute', 'test_autodoc.InstAttCls.ia2'), ('attribute', 'target.InstAttCls.ia2'),
], 'class', 'InstAttCls') ], 'class', 'InstAttCls')
del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module'] del directive.env.temp_data['autodoc:module']
options.members = ['ca1', 'ia1'] options.members = ['ca1', 'ia1']
assert_processes([ assert_processes([
('class', 'test_autodoc.InstAttCls'), ('class', 'target.InstAttCls'),
('attribute', 'test_autodoc.InstAttCls.ca1'), ('attribute', 'target.InstAttCls.ca1'),
('attribute', 'test_autodoc.InstAttCls.ia1'), ('attribute', 'target.InstAttCls.ia1'),
], 'class', 'InstAttCls') ], 'class', 'InstAttCls')
del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module'] del directive.env.temp_data['autodoc:module']
del directive.env.ref_context['py:module'] del directive.env.ref_context['py:module']
# test members with enum attributes # test members with enum attributes
directive.env.ref_context['py:module'] = 'test_autodoc' directive.env.ref_context['py:module'] = 'target'
options.inherited_members = False options.inherited_members = False
options.undoc_members = False options.undoc_members = False
options.members = ALL options.members = ALL
assert_processes([ assert_processes([
('class', 'test_autodoc.EnumCls'), ('class', 'target.EnumCls'),
('attribute', 'test_autodoc.EnumCls.val1'), ('attribute', 'target.EnumCls.val1'),
('attribute', 'test_autodoc.EnumCls.val2'), ('attribute', 'target.EnumCls.val2'),
('attribute', 'test_autodoc.EnumCls.val3'), ('attribute', 'target.EnumCls.val3'),
], 'class', 'EnumCls') ], 'class', 'EnumCls')
assert_result_contains( assert_result_contains(
' :annotation: = 12', 'attribute', 'EnumCls.val1') ' :annotation: = 12', 'attribute', 'EnumCls.val1')
@ -878,11 +886,11 @@ def test_generate():
# test descriptor class documentation # test descriptor class documentation
options.members = ['CustomDataDescriptor', 'CustomDataDescriptor2'] options.members = ['CustomDataDescriptor', 'CustomDataDescriptor2']
assert_result_contains('.. py:class:: CustomDataDescriptor(doc)', assert_result_contains('.. py:class:: CustomDataDescriptor(doc)',
'module', 'test_autodoc') 'module', 'target')
assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()', assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()',
'module', 'test_autodoc') 'module', 'target')
assert_result_contains('.. py:class:: CustomDataDescriptor2(doc)', assert_result_contains('.. py:class:: CustomDataDescriptor2(doc)',
'module', 'test_autodoc') 'module', 'target')
# test mocked module imports # test mocked module imports
options.members = ['TestAutodoc'] options.members = ['TestAutodoc']
@ -894,224 +902,3 @@ def test_generate():
options.members = ['decoratedFunction'] options.members = ['decoratedFunction']
assert_result_contains('.. py:function:: decoratedFunction()', assert_result_contains('.. py:function:: decoratedFunction()',
'module', 'autodoc_missing_imports') 'module', 'autodoc_missing_imports')
# --- generate fodder ------------
__all__ = ['Class']
#: documentation for the integer
integer = 1
def raises(exc, func, *args, **kwds):
"""Raise AssertionError if ``func(*args, **kwds)`` does not raise *exc*."""
pass
class CustomEx(Exception):
"""My custom exception."""
def f(self):
"""Exception method."""
class CustomDataDescriptor(object):
"""Descriptor class docstring."""
def __init__(self, doc):
self.__doc__ = doc
def __get__(self, obj, type=None):
if obj is None:
return self
return 42
def meth(self):
"""Function."""
return "The Answer"
class CustomDataDescriptorMeta(type):
"""Descriptor metaclass docstring."""
@add_metaclass(CustomDataDescriptorMeta)
class CustomDataDescriptor2(CustomDataDescriptor):
"""Descriptor class with custom metaclass docstring."""
def _funky_classmethod(name, b, c, d, docstring=None):
"""Generates a classmethod for a class from a template by filling out
some arguments."""
def template(cls, a, b, c, d=4, e=5, f=6):
return a, b, c, d, e, f
from functools import partial
function = partial(template, b=b, c=c, d=d)
function.__name__ = name
function.__doc__ = docstring
return classmethod(function)
class Base(object):
def inheritedmeth(self):
"""Inherited function."""
class Derived(Base):
def inheritedmeth(self):
# no docstring here
pass
class Class(Base):
"""Class to document."""
descr = CustomDataDescriptor("Descriptor instance docstring.")
def meth(self):
"""Function."""
def undocmeth(self):
pass
def skipmeth(self):
"""Method that should be skipped."""
def excludemeth(self):
"""Method that should be excluded."""
# should not be documented
skipattr = 'foo'
#: should be documented -- süß
attr = 'bar'
@property
def prop(self):
"""Property."""
docattr = 'baz'
"""should likewise be documented -- süß"""
udocattr = 'quux'
u"""should be documented as well - süß"""
# initialized to any class imported from another module
mdocattr = StringIO()
"""should be documented as well - süß"""
roger = _funky_classmethod("roger", 2, 3, 4)
moore = _funky_classmethod("moore", 9, 8, 7,
docstring="moore(a, e, f) -> happiness")
def __init__(self, arg):
self.inst_attr_inline = None #: an inline documented instance attr
#: a documented instance attribute
self.inst_attr_comment = None
self.inst_attr_string = None
"""a documented instance attribute"""
self._private_inst_attr = None #: a private instance attribute
def __special1__(self):
"""documented special method"""
def __special2__(self):
# undocumented special method
pass
class CustomDict(dict):
"""Docstring."""
def function(foo, *args, **kwds):
"""
Return spam.
"""
pass
class Outer(object):
"""Foo"""
class Inner(object):
"""Foo"""
def meth(self):
"""Foo"""
# should be documented as an alias
factory = dict
class DocstringSig(object):
def meth(self):
"""meth(FOO, BAR=1) -> BAZ
First line of docstring
rest of docstring
"""
def meth2(self):
"""First line, no signature
Second line followed by indentation::
indented line
"""
@property
def prop1(self):
"""DocstringSig.prop1(self)
First line of docstring
"""
return 123
@property
def prop2(self):
"""First line of docstring
Second line of docstring
"""
return 456
class StrRepr(str):
def __repr__(self):
return self
class AttCls(object):
a1 = StrRepr('hello\nworld')
a2 = None
class InstAttCls(object):
"""Class with documented class and instance attributes."""
#: Doc comment for class attribute InstAttCls.ca1.
#: It can have multiple lines.
ca1 = 'a'
ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only.
ca3 = 'c'
"""Docstring for class attribute InstAttCls.ca3."""
def __init__(self):
#: Doc comment for instance attribute InstAttCls.ia1
self.ia1 = 'd'
self.ia2 = 'e'
"""Docstring for instance attribute InstAttCls.ia2."""
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""

View File

@ -182,8 +182,8 @@ def test_html_warnings(app, warning):
r'-| |-'), r'-| |-'),
], ],
'autodoc.html': [ 'autodoc.html': [
(".//dt[@id='test_autodoc.Class']", ''), (".//dt[@id='autodoc_target.Class']", ''),
(".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'), (".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
(".//dd/p", r'Return spam\.'), (".//dd/p", r'Return spam\.'),
], ],
'extapi.html': [ 'extapi.html': [

View File

@ -90,8 +90,8 @@ def cached_etree_parse():
r'-| |-'), r'-| |-'),
], ],
'autodoc.html': [ 'autodoc.html': [
(".//dt[@id='test_autodoc.Class']", ''), (".//dt[@id='autodoc_target.Class']", ''),
(".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'), (".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
(".//dd/p", r'Return spam\.'), (".//dd/p", r'Return spam\.'),
], ],
'extapi.html': [ 'extapi.html': [

View File

@ -335,6 +335,43 @@ def test_numref_with_language_ja(app, status, warning):
'\\nameref{\\detokenize{foo:foo}}}') in result '\\nameref{\\detokenize{foo:foo}}}') in result
@pytest.mark.sphinx('latex', testroot='latex-numfig')
def test_latex_obey_numfig_is_false(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8')
assert '\\usepackage{sphinx}' in result
result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8')
assert '\\usepackage{sphinx}' in result
@pytest.mark.sphinx(
'latex', testroot='latex-numfig',
confoverrides={'numfig': True, 'numfig_secnum_depth': 0})
def test_latex_obey_numfig_secnum_depth_is_zero(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8')
assert '\\usepackage[,nonumfigreset]{sphinx}' in result
result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8')
assert '\\usepackage[,nonumfigreset]{sphinx}' in result
@pytest.mark.sphinx(
'latex', testroot='latex-numfig',
confoverrides={'numfig': True, 'numfig_secnum_depth': 2})
def test_latex_obey_numfig_secnum_depth_is_two(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxManual.tex').text(encoding='utf8')
assert '\\usepackage[,numfigreset=2]{sphinx}' in result
result = (app.outdir / 'SphinxHowTo.tex').text(encoding='utf8')
assert '\\usepackage[,numfigreset=3]{sphinx}' in result
@pytest.mark.sphinx('latex') @pytest.mark.sphinx('latex')
def test_latex_add_latex_package(app, status, warning): def test_latex_add_latex_package(app, status, warning):
app.add_latex_package('foo') app.add_latex_package('foo')
@ -712,20 +749,16 @@ def test_latex_logo_if_not_found(app, status, warning):
assert isinstance(exc, SphinxError) assert isinstance(exc, SphinxError)
@pytest.mark.sphinx('latex', testroot='toctree-maxdepth', @pytest.mark.sphinx('latex', testroot='toctree-maxdepth')
confoverrides={'latex_documents': [
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'manual'),
]})
def test_toctree_maxdepth_manual(app, status, warning): def test_toctree_maxdepth_manual(app, status, warning):
app.builder.build_all() app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8') result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result) print(result)
print(status.getvalue()) print(status.getvalue())
print(warning.getvalue()) print(warning.getvalue())
assert '\\setcounter{tocdepth}{1}' in result assert '\\setcounter{tocdepth}{1}' in result
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
assert '\\chapter{Foo}' in result
@pytest.mark.sphinx( @pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth', 'latex', testroot='toctree-maxdepth',
@ -741,7 +774,7 @@ def test_toctree_maxdepth_howto(app, status, warning):
print(warning.getvalue()) print(warning.getvalue())
assert '\\setcounter{tocdepth}{2}' in result assert '\\setcounter{tocdepth}{2}' in result
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
assert '\\section{Foo}' in result
@pytest.mark.sphinx( @pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth', 'latex', testroot='toctree-maxdepth',
@ -754,7 +787,7 @@ def test_toctree_not_found(app, status, warning):
print(warning.getvalue()) print(warning.getvalue())
assert '\\setcounter{tocdepth}' not in result assert '\\setcounter{tocdepth}' not in result
assert '\\setcounter{secnumdepth}' not in result assert '\\setcounter{secnumdepth}' not in result
assert '\\chapter{Foo A}' in result
@pytest.mark.sphinx( @pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth', 'latex', testroot='toctree-maxdepth',
@ -804,6 +837,26 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning):
print(status.getvalue()) print(status.getvalue())
print(warning.getvalue()) print(warning.getvalue())
assert '\\part{Foo}' in result assert '\\part{Foo}' in result
assert '\\chapter{Foo A}' in result
assert '\\chapter{Foo B}' in result
@pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'part',
'latex_documents': [
('index', 'Python.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto')
]})
def test_latex_toplevel_sectioning_is_part_with_howto(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\part{Foo}' in result
assert '\\section{Foo A}' in result
assert '\\section{Foo B}' in result
@pytest.mark.sphinx( @pytest.mark.sphinx(
@ -818,6 +871,22 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
assert '\\chapter{Foo}' in result assert '\\chapter{Foo}' in result
@pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'chapter',
'latex_documents': [
('index', 'Python.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto')
]})
def test_latex_toplevel_sectioning_is_chapter_with_howto(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\section{Foo}' in result
@pytest.mark.sphinx( @pytest.mark.sphinx(
'latex', testroot='toctree-maxdepth', 'latex', testroot='toctree-maxdepth',
confoverrides={'latex_toplevel_sectioning': 'section'}) confoverrides={'latex_toplevel_sectioning': 'section'})

View File

@ -21,9 +21,9 @@ def test_build(app, status, warning):
py_undoc = (app.outdir / 'python.txt').text() py_undoc = (app.outdir / 'python.txt').text()
assert py_undoc.startswith('Undocumented Python objects\n' assert py_undoc.startswith('Undocumented Python objects\n'
'===========================\n') '===========================\n')
assert 'test_autodoc\n------------\n' in py_undoc assert 'autodoc_target\n--------------\n' in py_undoc
assert ' * Class -- missing methods:\n' in py_undoc assert ' * Class -- missing methods:\n' in py_undoc
assert ' * process_docstring\n' in py_undoc assert ' * raises\n' in py_undoc
assert ' * function\n' not in py_undoc # these two are documented assert ' * function\n' not in py_undoc # these two are documented
assert ' * Class\n' not in py_undoc # in autodoc.txt assert ' * Class\n' not in py_undoc # in autodoc.txt
@ -40,9 +40,9 @@ def test_build(app, status, warning):
# the key is the full path to the header file, which isn't testable # the key is the full path to the header file, which isn't testable
assert list(undoc_c.values())[0] == set([('function', 'Py_SphinxTest')]) assert list(undoc_c.values())[0] == set([('function', 'Py_SphinxTest')])
assert 'test_autodoc' in undoc_py assert 'autodoc_target' in undoc_py
assert 'funcs' in undoc_py['test_autodoc'] assert 'funcs' in undoc_py['autodoc_target']
assert 'process_docstring' in undoc_py['test_autodoc']['funcs'] assert 'raises' in undoc_py['autodoc_target']['funcs']
assert 'classes' in undoc_py['test_autodoc'] assert 'classes' in undoc_py['autodoc_target']
assert 'Class' in undoc_py['test_autodoc']['classes'] assert 'Class' in undoc_py['autodoc_target']['classes']
assert 'undocmeth' in undoc_py['test_autodoc']['classes']['Class'] assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class']