mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x'
This commit is contained in:
commit
42aa293679
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@
|
|||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
.ropeproject/
|
.ropeproject/
|
||||||
|
.vscode/
|
||||||
TAGS
|
TAGS
|
||||||
.tags
|
.tags
|
||||||
.tox/
|
.tox/
|
||||||
|
29
CHANGES
29
CHANGES
@ -43,18 +43,40 @@ Incompatible changes
|
|||||||
Deprecated
|
Deprecated
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* The first argument for sphinx.ext.autosummary.generate.AutosummaryRenderer has
|
||||||
|
been changed to Sphinx object
|
||||||
|
* ``sphinx.ext.autosummary.generate.AutosummaryRenderer`` takes an object type
|
||||||
|
as an argument
|
||||||
|
* The ``template_dir`` argument of ``sphinx.ext.autosummary.generate.
|
||||||
|
AutosummaryRenderer``
|
||||||
* The ``module`` argument of ``sphinx.ext.autosummary.generate.
|
* The ``module`` argument of ``sphinx.ext.autosummary.generate.
|
||||||
find_autosummary_in_docstring()``
|
find_autosummary_in_docstring()``
|
||||||
|
* The ``builder`` argument of ``sphinx.ext.autosummary.generate.
|
||||||
|
generate_autosummary_docs()``
|
||||||
|
* The ``template_dir`` argument of ``sphinx.ext.autosummary.generate.
|
||||||
|
generate_autosummary_docs()``
|
||||||
|
* ``sphinx.ext.autosummary.generate.AutosummaryRenderer.exists()``
|
||||||
|
|
||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
* LaTeX: Make the ``toplevel_sectioning`` setting optional in LaTeX theme
|
* LaTeX: Make the ``toplevel_sectioning`` setting optional in LaTeX theme
|
||||||
|
* LaTeX: Allow to override papersize and pointsize from LaTeX themes
|
||||||
|
* LaTeX: Add :confval:`latex_theme_options` to override theme options
|
||||||
* #7410: Allow to suppress "circular toctree references detected" warnings using
|
* #7410: Allow to suppress "circular toctree references detected" warnings using
|
||||||
:confval:`suppress_warnings`
|
:confval:`suppress_warnings`
|
||||||
* C, added scope control directives, :rst:dir:`c:namespace`,
|
* C, added scope control directives, :rst:dir:`c:namespace`,
|
||||||
:rst:dir:`c:namespace-push`, and :rst:dir:`c:namespace-pop`.
|
:rst:dir:`c:namespace-push`, and :rst:dir:`c:namespace-pop`.
|
||||||
|
* #2044: autodoc: Suppress default value for instance attributes
|
||||||
|
* #7473: autodoc: consider a member public if docstring contains
|
||||||
|
``:meta public:`` in info-field-list
|
||||||
* #7466: autosummary: headings in generated documents are not translated
|
* #7466: autosummary: headings in generated documents are not translated
|
||||||
|
* #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a
|
||||||
|
caption to the toctree
|
||||||
|
* #248, #6040: autosummary: Add ``:recursive:`` option to autosummary directive
|
||||||
|
to generate stub files recursively
|
||||||
|
* #7535: sphinx-autogen: crashes when custom template uses inheritance
|
||||||
|
* #7536: sphinx-autogen: crashes when template uses i18n feature
|
||||||
* #7481: html theme: Add right margin to footnote/citation labels
|
* #7481: html theme: Add right margin to footnote/citation labels
|
||||||
* #7482: html theme: CSS spacing for code blocks with captions and line numbers
|
* #7482: html theme: CSS spacing for code blocks with captions and line numbers
|
||||||
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and
|
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and
|
||||||
@ -63,10 +85,17 @@ Features added
|
|||||||
* #7484: html theme: Avoid clashes between sidebar and other blocks
|
* #7484: html theme: Avoid clashes between sidebar and other blocks
|
||||||
* #7476: html theme: Relbar breadcrumb should contain current page
|
* #7476: html theme: Relbar breadcrumb should contain current page
|
||||||
* #7506: html theme: A canonical URL is not escaped
|
* #7506: html theme: A canonical URL is not escaped
|
||||||
|
* #7533: html theme: Avoid whitespace at the beginning of genindex.html
|
||||||
|
* #7541: html theme: Add a "clearer" at the end of the "body"
|
||||||
|
* #7542: html theme: Make admonition/topic/sidebar scrollable
|
||||||
|
* C and C++: allow semicolon in the end of declarations.
|
||||||
|
* C++, parse parameterized noexcept specifiers.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* #6703: autodoc: incremental build does not work for imported objects
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
1
doc/_themes/sphinx13/static/sphinx13.css
vendored
1
doc/_themes/sphinx13/static/sphinx13.css
vendored
@ -127,6 +127,7 @@ div.sphinxsidebar {
|
|||||||
float: right;
|
float: right;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
max-height: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar .logo {
|
div.sphinxsidebar .logo {
|
||||||
|
@ -56,12 +56,48 @@ The following is a list of deprecated interfaces.
|
|||||||
- 6.0
|
- 6.0
|
||||||
- ``docutils.utils.smartyquotes``
|
- ``docutils.utils.smartyquotes``
|
||||||
|
|
||||||
|
* - The first argument for
|
||||||
|
``sphinx.ext.autosummary.generate.AutosummaryRenderer`` has been changed
|
||||||
|
to Sphinx object
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - ``sphinx.ext.autosummary.generate.AutosummaryRenderer`` takes an object
|
||||||
|
type as an argument
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - The ``template_dir`` argument of
|
||||||
|
``sphinx.ext.autosummary.generate.AutosummaryRenderer``
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
* - The ``module`` argument of
|
* - The ``module`` argument of
|
||||||
``sphinx.ext.autosummary.generate.find_autosummary_in_docstring()``
|
``sphinx.ext.autosummary.generate.find_autosummary_in_docstring()``
|
||||||
- 3.0
|
- 3.0
|
||||||
- 5.0
|
- 5.0
|
||||||
- N/A
|
- N/A
|
||||||
|
|
||||||
|
* - The ``builder`` argument of
|
||||||
|
``sphinx.ext.autosummary.generate.generate_autosummary_docs()``
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - The ``template_dir`` argument of
|
||||||
|
``sphinx.ext.autosummary.generate.generate_autosummary_docs()``
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
* - ``sphinx.ext.autosummary.generate.AutosummaryRenderer.exists()``
|
||||||
|
- 3.1
|
||||||
|
- 5.0
|
||||||
|
- N/A
|
||||||
|
|
||||||
* - ``desc_signature['first']``
|
* - ``desc_signature['first']``
|
||||||
-
|
-
|
||||||
- 3.0
|
- 3.0
|
||||||
|
@ -90,9 +90,9 @@ section describe an easy way to translate with *sphinx-intl*.
|
|||||||
locale_dirs = ['locale/'] # path is example but recommended.
|
locale_dirs = ['locale/'] # path is example but recommended.
|
||||||
gettext_compact = False # optional.
|
gettext_compact = False # optional.
|
||||||
|
|
||||||
This case-study assumes that :confval:`locale_dirs` is set to ``locale/`` and
|
This case-study assumes that BUILDDIR is set to ``_build``,
|
||||||
:confval:`gettext_compact` is set to ``False`` (the Sphinx document is
|
:confval:`locale_dirs` is set to ``locale/`` and :confval:`gettext_compact`
|
||||||
already configured as such).
|
is set to ``False`` (the Sphinx document is already configured as such).
|
||||||
|
|
||||||
#. Extract translatable messages into pot files.
|
#. Extract translatable messages into pot files.
|
||||||
|
|
||||||
|
@ -2117,6 +2117,13 @@ These options influence LaTeX output.
|
|||||||
|
|
||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
.. confval:: latex_theme_options
|
||||||
|
|
||||||
|
A dictionary of options that influence the look and feel of the selected
|
||||||
|
theme.
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
.. confval:: latex_theme_path
|
.. confval:: latex_theme_path
|
||||||
|
|
||||||
A list of paths that contain custom LaTeX themes as subdirectories. Relative
|
A list of paths that contain custom LaTeX themes as subdirectories. Relative
|
||||||
|
@ -154,6 +154,21 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
|||||||
|
|
||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
* autodoc considers a member public if its docstring contains
|
||||||
|
``:meta public:`` in its :ref:`info-field-lists`, even if it starts with
|
||||||
|
an underscore.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: rst
|
||||||
|
|
||||||
|
def _my_function(my_arg, my_other_arg):
|
||||||
|
"""blah blah blah
|
||||||
|
|
||||||
|
:meta public:
|
||||||
|
"""
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
* Python "special" members (that is, those named like ``__special__``) will
|
* Python "special" members (that is, those named like ``__special__``) will
|
||||||
be included if the ``special-members`` flag option is given::
|
be included if the ``special-members`` flag option is given::
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts:
|
|||||||
|
|
||||||
The :rst:dir:`autosummary` directive can also optionally serve as a
|
The :rst:dir:`autosummary` directive can also optionally serve as a
|
||||||
:rst:dir:`toctree` entry for the included items. Optionally, stub
|
:rst:dir:`toctree` entry for the included items. Optionally, stub
|
||||||
``.rst`` files for these items can also be automatically generated.
|
``.rst`` files for these items can also be automatically generated
|
||||||
|
when :confval:`autosummary_generate` is `True`.
|
||||||
|
|
||||||
For example, ::
|
For example, ::
|
||||||
|
|
||||||
@ -76,6 +77,12 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts:
|
|||||||
directory. If no argument is given, output is placed in the same directory
|
directory. If no argument is given, output is placed in the same directory
|
||||||
as the file that contains the directive.
|
as the file that contains the directive.
|
||||||
|
|
||||||
|
You can also use ``caption`` option to give a caption to the toctree.
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
caption option added.
|
||||||
|
|
||||||
* If you don't want the :rst:dir:`autosummary` to show function signatures in
|
* If you don't want the :rst:dir:`autosummary` to show function signatures in
|
||||||
the listing, include the ``nosignatures`` option::
|
the listing, include the ``nosignatures`` option::
|
||||||
|
|
||||||
@ -99,6 +106,17 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts:
|
|||||||
|
|
||||||
.. versionadded:: 1.0
|
.. versionadded:: 1.0
|
||||||
|
|
||||||
|
* You can specify the ``recursive`` option to generate documents for
|
||||||
|
modules and sub-packages recursively. It defaults to disabled.
|
||||||
|
For example, ::
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:recursive:
|
||||||
|
|
||||||
|
sphinx.environment.BuildEnvironment
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
|
|
||||||
:program:`sphinx-autogen` -- generate autodoc stub pages
|
:program:`sphinx-autogen` -- generate autodoc stub pages
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
@ -136,7 +154,7 @@ also use these config values:
|
|||||||
.. confval:: autosummary_generate
|
.. confval:: autosummary_generate
|
||||||
|
|
||||||
Boolean indicating whether to scan all found documents for autosummary
|
Boolean indicating whether to scan all found documents for autosummary
|
||||||
directives, and to generate stub pages for each.
|
directives, and to generate stub pages for each. It is disabled by default.
|
||||||
|
|
||||||
Can also be a list of documents for which stub pages should be generated.
|
Can also be a list of documents for which stub pages should be generated.
|
||||||
|
|
||||||
@ -263,6 +281,12 @@ The following variables available in the templates:
|
|||||||
List containing names of "public" attributes in the class. Only available
|
List containing names of "public" attributes in the class. Only available
|
||||||
for classes.
|
for classes.
|
||||||
|
|
||||||
|
.. data:: modules
|
||||||
|
|
||||||
|
List containing names of "public" modules in the package. Only available for
|
||||||
|
modules that are packages.
|
||||||
|
|
||||||
|
.. versionadded:: 3.1
|
||||||
|
|
||||||
Additionally, the following filters are available
|
Additionally, the following filters are available
|
||||||
|
|
||||||
|
@ -314,6 +314,8 @@ class LaTeXBuilder(Builder):
|
|||||||
self.context['title'] = title
|
self.context['title'] = title
|
||||||
self.context['author'] = author
|
self.context['author'] = author
|
||||||
self.context['docclass'] = theme.docclass
|
self.context['docclass'] = theme.docclass
|
||||||
|
self.context['papersize'] = theme.papersize
|
||||||
|
self.context['pointsize'] = theme.pointsize
|
||||||
self.context['wrapperclass'] = theme.wrapperclass
|
self.context['wrapperclass'] = theme.wrapperclass
|
||||||
|
|
||||||
def assemble_doctree(self, indexfile: str, toctree_only: bool, appendices: List[str]) -> nodes.document: # NOQA
|
def assemble_doctree(self, indexfile: str, toctree_only: bool, appendices: List[str]) -> nodes.document: # NOQA
|
||||||
@ -491,6 +493,14 @@ def validate_config_values(app: Sphinx, config: Config) -> None:
|
|||||||
config.latex_elements.pop(key)
|
config.latex_elements.pop(key)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_latex_theme_options(app: Sphinx, config: Config) -> None:
|
||||||
|
for key in list(config.latex_theme_options):
|
||||||
|
if key not in Theme.UPDATABLE_KEYS:
|
||||||
|
msg = __("Unknown theme option: latex_theme_options[%r], ignored.")
|
||||||
|
logger.warning(msg % (key,))
|
||||||
|
config.latex_theme_options.pop(key)
|
||||||
|
|
||||||
|
|
||||||
def default_latex_engine(config: Config) -> str:
|
def default_latex_engine(config: Config) -> str:
|
||||||
""" Better default latex_engine settings for specific languages. """
|
""" Better default latex_engine settings for specific languages. """
|
||||||
if config.language == 'ja':
|
if config.language == 'ja':
|
||||||
@ -537,6 +547,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
|
|
||||||
app.add_builder(LaTeXBuilder)
|
app.add_builder(LaTeXBuilder)
|
||||||
app.connect('config-inited', validate_config_values, priority=800)
|
app.connect('config-inited', validate_config_values, priority=800)
|
||||||
|
app.connect('config-inited', validate_latex_theme_options, priority=800)
|
||||||
|
|
||||||
app.add_config_value('latex_engine', default_latex_engine, None,
|
app.add_config_value('latex_engine', default_latex_engine, None,
|
||||||
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))
|
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))
|
||||||
@ -553,6 +564,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
app.add_config_value('latex_elements', {}, None)
|
app.add_config_value('latex_elements', {}, None)
|
||||||
app.add_config_value('latex_additional_files', [], None)
|
app.add_config_value('latex_additional_files', [], None)
|
||||||
app.add_config_value('latex_theme', 'manual', None, [str])
|
app.add_config_value('latex_theme', 'manual', None, [str])
|
||||||
|
app.add_config_value('latex_theme_options', {}, None)
|
||||||
app.add_config_value('latex_theme_path', [], None, [list])
|
app.add_config_value('latex_theme_path', [], None, [list])
|
||||||
|
|
||||||
app.add_config_value('latex_docclass', default_latex_docclass, None)
|
app.add_config_value('latex_docclass', default_latex_docclass, None)
|
||||||
|
@ -69,8 +69,8 @@ LUALATEX_DEFAULT_FONTPKG = XELATEX_DEFAULT_FONTPKG
|
|||||||
|
|
||||||
DEFAULT_SETTINGS = {
|
DEFAULT_SETTINGS = {
|
||||||
'latex_engine': 'pdflatex',
|
'latex_engine': 'pdflatex',
|
||||||
'papersize': 'letterpaper',
|
'papersize': '',
|
||||||
'pointsize': '10pt',
|
'pointsize': '',
|
||||||
'pxunit': '.75bp',
|
'pxunit': '.75bp',
|
||||||
'classoptions': '',
|
'classoptions': '',
|
||||||
'extraclassoptions': '',
|
'extraclassoptions': '',
|
||||||
|
@ -24,50 +24,59 @@ logger = logging.getLogger(__name__)
|
|||||||
class Theme:
|
class Theme:
|
||||||
"""A set of LaTeX configurations."""
|
"""A set of LaTeX configurations."""
|
||||||
|
|
||||||
|
LATEX_ELEMENTS_KEYS = ['papersize', 'pointsize']
|
||||||
|
UPDATABLE_KEYS = ['papersize', 'pointsize']
|
||||||
|
|
||||||
def __init__(self, name: str) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.docclass = name
|
self.docclass = name
|
||||||
self.wrapperclass = name
|
self.wrapperclass = name
|
||||||
|
self.papersize = 'letterpaper'
|
||||||
|
self.pointsize = '10pt'
|
||||||
self.toplevel_sectioning = 'chapter'
|
self.toplevel_sectioning = 'chapter'
|
||||||
|
|
||||||
|
def update(self, config: Config) -> None:
|
||||||
|
"""Override theme settings by user's configuration."""
|
||||||
|
for key in self.LATEX_ELEMENTS_KEYS:
|
||||||
|
if config.latex_elements.get(key):
|
||||||
|
value = config.latex_elements[key]
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
for key in self.UPDATABLE_KEYS:
|
||||||
|
if key in config.latex_theme_options:
|
||||||
|
value = config.latex_theme_options[key]
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
class BuiltInTheme(Theme):
|
class BuiltInTheme(Theme):
|
||||||
"""A built-in LaTeX theme."""
|
"""A built-in LaTeX theme."""
|
||||||
|
|
||||||
def __init__(self, name: str, config: Config) -> None:
|
def __init__(self, name: str, config: Config) -> None:
|
||||||
# Note: Don't call supermethod here.
|
super().__init__(name)
|
||||||
self.name = name
|
|
||||||
self.latex_docclass = config.latex_docclass # type: Dict[str, str]
|
|
||||||
|
|
||||||
@property
|
if name == 'howto':
|
||||||
def docclass(self) -> str: # type: ignore
|
self.docclass = config.latex_docclass.get('howto', 'article')
|
||||||
if self.name == 'howto':
|
|
||||||
return self.latex_docclass.get('howto', 'article')
|
|
||||||
else:
|
else:
|
||||||
return self.latex_docclass.get('manual', 'report')
|
self.docclass = config.latex_docclass.get('manual', 'report')
|
||||||
|
|
||||||
@property
|
if name in ('manual', 'howto'):
|
||||||
def wrapperclass(self) -> str: # type: ignore
|
self.wrapperclass = 'sphinx' + name
|
||||||
if self.name in ('manual', 'howto'):
|
|
||||||
return 'sphinx' + self.name
|
|
||||||
else:
|
else:
|
||||||
return self.name
|
self.wrapperclass = name
|
||||||
|
|
||||||
@property
|
|
||||||
def toplevel_sectioning(self) -> str: # type: ignore
|
|
||||||
# we assume LaTeX class provides \chapter command except in case
|
# we assume LaTeX class provides \chapter command except in case
|
||||||
# of non-Japanese 'howto' case
|
# of non-Japanese 'howto' case
|
||||||
if self.name == 'howto' and not self.docclass.startswith('j'):
|
if name == 'howto' and not self.docclass.startswith('j'):
|
||||||
return 'section'
|
self.toplevel_sectioning = 'section'
|
||||||
else:
|
else:
|
||||||
return 'chapter'
|
self.toplevel_sectioning = 'chapter'
|
||||||
|
|
||||||
|
|
||||||
class UserTheme(Theme):
|
class UserTheme(Theme):
|
||||||
"""A user defined LaTeX theme."""
|
"""A user defined LaTeX theme."""
|
||||||
|
|
||||||
REQUIRED_CONFIG_KEYS = ['docclass', 'wrapperclass']
|
REQUIRED_CONFIG_KEYS = ['docclass', 'wrapperclass']
|
||||||
OPTIONAL_CONFIG_KEYS = ['toplevel_sectioning']
|
OPTIONAL_CONFIG_KEYS = ['papersize', 'pointsize', 'toplevel_sectioning']
|
||||||
|
|
||||||
def __init__(self, name: str, filename: str) -> None:
|
def __init__(self, name: str, filename: str) -> None:
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
@ -97,6 +106,7 @@ class ThemeFactory:
|
|||||||
def __init__(self, app: Sphinx) -> None:
|
def __init__(self, app: Sphinx) -> None:
|
||||||
self.themes = {} # type: Dict[str, Theme]
|
self.themes = {} # type: Dict[str, Theme]
|
||||||
self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path]
|
self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path]
|
||||||
|
self.config = app.config
|
||||||
self.load_builtin_themes(app.config)
|
self.load_builtin_themes(app.config)
|
||||||
|
|
||||||
def load_builtin_themes(self, config: Config) -> None:
|
def load_builtin_themes(self, config: Config) -> None:
|
||||||
@ -107,13 +117,14 @@ class ThemeFactory:
|
|||||||
def get(self, name: str) -> Theme:
|
def get(self, name: str) -> Theme:
|
||||||
"""Get a theme for given *name*."""
|
"""Get a theme for given *name*."""
|
||||||
if name in self.themes:
|
if name in self.themes:
|
||||||
return self.themes[name]
|
theme = self.themes[name]
|
||||||
else:
|
else:
|
||||||
theme = self.find_user_theme(name)
|
theme = self.find_user_theme(name)
|
||||||
if theme:
|
if not theme:
|
||||||
return theme
|
theme = Theme(name)
|
||||||
else:
|
|
||||||
return Theme(name)
|
theme.update(self.config)
|
||||||
|
return theme
|
||||||
|
|
||||||
def find_user_theme(self, name: str) -> Theme:
|
def find_user_theme(self, name: str) -> Theme:
|
||||||
"""Find a theme named as *name* from latex_theme_path."""
|
"""Find a theme named as *name* from latex_theme_path."""
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from docutils.writers.latex2e import Babel
|
from docutils.writers.latex2e import Babel
|
||||||
|
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ class ExtBabel(Babel):
|
|||||||
self.supported = False
|
self.supported = False
|
||||||
return 'english' # fallback to english
|
return 'english' # fallback to english
|
||||||
|
|
||||||
def get_mainlanguage_options(self) -> str:
|
def get_mainlanguage_options(self) -> Optional[str]:
|
||||||
"""Return options for polyglossia's ``\\setmainlanguage``."""
|
"""Return options for polyglossia's ``\\setmainlanguage``."""
|
||||||
if self.use_polyglossia is False:
|
if self.use_polyglossia is False:
|
||||||
return None
|
return None
|
||||||
|
@ -76,6 +76,6 @@ class DeprecatedDict(dict):
|
|||||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||||
return super().get(key, default)
|
return super().get(key, default)
|
||||||
|
|
||||||
def update(self, other: Dict = None) -> None: # type: ignore
|
def update(self, other: Dict) -> None: # type: ignore
|
||||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||||
super().update(other)
|
super().update(other)
|
||||||
|
@ -1272,10 +1272,12 @@ class ASTEnumerator(ASTBase):
|
|||||||
|
|
||||||
|
|
||||||
class ASTDeclaration(ASTBaseBase):
|
class ASTDeclaration(ASTBaseBase):
|
||||||
def __init__(self, objectType: str, directiveType: str, declaration: Any) -> None:
|
def __init__(self, objectType: str, directiveType: str, declaration: Any,
|
||||||
|
semicolon: bool = False) -> None:
|
||||||
self.objectType = objectType
|
self.objectType = objectType
|
||||||
self.directiveType = directiveType
|
self.directiveType = directiveType
|
||||||
self.declaration = declaration
|
self.declaration = declaration
|
||||||
|
self.semicolon = semicolon
|
||||||
|
|
||||||
self.symbol = None # type: Symbol
|
self.symbol = None # type: Symbol
|
||||||
# set by CObject._add_enumerator_to_parent
|
# set by CObject._add_enumerator_to_parent
|
||||||
@ -1304,7 +1306,10 @@ class ASTDeclaration(ASTBaseBase):
|
|||||||
return self.get_id(_max_id, True)
|
return self.get_id(_max_id, True)
|
||||||
|
|
||||||
def _stringify(self, transform: StringifyTransform) -> str:
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
return transform(self.declaration)
|
res = transform(self.declaration)
|
||||||
|
if self.semicolon:
|
||||||
|
res += ';'
|
||||||
|
return res
|
||||||
|
|
||||||
def describe_signature(self, signode: TextElement, mode: str,
|
def describe_signature(self, signode: TextElement, mode: str,
|
||||||
env: "BuildEnvironment", options: Dict) -> None:
|
env: "BuildEnvironment", options: Dict) -> None:
|
||||||
@ -1340,6 +1345,8 @@ class ASTDeclaration(ASTBaseBase):
|
|||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
|
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
|
||||||
|
if self.semicolon:
|
||||||
|
mainDeclNode += nodes.Text(';')
|
||||||
|
|
||||||
|
|
||||||
class SymbolLookupResult:
|
class SymbolLookupResult:
|
||||||
@ -2742,7 +2749,7 @@ class DefinitionParser(BaseParser):
|
|||||||
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
||||||
decl = self._parse_declarator(named=True, paramMode=outer,
|
decl = self._parse_declarator(named=True, paramMode=outer,
|
||||||
typed=False)
|
typed=False)
|
||||||
self.assert_end()
|
self.assert_end(allowSemicolon=True)
|
||||||
except DefinitionError as exUntyped:
|
except DefinitionError as exUntyped:
|
||||||
desc = "If just a name"
|
desc = "If just a name"
|
||||||
prevErrors.append((exUntyped, desc))
|
prevErrors.append((exUntyped, desc))
|
||||||
@ -2875,7 +2882,12 @@ class DefinitionParser(BaseParser):
|
|||||||
declaration = self._parse_type(named=True, outer='type')
|
declaration = self._parse_type(named=True, outer='type')
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
return ASTDeclaration(objectType, directiveType, declaration)
|
if objectType != 'macro':
|
||||||
|
self.skip_ws()
|
||||||
|
semicolon = self.skip_string(';')
|
||||||
|
else:
|
||||||
|
semicolon = False
|
||||||
|
return ASTDeclaration(objectType, directiveType, declaration, semicolon)
|
||||||
|
|
||||||
def parse_namespace_object(self) -> ASTNestedName:
|
def parse_namespace_object(self) -> ASTNestedName:
|
||||||
return self._parse_nested_name()
|
return self._parse_nested_name()
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union
|
Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union, Optional
|
||||||
)
|
)
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
@ -109,7 +109,8 @@ T = TypeVar('T')
|
|||||||
simple-declaration ->
|
simple-declaration ->
|
||||||
attribute-specifier-seq[opt] decl-specifier-seq[opt]
|
attribute-specifier-seq[opt] decl-specifier-seq[opt]
|
||||||
init-declarator-list[opt] ;
|
init-declarator-list[opt] ;
|
||||||
# Drop the semi-colon. For now: drop the attributes (TODO).
|
# Make the semicolon optional.
|
||||||
|
# For now: drop the attributes (TODO).
|
||||||
# Use at most 1 init-declarator.
|
# Use at most 1 init-declarator.
|
||||||
-> decl-specifier-seq init-declarator
|
-> decl-specifier-seq init-declarator
|
||||||
-> decl-specifier-seq declarator initializer
|
-> decl-specifier-seq declarator initializer
|
||||||
@ -1266,7 +1267,7 @@ class ASTNoexceptExpr(ASTExpression):
|
|||||||
self.expr = expr
|
self.expr = expr
|
||||||
|
|
||||||
def _stringify(self, transform: StringifyTransform) -> str:
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
return "noexcept(" + transform(self.expr) + ")"
|
return 'noexcept(' + transform(self.expr) + ')'
|
||||||
|
|
||||||
def get_id(self, version: int) -> str:
|
def get_id(self, version: int) -> str:
|
||||||
return 'nx' + self.expr.get_id(version)
|
return 'nx' + self.expr.get_id(version)
|
||||||
@ -1812,10 +1813,28 @@ class ASTFunctionParameter(ASTBase):
|
|||||||
self.arg.describe_signature(signode, mode, env, symbol=symbol)
|
self.arg.describe_signature(signode, mode, env, symbol=symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTNoexceptSpec(ASTBase):
|
||||||
|
def __init__(self, expr: Optional[ASTExpression]):
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
if self.expr:
|
||||||
|
return 'noexcept(' + transform(self.expr) + ')'
|
||||||
|
return 'noexcept'
|
||||||
|
|
||||||
|
def describe_signature(self, signode: TextElement, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode += addnodes.desc_annotation('noexcept', 'noexcept')
|
||||||
|
if self.expr:
|
||||||
|
signode.append(nodes.Text('('))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')'))
|
||||||
|
|
||||||
|
|
||||||
class ASTParametersQualifiers(ASTBase):
|
class ASTParametersQualifiers(ASTBase):
|
||||||
def __init__(self, args: List[ASTFunctionParameter],
|
def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool,
|
||||||
volatile: bool, const: bool, refQual: str,
|
refQual: str, exceptionSpec: ASTNoexceptSpec, override: bool, final: bool,
|
||||||
exceptionSpec: str, override: bool, final: bool, initializer: str) -> None:
|
initializer: str) -> None:
|
||||||
self.args = args
|
self.args = args
|
||||||
self.volatile = volatile
|
self.volatile = volatile
|
||||||
self.const = const
|
self.const = const
|
||||||
@ -1874,7 +1893,7 @@ class ASTParametersQualifiers(ASTBase):
|
|||||||
res.append(self.refQual)
|
res.append(self.refQual)
|
||||||
if self.exceptionSpec:
|
if self.exceptionSpec:
|
||||||
res.append(' ')
|
res.append(' ')
|
||||||
res.append(str(self.exceptionSpec))
|
res.append(transform(self.exceptionSpec))
|
||||||
if self.final:
|
if self.final:
|
||||||
res.append(' final')
|
res.append(' final')
|
||||||
if self.override:
|
if self.override:
|
||||||
@ -1911,7 +1930,8 @@ class ASTParametersQualifiers(ASTBase):
|
|||||||
if self.refQual:
|
if self.refQual:
|
||||||
_add_text(signode, self.refQual)
|
_add_text(signode, self.refQual)
|
||||||
if self.exceptionSpec:
|
if self.exceptionSpec:
|
||||||
_add_anno(signode, str(self.exceptionSpec))
|
signode += nodes.Text(' ')
|
||||||
|
self.exceptionSpec.describe_signature(signode, mode, env, symbol)
|
||||||
if self.final:
|
if self.final:
|
||||||
_add_anno(signode, 'final')
|
_add_anno(signode, 'final')
|
||||||
if self.override:
|
if self.override:
|
||||||
@ -3465,12 +3485,14 @@ class ASTTemplateDeclarationPrefix(ASTBase):
|
|||||||
|
|
||||||
class ASTDeclaration(ASTBase):
|
class ASTDeclaration(ASTBase):
|
||||||
def __init__(self, objectType: str, directiveType: str, visibility: str,
|
def __init__(self, objectType: str, directiveType: str, visibility: str,
|
||||||
templatePrefix: ASTTemplateDeclarationPrefix, declaration: Any) -> None:
|
templatePrefix: ASTTemplateDeclarationPrefix, declaration: Any,
|
||||||
|
semicolon: bool = False) -> None:
|
||||||
self.objectType = objectType
|
self.objectType = objectType
|
||||||
self.directiveType = directiveType
|
self.directiveType = directiveType
|
||||||
self.visibility = visibility
|
self.visibility = visibility
|
||||||
self.templatePrefix = templatePrefix
|
self.templatePrefix = templatePrefix
|
||||||
self.declaration = declaration
|
self.declaration = declaration
|
||||||
|
self.semicolon = semicolon
|
||||||
|
|
||||||
self.symbol = None # type: Symbol
|
self.symbol = None # type: Symbol
|
||||||
# set by CPPObject._add_enumerator_to_parent
|
# set by CPPObject._add_enumerator_to_parent
|
||||||
@ -3483,7 +3505,7 @@ class ASTDeclaration(ASTBase):
|
|||||||
templatePrefixClone = None
|
templatePrefixClone = None
|
||||||
return ASTDeclaration(self.objectType, self.directiveType,
|
return ASTDeclaration(self.objectType, self.directiveType,
|
||||||
self.visibility, templatePrefixClone,
|
self.visibility, templatePrefixClone,
|
||||||
self.declaration.clone())
|
self.declaration.clone(), self.semicolon)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> ASTNestedName:
|
def name(self) -> ASTNestedName:
|
||||||
@ -3525,6 +3547,8 @@ class ASTDeclaration(ASTBase):
|
|||||||
if self.templatePrefix:
|
if self.templatePrefix:
|
||||||
res.append(transform(self.templatePrefix))
|
res.append(transform(self.templatePrefix))
|
||||||
res.append(transform(self.declaration))
|
res.append(transform(self.declaration))
|
||||||
|
if self.semicolon:
|
||||||
|
res.append(';')
|
||||||
return ''.join(res)
|
return ''.join(res)
|
||||||
|
|
||||||
def describe_signature(self, signode: desc_signature, mode: str,
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
@ -3578,6 +3602,8 @@ class ASTDeclaration(ASTBase):
|
|||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
|
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
|
||||||
|
if self.semicolon:
|
||||||
|
mainDeclNode += nodes.Text(';')
|
||||||
|
|
||||||
|
|
||||||
class ASTNamespace(ASTBase):
|
class ASTNamespace(ASTBase):
|
||||||
@ -5498,11 +5524,14 @@ class DefinitionParser(BaseParser):
|
|||||||
initializer = None
|
initializer = None
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
if self.skip_string('noexcept'):
|
if self.skip_string('noexcept'):
|
||||||
exceptionSpec = 'noexcept'
|
if self.skip_string_and_ws('('):
|
||||||
self.skip_ws()
|
expr = self._parse_constant_expression(False)
|
||||||
if self.skip_string('('):
|
self.skip_ws()
|
||||||
self.fail('Parameterised "noexcept" not yet implemented.')
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expecting ')' to end 'noexcept'.")
|
||||||
|
exceptionSpec = ASTNoexceptSpec(expr)
|
||||||
|
else:
|
||||||
|
exceptionSpec = ASTNoexceptSpec(None)
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
override = self.skip_word_and_ws('override')
|
override = self.skip_word_and_ws('override')
|
||||||
final = self.skip_word_and_ws('final')
|
final = self.skip_word_and_ws('final')
|
||||||
@ -5875,7 +5904,7 @@ class DefinitionParser(BaseParser):
|
|||||||
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
||||||
decl = self._parse_declarator(named=True, paramMode=outer,
|
decl = self._parse_declarator(named=True, paramMode=outer,
|
||||||
typed=False)
|
typed=False)
|
||||||
self.assert_end()
|
self.assert_end(allowSemicolon=True)
|
||||||
except DefinitionError as exUntyped:
|
except DefinitionError as exUntyped:
|
||||||
if outer == 'type':
|
if outer == 'type':
|
||||||
desc = "If just a name"
|
desc = "If just a name"
|
||||||
@ -6286,8 +6315,10 @@ class DefinitionParser(BaseParser):
|
|||||||
templatePrefix,
|
templatePrefix,
|
||||||
fullSpecShorthand=False,
|
fullSpecShorthand=False,
|
||||||
isMember=objectType == 'member')
|
isMember=objectType == 'member')
|
||||||
|
self.skip_ws()
|
||||||
|
semicolon = self.skip_string(';')
|
||||||
return ASTDeclaration(objectType, directiveType, visibility,
|
return ASTDeclaration(objectType, directiveType, visibility,
|
||||||
templatePrefix, declaration)
|
templatePrefix, declaration, semicolon)
|
||||||
|
|
||||||
def parse_namespace_object(self) -> ASTNamespace:
|
def parse_namespace_object(self) -> ASTNamespace:
|
||||||
templatePrefix = self._parse_template_declaration_prefix(objectType="namespace")
|
templatePrefix = self._parse_template_declaration_prefix(objectType="namespace")
|
||||||
|
@ -65,6 +65,7 @@ def identity(x: Any) -> Any:
|
|||||||
|
|
||||||
|
|
||||||
ALL = object()
|
ALL = object()
|
||||||
|
UNINITIALIZED_ATTR = object()
|
||||||
INSTANCEATTR = object()
|
INSTANCEATTR = object()
|
||||||
SLOTSATTR = object()
|
SLOTSATTR = object()
|
||||||
|
|
||||||
@ -573,6 +574,9 @@ class Documenter:
|
|||||||
if 'private' in metadata:
|
if 'private' in metadata:
|
||||||
# consider a member private if docstring has "private" metadata
|
# consider a member private if docstring has "private" metadata
|
||||||
isprivate = True
|
isprivate = True
|
||||||
|
elif 'public' in metadata:
|
||||||
|
# consider a member public if docstring has "public" metadata
|
||||||
|
isprivate = False
|
||||||
else:
|
else:
|
||||||
isprivate = membername.startswith('_')
|
isprivate = membername.startswith('_')
|
||||||
|
|
||||||
@ -727,7 +731,8 @@ class Documenter:
|
|||||||
# where the attribute documentation would actually be found in.
|
# where the attribute documentation would actually be found in.
|
||||||
# This is used for situations where you have a module that collects the
|
# This is used for situations where you have a module that collects the
|
||||||
# functions and classes of internal submodules.
|
# functions and classes of internal submodules.
|
||||||
self.real_modname = real_modname or self.get_real_modname() # type: str
|
guess_modname = self.get_real_modname()
|
||||||
|
self.real_modname = real_modname or guess_modname
|
||||||
|
|
||||||
# try to also get a source code analyzer for attribute docs
|
# try to also get a source code analyzer for attribute docs
|
||||||
try:
|
try:
|
||||||
@ -745,6 +750,14 @@ class Documenter:
|
|||||||
else:
|
else:
|
||||||
self.directive.filename_set.add(self.analyzer.srcname)
|
self.directive.filename_set.add(self.analyzer.srcname)
|
||||||
|
|
||||||
|
if self.real_modname != guess_modname:
|
||||||
|
# Add module to dependency list if target object is defined in other module.
|
||||||
|
try:
|
||||||
|
analyzer = ModuleAnalyzer.for_module(guess_modname)
|
||||||
|
self.directive.filename_set.add(analyzer.srcname)
|
||||||
|
except PycodeError:
|
||||||
|
pass
|
||||||
|
|
||||||
# check __module__ of object (for members not given explicitly)
|
# check __module__ of object (for members not given explicitly)
|
||||||
if check_module:
|
if check_module:
|
||||||
if not self.check_module():
|
if not self.check_module():
|
||||||
@ -1347,8 +1360,11 @@ class DataDocumenter(ModuleLevelDocumenter):
|
|||||||
sourcename)
|
sourcename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
objrepr = object_description(self.object)
|
if self.object is UNINITIALIZED_ATTR:
|
||||||
self.add_line(' :value: ' + objrepr, sourcename)
|
pass
|
||||||
|
else:
|
||||||
|
objrepr = object_description(self.object)
|
||||||
|
self.add_line(' :value: ' + objrepr, sourcename)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
elif self.options.annotation is SUPPRESS:
|
elif self.options.annotation is SUPPRESS:
|
||||||
@ -1389,6 +1405,7 @@ class DataDeclarationDocumenter(DataDocumenter):
|
|||||||
"""Never import anything."""
|
"""Never import anything."""
|
||||||
# disguise as a data
|
# disguise as a data
|
||||||
self.objtype = 'data'
|
self.objtype = 'data'
|
||||||
|
self.object = UNINITIALIZED_ATTR
|
||||||
try:
|
try:
|
||||||
# import module to obtain type annotation
|
# import module to obtain type annotation
|
||||||
self.parent = importlib.import_module(self.modname)
|
self.parent = importlib.import_module(self.modname)
|
||||||
@ -1599,8 +1616,11 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
|
|||||||
sourcename)
|
sourcename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
objrepr = object_description(self.object)
|
if self.object is INSTANCEATTR:
|
||||||
self.add_line(' :value: ' + objrepr, sourcename)
|
pass
|
||||||
|
else:
|
||||||
|
objrepr = object_description(self.object)
|
||||||
|
self.add_line(' :value: ' + objrepr, sourcename)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
elif self.options.annotation is SUPPRESS:
|
elif self.options.annotation is SUPPRESS:
|
||||||
@ -1671,6 +1691,7 @@ class InstanceAttributeDocumenter(AttributeDocumenter):
|
|||||||
"""Never import anything."""
|
"""Never import anything."""
|
||||||
# disguise as an attribute
|
# disguise as an attribute
|
||||||
self.objtype = 'attribute'
|
self.objtype = 'attribute'
|
||||||
|
self.object = INSTANCEATTR
|
||||||
self._datadescriptor = False
|
self._datadescriptor = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -224,8 +224,10 @@ class Autosummary(SphinxDirective):
|
|||||||
final_argument_whitespace = False
|
final_argument_whitespace = False
|
||||||
has_content = True
|
has_content = True
|
||||||
option_spec = {
|
option_spec = {
|
||||||
|
'caption': directives.unchanged_required,
|
||||||
'toctree': directives.unchanged,
|
'toctree': directives.unchanged,
|
||||||
'nosignatures': directives.flag,
|
'nosignatures': directives.flag,
|
||||||
|
'recursive': directives.flag,
|
||||||
'template': directives.unchanged,
|
'template': directives.unchanged,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,9 +268,14 @@ class Autosummary(SphinxDirective):
|
|||||||
tocnode['entries'] = [(None, docn) for docn in docnames]
|
tocnode['entries'] = [(None, docn) for docn in docnames]
|
||||||
tocnode['maxdepth'] = -1
|
tocnode['maxdepth'] = -1
|
||||||
tocnode['glob'] = None
|
tocnode['glob'] = None
|
||||||
|
tocnode['caption'] = self.options.get('caption')
|
||||||
|
|
||||||
nodes.append(autosummary_toc('', '', tocnode))
|
nodes.append(autosummary_toc('', '', tocnode))
|
||||||
|
|
||||||
|
if 'toctree' not in self.options and 'caption' in self.options:
|
||||||
|
logger.warning(__('A captioned autosummary requires :toctree: option. ignored.'),
|
||||||
|
location=nodes[-1])
|
||||||
|
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]:
|
def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]:
|
||||||
@ -741,8 +748,7 @@ def process_generate_options(app: Sphinx) -> None:
|
|||||||
|
|
||||||
imported_members = app.config.autosummary_imported_members
|
imported_members = app.config.autosummary_imported_members
|
||||||
with mock(app.config.autosummary_mock_imports):
|
with mock(app.config.autosummary_mock_imports):
|
||||||
generate_autosummary_docs(genfiles, builder=app.builder,
|
generate_autosummary_docs(genfiles, suffix=suffix, base_path=app.srcdir,
|
||||||
suffix=suffix, base_path=app.srcdir,
|
|
||||||
app=app, imported_members=imported_members,
|
app=app, imported_members=imported_members,
|
||||||
overwrite=app.config.autosummary_generate_overwrite)
|
overwrite=app.config.autosummary_generate_overwrite)
|
||||||
|
|
||||||
|
@ -20,29 +20,34 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import locale
|
import locale
|
||||||
import os
|
import os
|
||||||
|
import pkgutil
|
||||||
import pydoc
|
import pydoc
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple, Type
|
from gettext import NullTranslations
|
||||||
|
from os import path
|
||||||
|
from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple, Type, Union
|
||||||
|
|
||||||
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
|
||||||
import sphinx.locale
|
import sphinx.locale
|
||||||
from sphinx import __display_version__
|
from sphinx import __display_version__
|
||||||
from sphinx import package_dir
|
from sphinx import package_dir
|
||||||
|
from sphinx.application import Sphinx
|
||||||
from sphinx.builders import Builder
|
from sphinx.builders import Builder
|
||||||
|
from sphinx.config import Config
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||||
from sphinx.ext.autodoc import Documenter
|
from sphinx.ext.autodoc import Documenter
|
||||||
from sphinx.ext.autosummary import import_by_name, get_documenter
|
from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||||
from sphinx.jinja2glue import BuiltinTemplateLoader
|
|
||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.registry import SphinxComponentRegistry
|
from sphinx.registry import SphinxComponentRegistry
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util import rst
|
from sphinx.util import rst
|
||||||
from sphinx.util.inspect import safe_getattr
|
from sphinx.util.inspect import safe_getattr
|
||||||
from sphinx.util.osutil import ensuredir
|
from sphinx.util.osutil import ensuredir
|
||||||
|
from sphinx.util.template import SphinxTemplateLoader
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -51,20 +56,26 @@ logger = logging.getLogger(__name__)
|
|||||||
class DummyApplication:
|
class DummyApplication:
|
||||||
"""Dummy Application class for sphinx-autogen command."""
|
"""Dummy Application class for sphinx-autogen command."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self, translator: NullTranslations) -> None:
|
||||||
|
self.config = Config()
|
||||||
self.registry = SphinxComponentRegistry()
|
self.registry = SphinxComponentRegistry()
|
||||||
self.messagelog = [] # type: List[str]
|
self.messagelog = [] # type: List[str]
|
||||||
|
self.srcdir = "/"
|
||||||
|
self.translator = translator
|
||||||
self.verbosity = 0
|
self.verbosity = 0
|
||||||
self._warncount = 0
|
self._warncount = 0
|
||||||
self.warningiserror = False
|
self.warningiserror = False
|
||||||
|
|
||||||
|
self.config.init_values()
|
||||||
|
|
||||||
def emit_firstresult(self, *args: Any) -> None:
|
def emit_firstresult(self, *args: Any) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
||||||
('path', str),
|
('path', str),
|
||||||
('template', str)])
|
('template', str),
|
||||||
|
('recursive', bool)])
|
||||||
|
|
||||||
|
|
||||||
def setup_documenters(app: Any) -> None:
|
def setup_documenters(app: Any) -> None:
|
||||||
@ -103,39 +114,59 @@ def _underline(title: str, line: str = '=') -> str:
|
|||||||
class AutosummaryRenderer:
|
class AutosummaryRenderer:
|
||||||
"""A helper class for rendering."""
|
"""A helper class for rendering."""
|
||||||
|
|
||||||
def __init__(self, builder: Builder, template_dir: str) -> None:
|
def __init__(self, app: Union[Builder, Sphinx], template_dir: str = None) -> None:
|
||||||
loader = None # type: BaseLoader
|
if isinstance(app, Builder):
|
||||||
template_dirs = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
warnings.warn('The first argument for AutosummaryRenderer has been '
|
||||||
if builder is None:
|
'changed to Sphinx object',
|
||||||
if template_dir:
|
RemovedInSphinx50Warning, stacklevel=2)
|
||||||
template_dirs.insert(0, template_dir)
|
if template_dir:
|
||||||
loader = FileSystemLoader(template_dirs)
|
warnings.warn('template_dir argument for AutosummaryRenderer is deprecated.',
|
||||||
else:
|
RemovedInSphinx50Warning)
|
||||||
# allow the user to override the templates
|
|
||||||
loader = BuiltinTemplateLoader()
|
system_templates_path = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')]
|
||||||
loader.init(builder, dirs=template_dirs)
|
loader = SphinxTemplateLoader(app.srcdir, app.config.templates_path,
|
||||||
|
system_templates_path)
|
||||||
|
|
||||||
self.env = SandboxedEnvironment(loader=loader)
|
self.env = SandboxedEnvironment(loader=loader)
|
||||||
self.env.filters['escape'] = rst.escape
|
self.env.filters['escape'] = rst.escape
|
||||||
self.env.filters['e'] = rst.escape
|
self.env.filters['e'] = rst.escape
|
||||||
self.env.filters['underline'] = _underline
|
self.env.filters['underline'] = _underline
|
||||||
|
|
||||||
if builder:
|
if isinstance(app, (Sphinx, DummyApplication)):
|
||||||
if builder.app.translator:
|
if app.translator:
|
||||||
self.env.add_extension("jinja2.ext.i18n")
|
self.env.add_extension("jinja2.ext.i18n")
|
||||||
self.env.install_gettext_translations(builder.app.translator) # type: ignore
|
self.env.install_gettext_translations(app.translator) # type: ignore
|
||||||
|
elif isinstance(app, Builder):
|
||||||
|
if app.app.translator:
|
||||||
|
self.env.add_extension("jinja2.ext.i18n")
|
||||||
|
self.env.install_gettext_translations(app.app.translator) # type: ignore
|
||||||
|
|
||||||
def exists(self, template_name: str) -> bool:
|
def exists(self, template_name: str) -> bool:
|
||||||
"""Check if template file exists."""
|
"""Check if template file exists."""
|
||||||
|
warnings.warn('AutosummaryRenderer.exists() is deprecated.',
|
||||||
|
RemovedInSphinx50Warning, stacklevel=2)
|
||||||
try:
|
try:
|
||||||
self.env.get_template(template_name)
|
self.env.get_template(template_name)
|
||||||
return True
|
return True
|
||||||
except TemplateNotFound:
|
except TemplateNotFound:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def render(self, template_name: str, context: Dict) -> str:
|
def render(self, objtype: str, context: Dict) -> str:
|
||||||
"""Render a template file."""
|
"""Render a template file."""
|
||||||
return self.env.get_template(template_name).render(context)
|
if objtype.endswith('.rst'):
|
||||||
|
# old styled: template_name is given
|
||||||
|
warnings.warn('AutosummaryRenderer.render() takes an object type as an argument.',
|
||||||
|
RemovedInSphinx50Warning, stacklevel=2)
|
||||||
|
return self.env.get_template(objtype).render(context)
|
||||||
|
else:
|
||||||
|
# objtype is given
|
||||||
|
try:
|
||||||
|
template = self.env.get_template('autosummary/%s.rst' % objtype)
|
||||||
|
except TemplateNotFound:
|
||||||
|
# fallback to base.rst
|
||||||
|
template = self.env.get_template('autosummary/base.rst')
|
||||||
|
|
||||||
|
return template.render(context)
|
||||||
|
|
||||||
|
|
||||||
# -- Generating output ---------------------------------------------------------
|
# -- Generating output ---------------------------------------------------------
|
||||||
@ -143,14 +174,10 @@ class AutosummaryRenderer:
|
|||||||
|
|
||||||
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||||
template: AutosummaryRenderer, template_name: str,
|
template: AutosummaryRenderer, template_name: str,
|
||||||
imported_members: bool, app: Any) -> str:
|
imported_members: bool, app: Any,
|
||||||
|
recursive: bool) -> str:
|
||||||
doc = get_documenter(app, obj, parent)
|
doc = get_documenter(app, obj, parent)
|
||||||
|
|
||||||
if template_name is None:
|
|
||||||
template_name = 'autosummary/%s.rst' % doc.objtype
|
|
||||||
if not template.exists(template_name):
|
|
||||||
template_name = 'autosummary/base.rst'
|
|
||||||
|
|
||||||
def skip_member(obj: Any, name: str, objtype: str) -> bool:
|
def skip_member(obj: Any, name: str, objtype: str) -> bool:
|
||||||
try:
|
try:
|
||||||
return app.emit_firstresult('autodoc-skip-member', objtype, name,
|
return app.emit_firstresult('autodoc-skip-member', objtype, name,
|
||||||
@ -188,6 +215,14 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
public.append(name)
|
public.append(name)
|
||||||
return public, items
|
return public, items
|
||||||
|
|
||||||
|
def get_modules(obj: Any) -> Tuple[List[str], List[str]]:
|
||||||
|
items = [] # type: List[str]
|
||||||
|
for _, modname, ispkg in pkgutil.iter_modules(obj.__path__):
|
||||||
|
fullname = name + '.' + modname
|
||||||
|
items.append(fullname)
|
||||||
|
public = [x for x in items if not x.split('.')[-1].startswith('_')]
|
||||||
|
return public, items
|
||||||
|
|
||||||
ns = {} # type: Dict[str, Any]
|
ns = {} # type: Dict[str, Any]
|
||||||
|
|
||||||
if doc.objtype == 'module':
|
if doc.objtype == 'module':
|
||||||
@ -198,6 +233,9 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
get_members(obj, {'class'}, imported=imported_members)
|
get_members(obj, {'class'}, imported=imported_members)
|
||||||
ns['exceptions'], ns['all_exceptions'] = \
|
ns['exceptions'], ns['all_exceptions'] = \
|
||||||
get_members(obj, {'exception'}, imported=imported_members)
|
get_members(obj, {'exception'}, imported=imported_members)
|
||||||
|
ispackage = hasattr(obj, '__path__')
|
||||||
|
if ispackage and recursive:
|
||||||
|
ns['modules'], ns['all_modules'] = get_modules(obj)
|
||||||
elif doc.objtype == 'class':
|
elif doc.objtype == 'class':
|
||||||
ns['members'] = dir(obj)
|
ns['members'] = dir(obj)
|
||||||
ns['inherited_members'] = \
|
ns['inherited_members'] = \
|
||||||
@ -224,7 +262,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
|||||||
ns['objtype'] = doc.objtype
|
ns['objtype'] = doc.objtype
|
||||||
ns['underline'] = len(name) * '='
|
ns['underline'] = len(name) * '='
|
||||||
|
|
||||||
return template.render(template_name, ns)
|
return template.render(doc.objtype, ns)
|
||||||
|
|
||||||
|
|
||||||
def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||||
@ -247,6 +285,14 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
|||||||
else:
|
else:
|
||||||
_warn = logger.warning
|
_warn = logger.warning
|
||||||
|
|
||||||
|
if builder:
|
||||||
|
warnings.warn('builder argument for generate_autosummary_docs() is deprecated.',
|
||||||
|
RemovedInSphinx50Warning)
|
||||||
|
|
||||||
|
if template_dir:
|
||||||
|
warnings.warn('template_dir argument for generate_autosummary_docs() is deprecated.',
|
||||||
|
RemovedInSphinx50Warning)
|
||||||
|
|
||||||
showed_sources = list(sorted(sources))
|
showed_sources = list(sorted(sources))
|
||||||
if len(showed_sources) > 20:
|
if len(showed_sources) > 20:
|
||||||
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
||||||
@ -259,7 +305,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
|||||||
if base_path is not None:
|
if base_path is not None:
|
||||||
sources = [os.path.join(base_path, filename) for filename in sources]
|
sources = [os.path.join(base_path, filename) for filename in sources]
|
||||||
|
|
||||||
template = AutosummaryRenderer(builder, template_dir)
|
template = AutosummaryRenderer(app)
|
||||||
|
|
||||||
# read
|
# read
|
||||||
items = find_autosummary_in_files(sources)
|
items = find_autosummary_in_files(sources)
|
||||||
@ -284,7 +330,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
content = generate_autosummary_content(name, obj, parent, template, entry.template,
|
content = generate_autosummary_content(name, obj, parent, template, entry.template,
|
||||||
imported_members, app)
|
imported_members, app, entry.recursive)
|
||||||
|
|
||||||
filename = os.path.join(path, name + suffix)
|
filename = os.path.join(path, name + suffix)
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
@ -306,8 +352,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
|||||||
if new_files:
|
if new_files:
|
||||||
generate_autosummary_docs(new_files, output_dir=output_dir,
|
generate_autosummary_docs(new_files, output_dir=output_dir,
|
||||||
suffix=suffix, warn=warn, info=info,
|
suffix=suffix, warn=warn, info=info,
|
||||||
base_path=base_path, builder=builder,
|
base_path=base_path,
|
||||||
template_dir=template_dir,
|
|
||||||
imported_members=imported_members, app=app,
|
imported_members=imported_members, app=app,
|
||||||
overwrite=overwrite)
|
overwrite=overwrite)
|
||||||
|
|
||||||
@ -369,11 +414,13 @@ def find_autosummary_in_lines(lines: List[str], module: str = None, filename: st
|
|||||||
module_re = re.compile(
|
module_re = re.compile(
|
||||||
r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
r'^\s*\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
||||||
autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
|
autosummary_item_re = re.compile(r'^\s+(~?[_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
|
||||||
|
recursive_arg_re = re.compile(r'^\s+:recursive:\s*$')
|
||||||
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
||||||
template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$')
|
template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$')
|
||||||
|
|
||||||
documented = [] # type: List[AutosummaryEntry]
|
documented = [] # type: List[AutosummaryEntry]
|
||||||
|
|
||||||
|
recursive = False
|
||||||
toctree = None # type: str
|
toctree = None # type: str
|
||||||
template = None
|
template = None
|
||||||
current_module = module
|
current_module = module
|
||||||
@ -382,6 +429,11 @@ def find_autosummary_in_lines(lines: List[str], module: str = None, filename: st
|
|||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if in_autosummary:
|
if in_autosummary:
|
||||||
|
m = recursive_arg_re.match(line)
|
||||||
|
if m:
|
||||||
|
recursive = True
|
||||||
|
continue
|
||||||
|
|
||||||
m = toctree_arg_re.match(line)
|
m = toctree_arg_re.match(line)
|
||||||
if m:
|
if m:
|
||||||
toctree = m.group(1)
|
toctree = m.group(1)
|
||||||
@ -406,7 +458,7 @@ def find_autosummary_in_lines(lines: List[str], module: str = None, filename: st
|
|||||||
if current_module and \
|
if current_module and \
|
||||||
not name.startswith(current_module + '.'):
|
not name.startswith(current_module + '.'):
|
||||||
name = "%s.%s" % (current_module, name)
|
name = "%s.%s" % (current_module, name)
|
||||||
documented.append(AutosummaryEntry(name, toctree, template))
|
documented.append(AutosummaryEntry(name, toctree, template, recursive))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not line.strip() or line.startswith(base_indent + " "):
|
if not line.strip() or line.startswith(base_indent + " "):
|
||||||
@ -418,6 +470,7 @@ def find_autosummary_in_lines(lines: List[str], module: str = None, filename: st
|
|||||||
if m:
|
if m:
|
||||||
in_autosummary = True
|
in_autosummary = True
|
||||||
base_indent = m.group(1)
|
base_indent = m.group(1)
|
||||||
|
recursive = False
|
||||||
toctree = None
|
toctree = None
|
||||||
template = None
|
template = None
|
||||||
continue
|
continue
|
||||||
@ -483,14 +536,18 @@ The format of the autosummary directive is documented in the
|
|||||||
def main(argv: List[str] = sys.argv[1:]) -> None:
|
def main(argv: List[str] = sys.argv[1:]) -> None:
|
||||||
sphinx.locale.setlocale(locale.LC_ALL, '')
|
sphinx.locale.setlocale(locale.LC_ALL, '')
|
||||||
sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx')
|
sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx')
|
||||||
|
translator, _ = sphinx.locale.init([], None)
|
||||||
|
|
||||||
app = DummyApplication()
|
app = DummyApplication(translator)
|
||||||
logging.setup(app, sys.stdout, sys.stderr) # type: ignore
|
logging.setup(app, sys.stdout, sys.stderr) # type: ignore
|
||||||
setup_documenters(app)
|
setup_documenters(app)
|
||||||
args = get_parser().parse_args(argv)
|
args = get_parser().parse_args(argv)
|
||||||
|
|
||||||
|
if args.templates:
|
||||||
|
app.config.templates_path.append(path.abspath(args.templates))
|
||||||
|
|
||||||
generate_autosummary_docs(args.source_file, args.output_dir,
|
generate_autosummary_docs(args.source_file, args.output_dir,
|
||||||
'.' + args.suffix,
|
'.' + args.suffix,
|
||||||
template_dir=args.templates,
|
|
||||||
imported_members=args.imported_members,
|
imported_members=args.imported_members,
|
||||||
app=app)
|
app=app)
|
||||||
|
|
||||||
|
@ -34,3 +34,16 @@
|
|||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modules %}
|
||||||
|
{% if modules %}
|
||||||
|
.. rubric:: Modules
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree:
|
||||||
|
:recursive:
|
||||||
|
{% for item in modules %}
|
||||||
|
{{ item }}
|
||||||
|
{%- endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
from typing import Any, Iterable
|
from typing import Any, Iterable, Optional
|
||||||
|
|
||||||
|
|
||||||
class peek_iter:
|
class peek_iter:
|
||||||
@ -62,7 +62,7 @@ class peek_iter:
|
|||||||
def __next__(self, n: int = None) -> Any:
|
def __next__(self, n: int = None) -> Any:
|
||||||
return self.next(n)
|
return self.next(n)
|
||||||
|
|
||||||
def _fillcache(self, n: int) -> None:
|
def _fillcache(self, n: Optional[int]) -> None:
|
||||||
"""Cache `n` items. If `n` is 0 or None, then 1 item is cached."""
|
"""Cache `n` items. If `n` is 0 or None, then 1 item is cached."""
|
||||||
if not n:
|
if not n:
|
||||||
n = 1
|
n = 1
|
||||||
@ -123,7 +123,7 @@ class peek_iter:
|
|||||||
result = [self._cache.popleft() for i in range(n)]
|
result = [self._cache.popleft() for i in range(n)]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def peek(self, n: int = None) -> Any:
|
def peek(self, n: Optional[int] = None) -> Any:
|
||||||
"""Preview the next item or `n` items of the iterator.
|
"""Preview the next item or `n` items of the iterator.
|
||||||
|
|
||||||
The iterator is not advanced when peek is called.
|
The iterator is not advanced when peek is called.
|
||||||
@ -220,7 +220,7 @@ class modify_iter(peek_iter):
|
|||||||
'modifier must be callable')
|
'modifier must be callable')
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
|
|
||||||
def _fillcache(self, n: int) -> None:
|
def _fillcache(self, n: Optional[int]) -> None:
|
||||||
"""Cache `n` modified items. If `n` is 0 or None, 1 item is cached.
|
"""Cache `n` modified items. If `n` is 0 or None, 1 item is cached.
|
||||||
|
|
||||||
Each item returned by the iterator is passed through the
|
Each item returned by the iterator is passed through the
|
||||||
|
@ -12,7 +12,7 @@ import gettext
|
|||||||
import locale
|
import locale
|
||||||
from collections import UserString, defaultdict
|
from collections import UserString, defaultdict
|
||||||
from gettext import NullTranslations
|
from gettext import NullTranslations
|
||||||
from typing import Any, Callable, Dict, Iterable, List, Tuple, Union
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
|
|
||||||
class _TranslationProxy(UserString):
|
class _TranslationProxy(UserString):
|
||||||
@ -173,7 +173,7 @@ def init_console(locale_dir: str, catalog: str) -> Tuple[NullTranslations, bool]
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# encoding is ignored
|
# encoding is ignored
|
||||||
language, _ = locale.getlocale(locale.LC_MESSAGES)
|
language, _ = locale.getlocale(locale.LC_MESSAGES) # type: Tuple[Optional[str], Any]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# LC_MESSAGES is not always defined. Fallback to the default language
|
# LC_MESSAGES is not always defined. Fallback to the default language
|
||||||
# in case it is not.
|
# in case it is not.
|
||||||
|
@ -58,7 +58,7 @@ def parse(code: str, mode: str = 'exec') -> "ast.AST":
|
|||||||
return ast.parse(code, mode=mode)
|
return ast.parse(code, mode=mode)
|
||||||
|
|
||||||
|
|
||||||
def unparse(node: ast.AST) -> str:
|
def unparse(node: Optional[ast.AST]) -> Optional[str]:
|
||||||
"""Unparse an AST to string."""
|
"""Unparse an AST to string."""
|
||||||
if node is None:
|
if node is None:
|
||||||
return None
|
return None
|
||||||
@ -138,7 +138,7 @@ def _unparse_arg(arg: ast.arg, default: Optional[ast.AST]) -> str:
|
|||||||
|
|
||||||
def unparse_arguments(node: ast.arguments) -> str:
|
def unparse_arguments(node: ast.arguments) -> str:
|
||||||
"""Unparse an arguments to string."""
|
"""Unparse an arguments to string."""
|
||||||
defaults = list(node.defaults)
|
defaults = list(node.defaults) # type: List[Optional[ast.AST]]
|
||||||
positionals = len(node.args)
|
positionals = len(node.args)
|
||||||
posonlyargs = 0
|
posonlyargs = 0
|
||||||
if hasattr(node, "posonlyargs"): # for py38+
|
if hasattr(node, "posonlyargs"): # for py38+
|
||||||
@ -147,7 +147,7 @@ def unparse_arguments(node: ast.arguments) -> str:
|
|||||||
for _ in range(len(defaults), positionals):
|
for _ in range(len(defaults), positionals):
|
||||||
defaults.insert(0, None)
|
defaults.insert(0, None)
|
||||||
|
|
||||||
kw_defaults = list(node.kw_defaults)
|
kw_defaults = list(node.kw_defaults) # type: List[Optional[ast.AST]]
|
||||||
for _ in range(len(kw_defaults), len(node.kwonlyargs)):
|
for _ in range(len(kw_defaults), len(node.kwonlyargs)):
|
||||||
kw_defaults.insert(0, None)
|
kw_defaults.insert(0, None)
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
|
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
|
||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
#}
|
#}
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% set title = _('Index') %}
|
||||||
|
|
||||||
{% macro indexentries(firstname, links) %}
|
{% macro indexentries(firstname, links) %}
|
||||||
{%- if links -%}
|
{%- if links -%}
|
||||||
<a href="{{ links[0][1] }}">
|
<a href="{{ links[0][1] }}">
|
||||||
@ -26,8 +29,6 @@
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{%- extends "layout.html" %}
|
|
||||||
{% set title = _('Index') %}
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
<h1 id="index">{{ _('Index') }}</h1>
|
<h1 id="index">{{ _('Index') }}</h1>
|
||||||
|
@ -181,6 +181,7 @@
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
<div class="body" role="main">
|
<div class="body" role="main">
|
||||||
{% block body %} {% endblock %}
|
{% block body %} {% endblock %}
|
||||||
|
<div class="clearer"></div>
|
||||||
</div>
|
</div>
|
||||||
{%- if render_sidebar %}
|
{%- if render_sidebar %}
|
||||||
</div>
|
</div>
|
||||||
@ -208,7 +209,7 @@
|
|||||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if show_sphinx %}
|
{%- if show_sphinx %}
|
||||||
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
|
{% trans sphinx_version=sphinx_version|e %}Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
|
@ -321,13 +321,14 @@ div.sidebar {
|
|||||||
width: 40%;
|
width: 40%;
|
||||||
float: right;
|
float: right;
|
||||||
clear: right;
|
clear: right;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.sidebar-title {
|
p.sidebar-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.admonition, div.topic, pre {
|
div.admonition, div.topic, pre, div[class|="highlight"] {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +338,7 @@ div.topic {
|
|||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
padding: 7px 7px 0 7px;
|
padding: 7px 7px 0 7px;
|
||||||
margin: 10px 0 10px 0;
|
margin: 10px 0 10px 0;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.topic-title {
|
p.topic-title {
|
||||||
@ -351,6 +353,7 @@ div.admonition {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.admonition dt {
|
div.admonition dt {
|
||||||
|
@ -338,10 +338,14 @@ class BaseParser:
|
|||||||
self.pos = self.end
|
self.pos = self.end
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
def assert_end(self) -> None:
|
def assert_end(self, *, allowSemicolon: bool = False) -> None:
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
if not self.eof:
|
if allowSemicolon:
|
||||||
self.fail('Expected end of definition.')
|
if not self.eof and self.definition[self.pos:] != ';':
|
||||||
|
self.fail('Expected end of definition or ;.')
|
||||||
|
else:
|
||||||
|
if not self.eof:
|
||||||
|
self.fail('Expected end of definition.')
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import base64
|
|||||||
import imghdr
|
import imghdr
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from os import path
|
from os import path
|
||||||
from typing import IO, NamedTuple, Tuple
|
from typing import IO, NamedTuple, Optional, Tuple
|
||||||
|
|
||||||
import imagesize
|
import imagesize
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ DataURI = NamedTuple('DataURI', [('mimetype', str),
|
|||||||
('data', bytes)])
|
('data', bytes)])
|
||||||
|
|
||||||
|
|
||||||
def get_image_size(filename: str) -> Tuple[int, int]:
|
def get_image_size(filename: str) -> Optional[Tuple[int, int]]:
|
||||||
try:
|
try:
|
||||||
size = imagesize.get(filename)
|
size = imagesize.get(filename)
|
||||||
if size[0] == -1:
|
if size[0] == -1:
|
||||||
@ -53,7 +53,7 @@ def get_image_size(filename: str) -> Tuple[int, int]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def guess_mimetype_for_stream(stream: IO, default: str = None) -> str:
|
def guess_mimetype_for_stream(stream: IO, default: Optional[str] = None) -> Optional[str]:
|
||||||
imgtype = imghdr.what(stream) # type: ignore
|
imgtype = imghdr.what(stream) # type: ignore
|
||||||
if imgtype:
|
if imgtype:
|
||||||
return 'image/' + imgtype
|
return 'image/' + imgtype
|
||||||
@ -61,7 +61,7 @@ def guess_mimetype_for_stream(stream: IO, default: str = None) -> str:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def guess_mimetype(filename: str = '', default: str = None) -> str:
|
def guess_mimetype(filename: str = '', default: Optional[str] = None) -> Optional[str]:
|
||||||
_, ext = path.splitext(filename.lower())
|
_, ext = path.splitext(filename.lower())
|
||||||
if ext in mime_suffixes:
|
if ext in mime_suffixes:
|
||||||
return mime_suffixes[ext]
|
return mime_suffixes[ext]
|
||||||
@ -72,7 +72,7 @@ def guess_mimetype(filename: str = '', default: str = None) -> str:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def get_image_extension(mimetype: str) -> str:
|
def get_image_extension(mimetype: str) -> Optional[str]:
|
||||||
for ext, _mimetype in mime_suffixes.items():
|
for ext, _mimetype in mime_suffixes.items():
|
||||||
if mimetype == _mimetype:
|
if mimetype == _mimetype:
|
||||||
return ext
|
return ext
|
||||||
@ -80,7 +80,7 @@ def get_image_extension(mimetype: str) -> str:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def parse_data_uri(uri: str) -> DataURI:
|
def parse_data_uri(uri: str) -> Optional[DataURI]:
|
||||||
if not uri.startswith('data:'):
|
if not uri.startswith('data:'):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ def parse_data_uri(uri: str) -> DataURI:
|
|||||||
return DataURI(mimetype, charset, image_data)
|
return DataURI(mimetype, charset, image_data)
|
||||||
|
|
||||||
|
|
||||||
def test_svg(h: bytes, f: IO) -> str:
|
def test_svg(h: bytes, f: IO) -> Optional[str]:
|
||||||
"""An additional imghdr library helper; test the header is SVG's or not."""
|
"""An additional imghdr library helper; test the header is SVG's or not."""
|
||||||
try:
|
try:
|
||||||
if '<svg' in h.decode().lower():
|
if '<svg' in h.decode().lower():
|
||||||
|
@ -20,7 +20,7 @@ from inspect import ( # NOQA
|
|||||||
Parameter, isclass, ismethod, ismethoddescriptor
|
Parameter, isclass, ismethod, ismethoddescriptor
|
||||||
)
|
)
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from typing import Any, Callable, Mapping, List, Tuple
|
from typing import Any, Callable, Mapping, List, Optional, Tuple
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||||
@ -565,7 +565,7 @@ class Signature:
|
|||||||
self.partialmethod_with_noargs = False
|
self.partialmethod_with_noargs = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.signature = inspect.signature(subject)
|
self.signature = inspect.signature(subject) # type: Optional[inspect.Signature]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Until python 3.6.4, cpython has been crashed on inspection for
|
# Until python 3.6.4, cpython has been crashed on inspection for
|
||||||
# partialmethods not having any arguments.
|
# partialmethods not having any arguments.
|
||||||
|
@ -18,7 +18,7 @@ import sys
|
|||||||
import warnings
|
import warnings
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Any, Generator, Iterator, List, Tuple, Type
|
from typing import Any, Generator, Iterator, List, Optional, Tuple, Type
|
||||||
|
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ class FileAvoidWrite:
|
|||||||
"""
|
"""
|
||||||
def __init__(self, path: str) -> None:
|
def __init__(self, path: str) -> None:
|
||||||
self._path = path
|
self._path = path
|
||||||
self._io = None # type: StringIO
|
self._io = None # type: Optional[StringIO]
|
||||||
|
|
||||||
def write(self, data: str) -> None:
|
def write(self, data: str) -> None:
|
||||||
if not self._io:
|
if not self._io:
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import struct
|
import struct
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
LEN_IEND = 12
|
LEN_IEND = 12
|
||||||
@ -20,7 +21,7 @@ DEPTH_CHUNK_START = b'tEXtDepth\x00'
|
|||||||
IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82'
|
IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82'
|
||||||
|
|
||||||
|
|
||||||
def read_png_depth(filename: str) -> int:
|
def read_png_depth(filename: str) -> Optional[int]:
|
||||||
"""Read the special tEXt chunk indicating the depth from a PNG file."""
|
"""Read the special tEXt chunk indicating the depth from a PNG file."""
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
f.seek(- (LEN_IEND + LEN_DEPTH), 2)
|
f.seek(- (LEN_IEND + LEN_DEPTH), 2)
|
||||||
|
@ -10,8 +10,11 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Dict, List, Union
|
from os import path
|
||||||
|
from typing import Callable, Dict, List, Tuple, Union
|
||||||
|
|
||||||
|
from jinja2 import TemplateNotFound
|
||||||
|
from jinja2.environment import Environment
|
||||||
from jinja2.loaders import BaseLoader
|
from jinja2.loaders import BaseLoader
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
|
||||||
@ -94,3 +97,36 @@ class ReSTRenderer(SphinxRenderer):
|
|||||||
self.env.filters['e'] = rst.escape
|
self.env.filters['e'] = rst.escape
|
||||||
self.env.filters['escape'] = rst.escape
|
self.env.filters['escape'] = rst.escape
|
||||||
self.env.filters['heading'] = rst.heading
|
self.env.filters['heading'] = rst.heading
|
||||||
|
|
||||||
|
|
||||||
|
class SphinxTemplateLoader(BaseLoader):
|
||||||
|
"""A loader supporting template inheritance"""
|
||||||
|
|
||||||
|
def __init__(self, confdir: str, templates_paths: List[str],
|
||||||
|
system_templates_paths: List[str]) -> None:
|
||||||
|
self.loaders = []
|
||||||
|
self.sysloaders = []
|
||||||
|
|
||||||
|
for templates_path in templates_paths:
|
||||||
|
loader = SphinxFileSystemLoader(path.join(confdir, templates_path))
|
||||||
|
self.loaders.append(loader)
|
||||||
|
|
||||||
|
for templates_path in system_templates_paths:
|
||||||
|
loader = SphinxFileSystemLoader(templates_path)
|
||||||
|
self.loaders.append(loader)
|
||||||
|
self.sysloaders.append(loader)
|
||||||
|
|
||||||
|
def get_source(self, environment: Environment, template: str) -> Tuple[str, str, Callable]:
|
||||||
|
if template.startswith('!'):
|
||||||
|
# search a template from ``system_templates_paths``
|
||||||
|
loaders = self.sysloaders
|
||||||
|
template = template[1:]
|
||||||
|
else:
|
||||||
|
loaders = self.loaders
|
||||||
|
|
||||||
|
for loader in loaders:
|
||||||
|
try:
|
||||||
|
return loader.get_source(environment, template)
|
||||||
|
except TemplateNotFound:
|
||||||
|
pass
|
||||||
|
raise TemplateNotFound(template)
|
||||||
|
10
tests/roots/test-domain-c/semicolon.rst
Normal file
10
tests/roots/test-domain-c/semicolon.rst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.. c:member:: int member;
|
||||||
|
.. c:var:: int var;
|
||||||
|
.. c:function:: void f();
|
||||||
|
.. .. c:macro:: NO_SEMICOLON;
|
||||||
|
.. c:struct:: Struct;
|
||||||
|
.. c:union:: Union;
|
||||||
|
.. c:enum:: Enum;
|
||||||
|
.. c:enumerator:: Enumerator;
|
||||||
|
.. c:type:: Type;
|
||||||
|
.. c:type:: int TypeDef;
|
14
tests/roots/test-domain-cpp/semicolon.rst
Normal file
14
tests/roots/test-domain-cpp/semicolon.rst
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.. cpp:class:: Class;
|
||||||
|
.. cpp:struct:: Struct;
|
||||||
|
.. cpp:union:: Union;
|
||||||
|
.. cpp:function:: void f();
|
||||||
|
.. cpp:member:: int member;
|
||||||
|
.. cpp:var:: int var;
|
||||||
|
.. cpp:type:: Type;
|
||||||
|
.. cpp:type:: int TypeDef;
|
||||||
|
.. cpp:type:: Alias = int;
|
||||||
|
.. cpp:concept:: template<typename T> Concept;
|
||||||
|
.. cpp:enum:: Enum;
|
||||||
|
.. cpp:enum-struct:: EnumStruct;
|
||||||
|
.. cpp:enum-class:: EnumClass;
|
||||||
|
.. cpp:enumerator:: Enumerator;
|
@ -3,3 +3,9 @@ def private_function(name):
|
|||||||
|
|
||||||
:meta private:
|
:meta private:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def _public_function(name):
|
||||||
|
"""public_function is a docstring().
|
||||||
|
|
||||||
|
:meta public:
|
||||||
|
"""
|
||||||
|
7
tests/roots/test-ext-autosummary-recursive/conf.py
Normal file
7
tests/roots/test-ext-autosummary-recursive/conf.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
extensions = ['sphinx.ext.autosummary']
|
||||||
|
autosummary_generate = True
|
15
tests/roots/test-ext-autosummary-recursive/index.rst
Normal file
15
tests/roots/test-ext-autosummary-recursive/index.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. rubric:: Packages
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated
|
||||||
|
:recursive:
|
||||||
|
|
||||||
|
package
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated
|
||||||
|
|
||||||
|
package2
|
13
tests/roots/test-ext-autosummary-recursive/package/module.py
Normal file
13
tests/roots/test-ext-autosummary-recursive/package/module.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from os import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bar(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def baz(self):
|
||||||
|
pass
|
@ -0,0 +1,4 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
# Fail module import in a catastrophic way
|
||||||
|
sys.exit(1)
|
@ -0,0 +1,13 @@
|
|||||||
|
from os import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bar(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def baz(self):
|
||||||
|
pass
|
@ -0,0 +1,13 @@
|
|||||||
|
from os import * # NOQA
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def bar(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def baz(self):
|
||||||
|
pass
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
.. autosummary::
|
.. autosummary::
|
||||||
:toctree: generated
|
:toctree: generated
|
||||||
|
:caption: An autosummary
|
||||||
|
|
||||||
autosummary_dummy_module
|
autosummary_dummy_module
|
||||||
autosummary_dummy_module.Foo
|
autosummary_dummy_module.Foo
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
[theme]
|
[theme]
|
||||||
docclass = book
|
docclass = book
|
||||||
wrapperclass = sphinxbook
|
wrapperclass = sphinxbook
|
||||||
|
papersize = a4paper
|
||||||
|
pointsize = 12pt
|
||||||
toplevel_sectioning = chapter
|
toplevel_sectioning = chapter
|
||||||
|
@ -1032,14 +1032,12 @@ def test_instance_attributes(app):
|
|||||||
'',
|
'',
|
||||||
' .. py:attribute:: InstAttCls.ia1',
|
' .. py:attribute:: InstAttCls.ia1',
|
||||||
' :module: target',
|
' :module: target',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' Doc comment for instance attribute InstAttCls.ia1',
|
' Doc comment for instance attribute InstAttCls.ia1',
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
' .. py:attribute:: InstAttCls.ia2',
|
' .. py:attribute:: InstAttCls.ia2',
|
||||||
' :module: target',
|
' :module: target',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' Docstring for instance attribute InstAttCls.ia2.',
|
' Docstring for instance attribute InstAttCls.ia2.',
|
||||||
''
|
''
|
||||||
@ -1066,7 +1064,6 @@ def test_instance_attributes(app):
|
|||||||
'',
|
'',
|
||||||
' .. py:attribute:: InstAttCls.ia1',
|
' .. py:attribute:: InstAttCls.ia1',
|
||||||
' :module: target',
|
' :module: target',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' Doc comment for instance attribute InstAttCls.ia1',
|
' Doc comment for instance attribute InstAttCls.ia1',
|
||||||
''
|
''
|
||||||
@ -1485,7 +1482,6 @@ def test_autodoc_typed_instance_variables(app):
|
|||||||
' .. py:attribute:: Class.attr2',
|
' .. py:attribute:: Class.attr2',
|
||||||
' :module: target.typed_vars',
|
' :module: target.typed_vars',
|
||||||
' :type: int',
|
' :type: int',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
' .. py:attribute:: Class.attr3',
|
' .. py:attribute:: Class.attr3',
|
||||||
@ -1497,7 +1493,6 @@ def test_autodoc_typed_instance_variables(app):
|
|||||||
' .. py:attribute:: Class.attr4',
|
' .. py:attribute:: Class.attr4',
|
||||||
' :module: target.typed_vars',
|
' :module: target.typed_vars',
|
||||||
' :type: int',
|
' :type: int',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' attr4',
|
' attr4',
|
||||||
'',
|
'',
|
||||||
@ -1505,7 +1500,6 @@ def test_autodoc_typed_instance_variables(app):
|
|||||||
' .. py:attribute:: Class.attr5',
|
' .. py:attribute:: Class.attr5',
|
||||||
' :module: target.typed_vars',
|
' :module: target.typed_vars',
|
||||||
' :type: int',
|
' :type: int',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' attr5',
|
' attr5',
|
||||||
'',
|
'',
|
||||||
@ -1513,7 +1507,6 @@ def test_autodoc_typed_instance_variables(app):
|
|||||||
' .. py:attribute:: Class.attr6',
|
' .. py:attribute:: Class.attr6',
|
||||||
' :module: target.typed_vars',
|
' :module: target.typed_vars',
|
||||||
' :type: int',
|
' :type: int',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' attr6',
|
' attr6',
|
||||||
'',
|
'',
|
||||||
@ -1529,7 +1522,6 @@ def test_autodoc_typed_instance_variables(app):
|
|||||||
'.. py:data:: attr2',
|
'.. py:data:: attr2',
|
||||||
' :module: target.typed_vars',
|
' :module: target.typed_vars',
|
||||||
' :type: str',
|
' :type: str',
|
||||||
' :value: None',
|
|
||||||
'',
|
'',
|
||||||
' attr2',
|
' attr2',
|
||||||
'',
|
'',
|
||||||
|
@ -220,7 +220,29 @@ def test_latex_theme(app, status, warning):
|
|||||||
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
||||||
print(result)
|
print(result)
|
||||||
assert r'\def\sphinxdocclass{book}' in result
|
assert r'\def\sphinxdocclass{book}' in result
|
||||||
assert r'\documentclass[letterpaper,10pt,english]{sphinxbook}' in result
|
assert r'\documentclass[a4paper,12pt,english]{sphinxbook}' in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('latex', testroot='latex-theme',
|
||||||
|
confoverrides={'latex_elements': {'papersize': 'b5paper',
|
||||||
|
'pointsize': '9pt'}})
|
||||||
|
def test_latex_theme_papersize(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
||||||
|
print(result)
|
||||||
|
assert r'\def\sphinxdocclass{book}' in result
|
||||||
|
assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('latex', testroot='latex-theme',
|
||||||
|
confoverrides={'latex_theme_options': {'papersize': 'b5paper',
|
||||||
|
'pointsize': '9pt'}})
|
||||||
|
def test_latex_theme_options(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
||||||
|
print(result)
|
||||||
|
assert r'\def\sphinxdocclass{book}' in result
|
||||||
|
assert r'\documentclass[b5paper,9pt,english]{sphinxbook}' in result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
|
@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
|
||||||
|
@ -27,10 +27,8 @@ def parse(name, string):
|
|||||||
return ast
|
return ast
|
||||||
|
|
||||||
|
|
||||||
def check(name, input, idDict, output=None):
|
def _check(name, input, idDict, output):
|
||||||
# first a simple check of the AST
|
# first a simple check of the AST
|
||||||
if output is None:
|
|
||||||
output = input
|
|
||||||
ast = parse(name, input)
|
ast = parse(name, input)
|
||||||
res = str(ast)
|
res = str(ast)
|
||||||
if res != output:
|
if res != output:
|
||||||
@ -77,6 +75,16 @@ def check(name, input, idDict, output=None):
|
|||||||
raise DefinitionError("")
|
raise DefinitionError("")
|
||||||
|
|
||||||
|
|
||||||
|
def check(name, input, idDict, output=None):
|
||||||
|
if output is None:
|
||||||
|
output = input
|
||||||
|
# First, check without semicolon
|
||||||
|
_check(name, input, idDict, output)
|
||||||
|
if name != 'macro':
|
||||||
|
# Second, check with semicolon
|
||||||
|
_check(name, input + ' ;', idDict, output + ';')
|
||||||
|
|
||||||
|
|
||||||
def test_expressions():
|
def test_expressions():
|
||||||
def exprCheck(expr, output=None):
|
def exprCheck(expr, output=None):
|
||||||
class Config:
|
class Config:
|
||||||
@ -469,8 +477,9 @@ def test_build_domain_c(app, status, warning):
|
|||||||
ws = filter_warnings(warning, "index")
|
ws = filter_warnings(warning, "index")
|
||||||
assert len(ws) == 0
|
assert len(ws) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||||
def test_build_domain_c(app, status, warning):
|
def test_build_domain_c_namespace(app, status, warning):
|
||||||
app.builder.build_all()
|
app.builder.build_all()
|
||||||
ws = filter_warnings(warning, "namespace")
|
ws = filter_warnings(warning, "namespace")
|
||||||
assert len(ws) == 0
|
assert len(ws) == 0
|
||||||
@ -478,6 +487,7 @@ def test_build_domain_c(app, status, warning):
|
|||||||
for id_ in ('NS.NSVar', 'NULLVar', 'ZeroVar', 'NS2.NS3.NS2NS3Var', 'PopVar'):
|
for id_ in ('NS.NSVar', 'NULLVar', 'ZeroVar', 'NS2.NS3.NS2NS3Var', 'PopVar'):
|
||||||
assert 'id="c.{}"'.format(id_) in t
|
assert 'id="c.{}"'.format(id_) in t
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||||
def test_build_domain_c_anon_dup_decl(app, status, warning):
|
def test_build_domain_c_anon_dup_decl(app, status, warning):
|
||||||
app.builder.build_all()
|
app.builder.build_all()
|
||||||
@ -487,6 +497,13 @@ def test_build_domain_c_anon_dup_decl(app, status, warning):
|
|||||||
assert "WARNING: c:identifier reference target not found: @b" in ws[1]
|
assert "WARNING: c:identifier reference target not found: @b" in ws[1]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx(testroot='domain-c', confoverrides={'nitpicky': True})
|
||||||
|
def test_build_domain_c_semicolon(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
ws = filter_warnings(warning, "semicolon")
|
||||||
|
assert len(ws) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_cfunction(app):
|
def test_cfunction(app):
|
||||||
text = (".. c:function:: PyObject* "
|
text = (".. c:function:: PyObject* "
|
||||||
"PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)")
|
"PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)")
|
||||||
|
@ -32,10 +32,8 @@ def parse(name, string):
|
|||||||
return ast
|
return ast
|
||||||
|
|
||||||
|
|
||||||
def check(name, input, idDict, output=None):
|
def _check(name, input, idDict, output):
|
||||||
# first a simple check of the AST
|
# first a simple check of the AST
|
||||||
if output is None:
|
|
||||||
output = input
|
|
||||||
ast = parse(name, input)
|
ast = parse(name, input)
|
||||||
res = str(ast)
|
res = str(ast)
|
||||||
if res != output:
|
if res != output:
|
||||||
@ -82,6 +80,15 @@ def check(name, input, idDict, output=None):
|
|||||||
raise DefinitionError("")
|
raise DefinitionError("")
|
||||||
|
|
||||||
|
|
||||||
|
def check(name, input, idDict, output=None):
|
||||||
|
if output is None:
|
||||||
|
output = input
|
||||||
|
# First, check without semicolon
|
||||||
|
_check(name, input, idDict, output)
|
||||||
|
# Second, check with semicolon
|
||||||
|
_check(name, input + ' ;', idDict, output + ';')
|
||||||
|
|
||||||
|
|
||||||
def test_fundamental_types():
|
def test_fundamental_types():
|
||||||
# see https://en.cppreference.com/w/cpp/language/types
|
# see https://en.cppreference.com/w/cpp/language/types
|
||||||
for t, id_v2 in cppDomain._id_fundamental_v2.items():
|
for t, id_v2 in cppDomain._id_fundamental_v2.items():
|
||||||
@ -392,7 +399,7 @@ def test_function_definitions():
|
|||||||
x = 'std::vector<std::pair<std::string, int>> &module::test(register int ' \
|
x = 'std::vector<std::pair<std::string, int>> &module::test(register int ' \
|
||||||
'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
|
'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
|
||||||
check('function', x, {1: "module::test__i.bar.ssC",
|
check('function', x, {1: "module::test__i.bar.ssC",
|
||||||
2: "NK6module4testEi3barNSt6stringE"})
|
2: "NK6module4testEi3barNSt6stringE"})
|
||||||
check('function', 'void f(std::pair<A, B>)',
|
check('function', 'void f(std::pair<A, B>)',
|
||||||
{1: "f__std::pair:A.B:", 2: "1fNSt4pairI1A1BEE"})
|
{1: "f__std::pair:A.B:", 2: "1fNSt4pairI1A1BEE"})
|
||||||
check('function', 'explicit module::myclass::foo::foo()',
|
check('function', 'explicit module::myclass::foo::foo()',
|
||||||
@ -426,6 +433,10 @@ def test_function_definitions():
|
|||||||
{1: "get_valueCE", 2: "9get_valuev"})
|
{1: "get_valueCE", 2: "9get_valuev"})
|
||||||
check('function', 'int get_value() const noexcept',
|
check('function', 'int get_value() const noexcept',
|
||||||
{1: "get_valueC", 2: "NK9get_valueEv"})
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
||||||
|
check('function', 'int get_value() const noexcept(std::is_nothrow_move_constructible<T>::value)',
|
||||||
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
||||||
|
check('function', 'int get_value() const noexcept("see below")',
|
||||||
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
||||||
check('function', 'int get_value() const noexcept = delete',
|
check('function', 'int get_value() const noexcept = delete',
|
||||||
{1: "get_valueC", 2: "NK9get_valueEv"})
|
{1: "get_valueC", 2: "NK9get_valueEv"})
|
||||||
check('function', 'int get_value() volatile const',
|
check('function', 'int get_value() volatile const',
|
||||||
@ -867,7 +878,7 @@ def test_xref_parsing():
|
|||||||
|
|
||||||
|
|
||||||
def filter_warnings(warning, file):
|
def filter_warnings(warning, file):
|
||||||
lines = warning.getvalue().split("\n");
|
lines = warning.getvalue().split("\n")
|
||||||
res = [l for l in lines if "domain-cpp" in l and "{}.rst".format(file) in l and
|
res = [l for l in lines if "domain-cpp" in l and "{}.rst".format(file) in l and
|
||||||
"WARNING: document isn't included in any toctree" not in l]
|
"WARNING: document isn't included in any toctree" not in l]
|
||||||
print("Filtered warnings for file '{}':".format(file))
|
print("Filtered warnings for file '{}':".format(file))
|
||||||
@ -902,6 +913,13 @@ def test_build_domain_cpp_backslash_ok(app, status, warning):
|
|||||||
assert len(ws) == 0
|
assert len(ws) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx(testroot='domain-cpp', confoverrides={'nitpicky': True})
|
||||||
|
def test_build_domain_cpp_semicolon(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
ws = filter_warnings(warning, "semicolon")
|
||||||
|
assert len(ws) == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(testroot='domain-cpp',
|
@pytest.mark.sphinx(testroot='domain-cpp',
|
||||||
confoverrides={'nitpicky': True, 'strip_signature_backslash': True})
|
confoverrides={'nitpicky': True, 'strip_signature_backslash': True})
|
||||||
def test_build_domain_cpp_backslash_ok(app, status, warning):
|
def test_build_domain_cpp_backslash_ok(app, status, warning):
|
||||||
|
@ -22,6 +22,14 @@ def test_private_field(app):
|
|||||||
'',
|
'',
|
||||||
'.. py:module:: target.private',
|
'.. py:module:: target.private',
|
||||||
'',
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: _public_function(name)',
|
||||||
|
' :module: target.private',
|
||||||
|
'',
|
||||||
|
' public_function is a docstring().',
|
||||||
|
'',
|
||||||
|
' :meta public:',
|
||||||
|
'',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -36,6 +44,14 @@ def test_private_field_and_private_members(app):
|
|||||||
'.. py:module:: target.private',
|
'.. py:module:: target.private',
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
|
'.. py:function:: _public_function(name)',
|
||||||
|
' :module: target.private',
|
||||||
|
'',
|
||||||
|
' public_function is a docstring().',
|
||||||
|
'',
|
||||||
|
' :meta public:',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
'.. py:function:: private_function(name)',
|
'.. py:function:: private_function(name)',
|
||||||
' :module: target.private',
|
' :module: target.private',
|
||||||
'',
|
'',
|
||||||
|
@ -19,9 +19,10 @@ from sphinx import addnodes
|
|||||||
from sphinx.ext.autosummary import (
|
from sphinx.ext.autosummary import (
|
||||||
autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary
|
autosummary_table, autosummary_toc, mangle_signature, import_by_name, extract_summary
|
||||||
)
|
)
|
||||||
from sphinx.ext.autosummary.generate import AutosummaryEntry, generate_autosummary_docs
|
from sphinx.ext.autosummary.generate import AutosummaryEntry, generate_autosummary_docs, main as autogen_main
|
||||||
from sphinx.testing.util import assert_node, etree_parse
|
from sphinx.testing.util import assert_node, etree_parse
|
||||||
from sphinx.util.docutils import new_document
|
from sphinx.util.docutils import new_document
|
||||||
|
from sphinx.util.osutil import cd
|
||||||
|
|
||||||
html_warnfile = StringIO()
|
html_warnfile = StringIO()
|
||||||
|
|
||||||
@ -197,7 +198,7 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
nodes.paragraph,
|
nodes.paragraph,
|
||||||
addnodes.tabular_col_spec,
|
addnodes.tabular_col_spec,
|
||||||
autosummary_table,
|
autosummary_table,
|
||||||
autosummary_toc))
|
[autosummary_toc, addnodes.toctree]))
|
||||||
assert_node(doctree[3],
|
assert_node(doctree[3],
|
||||||
[autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec,
|
[autosummary_table, nodes.table, nodes.tgroup, (nodes.colspec,
|
||||||
nodes.colspec,
|
nodes.colspec,
|
||||||
@ -205,6 +206,8 @@ def test_autosummary_generate(app, status, warning):
|
|||||||
nodes.row,
|
nodes.row,
|
||||||
nodes.row,
|
nodes.row,
|
||||||
nodes.row)])])
|
nodes.row)])])
|
||||||
|
assert_node(doctree[4][0], addnodes.toctree, caption="An autosummary")
|
||||||
|
|
||||||
assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n'
|
assert doctree[3][0][0][2][0].astext() == 'autosummary_dummy_module\n\n'
|
||||||
assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n'
|
assert doctree[3][0][0][2][1].astext() == 'autosummary_dummy_module.Foo()\n\n'
|
||||||
assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n'
|
assert doctree[3][0][0][2][2].astext() == 'autosummary_dummy_module.bar(x[, y])\n\n'
|
||||||
@ -259,6 +262,31 @@ def test_autosummary_generate_overwrite2(app_params, make_app):
|
|||||||
assert 'autosummary_dummy_module.rst' not in app._warning.getvalue()
|
assert 'autosummary_dummy_module.rst' not in app._warning.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive')
|
||||||
|
def test_autosummary_recursive(app, status, warning):
|
||||||
|
app.build()
|
||||||
|
|
||||||
|
# autosummary having :recursive: option
|
||||||
|
assert (app.srcdir / 'generated' / 'package.rst').exists()
|
||||||
|
assert (app.srcdir / 'generated' / 'package.module.rst').exists()
|
||||||
|
assert (app.srcdir / 'generated' / 'package.module_importfail.rst').exists() is False
|
||||||
|
assert (app.srcdir / 'generated' / 'package.package.rst').exists()
|
||||||
|
assert (app.srcdir / 'generated' / 'package.package.module.rst').exists()
|
||||||
|
|
||||||
|
# autosummary not having :recursive: option
|
||||||
|
assert (app.srcdir / 'generated' / 'package2.rst').exists()
|
||||||
|
assert (app.srcdir / 'generated' / 'package2.module.rst').exists() is False
|
||||||
|
|
||||||
|
# Check content of recursively generated stub-files
|
||||||
|
content = (app.srcdir / 'generated' / 'package.rst').read_text()
|
||||||
|
assert 'package.module' in content
|
||||||
|
assert 'package.package' in content
|
||||||
|
assert 'package.module_importfail' in content
|
||||||
|
|
||||||
|
content = (app.srcdir / 'generated' / 'package.package.rst').read_text()
|
||||||
|
assert 'package.package.module' in content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('latex', **default_kw)
|
@pytest.mark.sphinx('latex', **default_kw)
|
||||||
def test_autosummary_latex_table_colspec(app, status, warning):
|
def test_autosummary_latex_table_colspec(app, status, warning):
|
||||||
app.builder.build_all()
|
app.builder.build_all()
|
||||||
@ -328,7 +356,7 @@ def test_autosummary_imported_members(app, status, warning):
|
|||||||
@pytest.mark.sphinx(testroot='ext-autodoc')
|
@pytest.mark.sphinx(testroot='ext-autodoc')
|
||||||
def test_generate_autosummary_docs_property(app):
|
def test_generate_autosummary_docs_property(app):
|
||||||
with patch('sphinx.ext.autosummary.generate.find_autosummary_in_files') as mock:
|
with patch('sphinx.ext.autosummary.generate.find_autosummary_in_files') as mock:
|
||||||
mock.return_value = [AutosummaryEntry('target.methods.Base.prop', 'prop', None)]
|
mock.return_value = [AutosummaryEntry('target.methods.Base.prop', 'prop', None, False)]
|
||||||
generate_autosummary_docs([], output_dir=app.srcdir, builder=app.builder, app=app)
|
generate_autosummary_docs([], output_dir=app.srcdir, builder=app.builder, app=app)
|
||||||
|
|
||||||
content = (app.srcdir / 'target.methods.Base.prop.rst').read_text()
|
content = (app.srcdir / 'target.methods.Base.prop.rst').read_text()
|
||||||
@ -361,3 +389,10 @@ def test_empty_autosummary_generate(app, status, warning):
|
|||||||
confoverrides={'autosummary_generate': ['unknown']})
|
confoverrides={'autosummary_generate': ['unknown']})
|
||||||
def test_invalid_autosummary_generate(app, status, warning):
|
def test_invalid_autosummary_generate(app, status, warning):
|
||||||
assert 'WARNING: autosummary_generate: file not found: unknown.rst' in warning.getvalue()
|
assert 'WARNING: autosummary_generate: file not found: unknown.rst' in warning.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
def test_autogen(rootdir, tempdir):
|
||||||
|
with cd(rootdir / 'test-templating'):
|
||||||
|
args = ['-o', tempdir, '-t', '.', 'autosummary_templating.txt']
|
||||||
|
autogen_main(args)
|
||||||
|
assert (tempdir / 'sphinx.application.TemplateBridge.rst').exists()
|
||||||
|
Loading…
Reference in New Issue
Block a user