mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'master' into ignore__all__
This commit is contained in:
commit
ffa9d48d0e
8
CHANGES
8
CHANGES
@ -49,7 +49,9 @@ Features added
|
||||
* HTML themes can set up default sidebars through ``theme.conf``
|
||||
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
|
||||
* #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__``
|
||||
|
||||
|
||||
@ -92,6 +94,8 @@ Bugs fixed
|
||||
* #4094: C++, allow empty template argument lists.
|
||||
* C++, also hyperlink types in the name of declarations with qualified names.
|
||||
* 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
|
||||
--------
|
||||
@ -134,6 +138,8 @@ Bugs fixed
|
||||
remote image
|
||||
* #1421: Respect the quiet flag in sphinx-quickstart
|
||||
* #4281: Race conditions when creating output directory
|
||||
* #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates
|
||||
``\chapter`` commands
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
1
EXAMPLES
1
EXAMPLES
@ -141,6 +141,7 @@ Documentation using the nature theme
|
||||
Documentation using another builtin theme
|
||||
-----------------------------------------
|
||||
|
||||
* Arcade: http://arcade.academy/ (sphinx_rtd_theme)
|
||||
* Breathe: https://breathe.readthedocs.io/ (haiku)
|
||||
* MPipe: https://vmlaker.github.io/mpipe/ (sphinx13)
|
||||
* NLTK: http://www.nltk.org/ (agogo)
|
||||
|
@ -348,13 +348,12 @@ General configuration
|
||||
section and ``1``, ``2``, ... if not in any top level section.)
|
||||
- etc...
|
||||
|
||||
.. note::
|
||||
|
||||
The LaTeX builder currently ignores this configuration setting. It will
|
||||
obey it at Sphinx 1.7.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
The LaTeX builder obeys this setting (if :confval:`numfig` is set to
|
||||
``True``).
|
||||
|
||||
.. confval:: tls_verify
|
||||
|
||||
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
|
||||
|
||||
This value determines the topmost sectioning unit. It should be chosen from
|
||||
``part``, ``chapter`` or ``section``. The default is ``None``; the topmost
|
||||
sectioning unit is switched by documentclass. ``section`` is used if
|
||||
``'part'``, ``'chapter'`` or ``'section'``. The default is ``None``;
|
||||
the topmost
|
||||
sectioning unit is switched by documentclass: ``section`` is used if
|
||||
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
|
||||
|
||||
.. confval:: latex_appendices
|
||||
|
@ -183,7 +183,7 @@
|
||||
% control caption around literal-block
|
||||
\RequirePackage{capt-of}
|
||||
\RequirePackage{needspace}
|
||||
|
||||
\RequirePackage{remreset}% provides \@removefromreset
|
||||
% to make pdf with correct encoded bookmarks in Japanese
|
||||
% this should precede the hyperref package
|
||||
\ifx\kanjiskip\@undefined
|
||||
@ -247,7 +247,9 @@
|
||||
\fi
|
||||
|
||||
\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.
|
||||
\newdimen\sphinxverbatimsep
|
||||
\newdimen\sphinxverbatimborder
|
||||
@ -349,6 +351,8 @@
|
||||
\ProcessKeyvalOptions*
|
||||
% don't allow use of maxlistdepth via \sphinxsetup.
|
||||
\DisableKeyvalOption{sphinx}{maxlistdepth}
|
||||
\DisableKeyvalOption{sphinx}{numfigreset}
|
||||
\DisableKeyvalOption{sphinx}{nonumfigreset}
|
||||
% user interface: options can be changed midway in a document!
|
||||
\newcommand\sphinxsetup[1]{\setkeys{sphinx}{#1}}
|
||||
|
||||
@ -657,6 +661,7 @@
|
||||
{\abovecaptionskip\smallskipamount
|
||||
\belowcaptionskip\smallskipamount}
|
||||
|
||||
|
||||
%% FOOTNOTES
|
||||
%
|
||||
% Support large numbered footnotes in minipage
|
||||
@ -665,6 +670,87 @@
|
||||
\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
|
||||
%
|
||||
% Based on use of "fancyvrb.sty"'s Verbatim.
|
||||
@ -680,15 +766,6 @@
|
||||
\let\endOriginalVerbatim\endVerbatim
|
||||
|
||||
% 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
|
||||
\newcommand*{\fnum@literalblock}{\literalblockname\nobreakspace\theliteralblock}
|
||||
% this will be overwritten in document preamble by Babel translation
|
||||
|
@ -48,7 +48,8 @@ BEGIN_DOC = r'''
|
||||
|
||||
|
||||
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
|
||||
SECNUMDEPTH = 3
|
||||
LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
|
||||
"subsubsection", "paragraph", "subparagraph"]
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
'latex_engine': 'pdflatex',
|
||||
@ -501,9 +502,9 @@ def rstdim_to_latexdim(width_str):
|
||||
|
||||
|
||||
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
|
||||
|
||||
# sphinx specific document classes
|
||||
@ -532,16 +533,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.compact_list = 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
|
||||
self.elements = DEFAULT_SETTINGS.copy()
|
||||
self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
|
||||
@ -562,16 +553,55 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.elements.update({
|
||||
'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':
|
||||
docclass = builder.config.latex_docclass.get('howto', 'article')
|
||||
if docclass[0] == 'j': # Japanese class...
|
||||
pass
|
||||
else:
|
||||
self.sectionnames.remove('chapter')
|
||||
else:
|
||||
docclass = builder.config.latex_docclass.get('manual', 'report')
|
||||
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:
|
||||
self.elements['date'] = builder.config.today
|
||||
else:
|
||||
self.elements['date'] = format_date(builder.config.today_fmt or _('%b %d, %Y'), # type: ignore # NOQA
|
||||
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:
|
||||
# no need for \\noindent here, used in flushright
|
||||
self.elements['logo'] = '\\sphinxincludegraphics{%s}\\par' % \
|
||||
@ -628,23 +658,32 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
return '\\usepackage{%s}' % (packagename,)
|
||||
usepackages = (declare_package(*p) for p in builder.usepackages)
|
||||
self.elements['usepackages'] += "\n".join(usepackages)
|
||||
|
||||
minsecnumdepth = self.secnumdepth # 2 from legacy sphinx manual/howto
|
||||
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 = 0: show parts and chapters
|
||||
# tocdepth = 1: show parts, chapters and sections
|
||||
# tocdepth = 2: show parts, chapters, sections and subsections
|
||||
# ...
|
||||
tocdepth = document['tocdepth'] + self.top_sectionlevel - 2
|
||||
maxdepth = len(self.sectionnames) - self.top_sectionlevel
|
||||
if tocdepth > maxdepth:
|
||||
if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \
|
||||
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.')
|
||||
tocdepth = maxdepth
|
||||
tocdepth = len(LATEXSECTIONNAMES) - 2
|
||||
|
||||
self.elements['tocdepth'] = '\\setcounter{tocdepth}{%d}' % tocdepth
|
||||
if tocdepth >= SECNUMDEPTH:
|
||||
# Increase secnumdepth if tocdepth is depther than default SECNUMDEPTH
|
||||
self.elements['secnumdepth'] = '\\setcounter{secnumdepth}{%d}' % tocdepth
|
||||
minsecnumdepth = max(minsecnumdepth, 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):
|
||||
self.elements['contentsname'] = \
|
||||
|
225
tests/roots/test-ext-autodoc/target/__init__.py
Normal file
225
tests/roots/test-ext-autodoc/target/__init__.py
Normal 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"""
|
10
tests/roots/test-latex-numfig/conf.py
Normal file
10
tests/roots/test-latex-numfig/conf.py
Normal 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'),
|
||||
]
|
9
tests/roots/test-latex-numfig/index.rst
Normal file
9
tests/roots/test-latex-numfig/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
=================
|
||||
test-latex-numfig
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:numbered:
|
||||
|
||||
indexmanual
|
||||
indexhowto
|
10
tests/roots/test-latex-numfig/indexhowto.rst
Normal file
10
tests/roots/test-latex-numfig/indexhowto.rst
Normal file
@ -0,0 +1,10 @@
|
||||
=======================
|
||||
test-latex-numfig-howto
|
||||
=======================
|
||||
|
||||
This is a part
|
||||
==============
|
||||
|
||||
This is a section
|
||||
-----------------
|
||||
|
13
tests/roots/test-latex-numfig/indexmanual.rst
Normal file
13
tests/roots/test-latex-numfig/indexmanual.rst
Normal file
@ -0,0 +1,13 @@
|
||||
========================
|
||||
test-latex-numfig-manual
|
||||
========================
|
||||
|
||||
First part
|
||||
==========
|
||||
|
||||
This is chapter
|
||||
---------------
|
||||
|
||||
This is section
|
||||
~~~~~~~~~~~~~~~
|
||||
|
@ -5,7 +5,7 @@ Just testing a few autodoc possibilities...
|
||||
|
||||
.. automodule:: util
|
||||
|
||||
.. automodule:: test_autodoc
|
||||
.. automodule:: autodoc_target
|
||||
:members:
|
||||
|
||||
.. autofunction:: function
|
||||
@ -34,7 +34,7 @@ Just testing a few autodoc possibilities...
|
||||
.. autoclass:: MarkupError
|
||||
|
||||
|
||||
.. currentmodule:: test_autodoc
|
||||
.. currentmodule:: autodoc_target
|
||||
|
||||
.. autoclass:: InstAttCls
|
||||
:members:
|
||||
|
225
tests/roots/test-root/autodoc_target.py
Normal file
225
tests/roots/test-root/autodoc_target.py
Normal 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"""
|
@ -10,13 +10,12 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from six import PY3
|
||||
|
||||
from sphinx.testing.util import SphinxTestApp, Struct # NOQA
|
||||
import pytest
|
||||
|
||||
import enum
|
||||
from six import StringIO, add_metaclass
|
||||
from docutils.statemachine import ViewList
|
||||
|
||||
from sphinx.ext.autodoc import AutoDirective, add_documenter, \
|
||||
@ -27,10 +26,13 @@ app = None
|
||||
|
||||
@pytest.fixture(scope='module', autouse=True)
|
||||
def setup_module(rootdir, sphinx_test_tempdir):
|
||||
try:
|
||||
global app
|
||||
srcdir = sphinx_test_tempdir / 'autodoc-root'
|
||||
if not srcdir.exists():
|
||||
(rootdir/'test-root').copytree(srcdir)
|
||||
(rootdir / 'test-root').copytree(srcdir)
|
||||
testroot = rootdir / 'test-ext-autodoc'
|
||||
sys.path.append(testroot)
|
||||
app = SphinxTestApp(srcdir=srcdir)
|
||||
app.builder.env.app = app
|
||||
app.builder.env.temp_data['docname'] = 'dummy'
|
||||
@ -38,7 +40,9 @@ def setup_module(rootdir, sphinx_test_tempdir):
|
||||
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
|
||||
@ -432,6 +436,8 @@ def test_get_doc():
|
||||
directive.env.config.autoclass_content = 'both'
|
||||
assert getdocl('class', I) == ['Class docstring', '', 'New docstring']
|
||||
|
||||
from target import Base, Derived
|
||||
|
||||
# NOTE: inspect.getdoc seems not to work with locally defined classes
|
||||
directive.env.config.autodoc_inherit_docstrings = False
|
||||
assert getdocl('method', Base.inheritedmeth) == ['Inherited function.']
|
||||
@ -509,24 +515,24 @@ def test_docstring_property_processing():
|
||||
|
||||
directive.env.config.autodoc_docstring_signature = False
|
||||
results, docstrings = \
|
||||
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1')
|
||||
genarate_docstring('attribute', 'target.DocstringSig.prop1')
|
||||
assert '.. py:attribute:: DocstringSig.prop1' in results
|
||||
assert 'First line of docstring' in docstrings
|
||||
assert 'DocstringSig.prop1(self)' in docstrings
|
||||
results, docstrings = \
|
||||
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2')
|
||||
genarate_docstring('attribute', 'target.DocstringSig.prop2')
|
||||
assert '.. py:attribute:: DocstringSig.prop2' in results
|
||||
assert 'First line of docstring' in docstrings
|
||||
assert 'Second line of docstring' in docstrings
|
||||
|
||||
directive.env.config.autodoc_docstring_signature = True
|
||||
results, docstrings = \
|
||||
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop1')
|
||||
genarate_docstring('attribute', 'target.DocstringSig.prop1')
|
||||
assert '.. py:attribute:: DocstringSig.prop1' in results
|
||||
assert 'First line of docstring' in docstrings
|
||||
assert 'DocstringSig.prop1(self)' not in docstrings
|
||||
results, docstrings = \
|
||||
genarate_docstring('attribute', 'test_autodoc.DocstringSig.prop2')
|
||||
genarate_docstring('attribute', 'target.DocstringSig.prop2')
|
||||
assert '.. py:attribute:: DocstringSig.prop2' in results
|
||||
assert 'First line of docstring' in docstrings
|
||||
assert 'Second line of docstring' in docstrings
|
||||
@ -557,11 +563,13 @@ def test_new_documenter():
|
||||
del directive.result[:]
|
||||
|
||||
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')
|
||||
def test_attrgetter_using():
|
||||
from target import Class
|
||||
|
||||
def assert_getter_works(objtype, name, obj, attrs=[], **kw):
|
||||
getattr_spy = []
|
||||
|
||||
@ -586,10 +594,10 @@ def test_attrgetter_using():
|
||||
|
||||
options.members = ALL
|
||||
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
|
||||
assert_getter_works('class', 'test_autodoc.Class', Class, ['meth', 'inheritedmeth'])
|
||||
assert_getter_works('class', 'target.Class', Class, ['meth', 'inheritedmeth'])
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
@ -656,11 +664,11 @@ def test_generate():
|
||||
assert_warns("failed to import function 'foobar' from module 'util'",
|
||||
'function', 'util.foobar', more_content=None)
|
||||
# method missing
|
||||
assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc';",
|
||||
'method', 'test_autodoc.Class.foobar', more_content=None)
|
||||
assert_warns("failed to import method 'Class.foobar' from module 'target';",
|
||||
'method', 'target.Class.foobar', more_content=None)
|
||||
|
||||
# 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')
|
||||
add_content = ViewList()
|
||||
add_content.append('Content.', '', 0)
|
||||
@ -675,63 +683,63 @@ def test_generate():
|
||||
assert len(directive.result) == 0
|
||||
|
||||
# assert that exceptions can be documented
|
||||
assert_works('exception', 'test_autodoc.CustomEx', all_members=True)
|
||||
assert_works('exception', 'test_autodoc.CustomEx')
|
||||
assert_works('exception', 'target.CustomEx', all_members=True)
|
||||
assert_works('exception', 'target.CustomEx')
|
||||
|
||||
# test diverse inclusion settings for members
|
||||
should = [('class', 'test_autodoc.Class')]
|
||||
should = [('class', 'target.Class')]
|
||||
assert_processes(should, 'class', 'Class')
|
||||
should.extend([('method', 'test_autodoc.Class.meth')])
|
||||
should.extend([('method', 'target.Class.meth')])
|
||||
options.members = ['meth']
|
||||
options.exclude_members = set(['excludemeth'])
|
||||
assert_processes(should, 'class', 'Class')
|
||||
should.extend([('attribute', 'test_autodoc.Class.prop'),
|
||||
('attribute', 'test_autodoc.Class.descr'),
|
||||
('attribute', 'test_autodoc.Class.attr'),
|
||||
('attribute', 'test_autodoc.Class.docattr'),
|
||||
('attribute', 'test_autodoc.Class.udocattr'),
|
||||
('attribute', 'test_autodoc.Class.mdocattr'),
|
||||
('attribute', 'test_autodoc.Class.inst_attr_comment'),
|
||||
('attribute', 'test_autodoc.Class.inst_attr_inline'),
|
||||
('attribute', 'test_autodoc.Class.inst_attr_string'),
|
||||
('method', 'test_autodoc.Class.moore'),
|
||||
should.extend([('attribute', 'target.Class.prop'),
|
||||
('attribute', 'target.Class.descr'),
|
||||
('attribute', 'target.Class.attr'),
|
||||
('attribute', 'target.Class.docattr'),
|
||||
('attribute', 'target.Class.udocattr'),
|
||||
('attribute', 'target.Class.mdocattr'),
|
||||
('attribute', 'target.Class.inst_attr_comment'),
|
||||
('attribute', 'target.Class.inst_attr_inline'),
|
||||
('attribute', 'target.Class.inst_attr_string'),
|
||||
('method', 'target.Class.moore'),
|
||||
])
|
||||
options.members = ALL
|
||||
assert_processes(should, 'class', 'Class')
|
||||
options.undoc_members = True
|
||||
should.extend((('attribute', 'test_autodoc.Class.skipattr'),
|
||||
('method', 'test_autodoc.Class.undocmeth'),
|
||||
('method', 'test_autodoc.Class.roger')))
|
||||
should.extend((('attribute', 'target.Class.skipattr'),
|
||||
('method', 'target.Class.undocmeth'),
|
||||
('method', 'target.Class.roger')))
|
||||
assert_processes(should, 'class', 'Class')
|
||||
options.inherited_members = True
|
||||
should.append(('method', 'test_autodoc.Class.inheritedmeth'))
|
||||
should.append(('method', 'target.Class.inheritedmeth'))
|
||||
assert_processes(should, 'class', 'Class')
|
||||
|
||||
# test special members
|
||||
options.special_members = ['__special1__']
|
||||
should.append(('method', 'test_autodoc.Class.__special1__'))
|
||||
should.append(('method', 'target.Class.__special1__'))
|
||||
assert_processes(should, 'class', 'Class')
|
||||
options.special_members = ALL
|
||||
should.append(('method', 'test_autodoc.Class.__special2__'))
|
||||
should.append(('method', 'target.Class.__special2__'))
|
||||
assert_processes(should, 'class', 'Class')
|
||||
options.special_members = False
|
||||
|
||||
options.members = []
|
||||
# test module flags
|
||||
assert_result_contains('.. py:module:: test_autodoc',
|
||||
'module', 'test_autodoc')
|
||||
assert_result_contains('.. py:module:: target',
|
||||
'module', 'target')
|
||||
options.synopsis = 'Synopsis'
|
||||
assert_result_contains(' :synopsis: Synopsis', 'module', 'test_autodoc')
|
||||
assert_result_contains(' :synopsis: Synopsis', 'module', 'target')
|
||||
options.deprecated = True
|
||||
assert_result_contains(' :deprecated:', 'module', 'test_autodoc')
|
||||
assert_result_contains(' :deprecated:', 'module', 'target')
|
||||
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
|
||||
options.members = ALL
|
||||
assert_result_contains('.. py:class:: Class(arg)', 'module', 'test_autodoc')
|
||||
assert_result_contains('.. py:class:: Class(arg)', 'module', 'target')
|
||||
try:
|
||||
assert_result_contains('.. py:exception:: CustomEx',
|
||||
'module', 'test_autodoc')
|
||||
'module', 'target')
|
||||
except AssertionError:
|
||||
pass
|
||||
else:
|
||||
@ -746,7 +754,7 @@ def test_generate():
|
||||
# test noindex flag
|
||||
options.members = []
|
||||
options.noindex = True
|
||||
assert_result_contains(' :noindex:', 'module', 'test_autodoc')
|
||||
assert_result_contains(' :noindex:', 'module', 'target')
|
||||
assert_result_contains(' :noindex:', 'class', 'Base')
|
||||
|
||||
# okay, now let's get serious about mixing Python and C signature stuff
|
||||
@ -754,14 +762,14 @@ def test_generate():
|
||||
all_members=True)
|
||||
|
||||
# test inner class handling
|
||||
assert_processes([('class', 'test_autodoc.Outer'),
|
||||
('class', 'test_autodoc.Outer.Inner'),
|
||||
('method', 'test_autodoc.Outer.Inner.meth')],
|
||||
assert_processes([('class', 'target.Outer'),
|
||||
('class', 'target.Outer.Inner'),
|
||||
('method', 'target.Outer.Inner.meth')],
|
||||
'class', 'Outer', all_members=True)
|
||||
|
||||
# test descriptor docstrings
|
||||
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)
|
||||
directive.env.ref_context['py:module'] = 'time'
|
||||
@ -769,7 +777,7 @@ def test_generate():
|
||||
assert_processes([('function', 'time.asctime')], 'function', 'asctime')
|
||||
|
||||
# test autodoc_member_order == 'source'
|
||||
directive.env.ref_context['py:module'] = 'test_autodoc'
|
||||
directive.env.ref_context['py:module'] = 'target'
|
||||
options.private_members = True
|
||||
if PY3:
|
||||
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']
|
||||
|
||||
# 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',
|
||||
'attribute', 'mdocattr')
|
||||
del directive.env.temp_data['autodoc:class']
|
||||
@ -803,25 +811,25 @@ def test_generate():
|
||||
# test autodoc_docstring_signature
|
||||
assert_result_contains(
|
||||
'.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method',
|
||||
'test_autodoc.DocstringSig.meth')
|
||||
'target.DocstringSig.meth')
|
||||
assert_result_contains(
|
||||
' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth')
|
||||
' rest of docstring', 'method', 'target.DocstringSig.meth')
|
||||
assert_result_contains(
|
||||
'.. py:method:: DocstringSig.meth2()', 'method',
|
||||
'test_autodoc.DocstringSig.meth2')
|
||||
'target.DocstringSig.meth2')
|
||||
assert_result_contains(
|
||||
' indented line', 'method',
|
||||
'test_autodoc.DocstringSig.meth2')
|
||||
'target.DocstringSig.meth2')
|
||||
assert_result_contains(
|
||||
'.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method',
|
||||
'test_autodoc.Class.moore')
|
||||
'target.Class.moore')
|
||||
|
||||
# test new attribute documenter behavior
|
||||
directive.env.ref_context['py:module'] = 'test_autodoc'
|
||||
directive.env.ref_context['py:module'] = 'target'
|
||||
options.undoc_members = True
|
||||
assert_processes([('class', 'test_autodoc.AttCls'),
|
||||
('attribute', 'test_autodoc.AttCls.a1'),
|
||||
('attribute', 'test_autodoc.AttCls.a2'),
|
||||
assert_processes([('class', 'target.AttCls'),
|
||||
('attribute', 'target.AttCls.a1'),
|
||||
('attribute', 'target.AttCls.a2'),
|
||||
], 'class', 'AttCls')
|
||||
assert_result_contains(
|
||||
' :annotation: = hello world', 'attribute', 'AttCls.a1')
|
||||
@ -831,40 +839,40 @@ def test_generate():
|
||||
# test explicit members with instance attributes
|
||||
del directive.env.temp_data['autodoc:class']
|
||||
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.undoc_members = False
|
||||
options.members = ALL
|
||||
assert_processes([
|
||||
('class', 'test_autodoc.InstAttCls'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ca1'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ca2'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ca3'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ia1'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ia2'),
|
||||
('class', 'target.InstAttCls'),
|
||||
('attribute', 'target.InstAttCls.ca1'),
|
||||
('attribute', 'target.InstAttCls.ca2'),
|
||||
('attribute', 'target.InstAttCls.ca3'),
|
||||
('attribute', 'target.InstAttCls.ia1'),
|
||||
('attribute', 'target.InstAttCls.ia2'),
|
||||
], 'class', 'InstAttCls')
|
||||
del directive.env.temp_data['autodoc:class']
|
||||
del directive.env.temp_data['autodoc:module']
|
||||
options.members = ['ca1', 'ia1']
|
||||
assert_processes([
|
||||
('class', 'test_autodoc.InstAttCls'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ca1'),
|
||||
('attribute', 'test_autodoc.InstAttCls.ia1'),
|
||||
('class', 'target.InstAttCls'),
|
||||
('attribute', 'target.InstAttCls.ca1'),
|
||||
('attribute', 'target.InstAttCls.ia1'),
|
||||
], 'class', 'InstAttCls')
|
||||
del directive.env.temp_data['autodoc:class']
|
||||
del directive.env.temp_data['autodoc:module']
|
||||
del directive.env.ref_context['py:module']
|
||||
|
||||
# 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.undoc_members = False
|
||||
options.members = ALL
|
||||
assert_processes([
|
||||
('class', 'test_autodoc.EnumCls'),
|
||||
('attribute', 'test_autodoc.EnumCls.val1'),
|
||||
('attribute', 'test_autodoc.EnumCls.val2'),
|
||||
('attribute', 'test_autodoc.EnumCls.val3'),
|
||||
('class', 'target.EnumCls'),
|
||||
('attribute', 'target.EnumCls.val1'),
|
||||
('attribute', 'target.EnumCls.val2'),
|
||||
('attribute', 'target.EnumCls.val3'),
|
||||
], 'class', 'EnumCls')
|
||||
assert_result_contains(
|
||||
' :annotation: = 12', 'attribute', 'EnumCls.val1')
|
||||
@ -878,11 +886,11 @@ def test_generate():
|
||||
# test descriptor class documentation
|
||||
options.members = ['CustomDataDescriptor', 'CustomDataDescriptor2']
|
||||
assert_result_contains('.. py:class:: CustomDataDescriptor(doc)',
|
||||
'module', 'test_autodoc')
|
||||
'module', 'target')
|
||||
assert_result_contains(' .. py:method:: CustomDataDescriptor.meth()',
|
||||
'module', 'test_autodoc')
|
||||
'module', 'target')
|
||||
assert_result_contains('.. py:class:: CustomDataDescriptor2(doc)',
|
||||
'module', 'test_autodoc')
|
||||
'module', 'target')
|
||||
|
||||
# test mocked module imports
|
||||
options.members = ['TestAutodoc']
|
||||
@ -894,224 +902,3 @@ def test_generate():
|
||||
options.members = ['decoratedFunction']
|
||||
assert_result_contains('.. py:function:: decoratedFunction()',
|
||||
'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"""
|
||||
|
@ -182,8 +182,8 @@ def test_html_warnings(app, warning):
|
||||
r'-| |-'),
|
||||
],
|
||||
'autodoc.html': [
|
||||
(".//dt[@id='test_autodoc.Class']", ''),
|
||||
(".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'),
|
||||
(".//dt[@id='autodoc_target.Class']", ''),
|
||||
(".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
|
||||
(".//dd/p", r'Return spam\.'),
|
||||
],
|
||||
'extapi.html': [
|
||||
|
@ -90,8 +90,8 @@ def cached_etree_parse():
|
||||
r'-| |-'),
|
||||
],
|
||||
'autodoc.html': [
|
||||
(".//dt[@id='test_autodoc.Class']", ''),
|
||||
(".//dt[@id='test_autodoc.function']/em", r'\*\*kwds'),
|
||||
(".//dt[@id='autodoc_target.Class']", ''),
|
||||
(".//dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
|
||||
(".//dd/p", r'Return spam\.'),
|
||||
],
|
||||
'extapi.html': [
|
||||
|
@ -335,6 +335,43 @@ def test_numref_with_language_ja(app, status, warning):
|
||||
'\\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')
|
||||
def test_latex_add_latex_package(app, status, warning):
|
||||
app.add_latex_package('foo')
|
||||
@ -712,20 +749,16 @@ def test_latex_logo_if_not_found(app, status, warning):
|
||||
assert isinstance(exc, SphinxError)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='toctree-maxdepth',
|
||||
confoverrides={'latex_documents': [
|
||||
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
|
||||
'Georg Brandl', 'manual'),
|
||||
]})
|
||||
@pytest.mark.sphinx('latex', testroot='toctree-maxdepth')
|
||||
def test_toctree_maxdepth_manual(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
|
||||
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||
print(result)
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
assert '\\setcounter{tocdepth}{1}' in result
|
||||
assert '\\setcounter{secnumdepth}' not in result
|
||||
|
||||
assert '\\chapter{Foo}' in result
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'latex', testroot='toctree-maxdepth',
|
||||
@ -741,7 +774,7 @@ def test_toctree_maxdepth_howto(app, status, warning):
|
||||
print(warning.getvalue())
|
||||
assert '\\setcounter{tocdepth}{2}' in result
|
||||
assert '\\setcounter{secnumdepth}' not in result
|
||||
|
||||
assert '\\section{Foo}' in result
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'latex', testroot='toctree-maxdepth',
|
||||
@ -754,7 +787,7 @@ def test_toctree_not_found(app, status, warning):
|
||||
print(warning.getvalue())
|
||||
assert '\\setcounter{tocdepth}' not in result
|
||||
assert '\\setcounter{secnumdepth}' not in result
|
||||
|
||||
assert '\\chapter{Foo A}' in result
|
||||
|
||||
@pytest.mark.sphinx(
|
||||
'latex', testroot='toctree-maxdepth',
|
||||
@ -804,6 +837,26 @@ def test_latex_toplevel_sectioning_is_part(app, status, warning):
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
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(
|
||||
@ -818,6 +871,22 @@ def test_latex_toplevel_sectioning_is_chapter(app, status, warning):
|
||||
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(
|
||||
'latex', testroot='toctree-maxdepth',
|
||||
confoverrides={'latex_toplevel_sectioning': 'section'})
|
||||
|
@ -21,9 +21,9 @@ def test_build(app, status, warning):
|
||||
py_undoc = (app.outdir / 'python.txt').text()
|
||||
assert py_undoc.startswith('Undocumented Python objects\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 ' * process_docstring\n' in py_undoc
|
||||
assert ' * raises\n' in py_undoc
|
||||
assert ' * function\n' not in py_undoc # these two are documented
|
||||
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
|
||||
assert list(undoc_c.values())[0] == set([('function', 'Py_SphinxTest')])
|
||||
|
||||
assert 'test_autodoc' in undoc_py
|
||||
assert 'funcs' in undoc_py['test_autodoc']
|
||||
assert 'process_docstring' in undoc_py['test_autodoc']['funcs']
|
||||
assert 'classes' in undoc_py['test_autodoc']
|
||||
assert 'Class' in undoc_py['test_autodoc']['classes']
|
||||
assert 'undocmeth' in undoc_py['test_autodoc']['classes']['Class']
|
||||
assert 'autodoc_target' in undoc_py
|
||||
assert 'funcs' in undoc_py['autodoc_target']
|
||||
assert 'raises' in undoc_py['autodoc_target']['funcs']
|
||||
assert 'classes' in undoc_py['autodoc_target']
|
||||
assert 'Class' in undoc_py['autodoc_target']['classes']
|
||||
assert 'undocmeth' in undoc_py['autodoc_target']['classes']['Class']
|
||||
|
Loading…
Reference in New Issue
Block a user